skilld 1.7.3 → 2.0.0
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/_chunks/add.mjs +66 -0
- package/dist/_chunks/add.mjs.map +1 -0
- package/dist/_chunks/agent-prompt.mjs +88 -0
- package/dist/_chunks/agent-prompt.mjs.map +1 -0
- package/dist/_chunks/agent.mjs +737 -619
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/args.mjs +42 -0
- package/dist/_chunks/args.mjs.map +1 -0
- package/dist/_chunks/assemble.mjs +11 -8
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author.mjs +77 -131
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +320 -54
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +7 -6
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/client.mjs +117 -0
- package/dist/_chunks/client.mjs.map +1 -0
- package/dist/_chunks/core.mjs +7 -4
- package/dist/_chunks/detect.mjs +54 -44
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/eject.mjs +69 -0
- package/dist/_chunks/eject.mjs.map +1 -0
- package/dist/_chunks/embedding-cache2.mjs +2 -2
- package/dist/_chunks/env.mjs +19 -0
- package/dist/_chunks/env.mjs.map +1 -0
- package/dist/_chunks/install-many.mjs +376 -0
- package/dist/_chunks/install-many.mjs.map +1 -0
- package/dist/_chunks/install.mjs +86 -371
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/intro.mjs +63 -0
- package/dist/_chunks/intro.mjs.map +1 -0
- package/dist/_chunks/list.mjs +2 -2
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +31 -7
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/login.mjs +233 -0
- package/dist/_chunks/login.mjs.map +1 -0
- package/dist/_chunks/logout.mjs +27 -0
- package/dist/_chunks/logout.mjs.map +1 -0
- package/dist/_chunks/map.mjs +11 -0
- package/dist/_chunks/map.mjs.map +1 -0
- package/dist/_chunks/markdown.mjs +79 -54
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/menu.mjs +33 -0
- package/dist/_chunks/menu.mjs.map +1 -0
- package/dist/_chunks/model-picker.mjs +61 -0
- package/dist/_chunks/model-picker.mjs.map +1 -0
- package/dist/_chunks/monorepo.mjs +73 -0
- package/dist/_chunks/monorepo.mjs.map +1 -0
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/paths.mjs +47 -0
- package/dist/_chunks/paths.mjs.map +1 -0
- package/dist/_chunks/pipeline.mjs +985 -0
- package/dist/_chunks/pipeline.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +2 -2
- package/dist/_chunks/portable.mjs +151 -0
- package/dist/_chunks/portable.mjs.map +1 -0
- package/dist/_chunks/prepare-hook.mjs +2 -0
- package/dist/_chunks/prepare-hook2.mjs +61 -0
- package/dist/_chunks/prepare-hook2.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +47 -3
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +9 -8
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +784 -26
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/pull.mjs +219 -0
- package/dist/_chunks/pull.mjs.map +1 -0
- package/dist/_chunks/regex.mjs +19 -0
- package/dist/_chunks/regex.mjs.map +1 -0
- package/dist/_chunks/retriv.mjs +2 -171
- package/dist/_chunks/retriv2.mjs +159 -0
- package/dist/_chunks/retriv2.mjs.map +1 -0
- package/dist/_chunks/sanitize.mjs +12 -9
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +9 -8
- package/dist/_chunks/search-helpers.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +23 -20
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +3 -4
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/{sources.mjs → semver.mjs} +1128 -838
- package/dist/_chunks/semver.mjs.map +1 -0
- package/dist/_chunks/skill-installer.mjs +2 -0
- package/dist/_chunks/skill-installer2.mjs +154 -0
- package/dist/_chunks/skill-installer2.mjs.map +1 -0
- package/dist/_chunks/skills.mjs +12 -12
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/store.mjs +107 -0
- package/dist/_chunks/store.mjs.map +1 -0
- package/dist/_chunks/sync.mjs +761 -1349
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +2 -3
- package/dist/_chunks/telemetry.mjs +26 -0
- package/dist/_chunks/telemetry.mjs.map +1 -0
- package/dist/_chunks/uninstall.mjs +15 -13
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/update.mjs +171 -0
- package/dist/_chunks/update.mjs.map +1 -0
- package/dist/_chunks/upload.mjs +4 -4
- package/dist/_chunks/validate.mjs +1 -1
- package/dist/_chunks/version.mjs +16 -27
- package/dist/_chunks/version.mjs.map +1 -1
- package/dist/_chunks/whoami.mjs +21 -0
- package/dist/_chunks/whoami.mjs.map +1 -0
- package/dist/_chunks/wizard.mjs +2 -190
- package/dist/_chunks/wizard2.mjs +200 -0
- package/dist/_chunks/wizard2.mjs.map +1 -0
- package/dist/cli.mjs +77 -59
- package/dist/cli.mjs.map +1 -1
- package/dist/prepare.mjs +5 -4
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/worker.d.mts +5 -1
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +1 -1
- package/package.json +20 -29
- package/dist/_chunks/author-group.mjs +0 -17
- package/dist/_chunks/author-group.mjs.map +0 -1
- package/dist/_chunks/cli-helpers.mjs +0 -335
- package/dist/_chunks/cli-helpers.mjs.map +0 -1
- package/dist/_chunks/cli-helpers2.mjs +0 -2
- package/dist/_chunks/config.mjs +0 -122
- package/dist/_chunks/config.mjs.map +0 -1
- package/dist/_chunks/index.d.mts +0 -151
- package/dist/_chunks/index.d.mts.map +0 -1
- package/dist/_chunks/index2.d.mts +0 -44
- package/dist/_chunks/index2.d.mts.map +0 -1
- package/dist/_chunks/index3.d.mts +0 -589
- package/dist/_chunks/index3.d.mts.map +0 -1
- package/dist/_chunks/prefix.mjs +0 -108
- package/dist/_chunks/prefix.mjs.map +0 -1
- package/dist/_chunks/retriv.mjs.map +0 -1
- package/dist/_chunks/setup.mjs +0 -17
- package/dist/_chunks/setup.mjs.map +0 -1
- package/dist/_chunks/shared.mjs +0 -503
- package/dist/_chunks/shared.mjs.map +0 -1
- package/dist/_chunks/skill.mjs +0 -329
- package/dist/_chunks/skill.mjs.map +0 -1
- package/dist/_chunks/sources.mjs.map +0 -1
- package/dist/_chunks/sync-registry.mjs +0 -59
- package/dist/_chunks/sync-registry.mjs.map +0 -1
- package/dist/_chunks/sync-shared.mjs +0 -2
- package/dist/_chunks/sync-shared2.mjs +0 -1020
- package/dist/_chunks/sync-shared2.mjs.map +0 -1
- package/dist/_chunks/types.d.mts +0 -88
- package/dist/_chunks/types.d.mts.map +0 -1
- package/dist/_chunks/wizard.mjs.map +0 -1
- package/dist/agent/index.d.mts +0 -346
- package/dist/agent/index.d.mts.map +0 -1
- package/dist/agent/index.mjs +0 -5
- package/dist/cache/index.d.mts +0 -2
- package/dist/cache/index.mjs +0 -4
- package/dist/index.d.mts +0 -5
- package/dist/index.mjs +0 -5
- package/dist/retriv/index.d.mts +0 -3
- package/dist/retriv/index.mjs +0 -2
- package/dist/sources/index.d.mts +0 -2
- package/dist/sources/index.mjs +0 -3
- package/dist/types.d.mts +0 -4
- package/dist/types.mjs +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.mjs","names":["agents","checkShippedDocs"],"sources":["../../src/commands/install.ts"],"sourcesContent":["/**\n * Install command - restore .skilld/ and SKILL.md from lockfile\n *\n * After cloning a repo, the .skilld/ symlinks are missing (gitignored).\n * If SKILL.md was deleted, a base version is regenerated from local metadata.\n * This command recreates them from the lockfile:\n * .claude/skills/<skill>/.skilld/pkg -> node_modules/<pkg> (always)\n * .claude/skills/<skill>/.skilld/docs -> ~/.skilld/references/<pkg>@<version>/docs (if external)\n * .claude/skills/<skill>/SKILL.md -> regenerated from package.json + cache state\n */\n\nimport type { AgentType, CustomPrompt, SkillSection } from '../agent/index.ts'\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type { SkillInfo } from '../core/lockfile.ts'\nimport { copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { dirname, join } from 'pathe'\nimport { agents, createToolProgress, getModelLabel, linkSkillToAgents, optimizeDocs } from '../agent/index.ts'\nimport { writeGeneratedSkillMd, writeSkillMd } from '../agent/prompts/skill.ts'\nimport {\n hasShippedDocs as checkShippedDocs,\n ensureCacheDir,\n getCacheDir,\n getPackageDbPath,\n getPkgKeyFiles,\n getRepoCacheDir,\n getShippedSkills,\n inferDocsTypeFromCache,\n isCached,\n isReadmeOnlyCache,\n linkPkgNamed,\n linkShippedSkill,\n listReferenceFiles,\n readCachedDocs,\n resolvePkgDir,\n writeToCache,\n} from '../cache/index.ts'\nimport { promptForAgent, resolveAgent, sharedArgs } from '../cli-helpers.ts'\nimport { defaultFeatures, readConfig } from '../core/config.ts'\nimport { timedSpinner } from '../core/formatting.ts'\nimport { mergeLocks, parsePackageNames, parsePackages, readLock, syncLockfilesToDirs, writeLock } from '../core/lockfile.ts'\nimport { readPackageJsonSafe } from '../core/package-json.ts'\nimport { toStoragePackageName } from '../core/prefix.ts'\nimport { sanitizeMarkdown } from '../core/sanitize.ts'\nimport { getSharedSkillsDir } from '../core/shared.ts'\nimport { createIndex, SearchDepsUnavailableError } from '../retriv/index.ts'\nimport { shutdownWorker } from '../retriv/pool.ts'\nimport { fetchGitSkills } from '../sources/git-skills.ts'\nimport {\n downloadLlmsDocs,\n fetchGitDocs,\n fetchGitHubRaw,\n fetchLlmsTxt,\n fetchReadmeContent,\n filterFrameworkDocs,\n isShallowGitDocs,\n normalizeLlmsLinks,\n parseGitHubUrl,\n resolveEntryFiles,\n resolvePackageDocs,\n} from '../sources/index.ts'\nimport { classifyCachedDoc, indexResources } from './sync-shared.ts'\nimport { selectLlmConfig, writePromptFiles } from './sync.ts'\n\nexport interface InstallOptions {\n global: boolean\n agent: AgentType\n}\n\nexport async function installCommand(opts: InstallOptions): Promise<void> {\n const cwd = process.cwd()\n const agent = agents[opts.agent]\n const shared = !opts.global && getSharedSkillsDir(cwd)\n const skillsDir = opts.global\n ? join(homedir(), '.skilld', 'skills')\n : shared || join(cwd, agent.skillsDir)\n\n // Collect lockfiles from all agent skill dirs and merge\n // In shared mode, read from .skills/ only\n const allSkillsDirs = shared\n ? [shared]\n : Object.values(agents).map(t =>\n opts.global ? t.globalSkillsDir : join(cwd, t.skillsDir),\n )\n const allLocks = allSkillsDirs\n .map(dir => readLock(dir))\n .filter((l): l is NonNullable<typeof l> => !!l && Object.keys(l.skills).length > 0)\n\n if (allLocks.length === 0) {\n p.log.warn('No skilld-lock.yaml found. Run `skilld` to sync skills first.')\n return\n }\n\n const lock = mergeLocks(allLocks)\n\n const skills = Object.entries(lock.skills)\n const toRestore: Array<{ name: string, info: SkillInfo }> = []\n const features = readConfig().features ?? defaultFeatures\n\n // Find skills with missing/broken references symlinks\n for (const [name, info] of skills) {\n if (!info.version)\n continue\n\n // Shipped skills: the skill dir IS the symlink, no references/ subdir\n if (info.source === 'shipped') {\n const skillDir = join(skillsDir, name)\n if (!existsSync(skillDir)) {\n toRestore.push({ name, info })\n }\n continue\n }\n\n const skillDir = join(skillsDir, name)\n const referencesPath = join(skillDir, '.skilld')\n const skillMdPath = join(skillDir, 'SKILL.md')\n\n // Check skill dir, SKILL.md, and all internal .skilld/ references\n const needsRestore = !existsSync(skillDir)\n || !existsSync(skillMdPath)\n || !existsSync(referencesPath)\n || hasStaleReferences(referencesPath, toStoragePackageName(info.packageName || name), info.version!, features)\n\n if (needsRestore) {\n toRestore.push({ name, info })\n }\n }\n\n if (toRestore.length === 0) {\n p.log.success('All up to date')\n return\n }\n\n p.log.info(`Restoring ${toRestore.length} references`)\n ensureCacheDir()\n\n const allSkillNames = skills.map(([, info]) => info.packageName || '').filter(Boolean)\n const regenerated: Array<{ name: string, pkgName: string, version: string, skillDir: string, packages?: string }> = []\n\n for (const { name, info } of toRestore) {\n const version = info.version!\n const identityName = info.packageName || unsanitizeName(name, info.source)\n const pkgName = toStoragePackageName(identityName)\n\n // Shipped skills: re-link from node_modules or cached dist\n if (info.source === 'shipped') {\n const shipped = getShippedSkills(pkgName, cwd, version)\n const match = shipped.find(s => s.skillName === name)\n if (match) {\n linkShippedSkill(skillsDir, name, match.skillDir)\n p.log.success(`Linked ${name}`)\n }\n else {\n p.log.warn(`${name}: package ${pkgName} no longer ships this skill`)\n }\n continue\n }\n\n // Git-sourced skills: re-fetch from remote\n if (info.source === 'github' || info.source === 'gitlab' || info.source === 'local') {\n const source = {\n type: info.source as 'github' | 'gitlab' | 'local',\n ...(info.repo?.includes('/') ? { owner: info.repo.split('/')[0], repo: info.repo.split('/')[1] } : {}),\n skillPath: info.path,\n ref: info.ref,\n ...(info.source === 'local' ? { localPath: info.repo } : {}),\n }\n const result = await fetchGitSkills(source)\n const match = result.skills.find(s => s.name === name)\n if (match) {\n const skillDir = join(skillsDir, name)\n mkdirSync(skillDir, { recursive: true })\n writeSkillMd(skillDir, sanitizeMarkdown(match.content))\n for (const f of match.files) {\n const filePath = join(skillDir, f.path)\n mkdirSync(dirname(filePath), { recursive: true })\n writeFileSync(filePath, f.content)\n }\n p.log.success(`Restored ${name} from ${info.repo}`)\n }\n else {\n p.log.warn(`${name}: skill not found in ${info.repo}`)\n }\n continue\n }\n\n const skillDir = join(skillsDir, name)\n const referencesPath = join(skillDir, '.skilld')\n const globalCachePath = getCacheDir(pkgName, version)\n const spin = timedSpinner()\n\n // Check if already in global cache - just create symlinks\n if (isCached(pkgName, version)) {\n spin.start(`Linking ${name}`)\n mkdirSync(skillDir, { recursive: true })\n mkdirSync(referencesPath, { recursive: true })\n linkPkgSymlink(referencesPath, pkgName, cwd, version)\n // Restore named symlinks for all tracked packages\n for (const pkg of parsePackages(info.packages))\n linkPkgNamed(skillDir, pkg.name, cwd, pkg.version)\n // Only link external docs if package doesn't ship its own and has more than just README\n if (!pkgHasShippedDocs(pkgName, cwd, version) && !isReadmeOnlyCache(globalCachePath)) {\n const docsLink = join(referencesPath, 'docs')\n const cachedDocs = join(globalCachePath, 'docs')\n if (existsSync(docsLink))\n unlinkSync(docsLink)\n if (existsSync(cachedDocs))\n symlinkSync(cachedDocs, docsLink, 'junction')\n }\n // Link issues, discussions, and releases (try repo cache first, fall back to package cache)\n const repoGh = info.repo ? parseGitHubUrl(`https://github.com/${info.repo}`) : null\n const repoCachePath = repoGh ? getRepoCacheDir(repoGh.owner, repoGh.repo) : null\n if (features.issues) {\n const issuesLink = join(referencesPath, 'issues')\n const repoIssues = repoCachePath ? join(repoCachePath, 'issues') : null\n const cachedIssues = (repoIssues && existsSync(repoIssues)) ? repoIssues : join(globalCachePath, 'issues')\n if (existsSync(issuesLink))\n unlinkSync(issuesLink)\n if (existsSync(cachedIssues))\n symlinkSync(cachedIssues, issuesLink, 'junction')\n }\n if (features.discussions) {\n const discussionsLink = join(referencesPath, 'discussions')\n const repoDiscussions = repoCachePath ? join(repoCachePath, 'discussions') : null\n const cachedDiscussions = (repoDiscussions && existsSync(repoDiscussions)) ? repoDiscussions : join(globalCachePath, 'discussions')\n if (existsSync(discussionsLink))\n unlinkSync(discussionsLink)\n if (existsSync(cachedDiscussions))\n symlinkSync(cachedDiscussions, discussionsLink, 'junction')\n }\n if (features.releases) {\n const releasesLink = join(referencesPath, 'releases')\n const repoReleases = repoCachePath ? join(repoCachePath, 'releases') : null\n const cachedReleases = (repoReleases && existsSync(repoReleases)) ? repoReleases : join(globalCachePath, 'releases')\n if (existsSync(releasesLink))\n unlinkSync(releasesLink)\n if (existsSync(cachedReleases))\n symlinkSync(cachedReleases, releasesLink, 'junction')\n }\n const sectionsLink = join(referencesPath, 'sections')\n const cachedSections = join(globalCachePath, 'sections')\n if (existsSync(sectionsLink))\n unlinkSync(sectionsLink)\n if (existsSync(cachedSections))\n symlinkSync(cachedSections, sectionsLink, 'junction')\n // Create search index from cached docs if missing\n if (features.search && !existsSync(getPackageDbPath(pkgName, version))) {\n spin.message(`Indexing ${name}`)\n const cached = readCachedDocs(pkgName, version)\n const docsToIndex = cached.map(d => ({\n id: d.path,\n content: d.content,\n metadata: { package: pkgName, source: d.path, type: classifyCachedDoc(d.path).type },\n }))\n await indexResources({ packageName: pkgName, version, cwd, docsToIndex, features, onProgress: msg => spin.message(msg) })\n }\n if (!copyFromExistingAgent(skillDir, name, allSkillsDirs)) {\n if (regenerateBaseSkillMd(skillDir, pkgName, version, cwd, allSkillNames, info.source, info.packages))\n regenerated.push({ name, pkgName, version, skillDir, packages: info.packages })\n }\n spin.stop(`Linked ${name}`)\n continue\n }\n\n // Need to download to global cache first\n spin.start(`Downloading ${name}@${version}`)\n\n const resolved = await resolvePackageDocs(pkgName, { version })\n\n if (!resolved) {\n spin.stop(`Could not resolve: ${name}`)\n continue\n }\n\n const cachedDocs: Array<{ path: string, content: string }> = []\n const docsToIndex: Array<{ id: string, content: string, metadata: Record<string, any> }> = []\n const isFrameworkDoc = (path: string) => filterFrameworkDocs([path], pkgName).length > 0\n\n // Try git docs first\n if (resolved.gitDocsUrl && resolved.repoUrl) {\n const gh = parseGitHubUrl(resolved.repoUrl)\n if (gh) {\n const gitDocs = await fetchGitDocs(gh.owner, gh.repo, version, pkgName)\n if (gitDocs?.files.length) {\n const BATCH_SIZE = 20\n for (let i = 0; i < gitDocs.files.length; i += BATCH_SIZE) {\n const batch = gitDocs.files.slice(i, i + BATCH_SIZE)\n const results = await Promise.all(\n batch.map(async (file) => {\n const url = `${gitDocs.baseUrl}/${file}`\n const content = await fetchGitHubRaw(url)\n if (!content)\n return null\n return { file, content }\n }),\n )\n for (const r of results) {\n if (r) {\n const stripped = gitDocs.docsPrefix ? r.file.replace(gitDocs.docsPrefix, '') : r.file\n const cachePath = stripped.startsWith('docs/') ? stripped : `docs/${stripped}`\n cachedDocs.push({ path: cachePath, content: r.content })\n docsToIndex.push({ id: cachePath, content: r.content, metadata: { package: pkgName, source: cachePath, type: 'doc' } })\n }\n }\n }\n\n // Shallow git-docs: if < threshold and llms.txt exists, discard and fall through\n if (isShallowGitDocs(cachedDocs.length) && resolved.llmsUrl) {\n cachedDocs.length = 0\n docsToIndex.length = 0\n }\n else if (cachedDocs.length > 0 && resolved.llmsUrl) {\n // Always cache llms.txt alongside good git-docs as supplementary reference\n const llmsContent = await fetchLlmsTxt(resolved.llmsUrl)\n if (llmsContent) {\n const baseUrl = resolved.docsUrl || new URL(resolved.llmsUrl).origin\n cachedDocs.push({ path: 'llms.txt', content: normalizeLlmsLinks(llmsContent.raw) })\n if (llmsContent.links.length > 0) {\n const docs = await downloadLlmsDocs(llmsContent, baseUrl)\n for (const doc of docs) {\n if (!isFrameworkDoc(doc.url))\n continue\n const localPath = doc.url.startsWith('/') ? doc.url.slice(1) : doc.url\n cachedDocs.push({ path: join('llms-docs', ...localPath.split('/')), content: doc.content })\n }\n }\n }\n }\n }\n }\n }\n\n // Try llms.txt\n if (resolved.llmsUrl && cachedDocs.length === 0) {\n const llmsContent = await fetchLlmsTxt(resolved.llmsUrl)\n if (llmsContent) {\n cachedDocs.push({ path: 'llms.txt', content: normalizeLlmsLinks(llmsContent.raw) })\n if (llmsContent.links.length > 0) {\n const baseUrl = resolved.docsUrl || new URL(resolved.llmsUrl).origin\n const docs = await downloadLlmsDocs(llmsContent, baseUrl)\n for (const doc of docs) {\n if (!isFrameworkDoc(doc.url))\n continue\n const localPath = doc.url.startsWith('/') ? doc.url.slice(1) : doc.url\n const cachePath = join('docs', ...localPath.split('/'))\n cachedDocs.push({ path: cachePath, content: doc.content })\n docsToIndex.push({ id: doc.url, content: doc.content, metadata: { package: pkgName, source: cachePath, type: 'doc' } })\n }\n }\n }\n }\n\n // Fallback to README\n if (resolved.readmeUrl && cachedDocs.length === 0) {\n const content = await fetchReadmeContent(resolved.readmeUrl)\n if (content) {\n cachedDocs.push({ path: 'docs/README.md', content })\n docsToIndex.push({ id: 'README.md', content, metadata: { package: pkgName, source: 'docs/README.md', type: 'doc' } })\n }\n }\n\n if (cachedDocs.length > 0) {\n writeToCache(pkgName, version, cachedDocs)\n\n mkdirSync(referencesPath, { recursive: true })\n linkPkgSymlink(referencesPath, pkgName, cwd, version)\n // Restore named symlinks for all tracked packages\n for (const pkg of parsePackages(info.packages))\n linkPkgNamed(skillDir, pkg.name, cwd, pkg.version)\n // Link fetched docs unless it's just a README (already in pkg/)\n if (!isReadmeOnlyCache(globalCachePath)) {\n const docsLink = join(referencesPath, 'docs')\n const cachedDocsDir = join(globalCachePath, 'docs')\n if (existsSync(docsLink))\n unlinkSync(docsLink)\n if (existsSync(cachedDocsDir))\n symlinkSync(cachedDocsDir, docsLink, 'junction')\n }\n\n if (features.search) {\n try {\n if (docsToIndex.length > 0) {\n await createIndex(docsToIndex, { dbPath: getPackageDbPath(pkgName, version) })\n }\n\n // Index package entry files (.d.ts / .js)\n const pkgDir = resolvePkgDir(pkgName, cwd, version)\n const entryFiles = pkgDir ? await resolveEntryFiles(pkgDir) : []\n if (entryFiles.length > 0) {\n await createIndex(entryFiles.map(e => ({\n id: e.path,\n content: e.content,\n metadata: { package: pkgName, source: `pkg/${e.path}`, type: e.type },\n })), { dbPath: getPackageDbPath(pkgName, version) })\n }\n }\n catch (err) {\n if (!(err instanceof SearchDepsUnavailableError))\n throw err\n }\n }\n\n if (!copyFromExistingAgent(skillDir, name, allSkillsDirs)) {\n if (regenerateBaseSkillMd(skillDir, pkgName, version, cwd, allSkillNames, info.source, info.packages))\n regenerated.push({ name, pkgName, version, skillDir, packages: info.packages })\n }\n spin.stop(`Downloaded and linked ${name}`)\n }\n else {\n spin.stop(`No docs found for ${name}`)\n }\n }\n\n // Offer LLM enhancement for regenerated SKILL.md files\n if (regenerated.length > 0 && !readConfig().skipLlm) {\n const names = regenerated.map(r => r.name).join(', ')\n const llmConfig = await selectLlmConfig(undefined, `Enhance SKILL.md for ${names}`)\n if (llmConfig?.promptOnly) {\n const features = readConfig().features ?? defaultFeatures\n for (const { pkgName, version, skillDir } of regenerated) {\n const globalCachePath = getCacheDir(pkgName, version)\n writePromptFiles({\n packageName: pkgName,\n skillDir,\n version,\n hasIssues: existsSync(join(globalCachePath, 'issues')),\n hasDiscussions: existsSync(join(globalCachePath, 'discussions')),\n hasReleases: existsSync(join(globalCachePath, 'releases')),\n hasChangelog: false,\n docsType: 'docs',\n hasShippedDocs: false,\n pkgFiles: getPkgKeyFiles(pkgName, process.cwd(), version),\n sections: llmConfig.sections,\n customPrompt: llmConfig.customPrompt,\n features,\n })\n }\n }\n else if (llmConfig) {\n p.log.step(getModelLabel(llmConfig.model))\n for (const { pkgName, version, skillDir, packages: pkgPackages } of regenerated) {\n await enhanceRegenerated(pkgName, version, skillDir, llmConfig.model, llmConfig.sections, llmConfig.customPrompt, pkgPackages)\n }\n }\n }\n\n // Write merged lockfile to target dir and sync to all other existing lockfiles\n for (const [name, info] of Object.entries(lock.skills))\n writeLock(skillsDir, name, info)\n\n // In shared mode: recreate per-agent symlinks, skip per-agent lockfile sync\n if (shared) {\n for (const [name] of skills)\n linkSkillToAgents(name, shared, cwd, opts.agent)\n }\n else {\n syncLockfilesToDirs(lock, allSkillsDirs.filter(d => d !== skillsDir))\n }\n\n await shutdownWorker()\n\n p.outro('Install complete')\n}\n\n/** Copy SKILL.md from another agent's skill dir if one exists */\nfunction copyFromExistingAgent(skillDir: string, name: string, allSkillsDirs: string[]): boolean {\n const targetMd = join(skillDir, 'SKILL.md')\n if (existsSync(targetMd))\n return false\n for (const dir of allSkillsDirs) {\n if (dir === skillDir)\n continue\n const candidateMd = join(dir, name, 'SKILL.md')\n if (existsSync(candidateMd) && !lstatSync(candidateMd).isSymbolicLink()) {\n mkdirSync(skillDir, { recursive: true })\n copyFileSync(candidateMd, targetMd)\n return true\n }\n }\n return false\n}\n\n/** Try to recover original package name from sanitized name + source */\nfunction unsanitizeName(sanitized: string, source?: string): string {\n if (source?.includes('ungh://')) {\n const match = source.match(/ungh:\\/\\/([^/]+)\\/(.+)/)\n if (match)\n return `@${match[1]}/${match[2]}`\n }\n\n if (sanitized.startsWith('antfu-'))\n return `@antfu/${sanitized.slice(6)}`\n if (sanitized.startsWith('clack-'))\n return `@clack/${sanitized.slice(6)}`\n if (sanitized.startsWith('nuxt-'))\n return `@nuxt/${sanitized.slice(5)}`\n if (sanitized.startsWith('vue-'))\n return `@vue/${sanitized.slice(4)}`\n if (sanitized.startsWith('vueuse-'))\n return `@vueuse/${sanitized.slice(7)}`\n\n return sanitized\n}\n\n/** Create pkg symlink inside references dir (links to entire package or cached dist) */\nfunction linkPkgSymlink(referencesDir: string, name: string, cwd: string, version?: string): void {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return\n\n const pkgLink = join(referencesDir, 'pkg')\n if (existsSync(pkgLink))\n unlinkSync(pkgLink)\n symlinkSync(pkgPath, pkgLink, 'junction')\n}\n\n/** Check if package ships its own docs folder */\nfunction pkgHasShippedDocs(name: string, cwd: string, version?: string): boolean {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return false\n\n const docsCandidates = ['docs', 'documentation', 'doc']\n for (const candidate of docsCandidates) {\n const docsPath = join(pkgPath, candidate)\n if (existsSync(docsPath))\n return true\n }\n return false\n}\n\n/** Run LLM enhancement on a regenerated SKILL.md */\nasync function enhanceRegenerated(\n pkgName: string,\n version: string,\n skillDir: string,\n model: Parameters<typeof optimizeDocs>[0]['model'],\n sections: SkillSection[],\n customPrompt?: CustomPrompt,\n packages?: string,\n): Promise<void> {\n const llmLog = p.taskLog({ title: `Agent exploring ${pkgName}`, limit: 3 })\n\n const docFiles = listReferenceFiles(skillDir)\n const globalCachePath = getCacheDir(pkgName, version)\n const hasIssues = existsSync(join(globalCachePath, 'issues'))\n const hasDiscussions = existsSync(join(globalCachePath, 'discussions'))\n const hasGithub = hasIssues || hasDiscussions\n const hasReleases = existsSync(join(globalCachePath, 'releases'))\n\n const features = readConfig().features ?? defaultFeatures\n const { optimized, wasOptimized } = await optimizeDocs({\n packageName: pkgName,\n skillDir,\n model,\n version,\n hasGithub,\n hasReleases,\n docFiles,\n sections,\n customPrompt,\n features,\n pkgFiles: getPkgKeyFiles(pkgName, process.cwd(), version),\n onProgress: createToolProgress(llmLog),\n })\n\n if (wasOptimized) {\n llmLog.success('Generated best practices')\n // Re-read local metadata for the enhanced version\n const cwd = process.cwd()\n const pkgPath = resolvePkgDir(pkgName, cwd, version)\n let description: string | undefined\n if (pkgPath) {\n const pkgJsonPath = join(pkgPath, 'package.json')\n const pkgJsonResult = readPackageJsonSafe(pkgJsonPath)\n if (pkgJsonResult) {\n description = pkgJsonResult.parsed.description as string | undefined\n }\n }\n\n const docsType = inferDocsTypeFromCache(globalCachePath)\n\n // Derive dirName from the skill directory name\n const dirName = skillDir.split('/').pop()\n\n const allPackages = parsePackageNames(packages)\n writeGeneratedSkillMd(skillDir, {\n name: pkgName,\n version,\n description,\n body: optimized,\n relatedSkills: [],\n hasIssues,\n hasDiscussions,\n hasReleases,\n docsType,\n hasShippedDocs: checkShippedDocs(pkgName, cwd, version),\n pkgFiles: getPkgKeyFiles(pkgName, cwd, version),\n dirName,\n packages: allPackages.length > 1 ? allPackages : undefined,\n features,\n })\n }\n else {\n llmLog.message('Enhancement skipped')\n }\n}\n\nexport const installCommandDef = defineCommand({\n meta: { name: 'install', description: 'Restore references from lockfile' },\n args: {\n global: sharedArgs.global,\n agent: sharedArgs.agent,\n },\n async run({ args }) {\n let agent = resolveAgent(args.agent)\n if (!agent || agent === 'none') {\n if (agent === 'none')\n return\n const picked = await promptForAgent()\n if (!picked || picked === 'none')\n return\n agent = picked\n }\n\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m install`)\n return installCommand({ global: args.global, agent })\n },\n})\n\n/** Regenerate base SKILL.md from local metadata if missing */\nfunction regenerateBaseSkillMd(\n skillDir: string,\n pkgName: string,\n version: string,\n cwd: string,\n allSkillNames: string[],\n source?: string,\n packages?: string,\n): boolean {\n const skillMdPath = join(skillDir, 'SKILL.md')\n if (existsSync(skillMdPath))\n return false\n\n // Read description + deps from local package.json\n const pkgPath = resolvePkgDir(pkgName, cwd, version)\n let description: string | undefined\n if (pkgPath) {\n const pkgResult = readPackageJsonSafe(join(pkgPath, 'package.json'))\n if (pkgResult) {\n description = pkgResult.parsed.description as string | undefined\n }\n }\n\n // Infer docsType from source or cache\n const globalCachePath = getCacheDir(pkgName, version)\n const docsType = inferDocsTypeFromCache(globalCachePath, source)\n\n // Check cache dirs for issues/discussions/releases (only if feature enabled)\n const feat = readConfig().features ?? defaultFeatures\n const hasIssues = feat.issues && existsSync(join(globalCachePath, 'issues'))\n const hasDiscussions = feat.discussions && existsSync(join(globalCachePath, 'discussions'))\n const hasReleases = feat.releases && existsSync(join(globalCachePath, 'releases'))\n\n // Related skills from other lockfile entries\n const relatedSkills = allSkillNames.filter(n => n !== pkgName)\n\n // Derive dirName from the skill directory name (lockfile key)\n const dirName = skillDir.split('/').pop()\n\n // Build multi-package list from lockfile packages field\n const allPackages = parsePackageNames(packages)\n\n mkdirSync(skillDir, { recursive: true })\n writeGeneratedSkillMd(skillDir, {\n name: pkgName,\n version,\n description,\n relatedSkills,\n hasIssues,\n hasDiscussions,\n hasReleases,\n docsType,\n hasShippedDocs: checkShippedDocs(pkgName, cwd, version),\n pkgFiles: getPkgKeyFiles(pkgName, cwd, version),\n dirName,\n packages: allPackages.length > 1 ? allPackages : undefined,\n features: readConfig().features ?? defaultFeatures,\n })\n\n return true\n}\n\n/** Check if .skilld/ has broken symlinks or is missing expected references from global cache */\nfunction hasStaleReferences(referencesPath: string, pkgName: string, version: string, features: FeaturesConfig): boolean {\n // Scan existing entries for broken symlinks\n for (const entry of readdirSync(referencesPath)) {\n const entryPath = join(referencesPath, entry)\n if (lstatSync(entryPath).isSymbolicLink() && !existsSync(entryPath))\n return true\n }\n\n // Check pkg link always expected\n if (!existsSync(join(referencesPath, 'pkg')))\n return true\n\n // Check expected links against global cache\n const globalCachePath = getCacheDir(pkgName, version)\n const expected: Array<[string, boolean]> = [\n ['docs', existsSync(join(globalCachePath, 'docs'))],\n ['issues', features.issues && existsSync(join(globalCachePath, 'issues'))],\n ['discussions', features.discussions && existsSync(join(globalCachePath, 'discussions'))],\n ['releases', features.releases && existsSync(join(globalCachePath, 'releases'))],\n ['sections', existsSync(join(globalCachePath, 'sections'))],\n ]\n\n for (const [name, shouldExist] of expected) {\n if (shouldExist && !existsSync(join(referencesPath, name)))\n return true\n }\n\n return false\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"install.mjs","names":["agents"],"sources":["../../src/commands/install.ts"],"sourcesContent":["/**\n * Install command - restore .skilld/ and SKILL.md from lockfile\n *\n * After cloning a repo, the .skilld/ symlinks are missing (gitignored).\n * If SKILL.md was deleted, a base version is regenerated from local metadata.\n * This command recreates them from the lockfile:\n * .claude/skills/<skill>/.skilld/pkg -> node_modules/<pkg> (always)\n * .claude/skills/<skill>/.skilld/docs -> ~/.skilld/references/<pkg>@<version>/docs (if external)\n * .claude/skills/<skill>/SKILL.md -> regenerated from package.json + cache state\n */\n\nimport type { AgentType } from '../agent/index.ts'\nimport type { SkillContext } from '../agent/skill-builder.ts'\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type { SkillInfo } from '../core/lockfile.ts'\nimport type { ResolvedPackage } from '../sources/index.ts'\nimport { copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { styleText } from 'node:util'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { dirname, join } from 'pathe'\nimport { agents, getModelLabel, linkSkillToAgents } from '../agent/index.ts'\nimport { writeSkillMd } from '../agent/prompts/skill.ts'\nimport { enhanceSkillWithLLM, writeBaseSkill, writePromptFiles } from '../agent/skill-builder.ts'\nimport { createReferenceCache, ensureCacheDir, getCacheDir } from '../cache/index.ts'\nimport { promptForAgent, resolveAgent } from '../cli/agent-prompt.ts'\nimport { sharedArgs } from '../cli/args.ts'\nimport { defaultFeatures, readConfig } from '../core/config.ts'\nimport { timedSpinner } from '../core/formatting.ts'\nimport { mergeLocks, parsePackageNames, parsePackages, readLock, syncLockfilesToDirs, writeLock } from '../core/lockfile.ts'\nimport { readPackageJsonSafe } from '../core/package-json.ts'\nimport { getSharedSkillsDir, skillInternalDir } from '../core/paths.ts'\nimport { toStoragePackageName } from '../core/prefix.ts'\nimport {\n getShippedSkills,\n linkShippedSkill,\n resolvePkgDir,\n} from '../core/prepare.ts'\nimport { sanitizeMarkdown } from '../core/sanitize.ts'\nimport { shutdownWorker } from '../retriv/pool.ts'\nimport { fetchGitSkills } from '../sources/git-skills.ts'\nimport { resolvePackageDocs } from '../sources/index.ts'\nimport { selectLlmConfig } from './llm-prompts.ts'\nimport { buildSkillContext, fetchAndCacheResources, prepareSkillReferences } from './sync/pipeline.ts'\n\nconst STATIC_REGEX_1 = /ungh:\\/\\/([^/]+)\\/(.+)/\n\nexport interface InstallOptions {\n global: boolean\n agent: AgentType\n}\n\nexport async function installCommand(opts: InstallOptions): Promise<void> {\n const cwd = process.cwd()\n const agent = agents[opts.agent]\n const shared = !opts.global && getSharedSkillsDir(cwd)\n const skillsDir = opts.global\n ? join(homedir(), '.skilld', 'skills')\n : shared || join(cwd, agent.skillsDir)\n\n // Collect lockfiles from all agent skill dirs and merge\n // In shared mode, read from .skills/ only\n const allSkillsDirs = shared\n ? [shared]\n : Object.values(agents).map(t =>\n opts.global ? t.globalSkillsDir : join(cwd, t.skillsDir),\n )\n const allLocks = allSkillsDirs\n .map(dir => readLock(dir))\n .filter((l): l is NonNullable<typeof l> => !!l && Object.keys(l.skills).length > 0)\n\n if (allLocks.length === 0) {\n p.log.warn('No skilld-lock.yaml found. Run `skilld` to sync skills first.')\n return\n }\n\n const lock = mergeLocks(allLocks)\n\n const skills = Object.entries(lock.skills)\n const toRestore: Array<{ name: string, info: SkillInfo }> = []\n const features = readConfig().features ?? defaultFeatures\n\n // Find skills with missing/broken references symlinks\n for (const [name, info] of skills) {\n if (!info.version)\n continue\n\n // Shipped skills: the skill dir IS the symlink, no references/ subdir\n if (info.source === 'shipped') {\n const skillDir = join(skillsDir, name)\n if (!existsSync(skillDir)) {\n toRestore.push({ name, info })\n }\n continue\n }\n\n const skillDir = join(skillsDir, name)\n const referencesPath = skillInternalDir(skillDir)\n const skillMdPath = join(skillDir, 'SKILL.md')\n\n // Check skill dir, SKILL.md, and all internal .skilld/ references\n const needsRestore = !existsSync(skillDir)\n || !existsSync(skillMdPath)\n || !existsSync(referencesPath)\n || hasStaleReferences(referencesPath, toStoragePackageName(info.packageName || name), info.version!, features)\n\n if (needsRestore) {\n toRestore.push({ name, info })\n }\n }\n\n if (toRestore.length === 0) {\n p.log.success('All up to date')\n return\n }\n\n p.log.info(`Restoring ${toRestore.length} references`)\n ensureCacheDir()\n\n const regenerated: Array<{ name: string, ctx: SkillContext }> = []\n\n for (const { name, info } of toRestore) {\n const version = info.version!\n const identityName = info.packageName || unsanitizeName(name, info.source)\n const pkgName = toStoragePackageName(identityName)\n\n // Shipped skills: re-link from node_modules or cached dist\n if (info.source === 'shipped') {\n const shipped = getShippedSkills(pkgName, cwd, version)\n const match = shipped.find(s => s.skillName === name)\n if (match) {\n linkShippedSkill(skillsDir, name, match.skillDir)\n p.log.success(`Linked ${name}`)\n }\n else {\n p.log.warn(`${name}: package ${pkgName} no longer ships this skill`)\n }\n continue\n }\n\n // Git-sourced skills: re-fetch from remote\n if (info.source === 'github' || info.source === 'gitlab' || info.source === 'local') {\n const source = {\n type: info.source as 'github' | 'gitlab' | 'local',\n ...(info.repo?.includes('/') ? { owner: info.repo.split('/')[0], repo: info.repo.split('/')[1] } : {}),\n skillPath: info.path,\n ref: info.ref,\n ...(info.source === 'local' ? { localPath: info.repo } : {}),\n }\n const result = await fetchGitSkills(source)\n const match = result.skills.find(s => s.name === name)\n if (match) {\n const skillDir = join(skillsDir, name)\n mkdirSync(skillDir, { recursive: true })\n writeSkillMd(skillDir, sanitizeMarkdown(match.content))\n for (const f of match.files) {\n const filePath = join(skillDir, f.path)\n mkdirSync(dirname(filePath), { recursive: true })\n writeFileSync(filePath, f.content)\n }\n p.log.success(`Restored ${name} from ${info.repo}`)\n }\n else {\n p.log.warn(`${name}: skill not found in ${info.repo}`)\n }\n continue\n }\n\n const skillDir = join(skillsDir, name)\n const cache = createReferenceCache(pkgName, version)\n const spin = timedSpinner()\n const wasCacheHit = cache.has()\n spin.start(wasCacheHit ? `Linking ${name}` : `Downloading ${name}@${version}`)\n mkdirSync(skillDir, { recursive: true })\n\n const resolved: ResolvedPackage | null = wasCacheHit\n ? synthesizeResolved(identityName, version, info, cwd)\n : await resolvePackageDocs(pkgName, { version })\n\n if (!resolved) {\n spin.stop(`Could not resolve: ${name}`)\n continue\n }\n\n const resources = await fetchAndCacheResources({\n packageName: pkgName,\n resolved,\n version,\n useCache: wasCacheHit,\n features,\n onProgress: msg => spin.message(msg),\n })\n\n for (const w of resources.warnings)\n p.log.warn(`${name}: ${w}`)\n\n if (!cache.has()) {\n spin.stop(`No docs found for ${name}`)\n continue\n }\n\n const prepared = await prepareSkillReferences({\n packageName: pkgName,\n version,\n cwd,\n skillDir,\n resources,\n features,\n baseDir: skillsDir,\n extraPackages: parsePackages(info.packages),\n onIndexProgress: msg => spin.message(msg),\n })\n\n const ctx = buildSkillContext({\n packageName: identityName,\n cachePackageName: pkgName,\n version,\n skillDir,\n skillDirName: name,\n resources,\n prepared,\n resolved,\n packages: parsePackageNames(info.packages),\n features,\n })\n\n if (!copyFromExistingAgent(skillDir, name, allSkillsDirs)) {\n if (!existsSync(join(skillDir, 'SKILL.md'))) {\n writeBaseSkill(ctx)\n regenerated.push({ name, ctx })\n }\n }\n spin.stop(wasCacheHit ? `Linked ${name}` : `Downloaded and linked ${name}`)\n }\n\n // Offer LLM enhancement for regenerated SKILL.md files\n if (regenerated.length > 0 && !readConfig().skipLlm) {\n const names = regenerated.map(r => r.name).join(', ')\n const llmConfig = await selectLlmConfig(undefined, `Enhance SKILL.md for ${names}`)\n if (llmConfig?.promptOnly) {\n for (const { ctx } of regenerated)\n writePromptFiles(ctx, { sections: llmConfig.sections, customPrompt: llmConfig.customPrompt })\n }\n else if (llmConfig) {\n p.log.step(getModelLabel(llmConfig.model))\n for (const { ctx } of regenerated) {\n await enhanceSkillWithLLM(ctx, {\n model: llmConfig.model,\n sections: llmConfig.sections,\n customPrompt: llmConfig.customPrompt,\n })\n }\n }\n }\n\n // Write merged lockfile to target dir and sync to all other existing lockfiles\n for (const [name, info] of Object.entries(lock.skills))\n writeLock(skillsDir, name, info)\n\n // In shared mode: recreate per-agent symlinks, skip per-agent lockfile sync\n if (shared) {\n for (const [name] of skills)\n linkSkillToAgents(name, shared, cwd, opts.agent)\n }\n else {\n syncLockfilesToDirs(lock, allSkillsDirs.filter(d => d !== skillsDir))\n }\n\n await shutdownWorker()\n\n p.outro('Install complete')\n}\n\n/** Copy SKILL.md from another agent's skill dir if one exists */\nfunction copyFromExistingAgent(skillDir: string, name: string, allSkillsDirs: string[]): boolean {\n const targetMd = join(skillDir, 'SKILL.md')\n if (existsSync(targetMd))\n return false\n for (const dir of allSkillsDirs) {\n if (dir === skillDir)\n continue\n const candidateMd = join(dir, name, 'SKILL.md')\n if (existsSync(candidateMd) && !lstatSync(candidateMd).isSymbolicLink()) {\n mkdirSync(skillDir, { recursive: true })\n copyFileSync(candidateMd, targetMd)\n return true\n }\n }\n return false\n}\n\n/** Try to recover original package name from sanitized name + source */\nfunction unsanitizeName(sanitized: string, source?: string): string {\n if (source?.includes('ungh://')) {\n const match = source.match(STATIC_REGEX_1)\n if (match)\n return `@${match[1]}/${match[2]}`\n }\n\n if (sanitized.startsWith('antfu-'))\n return `@antfu/${sanitized.slice(6)}`\n if (sanitized.startsWith('clack-'))\n return `@clack/${sanitized.slice(6)}`\n if (sanitized.startsWith('nuxt-'))\n return `@nuxt/${sanitized.slice(5)}`\n if (sanitized.startsWith('vue-'))\n return `@vue/${sanitized.slice(4)}`\n if (sanitized.startsWith('vueuse-'))\n return `@vueuse/${sanitized.slice(7)}`\n\n return sanitized\n}\n\n/** Build a minimal ResolvedPackage from lockfile state for cache-hit restoration. */\nfunction synthesizeResolved(identityName: string, version: string, info: SkillInfo, cwd: string): ResolvedPackage {\n const repoUrl = info.repo?.includes('/') ? `https://github.com/${info.repo}` : undefined\n const pkgPath = resolvePkgDir(toStoragePackageName(identityName), cwd, version)\n const description = pkgPath\n ? readPackageJsonSafe(join(pkgPath, 'package.json'))?.parsed.description as string | undefined\n : undefined\n return { name: identityName, version, repoUrl, description }\n}\n\nexport const installCommandDef = defineCommand({\n meta: { name: 'install', description: 'Restore references from lockfile' },\n args: {\n global: sharedArgs.global,\n agent: sharedArgs.agent,\n },\n async run({ args }) {\n let agent = resolveAgent(args.agent)\n if (!agent || agent === 'none') {\n if (agent === 'none')\n return\n const picked = await promptForAgent()\n if (!picked || picked === 'none')\n return\n agent = picked\n }\n\n p.intro(`${styleText(['bold', 'magenta'], 'skilld')} install`)\n return installCommand({ global: args.global, agent })\n },\n})\n\n/** Check if .skilld/ has broken symlinks or is missing expected references from global cache */\nfunction hasStaleReferences(referencesPath: string, pkgName: string, version: string, features: FeaturesConfig): boolean {\n // Scan existing entries for broken symlinks\n for (const entry of readdirSync(referencesPath)) {\n const entryPath = join(referencesPath, entry)\n if (lstatSync(entryPath).isSymbolicLink() && !existsSync(entryPath))\n return true\n }\n\n // Check pkg link always expected\n if (!existsSync(join(referencesPath, 'pkg')))\n return true\n\n // Check expected links against global cache\n const globalCachePath = getCacheDir(pkgName, version)\n const expected: Array<[string, boolean]> = [\n ['docs', existsSync(join(globalCachePath, 'docs'))],\n ['issues', features.issues && existsSync(join(globalCachePath, 'issues'))],\n ['discussions', features.discussions && existsSync(join(globalCachePath, 'discussions'))],\n ['releases', features.releases && existsSync(join(globalCachePath, 'releases'))],\n ['sections', existsSync(join(globalCachePath, 'sections'))],\n ]\n\n for (const [name, shouldExist] of expected) {\n if (shouldExist && !existsSync(join(referencesPath, name)))\n return true\n }\n\n return false\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { a as targets, i as getAgentVersion, t as detectInstalledAgents } from "./detect.mjs";
|
|
2
|
+
import { a as getModelName } from "./agent.mjs";
|
|
3
|
+
import { a as GIT_PROTOCOL_PREFIX_RE, i as GIT_PLUS_PREFIX_RE, o as GIT_SUFFIX_RE, r as GITHUB_SSH_URL_PREFIX_RE } from "./regex.mjs";
|
|
4
|
+
import { i as readPackageJsonSafe } from "./package-json.mjs";
|
|
5
|
+
import { t as version } from "./version.mjs";
|
|
6
|
+
import { styleText } from "node:util";
|
|
7
|
+
import { join } from "pathe";
|
|
8
|
+
const STATIC_REGEX_5 = /^https?:\/\/(www\.)?github\.com\//;
|
|
9
|
+
function getInstalledGenerators() {
|
|
10
|
+
return detectInstalledAgents().filter((id) => targets[id].cli).map((id) => {
|
|
11
|
+
const ver = getAgentVersion(id);
|
|
12
|
+
return ver ? {
|
|
13
|
+
name: targets[id].displayName,
|
|
14
|
+
version: ver
|
|
15
|
+
} : null;
|
|
16
|
+
}).filter((a) => a !== null);
|
|
17
|
+
}
|
|
18
|
+
function relativeTime(date) {
|
|
19
|
+
const diff = Date.now() - date.getTime();
|
|
20
|
+
const mins = Math.floor(diff / 6e4);
|
|
21
|
+
const hours = Math.floor(diff / 36e5);
|
|
22
|
+
const days = Math.floor(diff / 864e5);
|
|
23
|
+
if (mins < 1) return "just now";
|
|
24
|
+
if (mins < 60) return `${mins}m ago`;
|
|
25
|
+
if (hours < 24) return `${hours}h ago`;
|
|
26
|
+
return `${days}d ago`;
|
|
27
|
+
}
|
|
28
|
+
function getLastSynced(state) {
|
|
29
|
+
let latest = null;
|
|
30
|
+
for (const skill of state.skills) if (skill.info?.syncedAt) {
|
|
31
|
+
const d = new Date(skill.info.syncedAt);
|
|
32
|
+
if (!latest || d > latest) latest = d;
|
|
33
|
+
}
|
|
34
|
+
return latest ? relativeTime(latest) : null;
|
|
35
|
+
}
|
|
36
|
+
function introLine({ state, generators, modelId, agentId }) {
|
|
37
|
+
const name = styleText(["bold", "magenta"], "skilld");
|
|
38
|
+
const ver = styleText("gray", `v${version}`);
|
|
39
|
+
const lastSynced = getLastSynced(state);
|
|
40
|
+
const synced = lastSynced ? ` · ${styleText("gray", `synced ${lastSynced}`)}` : "";
|
|
41
|
+
const parts = [];
|
|
42
|
+
if (modelId) parts.push(getModelName(modelId));
|
|
43
|
+
else if (generators?.length) parts.push(generators.map((g) => `${g.name} v${g.version}`).join(", "));
|
|
44
|
+
if (agentId && targets[agentId]) parts.push(targets[agentId].displayName);
|
|
45
|
+
return `${name} ${ver}${synced}${parts.length > 0 ? `\n${styleText("gray", `↳ ${parts.join(" → ")}`)}` : ""}`;
|
|
46
|
+
}
|
|
47
|
+
function formatStatus(synced, outdated) {
|
|
48
|
+
const parts = [];
|
|
49
|
+
if (synced > 0) parts.push(styleText("green", `${synced} synced`));
|
|
50
|
+
if (outdated > 0) parts.push(styleText("yellow", `${outdated} outdated`));
|
|
51
|
+
return `Skills: ${parts.join(" · ")}`;
|
|
52
|
+
}
|
|
53
|
+
function getRepoHint(name, cwd) {
|
|
54
|
+
const result = readPackageJsonSafe(join(cwd, "node_modules", name, "package.json"));
|
|
55
|
+
if (!result) return void 0;
|
|
56
|
+
const pkg = result.parsed;
|
|
57
|
+
const url = typeof pkg.repository === "string" ? pkg.repository : pkg.repository?.url;
|
|
58
|
+
if (!url) return void 0;
|
|
59
|
+
return url.replace(GIT_PLUS_PREFIX_RE, "").replace(GIT_SUFFIX_RE, "").replace(GIT_PROTOCOL_PREFIX_RE, "https://").replace(GITHUB_SSH_URL_PREFIX_RE, "https://github.com").replace(STATIC_REGEX_5, "");
|
|
60
|
+
}
|
|
61
|
+
export { relativeTime as a, introLine as i, getInstalledGenerators as n, getRepoHint as r, formatStatus as t };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=intro.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intro.mjs","names":["agents"],"sources":["../../src/cli/intro.ts"],"sourcesContent":["import type { AgentType } from '../agent/index.ts'\nimport type { ProjectState } from '../core/skills.ts'\nimport { styleText } from 'node:util'\nimport { join } from 'pathe'\nimport { agents, detectInstalledAgents, getAgentVersion, getModelName } from '../agent/index.ts'\nimport { readPackageJsonSafe } from '../core/package-json.ts'\nimport { GIT_PLUS_PREFIX_RE, GIT_PROTOCOL_PREFIX_RE, GIT_SUFFIX_RE, GITHUB_SSH_URL_PREFIX_RE } from '../core/regex.ts'\nimport { version } from '../version.ts'\n\nconst STATIC_REGEX_5 = /^https?:\\/\\/(www\\.)?github\\.com\\//\n\nexport interface IntroOptions {\n state: ProjectState\n generators?: Array<{ name: string, version: string }>\n modelId?: string\n agentId?: string\n}\n\nexport function getInstalledGenerators(): Array<{ name: string, version: string }> {\n const installed = detectInstalledAgents()\n return installed\n .filter(id => agents[id].cli)\n .map((id) => {\n const ver = getAgentVersion(id)\n return ver ? { name: agents[id].displayName, version: ver } : null\n })\n .filter((a): a is { name: string, version: string } => a !== null)\n}\n\nexport function relativeTime(date: Date): string {\n const now = Date.now()\n const diff = now - date.getTime()\n const mins = Math.floor(diff / 60000)\n const hours = Math.floor(diff / 3600000)\n const days = Math.floor(diff / 86400000)\n if (mins < 1)\n return 'just now'\n if (mins < 60)\n return `${mins}m ago`\n if (hours < 24)\n return `${hours}h ago`\n return `${days}d ago`\n}\n\nexport function getLastSynced(state: ProjectState): string | null {\n let latest: Date | null = null\n for (const skill of state.skills) {\n if (skill.info?.syncedAt) {\n const d = new Date(skill.info.syncedAt)\n if (!latest || d > latest)\n latest = d\n }\n }\n return latest ? relativeTime(latest) : null\n}\n\nexport function introLine({ state, generators, modelId, agentId }: IntroOptions): string {\n const name = styleText(['bold', 'magenta'], 'skilld')\n const ver = styleText('gray', `v${version}`)\n const lastSynced = getLastSynced(state)\n const synced = lastSynced ? ` · ${styleText('gray', `synced ${lastSynced}`)}` : ''\n\n const parts: string[] = []\n if (modelId)\n parts.push(getModelName(modelId as any))\n else if (generators?.length)\n parts.push(generators.map(g => `${g.name} v${g.version}`).join(', '))\n if (agentId && agents[agentId as AgentType])\n parts.push(agents[agentId as AgentType].displayName)\n const statusLine = parts.length > 0\n ? `\\n${styleText('gray', `↳ ${parts.join(' → ')}`)}`\n : ''\n\n return `${name} ${ver}${synced}${statusLine}`\n}\n\nexport function formatStatus(synced: number, outdated: number): string {\n const parts: string[] = []\n if (synced > 0)\n parts.push(styleText('green', `${synced} synced`))\n if (outdated > 0)\n parts.push(styleText('yellow', `${outdated} outdated`))\n return `Skills: ${parts.join(' · ')}`\n}\n\nexport function getRepoHint(name: string, cwd: string): string | undefined {\n const result = readPackageJsonSafe(join(cwd, 'node_modules', name, 'package.json'))\n if (!result)\n return undefined\n const pkg = result.parsed as Record<string, any>\n const url = typeof pkg.repository === 'string'\n ? pkg.repository\n : pkg.repository?.url\n if (!url)\n return undefined\n return url\n .replace(GIT_PLUS_PREFIX_RE, '')\n .replace(GIT_SUFFIX_RE, '')\n .replace(GIT_PROTOCOL_PREFIX_RE, 'https://')\n .replace(GITHUB_SSH_URL_PREFIX_RE, 'https://github.com')\n .replace(STATIC_REGEX_5, '')\n}\n"],"mappings":";;;;;;;AASA,MAAM,iBAAiB;AASvB,SAAgB,yBAAmE;CAEjF,OADkB,uBACF,CACb,QAAO,OAAMA,QAAO,IAAI,IAAI,CAC5B,KAAK,OAAO;EACX,MAAM,MAAM,gBAAgB,GAAG;EAC/B,OAAO,MAAM;GAAE,MAAMA,QAAO,IAAI;GAAa,SAAS;GAAK,GAAG;GAC9D,CACD,QAAQ,MAA8C,MAAM,KAAK;;AAGtE,SAAgB,aAAa,MAAoB;CAE/C,MAAM,OADM,KAAK,KACD,GAAG,KAAK,SAAS;CACjC,MAAM,OAAO,KAAK,MAAM,OAAO,IAAM;CACrC,MAAM,QAAQ,KAAK,MAAM,OAAO,KAAQ;CACxC,MAAM,OAAO,KAAK,MAAM,OAAO,MAAS;CACxC,IAAI,OAAO,GACT,OAAO;CACT,IAAI,OAAO,IACT,OAAO,GAAG,KAAK;CACjB,IAAI,QAAQ,IACV,OAAO,GAAG,MAAM;CAClB,OAAO,GAAG,KAAK;;AAGjB,SAAgB,cAAc,OAAoC;CAChE,IAAI,SAAsB;CAC1B,KAAK,MAAM,SAAS,MAAM,QACxB,IAAI,MAAM,MAAM,UAAU;EACxB,MAAM,IAAI,IAAI,KAAK,MAAM,KAAK,SAAS;EACvC,IAAI,CAAC,UAAU,IAAI,QACjB,SAAS;;CAGf,OAAO,SAAS,aAAa,OAAO,GAAG;;AAGzC,SAAgB,UAAU,EAAE,OAAO,YAAY,SAAS,WAAiC;CACvF,MAAM,OAAO,UAAU,CAAC,QAAQ,UAAU,EAAE,SAAS;CACrD,MAAM,MAAM,UAAU,QAAQ,IAAI,UAAU;CAC5C,MAAM,aAAa,cAAc,MAAM;CACvC,MAAM,SAAS,aAAa,MAAM,UAAU,QAAQ,UAAU,aAAa,KAAK;CAEhF,MAAM,QAAkB,EAAE;CAC1B,IAAI,SACF,MAAM,KAAK,aAAa,QAAe,CAAC;MACrC,IAAI,YAAY,QACnB,MAAM,KAAK,WAAW,KAAI,MAAK,GAAG,EAAE,KAAK,IAAI,EAAE,UAAU,CAAC,KAAK,KAAK,CAAC;CACvE,IAAI,WAAWA,QAAO,UACpB,MAAM,KAAKA,QAAO,SAAsB,YAAY;CAKtD,OAAO,GAAG,KAAK,GAAG,MAAM,SAJL,MAAM,SAAS,IAC9B,KAAK,UAAU,QAAQ,KAAK,MAAM,KAAK,MAAM,GAAG,KAChD;;AAKN,SAAgB,aAAa,QAAgB,UAA0B;CACrE,MAAM,QAAkB,EAAE;CAC1B,IAAI,SAAS,GACX,MAAM,KAAK,UAAU,SAAS,GAAG,OAAO,SAAS,CAAC;CACpD,IAAI,WAAW,GACb,MAAM,KAAK,UAAU,UAAU,GAAG,SAAS,WAAW,CAAC;CACzD,OAAO,WAAW,MAAM,KAAK,MAAM;;AAGrC,SAAgB,YAAY,MAAc,KAAiC;CACzE,MAAM,SAAS,oBAAoB,KAAK,KAAK,gBAAgB,MAAM,eAAe,CAAC;CACnF,IAAI,CAAC,QACH,OAAO,KAAA;CACT,MAAM,MAAM,OAAO;CACnB,MAAM,MAAM,OAAO,IAAI,eAAe,WAClC,IAAI,aACJ,IAAI,YAAY;CACpB,IAAI,CAAC,KACH,OAAO,KAAA;CACT,OAAO,IACJ,QAAQ,oBAAoB,GAAG,CAC/B,QAAQ,eAAe,GAAG,CAC1B,QAAQ,wBAAwB,WAAW,CAC3C,QAAQ,0BAA0B,qBAAqB,CACvD,QAAQ,gBAAgB,GAAG"}
|
package/dist/_chunks/list.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { m as timeAgo, u as formatSource } from "./prompts.mjs";
|
|
2
|
+
import { t as sharedArgs } from "./args.mjs";
|
|
3
3
|
import { i as iterateSkills, t as getProjectState } from "./skills.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
async function listCommand(opts = {}) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.mjs","names":[],"sources":["../../src/commands/list.ts"],"sourcesContent":["import { defineCommand } from 'citty'\nimport { sharedArgs } from '../cli
|
|
1
|
+
{"version":3,"file":"list.mjs","names":[],"sources":["../../src/commands/list.ts"],"sourcesContent":["import { defineCommand } from 'citty'\nimport { sharedArgs } from '../cli/args.ts'\nimport { formatSource, timeAgo } from '../core/formatting.ts'\nimport { getProjectState, iterateSkills } from '../core/skills.ts'\n\nexport interface ListOptions {\n global?: boolean\n json?: boolean\n outdated?: boolean\n}\n\ninterface ListEntry {\n name: string\n version: string\n source: string\n synced: string\n latest?: string\n}\n\nexport async function listCommand(opts: ListOptions = {}): Promise<void> {\n if (opts.outdated) {\n const state = await getProjectState()\n const entries: ListEntry[] = state.outdated.map(skill => ({\n name: skill.name,\n version: skill.info?.version || '',\n latest: skill.latestVersion || '',\n source: formatSource(skill.info?.source),\n synced: timeAgo(skill.info?.syncedAt),\n }))\n\n if (opts.json) {\n process.stdout.write(`${JSON.stringify(entries)}\\n`)\n return\n }\n\n if (entries.length === 0) {\n process.stdout.write('All skills are up to date\\n')\n return\n }\n\n const nameW = Math.max(...entries.map(e => e.name.length))\n const verW = Math.max(...entries.map(e => e.version.length))\n const latW = Math.max(...entries.map(e => (e.latest || '').length))\n const srcW = Math.max(...entries.map(e => e.source.length))\n\n for (const e of entries) {\n const line = [\n e.name.padEnd(nameW),\n `${e.version.padEnd(verW)} → ${(e.latest || '').padEnd(latW)}`,\n e.source.padEnd(srcW),\n e.synced,\n ].join(' ')\n process.stdout.write(`${line}\\n`)\n }\n return\n }\n\n const scope = opts.global ? 'global' : 'all'\n const skills = [...iterateSkills({ scope })]\n\n // Deduplicate by package identity\n const seen = new Set<string>()\n const entries: ListEntry[] = []\n\n for (const skill of skills) {\n const key = skill.info?.packageName || skill.name\n if (seen.has(key))\n continue\n seen.add(key)\n entries.push({\n name: skill.name,\n version: skill.info?.version || '',\n source: formatSource(skill.info?.source),\n synced: timeAgo(skill.info?.syncedAt),\n })\n }\n\n if (opts.json) {\n process.stdout.write(`${JSON.stringify(entries)}\\n`)\n return\n }\n\n if (entries.length === 0) {\n process.stdout.write('No skills installed\\n')\n return\n }\n\n // Column widths\n const nameW = Math.max(...entries.map(e => e.name.length))\n const verW = Math.max(...entries.map(e => e.version.length))\n const srcW = Math.max(...entries.map(e => e.source.length))\n\n for (const e of entries) {\n const line = [\n e.name.padEnd(nameW),\n e.version.padEnd(verW),\n e.source.padEnd(srcW),\n e.synced,\n ].join(' ')\n process.stdout.write(`${line}\\n`)\n }\n}\n\nexport const listCommandDef = defineCommand({\n meta: { name: 'list', description: 'List installed skills' },\n args: {\n global: sharedArgs.global,\n json: {\n type: 'boolean' as const,\n description: 'Output as JSON',\n default: false,\n },\n outdated: {\n type: 'boolean' as const,\n alias: 'o',\n description: 'Show only outdated skills',\n default: false,\n },\n },\n run({ args }) {\n return listCommand({ global: args.global, json: args.json, outdated: args.outdated })\n },\n})\n"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { p as lockfilePath } from "./paths.mjs";
|
|
1
2
|
import { n as yamlParseKV, t as yamlEscape } from "./yaml.mjs";
|
|
2
3
|
import { i as parseFrontmatter } from "./markdown.mjs";
|
|
3
|
-
import { join } from "pathe";
|
|
4
4
|
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
|
+
const STATIC_REGEX_1 = /^ {2}(\S+):$/;
|
|
5
6
|
function parsePackages(packages) {
|
|
6
7
|
if (!packages) return [];
|
|
7
8
|
return packages.split(",").map((s) => {
|
|
@@ -54,13 +55,13 @@ function invalidateLockCache(skillsDir) {
|
|
|
54
55
|
function readLock(skillsDir) {
|
|
55
56
|
const cached = lockCache.get(skillsDir);
|
|
56
57
|
if (cached) return { skills: { ...cached.skills } };
|
|
57
|
-
const lockPath =
|
|
58
|
+
const lockPath = lockfilePath(skillsDir);
|
|
58
59
|
if (!existsSync(lockPath)) return null;
|
|
59
60
|
const content = readFileSync(lockPath, "utf-8");
|
|
60
61
|
const skills = {};
|
|
61
62
|
let currentSkill = null;
|
|
62
63
|
for (const line of content.split("\n")) {
|
|
63
|
-
const skillMatch = line.match(
|
|
64
|
+
const skillMatch = line.match(STATIC_REGEX_1);
|
|
64
65
|
if (skillMatch) {
|
|
65
66
|
currentSkill = skillMatch[1];
|
|
66
67
|
skills[currentSkill] = {};
|
|
@@ -76,6 +77,29 @@ function readLock(skillsDir) {
|
|
|
76
77
|
lockCache.set(skillsDir, lock);
|
|
77
78
|
return { skills: { ...lock.skills } };
|
|
78
79
|
}
|
|
80
|
+
function findSkillDirByPackage(lock, packageName) {
|
|
81
|
+
for (const [dirName, info] of Object.entries(lock.skills)) {
|
|
82
|
+
if (info.packageName === packageName) return dirName;
|
|
83
|
+
if (parsePackages(info.packages).some((p) => p.name === packageName)) return dirName;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
function findSkillDirsByPackage(lock, packageName, excludeDir) {
|
|
88
|
+
const out = [];
|
|
89
|
+
for (const [dirName, info] of Object.entries(lock.skills)) {
|
|
90
|
+
if (dirName === excludeDir) continue;
|
|
91
|
+
if (info.packageName === packageName || parsePackages(info.packages).some((p) => p.name === packageName)) out.push(dirName);
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
function buildPackageDirMap(lock) {
|
|
96
|
+
const map = /* @__PURE__ */ new Map();
|
|
97
|
+
for (const [dirName, info] of Object.entries(lock.skills)) {
|
|
98
|
+
if (info.packageName) map.set(info.packageName, dirName);
|
|
99
|
+
for (const pkg of parsePackages(info.packages)) map.set(pkg.name, dirName);
|
|
100
|
+
}
|
|
101
|
+
return map;
|
|
102
|
+
}
|
|
79
103
|
function serializeLock(lock) {
|
|
80
104
|
let yaml = "skills:\n";
|
|
81
105
|
for (const [name, skill] of Object.entries(lock.skills)) {
|
|
@@ -85,7 +109,7 @@ function serializeLock(lock) {
|
|
|
85
109
|
return yaml;
|
|
86
110
|
}
|
|
87
111
|
function writeLock(skillsDir, skillName, info) {
|
|
88
|
-
const lockPath =
|
|
112
|
+
const lockPath = lockfilePath(skillsDir);
|
|
89
113
|
let lock = { skills: {} };
|
|
90
114
|
if (existsSync(lockPath)) lock = readLock(skillsDir) || { skills: {} };
|
|
91
115
|
const existing = lock.skills[skillName];
|
|
@@ -122,7 +146,7 @@ function mergeLocks(locks) {
|
|
|
122
146
|
}
|
|
123
147
|
function syncLockfilesToDirs(sourceLock, dirs) {
|
|
124
148
|
for (const dir of dirs) {
|
|
125
|
-
const lockPath =
|
|
149
|
+
const lockPath = lockfilePath(dir);
|
|
126
150
|
if (!existsSync(lockPath)) continue;
|
|
127
151
|
const existing = readLock(dir);
|
|
128
152
|
if (!existing) continue;
|
|
@@ -131,7 +155,7 @@ function syncLockfilesToDirs(sourceLock, dirs) {
|
|
|
131
155
|
}
|
|
132
156
|
}
|
|
133
157
|
function removeLockEntry(skillsDir, skillName) {
|
|
134
|
-
const lockPath =
|
|
158
|
+
const lockPath = lockfilePath(skillsDir);
|
|
135
159
|
const lock = readLock(skillsDir);
|
|
136
160
|
if (!lock) return;
|
|
137
161
|
delete lock.skills[skillName];
|
|
@@ -143,6 +167,6 @@ function removeLockEntry(skillsDir, skillName) {
|
|
|
143
167
|
writeFileSync(lockPath, serializeLock(lock));
|
|
144
168
|
invalidateLockCache(skillsDir);
|
|
145
169
|
}
|
|
146
|
-
export {
|
|
170
|
+
export { parsePackageNames as a, readLock as c, writeLock as d, mergeLocks as i, removeLockEntry as l, findSkillDirByPackage as n, parsePackages as o, findSkillDirsByPackage as r, parseSkillFrontmatter as s, buildPackageDirMap as t, syncLockfilesToDirs as u };
|
|
147
171
|
|
|
148
172
|
//# sourceMappingURL=lockfile.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lockfile.mjs","names":[],"sources":["../../src/core/lockfile.ts"],"sourcesContent":["import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { parseFrontmatter } from './markdown.ts'\nimport { yamlEscape, yamlParseKV } from './yaml.ts'\n\nexport interface SkillInfo {\n packageName?: string\n version?: string\n /** All tracked packages as comma-separated \"name@version\" pairs (multi-package skills) */\n packages?: string\n repo?: string\n source?: string\n syncedAt?: string\n generator?: string\n /** Skill path within repo (git-sourced skills) */\n path?: string\n /** Git ref tracked for updates */\n ref?: string\n /** Git commit SHA at install time */\n commit?: string\n}\n\nexport function parsePackages(packages?: string): Array<{ name: string, version: string }> {\n if (!packages)\n return []\n return packages.split(',').map((s) => {\n const trimmed = s.trim()\n const atIdx = trimmed.lastIndexOf('@')\n if (atIdx <= 0)\n return { name: trimmed, version: '' }\n return { name: trimmed.slice(0, atIdx), version: trimmed.slice(atIdx + 1) }\n }).filter(p => p.name)\n}\n\nexport function parsePackageNames(packages?: string): Array<{ name: string }> {\n return parsePackages(packages).map(({ name }) => ({ name }))\n}\n\nexport function serializePackages(pkgs: Array<{ name: string, version: string }>): string {\n return pkgs.map(p => `${p.name}@${p.version}`).join(', ')\n}\n\nexport interface SkilldLock {\n skills: Record<string, SkillInfo>\n}\n\nconst SKILL_FM_KEYS: (keyof SkillInfo)[] = ['packageName', 'version', 'packages', 'repo', 'source', 'syncedAt', 'generator', 'path', 'ref', 'commit']\n\nfunction isSkillInfoKey(key: string): key is keyof SkillInfo {\n return (SKILL_FM_KEYS as readonly string[]).includes(key)\n}\n\nexport function parseSkillFrontmatter(skillPath: string): SkillInfo | null {\n if (!existsSync(skillPath))\n return null\n const content = readFileSync(skillPath, 'utf-8')\n const fm = parseFrontmatter(content)\n if (Object.keys(fm).length === 0)\n return null\n\n const info: SkillInfo = {}\n for (const key of SKILL_FM_KEYS) {\n if (fm[key])\n info[key] = fm[key]\n }\n return info\n}\n\nconst lockCache = new Map<string, SkilldLock>()\n\nexport function invalidateLockCache(skillsDir?: string): void {\n if (skillsDir)\n lockCache.delete(skillsDir)\n else\n lockCache.clear()\n}\n\nexport function readLock(skillsDir: string): SkilldLock | null {\n const cached = lockCache.get(skillsDir)\n if (cached)\n return { skills: { ...cached.skills } }\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n if (!existsSync(lockPath))\n return null\n const content = readFileSync(lockPath, 'utf-8')\n\n const skills: Record<string, SkillInfo> = {}\n let currentSkill: string | null = null\n\n for (const line of content.split('\\n')) {\n const skillMatch = line.match(/^ {2}(\\S+):$/)\n if (skillMatch) {\n currentSkill = skillMatch[1]!\n skills[currentSkill] = {}\n continue\n }\n if (currentSkill && line.startsWith(' ')) {\n const kv = yamlParseKV(line)\n if (kv && isSkillInfoKey(kv[0]))\n skills[currentSkill]![kv[0]] = kv[1]\n }\n }\n // Normalize legacy source values\n for (const info of Object.values(skills)) {\n if (info.source === 'npm')\n info.source = 'registry'\n }\n const lock = { skills }\n lockCache.set(skillsDir, lock)\n return { skills: { ...lock.skills } }\n}\n\nfunction serializeLock(lock: SkilldLock): string {\n let yaml = 'skills:\\n'\n for (const [name, skill] of Object.entries(lock.skills)) {\n yaml += ` ${name}:\\n`\n for (const key of SKILL_FM_KEYS) {\n if (skill[key])\n yaml += ` ${key}: ${yamlEscape(skill[key])}\\n`\n }\n }\n return yaml\n}\n\nexport function writeLock(skillsDir: string, skillName: string, info: SkillInfo): void {\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n let lock: SkilldLock = { skills: {} }\n if (existsSync(lockPath)) {\n lock = readLock(skillsDir) || { skills: {} }\n }\n\n const existing = lock.skills[skillName]\n if (existing && info.packageName) {\n // Merge packages list\n const existingPkgs = parsePackages(existing.packages)\n // Also include existing primary if not yet in packages list\n if (existing.packageName && !existingPkgs.some(p => p.name === existing.packageName)) {\n existingPkgs.unshift({ name: existing.packageName, version: existing.version || '' })\n }\n // Add/update new package\n const idx = existingPkgs.findIndex(p => p.name === info.packageName)\n if (idx >= 0) {\n existingPkgs[idx]!.version = info.version || ''\n }\n else {\n existingPkgs.push({ name: info.packageName, version: info.version || '' })\n }\n info.packages = serializePackages(existingPkgs)\n // Keep primary as first package\n info.packageName = existingPkgs[0]!.name\n info.version = existingPkgs[0]!.version\n // Preserve fields from existing entry that aren't in new info\n if (!info.repo && existing.repo)\n info.repo = existing.repo\n if (!info.source && existing.source)\n info.source = existing.source\n if (!info.generator && existing.generator)\n info.generator = existing.generator\n }\n\n lock.skills[skillName] = info\n writeFileSync(lockPath, serializeLock(lock))\n invalidateLockCache(skillsDir)\n}\n\n/**\n * Merge multiple lockfiles, preferring the most recently synced entry per skill.\n */\nexport function mergeLocks(locks: SkilldLock[]): SkilldLock {\n const merged: Record<string, SkillInfo> = {}\n for (const lock of locks) {\n for (const [name, info] of Object.entries(lock.skills)) {\n const existing = merged[name]\n if (!existing || (info.syncedAt && (!existing.syncedAt || info.syncedAt > existing.syncedAt)))\n merged[name] = info\n }\n }\n return { skills: merged }\n}\n\n/**\n * Sync a lockfile to all other dirs that already have a skilld-lock.yaml.\n * Only updates existing lockfiles — does not create new ones.\n */\nexport function syncLockfilesToDirs(sourceLock: SkilldLock, dirs: string[]): void {\n for (const dir of dirs) {\n const lockPath = join(dir, 'skilld-lock.yaml')\n if (!existsSync(lockPath))\n continue\n const existing = readLock(dir)\n if (!existing)\n continue\n // Merge source into existing\n const merged = mergeLocks([existing, sourceLock])\n writeFileSync(lockPath, serializeLock(merged))\n invalidateLockCache(dir)\n }\n}\n\nexport function removeLockEntry(skillsDir: string, skillName: string): void {\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n const lock = readLock(skillsDir)\n if (!lock)\n return\n\n delete lock.skills[skillName]\n\n if (Object.keys(lock.skills).length === 0) {\n unlinkSync(lockPath)\n invalidateLockCache(skillsDir)\n return\n }\n\n writeFileSync(lockPath, serializeLock(lock))\n invalidateLockCache(skillsDir)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lockfile.mjs","names":[],"sources":["../../src/core/lockfile.ts"],"sourcesContent":["import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { parseFrontmatter } from './markdown.ts'\nimport { lockfilePath } from './paths.ts'\nimport { yamlEscape, yamlParseKV } from './yaml.ts'\n\nconst STATIC_REGEX_1 = /^ {2}(\\S+):$/\n\nexport interface SkillInfo {\n packageName?: string\n version?: string\n /** All tracked packages as comma-separated \"name@version\" pairs (multi-package skills) */\n packages?: string\n repo?: string\n source?: string\n syncedAt?: string\n generator?: string\n /** Skill path within repo (git-sourced skills) */\n path?: string\n /** Git ref tracked for updates */\n ref?: string\n /** Git commit SHA at install time */\n commit?: string\n}\n\nexport function parsePackages(packages?: string): Array<{ name: string, version: string }> {\n if (!packages)\n return []\n return packages.split(',').map((s) => {\n const trimmed = s.trim()\n const atIdx = trimmed.lastIndexOf('@')\n if (atIdx <= 0)\n return { name: trimmed, version: '' }\n return { name: trimmed.slice(0, atIdx), version: trimmed.slice(atIdx + 1) }\n }).filter(p => p.name)\n}\n\nexport function parsePackageNames(packages?: string): Array<{ name: string }> {\n return parsePackages(packages).map(({ name }) => ({ name }))\n}\n\nexport function serializePackages(pkgs: Array<{ name: string, version: string }>): string {\n return pkgs.map(p => `${p.name}@${p.version}`).join(', ')\n}\n\nexport interface SkilldLock {\n skills: Record<string, SkillInfo>\n}\n\nconst SKILL_FM_KEYS: (keyof SkillInfo)[] = ['packageName', 'version', 'packages', 'repo', 'source', 'syncedAt', 'generator', 'path', 'ref', 'commit']\n\nfunction isSkillInfoKey(key: string): key is keyof SkillInfo {\n return (SKILL_FM_KEYS as readonly string[]).includes(key)\n}\n\nexport function parseSkillFrontmatter(skillPath: string): SkillInfo | null {\n if (!existsSync(skillPath))\n return null\n const content = readFileSync(skillPath, 'utf-8')\n const fm = parseFrontmatter(content)\n if (Object.keys(fm).length === 0)\n return null\n\n const info: SkillInfo = {}\n for (const key of SKILL_FM_KEYS) {\n if (fm[key])\n info[key] = fm[key]\n }\n return info\n}\n\nconst lockCache = new Map<string, SkilldLock>()\n\nexport function invalidateLockCache(skillsDir?: string): void {\n if (skillsDir)\n lockCache.delete(skillsDir)\n else\n lockCache.clear()\n}\n\nexport function readLock(skillsDir: string): SkilldLock | null {\n const cached = lockCache.get(skillsDir)\n if (cached)\n return { skills: { ...cached.skills } }\n const lockPath = lockfilePath(skillsDir)\n if (!existsSync(lockPath))\n return null\n const content = readFileSync(lockPath, 'utf-8')\n\n const skills: Record<string, SkillInfo> = {}\n let currentSkill: string | null = null\n\n for (const line of content.split('\\n')) {\n const skillMatch = line.match(STATIC_REGEX_1)\n if (skillMatch) {\n currentSkill = skillMatch[1]!\n skills[currentSkill] = {}\n continue\n }\n if (currentSkill && line.startsWith(' ')) {\n const kv = yamlParseKV(line)\n if (kv && isSkillInfoKey(kv[0]))\n skills[currentSkill]![kv[0]] = kv[1]\n }\n }\n // Normalize legacy source values\n for (const info of Object.values(skills)) {\n if (info.source === 'npm')\n info.source = 'registry'\n }\n const lock = { skills }\n lockCache.set(skillsDir, lock)\n return { skills: { ...lock.skills } }\n}\n\n/**\n * Find the skill dir that tracks `packageName` (as primary or in `packages`),\n * or null. Single source of truth for \"is this package already synced?\".\n */\nexport function findSkillDirByPackage(lock: SkilldLock, packageName: string): string | null {\n for (const [dirName, info] of Object.entries(lock.skills)) {\n if (info.packageName === packageName)\n return dirName\n if (parsePackages(info.packages).some(p => p.name === packageName))\n return dirName\n }\n return null\n}\n\n/**\n * Every skill dir referencing `packageName`, optionally excluding one. Used by\n * the installer to dedupe stale entries when a skill is renamed or merged.\n */\nexport function findSkillDirsByPackage(lock: SkilldLock, packageName: string, excludeDir?: string): string[] {\n const out: string[] = []\n for (const [dirName, info] of Object.entries(lock.skills)) {\n if (dirName === excludeDir)\n continue\n if (info.packageName === packageName || parsePackages(info.packages).some(p => p.name === packageName))\n out.push(dirName)\n }\n return out\n}\n\n/**\n * Build a `packageName → skillDir` map covering both primary names and\n * additional packages tracked in `packages`. Used for related-skill lookup.\n */\nexport function buildPackageDirMap(lock: SkilldLock): Map<string, string> {\n const map = new Map<string, string>()\n for (const [dirName, info] of Object.entries(lock.skills)) {\n if (info.packageName)\n map.set(info.packageName, dirName)\n for (const pkg of parsePackages(info.packages))\n map.set(pkg.name, dirName)\n }\n return map\n}\n\nfunction serializeLock(lock: SkilldLock): string {\n let yaml = 'skills:\\n'\n for (const [name, skill] of Object.entries(lock.skills)) {\n yaml += ` ${name}:\\n`\n for (const key of SKILL_FM_KEYS) {\n if (skill[key])\n yaml += ` ${key}: ${yamlEscape(skill[key])}\\n`\n }\n }\n return yaml\n}\n\nexport function writeLock(skillsDir: string, skillName: string, info: SkillInfo): void {\n const lockPath = lockfilePath(skillsDir)\n let lock: SkilldLock = { skills: {} }\n if (existsSync(lockPath)) {\n lock = readLock(skillsDir) || { skills: {} }\n }\n\n const existing = lock.skills[skillName]\n if (existing && info.packageName) {\n // Merge packages list\n const existingPkgs = parsePackages(existing.packages)\n // Also include existing primary if not yet in packages list\n if (existing.packageName && !existingPkgs.some(p => p.name === existing.packageName)) {\n existingPkgs.unshift({ name: existing.packageName, version: existing.version || '' })\n }\n // Add/update new package\n const idx = existingPkgs.findIndex(p => p.name === info.packageName)\n if (idx >= 0) {\n existingPkgs[idx]!.version = info.version || ''\n }\n else {\n existingPkgs.push({ name: info.packageName, version: info.version || '' })\n }\n info.packages = serializePackages(existingPkgs)\n // Keep primary as first package\n info.packageName = existingPkgs[0]!.name\n info.version = existingPkgs[0]!.version\n // Preserve fields from existing entry that aren't in new info\n if (!info.repo && existing.repo)\n info.repo = existing.repo\n if (!info.source && existing.source)\n info.source = existing.source\n if (!info.generator && existing.generator)\n info.generator = existing.generator\n }\n\n lock.skills[skillName] = info\n writeFileSync(lockPath, serializeLock(lock))\n invalidateLockCache(skillsDir)\n}\n\n/**\n * Merge multiple lockfiles, preferring the most recently synced entry per skill.\n */\nexport function mergeLocks(locks: SkilldLock[]): SkilldLock {\n const merged: Record<string, SkillInfo> = {}\n for (const lock of locks) {\n for (const [name, info] of Object.entries(lock.skills)) {\n const existing = merged[name]\n if (!existing || (info.syncedAt && (!existing.syncedAt || info.syncedAt > existing.syncedAt)))\n merged[name] = info\n }\n }\n return { skills: merged }\n}\n\n/**\n * Sync a lockfile to all other dirs that already have a skilld-lock.yaml.\n * Only updates existing lockfiles — does not create new ones.\n */\nexport function syncLockfilesToDirs(sourceLock: SkilldLock, dirs: string[]): void {\n for (const dir of dirs) {\n const lockPath = lockfilePath(dir)\n if (!existsSync(lockPath))\n continue\n const existing = readLock(dir)\n if (!existing)\n continue\n // Merge source into existing\n const merged = mergeLocks([existing, sourceLock])\n writeFileSync(lockPath, serializeLock(merged))\n invalidateLockCache(dir)\n }\n}\n\nexport function removeLockEntry(skillsDir: string, skillName: string): void {\n const lockPath = lockfilePath(skillsDir)\n const lock = readLock(skillsDir)\n if (!lock)\n return\n\n delete lock.skills[skillName]\n\n if (Object.keys(lock.skills).length === 0) {\n unlinkSync(lockPath)\n invalidateLockCache(skillsDir)\n return\n }\n\n writeFileSync(lockPath, serializeLock(lock))\n invalidateLockCache(skillsDir)\n}\n"],"mappings":"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"}
|