@syncer/cli
Advanced tools
| #!/usr/bin/env node | ||
| import { | ||
| ensureDir, | ||
| urlToKey | ||
| } from "./chunk-N6JPW7IT.js"; | ||
| import { | ||
| CACHE_DIR | ||
| } from "./chunk-NQISZLI7.js"; | ||
| // src/core/registry.ts | ||
| import fs from "fs"; | ||
| import path from "path"; | ||
| import { simpleGit } from "simple-git"; | ||
| function registryCachePath(registryUrl) { | ||
| return path.join(CACHE_DIR, urlToKey(registryUrl)); | ||
| } | ||
| async function ensureRegistry(registryUrl, version = "latest") { | ||
| ensureDir(CACHE_DIR); | ||
| const cachePath = registryCachePath(registryUrl); | ||
| if (fs.existsSync(cachePath)) { | ||
| return await fetchRegistry(cachePath, registryUrl, version); | ||
| } else { | ||
| return await cloneRegistry(cachePath, registryUrl, version); | ||
| } | ||
| } | ||
| async function cloneRegistry(cachePath, registryUrl, version) { | ||
| const git = simpleGit(); | ||
| const isLatest = version === "latest"; | ||
| try { | ||
| if (isLatest) { | ||
| await git.clone(registryUrl, cachePath, ["--depth=1"]); | ||
| } else { | ||
| await git.clone(registryUrl, cachePath); | ||
| } | ||
| const repoGit = simpleGit(cachePath); | ||
| if (!isLatest) { | ||
| await repoGit.checkout(version); | ||
| } | ||
| const commit = await getCommitHash(repoGit); | ||
| return { cachePath, commit, fromCache: false }; | ||
| } catch (err) { | ||
| if (!fs.existsSync(cachePath)) throw err; | ||
| fs.rmSync(cachePath, { recursive: true, force: true }); | ||
| throw err; | ||
| } | ||
| } | ||
| async function fetchRegistry(cachePath, registryUrl, version) { | ||
| const repoGit = simpleGit(cachePath); | ||
| try { | ||
| await repoGit.fetch(["--prune"]); | ||
| const isLatest = version === "latest"; | ||
| if (isLatest) { | ||
| const defaultBranch = await getDefaultBranch(repoGit); | ||
| await repoGit.checkout(defaultBranch); | ||
| await repoGit.pull(); | ||
| } else { | ||
| await repoGit.checkout(version); | ||
| const isBranchLike = !/^[0-9a-f]{7,40}$/.test(version); | ||
| if (isBranchLike) { | ||
| try { | ||
| await repoGit.pull(); | ||
| } catch { | ||
| } | ||
| } | ||
| } | ||
| const commit = await getCommitHash(repoGit); | ||
| return { cachePath, commit, fromCache: false }; | ||
| } catch { | ||
| const commit = await getCommitHash(repoGit).catch(() => "unknown"); | ||
| return { cachePath, commit, fromCache: true }; | ||
| } | ||
| } | ||
| async function getCommitHash(git) { | ||
| const result = await git.revparse(["HEAD"]); | ||
| return result.trim(); | ||
| } | ||
| async function getDefaultBranch(git) { | ||
| try { | ||
| const result = await git.raw(["symbolic-ref", "refs/remotes/origin/HEAD"]); | ||
| return result.trim().replace("refs/remotes/origin/", ""); | ||
| } catch { | ||
| const branches = await git.branch(["-r"]); | ||
| if (branches.all.includes("origin/main")) return "main"; | ||
| return "master"; | ||
| } | ||
| } | ||
| async function listRegistryTags(registryUrl) { | ||
| const cachePath = registryCachePath(registryUrl); | ||
| if (!fs.existsSync(cachePath)) return []; | ||
| const git = simpleGit(cachePath); | ||
| const tags = await git.tags(); | ||
| return tags.all; | ||
| } | ||
| async function listRegistryBranches(registryUrl) { | ||
| const cachePath = registryCachePath(registryUrl); | ||
| if (!fs.existsSync(cachePath)) return []; | ||
| const git = simpleGit(cachePath); | ||
| const branches = await git.branch(["-r"]); | ||
| return branches.all.map((b) => b.trim().replace(/^origin\//, "")).filter((b) => b !== "HEAD"); | ||
| } | ||
| async function resolveRefType(registryUrl, ref) { | ||
| if (/^[0-9a-f]{7,40}$/.test(ref)) return "commit"; | ||
| const tags = await listRegistryTags(registryUrl); | ||
| if (tags.includes(ref)) return "tag"; | ||
| const branches = await listRegistryBranches(registryUrl); | ||
| if (branches.includes(ref)) return "branch"; | ||
| return null; | ||
| } | ||
| function registryFile(cachePath, ...segments) { | ||
| return path.join(cachePath, ...segments); | ||
| } | ||
| function registryCacheExists(registryUrl) { | ||
| return fs.existsSync(registryCachePath(registryUrl)); | ||
| } | ||
| export { | ||
| registryCachePath, | ||
| ensureRegistry, | ||
| listRegistryTags, | ||
| listRegistryBranches, | ||
| resolveRefType, | ||
| registryFile, | ||
| registryCacheExists | ||
| }; | ||
| //# sourceMappingURL=chunk-36KHT7HY.js.map |
| {"version":3,"sources":["../src/core/registry.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { simpleGit } from \"simple-git\";\nimport { CACHE_DIR } from \"./config.js\";\nimport { ensureDir, urlToKey } from \"../utils/fs.js\";\n\n/** Returns the path to the registry clone for a given URL */\nexport function registryCachePath(registryUrl: string): string {\n return path.join(CACHE_DIR, urlToKey(registryUrl));\n}\n\nexport interface RegistryInfo {\n cachePath: string;\n commit: string;\n fromCache: boolean; // true if offline and using cached version\n}\n\n/**\n * Ensure the registry is cloned/fetched and checked out at the target version.\n * Returns the path to the working tree and the current commit hash.\n */\nexport async function ensureRegistry(\n registryUrl: string,\n version = \"latest\"\n): Promise<RegistryInfo> {\n ensureDir(CACHE_DIR);\n const cachePath = registryCachePath(registryUrl);\n\n if (fs.existsSync(cachePath)) {\n return await fetchRegistry(cachePath, registryUrl, version);\n } else {\n return await cloneRegistry(cachePath, registryUrl, version);\n }\n}\n\nasync function cloneRegistry(\n cachePath: string,\n registryUrl: string,\n version: string\n): Promise<RegistryInfo> {\n const git = simpleGit();\n const isLatest = version === \"latest\";\n\n try {\n if (isLatest) {\n await git.clone(registryUrl, cachePath, [\"--depth=1\"]);\n } else {\n // Full clone needed for tag/commit/branch checkout\n await git.clone(registryUrl, cachePath);\n }\n\n const repoGit = simpleGit(cachePath);\n if (!isLatest) {\n await repoGit.checkout(version);\n }\n\n const commit = await getCommitHash(repoGit);\n return { cachePath, commit, fromCache: false };\n } catch (err) {\n // If clone failed and no cache exists, rethrow\n if (!fs.existsSync(cachePath)) throw err;\n // Partial clone — clean up and rethrow\n fs.rmSync(cachePath, { recursive: true, force: true });\n throw err;\n }\n}\n\nasync function fetchRegistry(\n cachePath: string,\n registryUrl: string,\n version: string\n): Promise<RegistryInfo> {\n const repoGit = simpleGit(cachePath);\n\n try {\n await repoGit.fetch([\"--prune\"]);\n\n const isLatest = version === \"latest\";\n if (isLatest) {\n // Checkout default branch (main or master)\n const defaultBranch = await getDefaultBranch(repoGit);\n await repoGit.checkout(defaultBranch);\n await repoGit.pull();\n } else {\n await repoGit.checkout(version);\n // Pull only if it's a branch (not a tag or commit hash)\n const isBranchLike = !/^[0-9a-f]{7,40}$/.test(version);\n if (isBranchLike) {\n try {\n await repoGit.pull();\n } catch {\n // May not have upstream tracking — ignore\n }\n }\n }\n\n const commit = await getCommitHash(repoGit);\n return { cachePath, commit, fromCache: false };\n } catch {\n // Offline or fetch failed — use whatever is checked out\n const commit = await getCommitHash(repoGit).catch(() => \"unknown\");\n return { cachePath, commit, fromCache: true };\n }\n}\n\nasync function getCommitHash(git: ReturnType<typeof simpleGit>): Promise<string> {\n const result = await git.revparse([\"HEAD\"]);\n return result.trim();\n}\n\nasync function getDefaultBranch(\n git: ReturnType<typeof simpleGit>\n): Promise<string> {\n try {\n // Try to get the symbolic ref of origin/HEAD\n const result = await git.raw([\"symbolic-ref\", \"refs/remotes/origin/HEAD\"]);\n return result.trim().replace(\"refs/remotes/origin/\", \"\");\n } catch {\n // Fallback: try main, then master\n const branches = await git.branch([\"-r\"]);\n if (branches.all.includes(\"origin/main\")) return \"main\";\n return \"master\";\n }\n}\n\n/** List all available tags in the registry */\nexport async function listRegistryTags(\n registryUrl: string\n): Promise<string[]> {\n const cachePath = registryCachePath(registryUrl);\n if (!fs.existsSync(cachePath)) return [];\n const git = simpleGit(cachePath);\n const tags = await git.tags();\n return tags.all;\n}\n\n/** List all remote branches in the registry cache */\nexport async function listRegistryBranches(\n registryUrl: string\n): Promise<string[]> {\n const cachePath = registryCachePath(registryUrl);\n if (!fs.existsSync(cachePath)) return [];\n const git = simpleGit(cachePath);\n const branches = await git.branch([\"-r\"]);\n return branches.all\n .map((b) => b.trim().replace(/^origin\\//, \"\"))\n .filter((b) => b !== \"HEAD\");\n}\n\n/**\n * Determine what type of ref a version string is.\n * Returns null if the ref is not found in the cached registry.\n */\nexport async function resolveRefType(\n registryUrl: string,\n ref: string\n): Promise<\"tag\" | \"branch\" | \"commit\" | null> {\n if (/^[0-9a-f]{7,40}$/.test(ref)) return \"commit\";\n const tags = await listRegistryTags(registryUrl);\n if (tags.includes(ref)) return \"tag\";\n const branches = await listRegistryBranches(registryUrl);\n if (branches.includes(ref)) return \"branch\";\n return null;\n}\n\n/** Read a file from the registry cache */\nexport function registryFile(cachePath: string, ...segments: string[]): string {\n return path.join(cachePath, ...segments);\n}\n\n/** Check if the registry cache exists */\nexport function registryCacheExists(registryUrl: string): boolean {\n return fs.existsSync(registryCachePath(registryUrl));\n}\n"],"mappings":"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","names":[]} |
| #!/usr/bin/env node | ||
| // src/core/config.ts | ||
| import fs from "fs"; | ||
| import path from "path"; | ||
| import os from "os"; | ||
| import { parse, stringify } from "yaml"; | ||
| var GLOBAL_DIR = path.join(os.homedir(), ".syncer"); | ||
| var GLOBAL_CONFIG_PATH = path.join(GLOBAL_DIR, "config.yaml"); | ||
| var GLOBAL_STATE_PATH = path.join(GLOBAL_DIR, "state.json"); | ||
| var CACHE_DIR = path.join(GLOBAL_DIR, "cache"); | ||
| var PROJECT_CONFIG_FILE = ".syncer.yaml"; | ||
| var PROJECT_CONFIG_FILE_NEW = ".syncer/syncer.yaml"; | ||
| var PROJECT_CONFIG_FILE_NEW_YML = ".syncer/syncer.yml"; | ||
| var PROJECT_LOCK_FILE = ".syncer/syncer.lock"; | ||
| var PROJECT_CACHE_DIR = ".syncer"; | ||
| var REGISTRY_MARKER_FILE = ".syncer-registry.yaml"; | ||
| function findProjectConfigPath(cwd) { | ||
| for (const rel of [PROJECT_CONFIG_FILE_NEW, PROJECT_CONFIG_FILE_NEW_YML, PROJECT_CONFIG_FILE]) { | ||
| const p = path.join(cwd, rel); | ||
| if (fs.existsSync(p)) return p; | ||
| } | ||
| return null; | ||
| } | ||
| function detectContext(cwd) { | ||
| if (fs.existsSync(path.join(cwd, REGISTRY_MARKER_FILE))) return "registry"; | ||
| if (findProjectConfigPath(cwd)) return "project"; | ||
| return "unconfigured"; | ||
| } | ||
| function readProjectConfig(cwd) { | ||
| const configPath = findProjectConfigPath(cwd); | ||
| if (!configPath) { | ||
| throw new Error( | ||
| `No syncer config found. Run \`syncer init\` to set up this project.` | ||
| ); | ||
| } | ||
| const raw = fs.readFileSync(configPath, "utf8"); | ||
| return parse(raw); | ||
| } | ||
| function writeProjectConfig(cwd, config) { | ||
| const configPath = findProjectConfigPath(cwd) ?? path.join(cwd, PROJECT_CONFIG_FILE_NEW); | ||
| fs.mkdirSync(path.dirname(configPath), { recursive: true }); | ||
| fs.writeFileSync(configPath, stringify(config), "utf8"); | ||
| } | ||
| function readRegistryMarker(cwd) { | ||
| const markerPath = path.join(cwd, REGISTRY_MARKER_FILE); | ||
| const raw = fs.readFileSync(markerPath, "utf8"); | ||
| return parse(raw); | ||
| } | ||
| function writeRegistryMarker(cwd, marker) { | ||
| const markerPath = path.join(cwd, REGISTRY_MARKER_FILE); | ||
| fs.writeFileSync(markerPath, stringify(marker), "utf8"); | ||
| } | ||
| function readGlobalConfig() { | ||
| if (!fs.existsSync(GLOBAL_CONFIG_PATH)) return {}; | ||
| const raw = fs.readFileSync(GLOBAL_CONFIG_PATH, "utf8"); | ||
| return parse(raw) ?? {}; | ||
| } | ||
| function writeGlobalConfig(config) { | ||
| fs.mkdirSync(GLOBAL_DIR, { recursive: true }); | ||
| fs.writeFileSync(GLOBAL_CONFIG_PATH, stringify(config), "utf8"); | ||
| } | ||
| function resolveConfig(project, global) { | ||
| const registry = project.registry ?? global.default_registry ?? ""; | ||
| const defaultPack = global.default_pack; | ||
| const packIncludes = project.packs?.include ?? []; | ||
| const packs = packIncludes.length > 0 ? packIncludes : defaultPack ? [defaultPack] : []; | ||
| return { | ||
| registry, | ||
| version: project.version ?? "latest", | ||
| targets: project.targets ?? ["claude"], | ||
| link_mode: project.link_mode ?? "symlink", | ||
| packs, | ||
| skills: { | ||
| include: project.skills?.include ?? [], | ||
| exclude: project.skills?.exclude ?? [] | ||
| }, | ||
| agents: { | ||
| include: project.agents?.include ?? [], | ||
| exclude: project.agents?.exclude ?? [] | ||
| }, | ||
| commands: { | ||
| include: project.commands?.include ?? [], | ||
| exclude: project.commands?.exclude ?? [] | ||
| } | ||
| }; | ||
| } | ||
| export { | ||
| GLOBAL_DIR, | ||
| GLOBAL_STATE_PATH, | ||
| CACHE_DIR, | ||
| PROJECT_CONFIG_FILE, | ||
| PROJECT_LOCK_FILE, | ||
| PROJECT_CACHE_DIR, | ||
| REGISTRY_MARKER_FILE, | ||
| findProjectConfigPath, | ||
| detectContext, | ||
| readProjectConfig, | ||
| writeProjectConfig, | ||
| readRegistryMarker, | ||
| writeRegistryMarker, | ||
| readGlobalConfig, | ||
| writeGlobalConfig, | ||
| resolveConfig | ||
| }; | ||
| //# sourceMappingURL=chunk-NQISZLI7.js.map |
| {"version":3,"sources":["../src/core/config.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { parse, stringify } from \"yaml\";\nimport type { GlobalConfig, ProjectConfig, RegistryMarker } from \"../types.js\";\n\n// ─── Paths ───────────────────────────────────────────────────────────────────\n\nexport const GLOBAL_DIR = path.join(os.homedir(), \".syncer\");\nexport const GLOBAL_CONFIG_PATH = path.join(GLOBAL_DIR, \"config.yaml\");\nexport const GLOBAL_STATE_PATH = path.join(GLOBAL_DIR, \"state.json\");\nexport const CACHE_DIR = path.join(GLOBAL_DIR, \"cache\");\n\nexport const PROJECT_CONFIG_FILE = \".syncer.yaml\"; // legacy root-level config\nexport const PROJECT_CONFIG_FILE_NEW = \".syncer/syncer.yaml\"; // new default location\nexport const PROJECT_CONFIG_FILE_NEW_YML = \".syncer/syncer.yml\"; // alternate extension\nexport const PROJECT_LOCK_FILE = \".syncer/syncer.lock\";\nexport const PROJECT_CACHE_DIR = \".syncer\";\nexport const REGISTRY_MARKER_FILE = \".syncer-registry.yaml\";\n\n// ─── Context detection ───────────────────────────────────────────────────────\n\nexport type Context = \"project\" | \"registry\" | \"unconfigured\";\n\n/** Returns the absolute path to the project config, checking new location first. */\nexport function findProjectConfigPath(cwd: string): string | null {\n for (const rel of [PROJECT_CONFIG_FILE_NEW, PROJECT_CONFIG_FILE_NEW_YML, PROJECT_CONFIG_FILE]) {\n const p = path.join(cwd, rel);\n if (fs.existsSync(p)) return p;\n }\n return null;\n}\n\nexport function detectContext(cwd: string): Context {\n if (fs.existsSync(path.join(cwd, REGISTRY_MARKER_FILE))) return \"registry\";\n if (findProjectConfigPath(cwd)) return \"project\";\n return \"unconfigured\";\n}\n\n// ─── Project config ──────────────────────────────────────────────────────────\n\nexport function readProjectConfig(cwd: string): ProjectConfig {\n const configPath = findProjectConfigPath(cwd);\n if (!configPath) {\n throw new Error(\n `No syncer config found. Run \\`syncer init\\` to set up this project.`\n );\n }\n const raw = fs.readFileSync(configPath, \"utf8\");\n return parse(raw) as ProjectConfig;\n}\n\nexport function writeProjectConfig(cwd: string, config: ProjectConfig): void {\n // Write back to wherever the config currently lives; default to new location.\n const configPath = findProjectConfigPath(cwd) ?? path.join(cwd, PROJECT_CONFIG_FILE_NEW);\n fs.mkdirSync(path.dirname(configPath), { recursive: true });\n fs.writeFileSync(configPath, stringify(config), \"utf8\");\n}\n\n// ─── Registry marker ─────────────────────────────────────────────────────────\n\nexport function readRegistryMarker(cwd: string): RegistryMarker {\n const markerPath = path.join(cwd, REGISTRY_MARKER_FILE);\n const raw = fs.readFileSync(markerPath, \"utf8\");\n return parse(raw) as RegistryMarker;\n}\n\nexport function writeRegistryMarker(\n cwd: string,\n marker: RegistryMarker\n): void {\n const markerPath = path.join(cwd, REGISTRY_MARKER_FILE);\n fs.writeFileSync(markerPath, stringify(marker), \"utf8\");\n}\n\n// ─── Global config ───────────────────────────────────────────────────────────\n\nexport function readGlobalConfig(): GlobalConfig {\n if (!fs.existsSync(GLOBAL_CONFIG_PATH)) return {};\n const raw = fs.readFileSync(GLOBAL_CONFIG_PATH, \"utf8\");\n return (parse(raw) as GlobalConfig) ?? {};\n}\n\nexport function writeGlobalConfig(config: GlobalConfig): void {\n fs.mkdirSync(GLOBAL_DIR, { recursive: true });\n fs.writeFileSync(GLOBAL_CONFIG_PATH, stringify(config), \"utf8\");\n}\n\n// ─── Merged / resolved config ────────────────────────────────────────────────\n\nexport interface ResolvedConfig {\n registry: string;\n version: string;\n targets: (string | import(\"../types.js\").CustomTarget)[];\n link_mode: \"symlink\" | \"copy\";\n packs: string[];\n skills: { include: string[]; exclude: string[] };\n agents: { include: string[]; exclude: string[] };\n commands: { include: string[]; exclude: string[] };\n}\n\nexport function resolveConfig(\n project: ProjectConfig,\n global: GlobalConfig\n): ResolvedConfig {\n const registry =\n project.registry ?? global.default_registry ?? \"\";\n\n const defaultPack = global.default_pack;\n const packIncludes = project.packs?.include ?? [];\n const packs =\n packIncludes.length > 0\n ? packIncludes\n : defaultPack\n ? [defaultPack]\n : [];\n\n return {\n registry,\n version: project.version ?? \"latest\",\n targets: project.targets ?? [\"claude\"],\n link_mode: project.link_mode ?? \"symlink\",\n packs,\n skills: {\n include: project.skills?.include ?? [],\n exclude: project.skills?.exclude ?? [],\n },\n agents: {\n include: project.agents?.include ?? [],\n exclude: project.agents?.exclude ?? [],\n },\n commands: {\n include: project.commands?.include ?? [],\n exclude: project.commands?.exclude ?? [],\n },\n };\n}\n"],"mappings":"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","names":[]} |
| #!/usr/bin/env node | ||
| import { | ||
| REGISTRY_MARKER_FILE, | ||
| readRegistryMarker | ||
| } from "./chunk-NQISZLI7.js"; | ||
| // src/core/resolver.ts | ||
| import fs from "fs"; | ||
| import path from "path"; | ||
| function loadPack(registryPath, packName) { | ||
| const markerPath = path.join(registryPath, REGISTRY_MARKER_FILE); | ||
| if (!fs.existsSync(markerPath)) { | ||
| throw new Error(`Pack "${packName}" not found in registry (no registry marker found)`); | ||
| } | ||
| const marker = readRegistryMarker(registryPath); | ||
| const entry = marker.packs?.[packName]; | ||
| if (!entry) { | ||
| throw new Error(`Pack "${packName}" not found in registry`); | ||
| } | ||
| return { name: packName, ...entry }; | ||
| } | ||
| function listAvailablePacks(registryPath) { | ||
| const markerPath = path.join(registryPath, REGISTRY_MARKER_FILE); | ||
| if (!fs.existsSync(markerPath)) return []; | ||
| const marker = readRegistryMarker(registryPath); | ||
| return Object.keys(marker.packs ?? {}); | ||
| } | ||
| function listAvailableSkills(registryPath) { | ||
| const dir = path.join(registryPath, "skills"); | ||
| if (!fs.existsSync(dir)) return []; | ||
| return fs.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name); | ||
| } | ||
| function listAvailableAgents(registryPath) { | ||
| const dir = path.join(registryPath, "agents"); | ||
| if (!fs.existsSync(dir)) return []; | ||
| return fs.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, "")); | ||
| } | ||
| function listAvailableCommands(registryPath) { | ||
| const dir = path.join(registryPath, "commands"); | ||
| if (!fs.existsSync(dir)) return []; | ||
| return fs.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, "")); | ||
| } | ||
| function resolvePacks(registryPath, packNames) { | ||
| const merged = { skills: [], agents: [], commands: [] }; | ||
| for (const packName of packNames) { | ||
| const resolved = resolveOnePack(registryPath, packName, []); | ||
| mergeInto(merged, resolved); | ||
| } | ||
| return { | ||
| skills: dedupe(merged.skills), | ||
| agents: dedupe(merged.agents), | ||
| commands: dedupe(merged.commands) | ||
| }; | ||
| } | ||
| function resolveOnePack(registryPath, packName, chain) { | ||
| if (chain.includes(packName)) { | ||
| throw new Error( | ||
| `Circular pack extends detected: ${[...chain, packName].join(" \u2192 ")}` | ||
| ); | ||
| } | ||
| const pack = loadPack(registryPath, packName); | ||
| const result = { skills: [], agents: [], commands: [] }; | ||
| if (pack.extends) { | ||
| const parent = resolveOnePack(registryPath, pack.extends, [ | ||
| ...chain, | ||
| packName | ||
| ]); | ||
| mergeInto(result, parent); | ||
| } | ||
| if (pack.skills) result.skills.push(...pack.skills); | ||
| if (pack.agents) result.agents.push(...pack.agents); | ||
| if (pack.commands) result.commands.push(...pack.commands); | ||
| return result; | ||
| } | ||
| function applyOverrides(base, config) { | ||
| return { | ||
| skills: applyOverride( | ||
| base.skills, | ||
| config.skills.include, | ||
| config.skills.exclude | ||
| ), | ||
| agents: applyOverride( | ||
| base.agents, | ||
| config.agents.include, | ||
| config.agents.exclude | ||
| ), | ||
| commands: applyOverride( | ||
| base.commands, | ||
| config.commands.include, | ||
| config.commands.exclude | ||
| ) | ||
| }; | ||
| } | ||
| function applyOverride(base, include, exclude) { | ||
| const set = /* @__PURE__ */ new Set([...base, ...include]); | ||
| for (const item of exclude) set.delete(item); | ||
| return Array.from(set); | ||
| } | ||
| function validateRegistry(registryPath) { | ||
| const errors = []; | ||
| const skillsDir = path.join(registryPath, "skills"); | ||
| if (fs.existsSync(skillsDir)) { | ||
| for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) { | ||
| if (!entry.isDirectory()) continue; | ||
| const skillMd = path.join(skillsDir, entry.name, "SKILL.md"); | ||
| if (!fs.existsSync(skillMd)) { | ||
| errors.push(`Skill "${entry.name}" is missing SKILL.md`); | ||
| } | ||
| } | ||
| } | ||
| const packNames = listAvailablePacks(registryPath); | ||
| const availableSkills = new Set(listAvailableSkills(registryPath)); | ||
| const availableAgents = new Set(listAvailableAgents(registryPath)); | ||
| const availableCommands = new Set(listAvailableCommands(registryPath)); | ||
| for (const packName of packNames) { | ||
| try { | ||
| const pack = loadPack(registryPath, packName); | ||
| if (pack.extends && !packNames.includes(pack.extends)) { | ||
| errors.push( | ||
| `Pack "${packName}" extends unknown pack "${pack.extends}"` | ||
| ); | ||
| } | ||
| try { | ||
| resolveOnePack(registryPath, packName, []); | ||
| } catch (err) { | ||
| errors.push(String(err)); | ||
| } | ||
| for (const skill of pack.skills ?? []) { | ||
| if (!availableSkills.has(skill)) { | ||
| errors.push( | ||
| `Pack "${packName}" references unknown skill "${skill}"` | ||
| ); | ||
| } | ||
| } | ||
| for (const agent of pack.agents ?? []) { | ||
| if (!availableAgents.has(agent)) { | ||
| errors.push( | ||
| `Pack "${packName}" references unknown agent "${agent}"` | ||
| ); | ||
| } | ||
| } | ||
| for (const cmd of pack.commands ?? []) { | ||
| if (!availableCommands.has(cmd)) { | ||
| errors.push( | ||
| `Pack "${packName}" references unknown command "${cmd}"` | ||
| ); | ||
| } | ||
| } | ||
| } catch (err) { | ||
| errors.push(`Pack "${packName}" failed to load: ${err}`); | ||
| } | ||
| } | ||
| return { valid: errors.length === 0, errors }; | ||
| } | ||
| function mergeInto(target, source) { | ||
| target.skills.push(...source.skills); | ||
| target.agents.push(...source.agents); | ||
| target.commands.push(...source.commands); | ||
| } | ||
| function dedupe(arr) { | ||
| return Array.from(new Set(arr)); | ||
| } | ||
| export { | ||
| loadPack, | ||
| listAvailablePacks, | ||
| listAvailableSkills, | ||
| listAvailableAgents, | ||
| listAvailableCommands, | ||
| resolvePacks, | ||
| applyOverrides, | ||
| validateRegistry | ||
| }; | ||
| //# sourceMappingURL=chunk-QRDVQXQR.js.map |
| {"version":3,"sources":["../src/core/resolver.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { parse } from \"yaml\";\nimport type { PackDef, ResolvedContent } from \"../types.js\";\nimport type { ResolvedConfig } from \"./config.js\";\nimport { readRegistryMarker, REGISTRY_MARKER_FILE } from \"./config.js\";\n\n// ─── Pack loading ─────────────────────────────────────────────────────────────\n\nexport function loadPack(registryPath: string, packName: string): PackDef {\n const markerPath = path.join(registryPath, REGISTRY_MARKER_FILE);\n if (!fs.existsSync(markerPath)) {\n throw new Error(`Pack \"${packName}\" not found in registry (no registry marker found)`);\n }\n const marker = readRegistryMarker(registryPath);\n const entry = marker.packs?.[packName];\n if (!entry) {\n throw new Error(`Pack \"${packName}\" not found in registry`);\n }\n return { name: packName, ...entry };\n}\n\n/** List all available pack names in the registry */\nexport function listAvailablePacks(registryPath: string): string[] {\n const markerPath = path.join(registryPath, REGISTRY_MARKER_FILE);\n if (!fs.existsSync(markerPath)) return [];\n const marker = readRegistryMarker(registryPath);\n return Object.keys(marker.packs ?? {});\n}\n\n/** List all available skills in the registry */\nexport function listAvailableSkills(registryPath: string): string[] {\n const dir = path.join(registryPath, \"skills\");\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n}\n\n/** List all available agents in the registry */\nexport function listAvailableAgents(registryPath: string): string[] {\n const dir = path.join(registryPath, \"agents\");\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(\".md\"))\n .map((f) => f.replace(/\\.md$/, \"\"));\n}\n\n/** List all available commands in the registry */\nexport function listAvailableCommands(registryPath: string): string[] {\n const dir = path.join(registryPath, \"commands\");\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(\".md\"))\n .map((f) => f.replace(/\\.md$/, \"\"));\n}\n\n// ─── Pack resolution ─────────────────────────────────────────────────────────\n\n/**\n * Resolve a list of pack names into merged skills/agents/commands.\n * Handles `extends` chains recursively with cycle detection.\n */\nexport function resolvePacks(\n registryPath: string,\n packNames: string[]\n): ResolvedContent {\n const merged: ResolvedContent = { skills: [], agents: [], commands: [] };\n\n for (const packName of packNames) {\n const resolved = resolveOnePack(registryPath, packName, []);\n mergeInto(merged, resolved);\n }\n\n return {\n skills: dedupe(merged.skills),\n agents: dedupe(merged.agents),\n commands: dedupe(merged.commands),\n };\n}\n\nfunction resolveOnePack(\n registryPath: string,\n packName: string,\n chain: string[]\n): ResolvedContent {\n if (chain.includes(packName)) {\n throw new Error(\n `Circular pack extends detected: ${[...chain, packName].join(\" → \")}`\n );\n }\n\n const pack = loadPack(registryPath, packName);\n const result: ResolvedContent = { skills: [], agents: [], commands: [] };\n\n // Resolve parent first (extends)\n if (pack.extends) {\n const parent = resolveOnePack(registryPath, pack.extends, [\n ...chain,\n packName,\n ]);\n mergeInto(result, parent);\n }\n\n // Add this pack's own items\n if (pack.skills) result.skills.push(...pack.skills);\n if (pack.agents) result.agents.push(...pack.agents);\n if (pack.commands) result.commands.push(...pack.commands);\n\n return result;\n}\n\n// ─── Override application ────────────────────────────────────────────────────\n\n/**\n * Apply project-level include/exclude overrides on top of resolved pack content.\n */\nexport function applyOverrides(\n base: ResolvedContent,\n config: ResolvedConfig\n): ResolvedContent {\n return {\n skills: applyOverride(\n base.skills,\n config.skills.include,\n config.skills.exclude\n ),\n agents: applyOverride(\n base.agents,\n config.agents.include,\n config.agents.exclude\n ),\n commands: applyOverride(\n base.commands,\n config.commands.include,\n config.commands.exclude\n ),\n };\n}\n\nfunction applyOverride(\n base: string[],\n include: string[],\n exclude: string[]\n): string[] {\n const set = new Set([...base, ...include]);\n for (const item of exclude) set.delete(item);\n return Array.from(set);\n}\n\n// ─── Validation (registry mode) ──────────────────────────────────────────────\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\nexport function validateRegistry(registryPath: string): ValidationResult {\n const errors: string[] = [];\n\n // Validate skills\n const skillsDir = path.join(registryPath, \"skills\");\n if (fs.existsSync(skillsDir)) {\n for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const skillMd = path.join(skillsDir, entry.name, \"SKILL.md\");\n if (!fs.existsSync(skillMd)) {\n errors.push(`Skill \"${entry.name}\" is missing SKILL.md`);\n }\n }\n }\n\n // Validate packs\n const packNames = listAvailablePacks(registryPath);\n const availableSkills = new Set(listAvailableSkills(registryPath));\n const availableAgents = new Set(listAvailableAgents(registryPath));\n const availableCommands = new Set(listAvailableCommands(registryPath));\n\n for (const packName of packNames) {\n try {\n const pack = loadPack(registryPath, packName);\n\n // Validate extends reference\n if (pack.extends && !packNames.includes(pack.extends)) {\n errors.push(\n `Pack \"${packName}\" extends unknown pack \"${pack.extends}\"`\n );\n }\n\n // Validate extends chains for cycles\n try {\n resolveOnePack(registryPath, packName, []);\n } catch (err) {\n errors.push(String(err));\n }\n\n // Validate referenced content exists\n for (const skill of pack.skills ?? []) {\n if (!availableSkills.has(skill)) {\n errors.push(\n `Pack \"${packName}\" references unknown skill \"${skill}\"`\n );\n }\n }\n for (const agent of pack.agents ?? []) {\n if (!availableAgents.has(agent)) {\n errors.push(\n `Pack \"${packName}\" references unknown agent \"${agent}\"`\n );\n }\n }\n for (const cmd of pack.commands ?? []) {\n if (!availableCommands.has(cmd)) {\n errors.push(\n `Pack \"${packName}\" references unknown command \"${cmd}\"`\n );\n }\n }\n } catch (err) {\n errors.push(`Pack \"${packName}\" failed to load: ${err}`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction mergeInto(target: ResolvedContent, source: ResolvedContent): void {\n target.skills.push(...source.skills);\n target.agents.push(...source.agents);\n target.commands.push(...source.commands);\n}\n\nfunction dedupe(arr: string[]): string[] {\n return Array.from(new Set(arr));\n}\n"],"mappings":"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","names":[]} |
| #!/usr/bin/env node | ||
| import { | ||
| ensureRegistry, | ||
| listRegistryBranches, | ||
| listRegistryTags, | ||
| registryCacheExists, | ||
| registryCachePath, | ||
| registryFile, | ||
| resolveRefType | ||
| } from "./chunk-36KHT7HY.js"; | ||
| import "./chunk-N6JPW7IT.js"; | ||
| import "./chunk-NQISZLI7.js"; | ||
| export { | ||
| ensureRegistry, | ||
| listRegistryBranches, | ||
| listRegistryTags, | ||
| registryCacheExists, | ||
| registryCachePath, | ||
| registryFile, | ||
| resolveRefType | ||
| }; | ||
| //# sourceMappingURL=registry-QSBFV2TE.js.map |
| {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]} |
| #!/usr/bin/env node | ||
| import { | ||
| applyOverrides, | ||
| listAvailableAgents, | ||
| listAvailableCommands, | ||
| listAvailablePacks, | ||
| listAvailableSkills, | ||
| loadPack, | ||
| resolvePacks, | ||
| validateRegistry | ||
| } from "./chunk-QRDVQXQR.js"; | ||
| import "./chunk-NQISZLI7.js"; | ||
| export { | ||
| applyOverrides, | ||
| listAvailableAgents, | ||
| listAvailableCommands, | ||
| listAvailablePacks, | ||
| listAvailableSkills, | ||
| loadPack, | ||
| resolvePacks, | ||
| validateRegistry | ||
| }; | ||
| //# sourceMappingURL=resolver-OCZF4L2V.js.map |
| {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]} |
+1
-1
| { | ||
| "name": "@syncer/cli", | ||
| "version": "0.3.0", | ||
| "version": "0.3.1", | ||
| "description": "Keep AI agent skills, subagents, and commands consistent across all repositories", | ||
@@ -5,0 +5,0 @@ "type": "module", |
| #!/usr/bin/env node | ||
| import { | ||
| REGISTRY_MARKER_FILE, | ||
| readRegistryMarker | ||
| } from "./chunk-YOYA4EIK.js"; | ||
| // src/core/resolver.ts | ||
| import fs from "fs"; | ||
| import path from "path"; | ||
| function loadPack(registryPath, packName) { | ||
| const markerPath = path.join(registryPath, REGISTRY_MARKER_FILE); | ||
| if (!fs.existsSync(markerPath)) { | ||
| throw new Error(`Pack "${packName}" not found in registry (no registry marker found)`); | ||
| } | ||
| const marker = readRegistryMarker(registryPath); | ||
| const entry = marker.packs?.[packName]; | ||
| if (!entry) { | ||
| throw new Error(`Pack "${packName}" not found in registry`); | ||
| } | ||
| return { name: packName, ...entry }; | ||
| } | ||
| function listAvailablePacks(registryPath) { | ||
| const markerPath = path.join(registryPath, REGISTRY_MARKER_FILE); | ||
| if (!fs.existsSync(markerPath)) return []; | ||
| const marker = readRegistryMarker(registryPath); | ||
| return Object.keys(marker.packs ?? {}); | ||
| } | ||
| function listAvailableSkills(registryPath) { | ||
| const dir = path.join(registryPath, "skills"); | ||
| if (!fs.existsSync(dir)) return []; | ||
| return fs.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name); | ||
| } | ||
| function listAvailableAgents(registryPath) { | ||
| const dir = path.join(registryPath, "agents"); | ||
| if (!fs.existsSync(dir)) return []; | ||
| return fs.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, "")); | ||
| } | ||
| function listAvailableCommands(registryPath) { | ||
| const dir = path.join(registryPath, "commands"); | ||
| if (!fs.existsSync(dir)) return []; | ||
| return fs.readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, "")); | ||
| } | ||
| function resolvePacks(registryPath, packNames) { | ||
| const merged = { skills: [], agents: [], commands: [] }; | ||
| for (const packName of packNames) { | ||
| const resolved = resolveOnePack(registryPath, packName, []); | ||
| mergeInto(merged, resolved); | ||
| } | ||
| return { | ||
| skills: dedupe(merged.skills), | ||
| agents: dedupe(merged.agents), | ||
| commands: dedupe(merged.commands) | ||
| }; | ||
| } | ||
| function resolveOnePack(registryPath, packName, chain) { | ||
| if (chain.includes(packName)) { | ||
| throw new Error( | ||
| `Circular pack extends detected: ${[...chain, packName].join(" \u2192 ")}` | ||
| ); | ||
| } | ||
| const pack = loadPack(registryPath, packName); | ||
| const result = { skills: [], agents: [], commands: [] }; | ||
| if (pack.extends) { | ||
| const parent = resolveOnePack(registryPath, pack.extends, [ | ||
| ...chain, | ||
| packName | ||
| ]); | ||
| mergeInto(result, parent); | ||
| } | ||
| if (pack.skills) result.skills.push(...pack.skills); | ||
| if (pack.agents) result.agents.push(...pack.agents); | ||
| if (pack.commands) result.commands.push(...pack.commands); | ||
| return result; | ||
| } | ||
| function applyOverrides(base, config) { | ||
| return { | ||
| skills: applyOverride( | ||
| base.skills, | ||
| config.skills.include, | ||
| config.skills.exclude | ||
| ), | ||
| agents: applyOverride( | ||
| base.agents, | ||
| config.agents.include, | ||
| config.agents.exclude | ||
| ), | ||
| commands: applyOverride( | ||
| base.commands, | ||
| config.commands.include, | ||
| config.commands.exclude | ||
| ) | ||
| }; | ||
| } | ||
| function applyOverride(base, include, exclude) { | ||
| const set = /* @__PURE__ */ new Set([...base, ...include]); | ||
| for (const item of exclude) set.delete(item); | ||
| return Array.from(set); | ||
| } | ||
| function validateRegistry(registryPath) { | ||
| const errors = []; | ||
| const skillsDir = path.join(registryPath, "skills"); | ||
| if (fs.existsSync(skillsDir)) { | ||
| for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) { | ||
| if (!entry.isDirectory()) continue; | ||
| const skillMd = path.join(skillsDir, entry.name, "SKILL.md"); | ||
| if (!fs.existsSync(skillMd)) { | ||
| errors.push(`Skill "${entry.name}" is missing SKILL.md`); | ||
| } | ||
| } | ||
| } | ||
| const packNames = listAvailablePacks(registryPath); | ||
| const availableSkills = new Set(listAvailableSkills(registryPath)); | ||
| const availableAgents = new Set(listAvailableAgents(registryPath)); | ||
| const availableCommands = new Set(listAvailableCommands(registryPath)); | ||
| for (const packName of packNames) { | ||
| try { | ||
| const pack = loadPack(registryPath, packName); | ||
| if (pack.extends && !packNames.includes(pack.extends)) { | ||
| errors.push( | ||
| `Pack "${packName}" extends unknown pack "${pack.extends}"` | ||
| ); | ||
| } | ||
| try { | ||
| resolveOnePack(registryPath, packName, []); | ||
| } catch (err) { | ||
| errors.push(String(err)); | ||
| } | ||
| for (const skill of pack.skills ?? []) { | ||
| if (!availableSkills.has(skill)) { | ||
| errors.push( | ||
| `Pack "${packName}" references unknown skill "${skill}"` | ||
| ); | ||
| } | ||
| } | ||
| for (const agent of pack.agents ?? []) { | ||
| if (!availableAgents.has(agent)) { | ||
| errors.push( | ||
| `Pack "${packName}" references unknown agent "${agent}"` | ||
| ); | ||
| } | ||
| } | ||
| for (const cmd of pack.commands ?? []) { | ||
| if (!availableCommands.has(cmd)) { | ||
| errors.push( | ||
| `Pack "${packName}" references unknown command "${cmd}"` | ||
| ); | ||
| } | ||
| } | ||
| } catch (err) { | ||
| errors.push(`Pack "${packName}" failed to load: ${err}`); | ||
| } | ||
| } | ||
| return { valid: errors.length === 0, errors }; | ||
| } | ||
| function mergeInto(target, source) { | ||
| target.skills.push(...source.skills); | ||
| target.agents.push(...source.agents); | ||
| target.commands.push(...source.commands); | ||
| } | ||
| function dedupe(arr) { | ||
| return Array.from(new Set(arr)); | ||
| } | ||
| export { | ||
| loadPack, | ||
| listAvailablePacks, | ||
| listAvailableSkills, | ||
| listAvailableAgents, | ||
| listAvailableCommands, | ||
| resolvePacks, | ||
| applyOverrides, | ||
| validateRegistry | ||
| }; | ||
| //# sourceMappingURL=chunk-3PXPG3CQ.js.map |
| {"version":3,"sources":["../src/core/resolver.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { parse } from \"yaml\";\nimport type { PackDef, ResolvedContent } from \"../types.js\";\nimport type { ResolvedConfig } from \"./config.js\";\nimport { readRegistryMarker, REGISTRY_MARKER_FILE } from \"./config.js\";\n\n// ─── Pack loading ─────────────────────────────────────────────────────────────\n\nexport function loadPack(registryPath: string, packName: string): PackDef {\n const markerPath = path.join(registryPath, REGISTRY_MARKER_FILE);\n if (!fs.existsSync(markerPath)) {\n throw new Error(`Pack \"${packName}\" not found in registry (no registry marker found)`);\n }\n const marker = readRegistryMarker(registryPath);\n const entry = marker.packs?.[packName];\n if (!entry) {\n throw new Error(`Pack \"${packName}\" not found in registry`);\n }\n return { name: packName, ...entry };\n}\n\n/** List all available pack names in the registry */\nexport function listAvailablePacks(registryPath: string): string[] {\n const markerPath = path.join(registryPath, REGISTRY_MARKER_FILE);\n if (!fs.existsSync(markerPath)) return [];\n const marker = readRegistryMarker(registryPath);\n return Object.keys(marker.packs ?? {});\n}\n\n/** List all available skills in the registry */\nexport function listAvailableSkills(registryPath: string): string[] {\n const dir = path.join(registryPath, \"skills\");\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n}\n\n/** List all available agents in the registry */\nexport function listAvailableAgents(registryPath: string): string[] {\n const dir = path.join(registryPath, \"agents\");\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(\".md\"))\n .map((f) => f.replace(/\\.md$/, \"\"));\n}\n\n/** List all available commands in the registry */\nexport function listAvailableCommands(registryPath: string): string[] {\n const dir = path.join(registryPath, \"commands\");\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(\".md\"))\n .map((f) => f.replace(/\\.md$/, \"\"));\n}\n\n// ─── Pack resolution ─────────────────────────────────────────────────────────\n\n/**\n * Resolve a list of pack names into merged skills/agents/commands.\n * Handles `extends` chains recursively with cycle detection.\n */\nexport function resolvePacks(\n registryPath: string,\n packNames: string[]\n): ResolvedContent {\n const merged: ResolvedContent = { skills: [], agents: [], commands: [] };\n\n for (const packName of packNames) {\n const resolved = resolveOnePack(registryPath, packName, []);\n mergeInto(merged, resolved);\n }\n\n return {\n skills: dedupe(merged.skills),\n agents: dedupe(merged.agents),\n commands: dedupe(merged.commands),\n };\n}\n\nfunction resolveOnePack(\n registryPath: string,\n packName: string,\n chain: string[]\n): ResolvedContent {\n if (chain.includes(packName)) {\n throw new Error(\n `Circular pack extends detected: ${[...chain, packName].join(\" → \")}`\n );\n }\n\n const pack = loadPack(registryPath, packName);\n const result: ResolvedContent = { skills: [], agents: [], commands: [] };\n\n // Resolve parent first (extends)\n if (pack.extends) {\n const parent = resolveOnePack(registryPath, pack.extends, [\n ...chain,\n packName,\n ]);\n mergeInto(result, parent);\n }\n\n // Add this pack's own items\n if (pack.skills) result.skills.push(...pack.skills);\n if (pack.agents) result.agents.push(...pack.agents);\n if (pack.commands) result.commands.push(...pack.commands);\n\n return result;\n}\n\n// ─── Override application ────────────────────────────────────────────────────\n\n/**\n * Apply project-level include/exclude overrides on top of resolved pack content.\n */\nexport function applyOverrides(\n base: ResolvedContent,\n config: ResolvedConfig\n): ResolvedContent {\n return {\n skills: applyOverride(\n base.skills,\n config.skills.include,\n config.skills.exclude\n ),\n agents: applyOverride(\n base.agents,\n config.agents.include,\n config.agents.exclude\n ),\n commands: applyOverride(\n base.commands,\n config.commands.include,\n config.commands.exclude\n ),\n };\n}\n\nfunction applyOverride(\n base: string[],\n include: string[],\n exclude: string[]\n): string[] {\n const set = new Set([...base, ...include]);\n for (const item of exclude) set.delete(item);\n return Array.from(set);\n}\n\n// ─── Validation (registry mode) ──────────────────────────────────────────────\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\nexport function validateRegistry(registryPath: string): ValidationResult {\n const errors: string[] = [];\n\n // Validate skills\n const skillsDir = path.join(registryPath, \"skills\");\n if (fs.existsSync(skillsDir)) {\n for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const skillMd = path.join(skillsDir, entry.name, \"SKILL.md\");\n if (!fs.existsSync(skillMd)) {\n errors.push(`Skill \"${entry.name}\" is missing SKILL.md`);\n }\n }\n }\n\n // Validate packs\n const packNames = listAvailablePacks(registryPath);\n const availableSkills = new Set(listAvailableSkills(registryPath));\n const availableAgents = new Set(listAvailableAgents(registryPath));\n const availableCommands = new Set(listAvailableCommands(registryPath));\n\n for (const packName of packNames) {\n try {\n const pack = loadPack(registryPath, packName);\n\n // Validate extends reference\n if (pack.extends && !packNames.includes(pack.extends)) {\n errors.push(\n `Pack \"${packName}\" extends unknown pack \"${pack.extends}\"`\n );\n }\n\n // Validate extends chains for cycles\n try {\n resolveOnePack(registryPath, packName, []);\n } catch (err) {\n errors.push(String(err));\n }\n\n // Validate referenced content exists\n for (const skill of pack.skills ?? []) {\n if (!availableSkills.has(skill)) {\n errors.push(\n `Pack \"${packName}\" references unknown skill \"${skill}\"`\n );\n }\n }\n for (const agent of pack.agents ?? []) {\n if (!availableAgents.has(agent)) {\n errors.push(\n `Pack \"${packName}\" references unknown agent \"${agent}\"`\n );\n }\n }\n for (const cmd of pack.commands ?? []) {\n if (!availableCommands.has(cmd)) {\n errors.push(\n `Pack \"${packName}\" references unknown command \"${cmd}\"`\n );\n }\n }\n } catch (err) {\n errors.push(`Pack \"${packName}\" failed to load: ${err}`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction mergeInto(target: ResolvedContent, source: ResolvedContent): void {\n target.skills.push(...source.skills);\n target.agents.push(...source.agents);\n target.commands.push(...source.commands);\n}\n\nfunction dedupe(arr: string[]): string[] {\n return Array.from(new Set(arr));\n}\n"],"mappings":"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","names":[]} |
| #!/usr/bin/env node | ||
| import { | ||
| ensureDir, | ||
| urlToKey | ||
| } from "./chunk-N6JPW7IT.js"; | ||
| import { | ||
| CACHE_DIR | ||
| } from "./chunk-YOYA4EIK.js"; | ||
| // src/core/registry.ts | ||
| import fs from "fs"; | ||
| import path from "path"; | ||
| import { simpleGit } from "simple-git"; | ||
| function registryCachePath(registryUrl) { | ||
| return path.join(CACHE_DIR, urlToKey(registryUrl)); | ||
| } | ||
| async function ensureRegistry(registryUrl, version = "latest") { | ||
| ensureDir(CACHE_DIR); | ||
| const cachePath = registryCachePath(registryUrl); | ||
| if (fs.existsSync(cachePath)) { | ||
| return await fetchRegistry(cachePath, registryUrl, version); | ||
| } else { | ||
| return await cloneRegistry(cachePath, registryUrl, version); | ||
| } | ||
| } | ||
| async function cloneRegistry(cachePath, registryUrl, version) { | ||
| const git = simpleGit(); | ||
| const isLatest = version === "latest"; | ||
| try { | ||
| if (isLatest) { | ||
| await git.clone(registryUrl, cachePath, ["--depth=1"]); | ||
| } else { | ||
| await git.clone(registryUrl, cachePath); | ||
| } | ||
| const repoGit = simpleGit(cachePath); | ||
| if (!isLatest) { | ||
| await repoGit.checkout(version); | ||
| } | ||
| const commit = await getCommitHash(repoGit); | ||
| return { cachePath, commit, fromCache: false }; | ||
| } catch (err) { | ||
| if (!fs.existsSync(cachePath)) throw err; | ||
| fs.rmSync(cachePath, { recursive: true, force: true }); | ||
| throw err; | ||
| } | ||
| } | ||
| async function fetchRegistry(cachePath, registryUrl, version) { | ||
| const repoGit = simpleGit(cachePath); | ||
| try { | ||
| await repoGit.fetch(["--prune"]); | ||
| const isLatest = version === "latest"; | ||
| if (isLatest) { | ||
| const defaultBranch = await getDefaultBranch(repoGit); | ||
| await repoGit.checkout(defaultBranch); | ||
| await repoGit.pull(); | ||
| } else { | ||
| await repoGit.checkout(version); | ||
| const isBranchLike = !/^[0-9a-f]{7,40}$/.test(version); | ||
| if (isBranchLike) { | ||
| try { | ||
| await repoGit.pull(); | ||
| } catch { | ||
| } | ||
| } | ||
| } | ||
| const commit = await getCommitHash(repoGit); | ||
| return { cachePath, commit, fromCache: false }; | ||
| } catch { | ||
| const commit = await getCommitHash(repoGit).catch(() => "unknown"); | ||
| return { cachePath, commit, fromCache: true }; | ||
| } | ||
| } | ||
| async function getCommitHash(git) { | ||
| const result = await git.revparse(["HEAD"]); | ||
| return result.trim(); | ||
| } | ||
| async function getDefaultBranch(git) { | ||
| try { | ||
| const result = await git.raw(["symbolic-ref", "refs/remotes/origin/HEAD"]); | ||
| return result.trim().replace("refs/remotes/origin/", ""); | ||
| } catch { | ||
| const branches = await git.branch(["-r"]); | ||
| if (branches.all.includes("origin/main")) return "main"; | ||
| return "master"; | ||
| } | ||
| } | ||
| async function listRegistryTags(registryUrl) { | ||
| const cachePath = registryCachePath(registryUrl); | ||
| if (!fs.existsSync(cachePath)) return []; | ||
| const git = simpleGit(cachePath); | ||
| const tags = await git.tags(); | ||
| return tags.all; | ||
| } | ||
| async function listRegistryBranches(registryUrl) { | ||
| const cachePath = registryCachePath(registryUrl); | ||
| if (!fs.existsSync(cachePath)) return []; | ||
| const git = simpleGit(cachePath); | ||
| const branches = await git.branch(["-r"]); | ||
| return branches.all.map((b) => b.trim().replace(/^origin\//, "")).filter((b) => b !== "HEAD"); | ||
| } | ||
| async function resolveRefType(registryUrl, ref) { | ||
| if (/^[0-9a-f]{7,40}$/.test(ref)) return "commit"; | ||
| const tags = await listRegistryTags(registryUrl); | ||
| if (tags.includes(ref)) return "tag"; | ||
| const branches = await listRegistryBranches(registryUrl); | ||
| if (branches.includes(ref)) return "branch"; | ||
| return null; | ||
| } | ||
| function registryFile(cachePath, ...segments) { | ||
| return path.join(cachePath, ...segments); | ||
| } | ||
| function registryCacheExists(registryUrl) { | ||
| return fs.existsSync(registryCachePath(registryUrl)); | ||
| } | ||
| export { | ||
| registryCachePath, | ||
| ensureRegistry, | ||
| listRegistryTags, | ||
| listRegistryBranches, | ||
| resolveRefType, | ||
| registryFile, | ||
| registryCacheExists | ||
| }; | ||
| //# sourceMappingURL=chunk-LBLURIVB.js.map |
| {"version":3,"sources":["../src/core/registry.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { simpleGit } from \"simple-git\";\nimport { CACHE_DIR } from \"./config.js\";\nimport { ensureDir, urlToKey } from \"../utils/fs.js\";\n\n/** Returns the path to the registry clone for a given URL */\nexport function registryCachePath(registryUrl: string): string {\n return path.join(CACHE_DIR, urlToKey(registryUrl));\n}\n\nexport interface RegistryInfo {\n cachePath: string;\n commit: string;\n fromCache: boolean; // true if offline and using cached version\n}\n\n/**\n * Ensure the registry is cloned/fetched and checked out at the target version.\n * Returns the path to the working tree and the current commit hash.\n */\nexport async function ensureRegistry(\n registryUrl: string,\n version = \"latest\"\n): Promise<RegistryInfo> {\n ensureDir(CACHE_DIR);\n const cachePath = registryCachePath(registryUrl);\n\n if (fs.existsSync(cachePath)) {\n return await fetchRegistry(cachePath, registryUrl, version);\n } else {\n return await cloneRegistry(cachePath, registryUrl, version);\n }\n}\n\nasync function cloneRegistry(\n cachePath: string,\n registryUrl: string,\n version: string\n): Promise<RegistryInfo> {\n const git = simpleGit();\n const isLatest = version === \"latest\";\n\n try {\n if (isLatest) {\n await git.clone(registryUrl, cachePath, [\"--depth=1\"]);\n } else {\n // Full clone needed for tag/commit/branch checkout\n await git.clone(registryUrl, cachePath);\n }\n\n const repoGit = simpleGit(cachePath);\n if (!isLatest) {\n await repoGit.checkout(version);\n }\n\n const commit = await getCommitHash(repoGit);\n return { cachePath, commit, fromCache: false };\n } catch (err) {\n // If clone failed and no cache exists, rethrow\n if (!fs.existsSync(cachePath)) throw err;\n // Partial clone — clean up and rethrow\n fs.rmSync(cachePath, { recursive: true, force: true });\n throw err;\n }\n}\n\nasync function fetchRegistry(\n cachePath: string,\n registryUrl: string,\n version: string\n): Promise<RegistryInfo> {\n const repoGit = simpleGit(cachePath);\n\n try {\n await repoGit.fetch([\"--prune\"]);\n\n const isLatest = version === \"latest\";\n if (isLatest) {\n // Checkout default branch (main or master)\n const defaultBranch = await getDefaultBranch(repoGit);\n await repoGit.checkout(defaultBranch);\n await repoGit.pull();\n } else {\n await repoGit.checkout(version);\n // Pull only if it's a branch (not a tag or commit hash)\n const isBranchLike = !/^[0-9a-f]{7,40}$/.test(version);\n if (isBranchLike) {\n try {\n await repoGit.pull();\n } catch {\n // May not have upstream tracking — ignore\n }\n }\n }\n\n const commit = await getCommitHash(repoGit);\n return { cachePath, commit, fromCache: false };\n } catch {\n // Offline or fetch failed — use whatever is checked out\n const commit = await getCommitHash(repoGit).catch(() => \"unknown\");\n return { cachePath, commit, fromCache: true };\n }\n}\n\nasync function getCommitHash(git: ReturnType<typeof simpleGit>): Promise<string> {\n const result = await git.revparse([\"HEAD\"]);\n return result.trim();\n}\n\nasync function getDefaultBranch(\n git: ReturnType<typeof simpleGit>\n): Promise<string> {\n try {\n // Try to get the symbolic ref of origin/HEAD\n const result = await git.raw([\"symbolic-ref\", \"refs/remotes/origin/HEAD\"]);\n return result.trim().replace(\"refs/remotes/origin/\", \"\");\n } catch {\n // Fallback: try main, then master\n const branches = await git.branch([\"-r\"]);\n if (branches.all.includes(\"origin/main\")) return \"main\";\n return \"master\";\n }\n}\n\n/** List all available tags in the registry */\nexport async function listRegistryTags(\n registryUrl: string\n): Promise<string[]> {\n const cachePath = registryCachePath(registryUrl);\n if (!fs.existsSync(cachePath)) return [];\n const git = simpleGit(cachePath);\n const tags = await git.tags();\n return tags.all;\n}\n\n/** List all remote branches in the registry cache */\nexport async function listRegistryBranches(\n registryUrl: string\n): Promise<string[]> {\n const cachePath = registryCachePath(registryUrl);\n if (!fs.existsSync(cachePath)) return [];\n const git = simpleGit(cachePath);\n const branches = await git.branch([\"-r\"]);\n return branches.all\n .map((b) => b.trim().replace(/^origin\\//, \"\"))\n .filter((b) => b !== \"HEAD\");\n}\n\n/**\n * Determine what type of ref a version string is.\n * Returns null if the ref is not found in the cached registry.\n */\nexport async function resolveRefType(\n registryUrl: string,\n ref: string\n): Promise<\"tag\" | \"branch\" | \"commit\" | null> {\n if (/^[0-9a-f]{7,40}$/.test(ref)) return \"commit\";\n const tags = await listRegistryTags(registryUrl);\n if (tags.includes(ref)) return \"tag\";\n const branches = await listRegistryBranches(registryUrl);\n if (branches.includes(ref)) return \"branch\";\n return null;\n}\n\n/** Read a file from the registry cache */\nexport function registryFile(cachePath: string, ...segments: string[]): string {\n return path.join(cachePath, ...segments);\n}\n\n/** Check if the registry cache exists */\nexport function registryCacheExists(registryUrl: string): boolean {\n return fs.existsSync(registryCachePath(registryUrl));\n}\n"],"mappings":"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","names":[]} |
| #!/usr/bin/env node | ||
| // src/core/config.ts | ||
| import fs from "fs"; | ||
| import path from "path"; | ||
| import os from "os"; | ||
| import { parse, stringify } from "yaml"; | ||
| var GLOBAL_DIR = path.join(os.homedir(), ".syncer"); | ||
| var GLOBAL_CONFIG_PATH = path.join(GLOBAL_DIR, "config.yaml"); | ||
| var GLOBAL_STATE_PATH = path.join(GLOBAL_DIR, "state.json"); | ||
| var CACHE_DIR = path.join(GLOBAL_DIR, "cache"); | ||
| var PROJECT_CONFIG_FILE = ".syncer.yaml"; | ||
| var PROJECT_CONFIG_FILE_NEW = ".syncer/syncer.yaml"; | ||
| var PROJECT_LOCK_FILE = ".syncer/syncer.lock"; | ||
| var PROJECT_CACHE_DIR = ".syncer"; | ||
| var REGISTRY_MARKER_FILE = ".syncer-registry.yaml"; | ||
| function findProjectConfigPath(cwd) { | ||
| for (const rel of [PROJECT_CONFIG_FILE_NEW, PROJECT_CONFIG_FILE_NEW_YML, PROJECT_CONFIG_FILE]) { | ||
| const p = path.join(cwd, rel); | ||
| if (fs.existsSync(p)) return p; | ||
| } | ||
| return null; | ||
| } | ||
| function detectContext(cwd) { | ||
| if (fs.existsSync(path.join(cwd, REGISTRY_MARKER_FILE))) return "registry"; | ||
| if (findProjectConfigPath(cwd)) return "project"; | ||
| return "unconfigured"; | ||
| } | ||
| function readProjectConfig(cwd) { | ||
| const configPath = findProjectConfigPath(cwd); | ||
| if (!configPath) { | ||
| throw new Error( | ||
| `No syncer config found. Run \`syncer init\` to set up this project.` | ||
| ); | ||
| } | ||
| const raw = fs.readFileSync(configPath, "utf8"); | ||
| return parse(raw); | ||
| } | ||
| function writeProjectConfig(cwd, config) { | ||
| const configPath = findProjectConfigPath(cwd) ?? path.join(cwd, PROJECT_CONFIG_FILE_NEW); | ||
| fs.mkdirSync(path.dirname(configPath), { recursive: true }); | ||
| fs.writeFileSync(configPath, stringify(config), "utf8"); | ||
| } | ||
| function readRegistryMarker(cwd) { | ||
| const markerPath = path.join(cwd, REGISTRY_MARKER_FILE); | ||
| const raw = fs.readFileSync(markerPath, "utf8"); | ||
| return parse(raw); | ||
| } | ||
| function writeRegistryMarker(cwd, marker) { | ||
| const markerPath = path.join(cwd, REGISTRY_MARKER_FILE); | ||
| fs.writeFileSync(markerPath, stringify(marker), "utf8"); | ||
| } | ||
| function readGlobalConfig() { | ||
| if (!fs.existsSync(GLOBAL_CONFIG_PATH)) return {}; | ||
| const raw = fs.readFileSync(GLOBAL_CONFIG_PATH, "utf8"); | ||
| return parse(raw) ?? {}; | ||
| } | ||
| function writeGlobalConfig(config) { | ||
| fs.mkdirSync(GLOBAL_DIR, { recursive: true }); | ||
| fs.writeFileSync(GLOBAL_CONFIG_PATH, stringify(config), "utf8"); | ||
| } | ||
| function resolveConfig(project, global) { | ||
| const registry = project.registry ?? global.default_registry ?? ""; | ||
| const defaultPack = global.default_pack; | ||
| const packIncludes = project.packs?.include ?? []; | ||
| const packs = packIncludes.length > 0 ? packIncludes : defaultPack ? [defaultPack] : []; | ||
| return { | ||
| registry, | ||
| version: project.version ?? "latest", | ||
| targets: project.targets ?? ["claude"], | ||
| link_mode: project.link_mode ?? "symlink", | ||
| packs, | ||
| skills: { | ||
| include: project.skills?.include ?? [], | ||
| exclude: project.skills?.exclude ?? [] | ||
| }, | ||
| agents: { | ||
| include: project.agents?.include ?? [], | ||
| exclude: project.agents?.exclude ?? [] | ||
| }, | ||
| commands: { | ||
| include: project.commands?.include ?? [], | ||
| exclude: project.commands?.exclude ?? [] | ||
| } | ||
| }; | ||
| } | ||
| export { | ||
| GLOBAL_DIR, | ||
| GLOBAL_STATE_PATH, | ||
| CACHE_DIR, | ||
| PROJECT_CONFIG_FILE, | ||
| PROJECT_LOCK_FILE, | ||
| PROJECT_CACHE_DIR, | ||
| REGISTRY_MARKER_FILE, | ||
| findProjectConfigPath, | ||
| detectContext, | ||
| readProjectConfig, | ||
| writeProjectConfig, | ||
| readRegistryMarker, | ||
| writeRegistryMarker, | ||
| readGlobalConfig, | ||
| writeGlobalConfig, | ||
| resolveConfig | ||
| }; | ||
| //# sourceMappingURL=chunk-YOYA4EIK.js.map |
| {"version":3,"sources":["../src/core/config.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { parse, stringify } from \"yaml\";\nimport type { GlobalConfig, ProjectConfig, RegistryMarker } from \"../types.js\";\n\n// ─── Paths ───────────────────────────────────────────────────────────────────\n\nexport const GLOBAL_DIR = path.join(os.homedir(), \".syncer\");\nexport const GLOBAL_CONFIG_PATH = path.join(GLOBAL_DIR, \"config.yaml\");\nexport const GLOBAL_STATE_PATH = path.join(GLOBAL_DIR, \"state.json\");\nexport const CACHE_DIR = path.join(GLOBAL_DIR, \"cache\");\n\nexport const PROJECT_CONFIG_FILE = \".syncer.yaml\"; // legacy root-level config\nexport const PROJECT_CONFIG_FILE_NEW = \".syncer/syncer.yaml\"; // new default location\nexport const PROJECT_LOCK_FILE = \".syncer/syncer.lock\";\nexport const PROJECT_CACHE_DIR = \".syncer\";\nexport const REGISTRY_MARKER_FILE = \".syncer-registry.yaml\";\n\n// ─── Context detection ───────────────────────────────────────────────────────\n\nexport type Context = \"project\" | \"registry\" | \"unconfigured\";\n\n/** Returns the absolute path to the project config, checking new location first. */\nexport function findProjectConfigPath(cwd: string): string | null {\n for (const rel of [PROJECT_CONFIG_FILE_NEW, PROJECT_CONFIG_FILE_NEW_YML, PROJECT_CONFIG_FILE]) {\n const p = path.join(cwd, rel);\n if (fs.existsSync(p)) return p;\n }\n return null;\n}\n\nexport function detectContext(cwd: string): Context {\n if (fs.existsSync(path.join(cwd, REGISTRY_MARKER_FILE))) return \"registry\";\n if (findProjectConfigPath(cwd)) return \"project\";\n return \"unconfigured\";\n}\n\n// ─── Project config ──────────────────────────────────────────────────────────\n\nexport function readProjectConfig(cwd: string): ProjectConfig {\n const configPath = findProjectConfigPath(cwd);\n if (!configPath) {\n throw new Error(\n `No syncer config found. Run \\`syncer init\\` to set up this project.`\n );\n }\n const raw = fs.readFileSync(configPath, \"utf8\");\n return parse(raw) as ProjectConfig;\n}\n\nexport function writeProjectConfig(cwd: string, config: ProjectConfig): void {\n // Write back to wherever the config currently lives; default to new location.\n const configPath = findProjectConfigPath(cwd) ?? path.join(cwd, PROJECT_CONFIG_FILE_NEW);\n fs.mkdirSync(path.dirname(configPath), { recursive: true });\n fs.writeFileSync(configPath, stringify(config), \"utf8\");\n}\n\n// ─── Registry marker ─────────────────────────────────────────────────────────\n\nexport function readRegistryMarker(cwd: string): RegistryMarker {\n const markerPath = path.join(cwd, REGISTRY_MARKER_FILE);\n const raw = fs.readFileSync(markerPath, \"utf8\");\n return parse(raw) as RegistryMarker;\n}\n\nexport function writeRegistryMarker(\n cwd: string,\n marker: RegistryMarker\n): void {\n const markerPath = path.join(cwd, REGISTRY_MARKER_FILE);\n fs.writeFileSync(markerPath, stringify(marker), \"utf8\");\n}\n\n// ─── Global config ───────────────────────────────────────────────────────────\n\nexport function readGlobalConfig(): GlobalConfig {\n if (!fs.existsSync(GLOBAL_CONFIG_PATH)) return {};\n const raw = fs.readFileSync(GLOBAL_CONFIG_PATH, \"utf8\");\n return (parse(raw) as GlobalConfig) ?? {};\n}\n\nexport function writeGlobalConfig(config: GlobalConfig): void {\n fs.mkdirSync(GLOBAL_DIR, { recursive: true });\n fs.writeFileSync(GLOBAL_CONFIG_PATH, stringify(config), \"utf8\");\n}\n\n// ─── Merged / resolved config ────────────────────────────────────────────────\n\nexport interface ResolvedConfig {\n registry: string;\n version: string;\n targets: (string | import(\"../types.js\").CustomTarget)[];\n link_mode: \"symlink\" | \"copy\";\n packs: string[];\n skills: { include: string[]; exclude: string[] };\n agents: { include: string[]; exclude: string[] };\n commands: { include: string[]; exclude: string[] };\n}\n\nexport function resolveConfig(\n project: ProjectConfig,\n global: GlobalConfig\n): ResolvedConfig {\n const registry =\n project.registry ?? global.default_registry ?? \"\";\n\n const defaultPack = global.default_pack;\n const packIncludes = project.packs?.include ?? [];\n const packs =\n packIncludes.length > 0\n ? packIncludes\n : defaultPack\n ? [defaultPack]\n : [];\n\n return {\n registry,\n version: project.version ?? \"latest\",\n targets: project.targets ?? [\"claude\"],\n link_mode: project.link_mode ?? \"symlink\",\n packs,\n skills: {\n include: project.skills?.include ?? [],\n exclude: project.skills?.exclude ?? [],\n },\n agents: {\n include: project.agents?.include ?? [],\n exclude: project.agents?.exclude ?? [],\n },\n commands: {\n include: project.commands?.include ?? [],\n exclude: project.commands?.exclude ?? [],\n },\n };\n}\n"],"mappings":"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","names":[]} |
| #!/usr/bin/env node | ||
| import { | ||
| ensureRegistry, | ||
| listRegistryBranches, | ||
| listRegistryTags, | ||
| registryCacheExists, | ||
| registryCachePath, | ||
| registryFile, | ||
| resolveRefType | ||
| } from "./chunk-LBLURIVB.js"; | ||
| import "./chunk-N6JPW7IT.js"; | ||
| import "./chunk-YOYA4EIK.js"; | ||
| export { | ||
| ensureRegistry, | ||
| listRegistryBranches, | ||
| listRegistryTags, | ||
| registryCacheExists, | ||
| registryCachePath, | ||
| registryFile, | ||
| resolveRefType | ||
| }; | ||
| //# sourceMappingURL=registry-YRN3VYE4.js.map |
| {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]} |
| #!/usr/bin/env node | ||
| import { | ||
| applyOverrides, | ||
| listAvailableAgents, | ||
| listAvailableCommands, | ||
| listAvailablePacks, | ||
| listAvailableSkills, | ||
| loadPack, | ||
| resolvePacks, | ||
| validateRegistry | ||
| } from "./chunk-3PXPG3CQ.js"; | ||
| import "./chunk-YOYA4EIK.js"; | ||
| export { | ||
| applyOverrides, | ||
| listAvailableAgents, | ||
| listAvailableCommands, | ||
| listAvailablePacks, | ||
| listAvailableSkills, | ||
| loadPack, | ||
| resolvePacks, | ||
| validateRegistry | ||
| }; | ||
| //# sourceMappingURL=resolver-LCDPSI5Y.js.map |
| {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]} |
Sorry, the diff of this file is too big to display
265715
0.06%2360
0.04%