skilld 1.1.0 → 1.1.2
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/agent.mjs +13 -1
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/assemble.mjs +2 -0
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +2 -0
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +3 -1
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/chunk.mjs +2 -0
- package/dist/_chunks/config.mjs +4 -0
- package/dist/_chunks/config.mjs.map +1 -1
- package/dist/_chunks/detect.mjs +30 -0
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/embedding-cache.mjs +6 -6
- package/dist/_chunks/embedding-cache.mjs.map +1 -1
- package/dist/_chunks/formatting.mjs +9 -1
- package/dist/_chunks/formatting.mjs.map +1 -1
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/install.mjs +3 -1
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs +2 -0
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/markdown.mjs +2 -0
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/pool.mjs +2 -0
- package/dist/_chunks/pool.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +29 -7
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/sanitize.mjs +3 -1
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +3 -1
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +183 -8
- package/dist/_chunks/search.mjs.map +1 -0
- package/dist/_chunks/shared.mjs +4 -0
- package/dist/_chunks/shared.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +4 -0
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/sources.mjs +88 -5
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +23 -12
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/uninstall.mjs +3 -1
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/validate.mjs +2 -0
- package/dist/_chunks/validate.mjs.map +1 -1
- package/dist/_chunks/yaml.mjs +2 -0
- package/dist/_chunks/yaml.mjs.map +1 -1
- package/dist/agent/index.d.mts +6 -3
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/cli.mjs +19 -9
- package/dist/cli.mjs.map +1 -1
- package/dist/retriv/index.mjs +5 -3
- package/dist/retriv/index.mjs.map +1 -1
- package/dist/retriv/worker.mjs +2 -0
- package/dist/retriv/worker.mjs.map +1 -1
- package/dist/types.d.mts +0 -1
- package/package.json +10 -10
- package/dist/_chunks/search2.mjs +0 -180
- package/dist/_chunks/search2.mjs.map +0 -1
- package/dist/_chunks/sync2.mjs +0 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.mjs","names":["agents"],"sources":["../../src/core/lockfile.ts","../../src/core/skills.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 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\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\nexport function readLock(skillsDir: string): SkilldLock | null {\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)\n (skills[currentSkill] as any)[kv[0]] = kv[1]\n }\n }\n return { 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 if (skill.packageName)\n yaml += ` packageName: ${yamlEscape(skill.packageName)}\\n`\n if (skill.version)\n yaml += ` version: ${yamlEscape(skill.version)}\\n`\n if (skill.packages)\n yaml += ` packages: ${yamlEscape(skill.packages)}\\n`\n if (skill.repo)\n yaml += ` repo: ${yamlEscape(skill.repo)}\\n`\n if (skill.source)\n yaml += ` source: ${yamlEscape(skill.source)}\\n`\n if (skill.syncedAt)\n yaml += ` syncedAt: ${yamlEscape(skill.syncedAt)}\\n`\n if (skill.generator)\n yaml += ` generator: ${yamlEscape(skill.generator)}\\n`\n if (skill.path)\n yaml += ` path: ${yamlEscape(skill.path)}\\n`\n if (skill.ref)\n yaml += ` ref: ${yamlEscape(skill.ref)}\\n`\n if (skill.commit)\n yaml += ` commit: ${yamlEscape(skill.commit)}\\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}\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 }\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 return\n }\n\n writeFileSync(lockPath, serializeLock(lock))\n}\n","import type { AgentType } from '../agent/index.ts'\nimport type { SkillInfo } from './lockfile.ts'\nimport { existsSync, readdirSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { agents } from '../agent/index.ts'\nimport { readLocalDependencies } from '../sources/index.ts'\nimport { parsePackages, parseSkillFrontmatter, readLock } from './lockfile.ts'\nimport { getSharedSkillsDir, semverGt } from './shared.ts'\n\nexport interface SkillEntry {\n name: string\n dir: string\n agent: AgentType\n info: SkillInfo | null\n scope: 'local' | 'global'\n /** Original package name from package.json (e.g., @scope/pkg) */\n packageName?: string\n /** Latest version from package.json deps */\n latestVersion?: string\n}\n\nexport interface ProjectState {\n skills: SkillEntry[]\n deps: Map<string, string>\n missing: string[]\n outdated: SkillEntry[]\n synced: SkillEntry[]\n /** Skills in lockfile but not matched to any local dep */\n unmatched: SkillEntry[]\n}\n\nexport interface IterateSkillsOptions {\n scope?: 'local' | 'global' | 'all'\n agents?: AgentType[]\n cwd?: string\n}\n\nexport function* iterateSkills(opts: IterateSkillsOptions = {}): Generator<SkillEntry> {\n const { scope = 'all', cwd = process.cwd() } = opts\n const agentTypes = opts.agents ?? (Object.keys(agents) as AgentType[])\n\n // When shared dir exists, read local skills from there (avoid duplicates from agent symlinks)\n const sharedDir = getSharedSkillsDir(cwd)\n let yieldedLocal = false\n\n if (sharedDir && (scope === 'local' || scope === 'all')) {\n yieldedLocal = true\n const lock = readLock(sharedDir)\n const entries = readdirSync(sharedDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n // Use first detected agent as the representative\n const firstAgent = agentTypes[0] ?? (Object.keys(agents) as AgentType[])[0]!\n for (const name of entries) {\n const dir = join(sharedDir, name)\n if (lock?.skills[name]) {\n yield { name, dir, agent: firstAgent, info: lock.skills[name], scope: 'local' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: firstAgent, info, scope: 'local' }\n }\n }\n }\n }\n\n for (const agentType of agentTypes) {\n const agent = agents[agentType]\n\n // Local skills (skip if already yielded from shared dir)\n if (!yieldedLocal && (scope === 'local' || scope === 'all')) {\n const localDir = join(cwd, agent.skillsDir)\n if (existsSync(localDir)) {\n const lock = readLock(localDir)\n const entries = readdirSync(localDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n for (const name of entries) {\n const dir = join(localDir, name)\n // Only track skills in lockfile OR with generator: \"skilld\"\n if (lock?.skills[name]) {\n yield { name, dir, agent: agentType, info: lock.skills[name], scope: 'local' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: agentType, info, scope: 'local' }\n }\n }\n }\n }\n }\n\n // Global skills\n if ((scope === 'global' || scope === 'all') && agent.globalSkillsDir) {\n const globalDir = agent.globalSkillsDir\n if (existsSync(globalDir)) {\n const lock = readLock(globalDir)\n const entries = readdirSync(globalDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n for (const name of entries) {\n const dir = join(globalDir, name)\n // Only track skills in lockfile OR with generator: \"skilld\"\n if (lock?.skills[name]) {\n yield { name, dir, agent: agentType, info: lock.skills[name], scope: 'global' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: agentType, info, scope: 'global' }\n }\n }\n }\n }\n }\n }\n}\n\nexport function isOutdated(skill: SkillEntry, depVersion: string): boolean {\n if (!skill.info?.version)\n return true\n\n const depClean = depVersion.replace(/^[\\^~]/, '')\n\n return semverGt(depClean, skill.info.version)\n}\n\nexport async function getProjectState(cwd: string = process.cwd()): Promise<ProjectState> {\n const skills = [...iterateSkills({ scope: 'local', cwd })]\n\n // Get package.json deps\n const localDeps = await readLocalDependencies(cwd).catch(() => [])\n const deps = new Map(localDeps.map(d => [d.name, d.version]))\n\n // Build skill name -> entry map (for lookup by package name)\n const skillByName = new Map(skills.map(s => [s.name, s]))\n\n // Secondary lookup: packageName from lockfile (shipped skills have different names)\n // Also includes all packages from multi-package skills\n const skillByPkgName = new Map<string, SkillEntry>()\n for (const s of skills) {\n if (s.info?.packageName)\n skillByPkgName.set(s.info.packageName, s)\n for (const pkg of parsePackages(s.info?.packages))\n skillByPkgName.set(pkg.name, s)\n }\n\n const missing: string[] = []\n const outdated: SkillEntry[] = []\n const synced: SkillEntry[] = []\n const matchedSkillNames = new Set<string>()\n\n for (const [pkgName, version] of deps) {\n // Normalize package name (e.g., @scope/pkg -> scope-pkg)\n const normalizedName = pkgName.replace(/^@/, '').replace(/\\//g, '-')\n const skill = skillByName.get(`${normalizedName}-skilld`) || skillByName.get(normalizedName) || skillByName.get(pkgName) || skillByPkgName.get(pkgName)\n\n if (!skill) {\n missing.push(pkgName)\n }\n else {\n matchedSkillNames.add(skill.name)\n if (isOutdated(skill, version)) {\n outdated.push({ ...skill, packageName: pkgName, latestVersion: version })\n }\n else {\n synced.push({ ...skill, packageName: pkgName, latestVersion: version })\n }\n }\n }\n\n // Skills in lockfile but not matched to any local dep\n const unmatched = skills.filter(s => !matchedSkillNames.has(s.name))\n\n return { skills, deps, missing, outdated, synced, unmatched }\n}\n\nexport function getSkillsDir(agent: AgentType, scope: 'local' | 'global', cwd: string = process.cwd()): string {\n const agentConfig = agents[agent]\n if (scope === 'global') {\n if (!agentConfig.globalSkillsDir) {\n throw new Error(`Agent ${agent} does not support global skills`)\n }\n return agentConfig.globalSkillsDir\n }\n return getSharedSkillsDir(cwd) || join(cwd, agentConfig.skillsDir)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"skills.mjs","names":["agents"],"sources":["../../src/core/lockfile.ts","../../src/core/skills.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 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\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\nexport function readLock(skillsDir: string): SkilldLock | null {\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)\n (skills[currentSkill] as any)[kv[0]] = kv[1]\n }\n }\n return { 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 if (skill.packageName)\n yaml += ` packageName: ${yamlEscape(skill.packageName)}\\n`\n if (skill.version)\n yaml += ` version: ${yamlEscape(skill.version)}\\n`\n if (skill.packages)\n yaml += ` packages: ${yamlEscape(skill.packages)}\\n`\n if (skill.repo)\n yaml += ` repo: ${yamlEscape(skill.repo)}\\n`\n if (skill.source)\n yaml += ` source: ${yamlEscape(skill.source)}\\n`\n if (skill.syncedAt)\n yaml += ` syncedAt: ${yamlEscape(skill.syncedAt)}\\n`\n if (skill.generator)\n yaml += ` generator: ${yamlEscape(skill.generator)}\\n`\n if (skill.path)\n yaml += ` path: ${yamlEscape(skill.path)}\\n`\n if (skill.ref)\n yaml += ` ref: ${yamlEscape(skill.ref)}\\n`\n if (skill.commit)\n yaml += ` commit: ${yamlEscape(skill.commit)}\\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}\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 }\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 return\n }\n\n writeFileSync(lockPath, serializeLock(lock))\n}\n","import type { AgentType } from '../agent/index.ts'\nimport type { SkillInfo } from './lockfile.ts'\nimport { existsSync, readdirSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { agents } from '../agent/index.ts'\nimport { readLocalDependencies } from '../sources/index.ts'\nimport { parsePackages, parseSkillFrontmatter, readLock } from './lockfile.ts'\nimport { getSharedSkillsDir, semverGt } from './shared.ts'\n\nexport interface SkillEntry {\n name: string\n dir: string\n agent: AgentType\n info: SkillInfo | null\n scope: 'local' | 'global'\n /** Original package name from package.json (e.g., @scope/pkg) */\n packageName?: string\n /** Latest version from package.json deps */\n latestVersion?: string\n}\n\nexport interface ProjectState {\n skills: SkillEntry[]\n deps: Map<string, string>\n missing: string[]\n outdated: SkillEntry[]\n synced: SkillEntry[]\n /** Skills in lockfile but not matched to any local dep */\n unmatched: SkillEntry[]\n}\n\nexport interface IterateSkillsOptions {\n scope?: 'local' | 'global' | 'all'\n agents?: AgentType[]\n cwd?: string\n}\n\nexport function* iterateSkills(opts: IterateSkillsOptions = {}): Generator<SkillEntry> {\n const { scope = 'all', cwd = process.cwd() } = opts\n const agentTypes = opts.agents ?? (Object.keys(agents) as AgentType[])\n\n // When shared dir exists, read local skills from there (avoid duplicates from agent symlinks)\n const sharedDir = getSharedSkillsDir(cwd)\n let yieldedLocal = false\n\n if (sharedDir && (scope === 'local' || scope === 'all')) {\n yieldedLocal = true\n const lock = readLock(sharedDir)\n const entries = readdirSync(sharedDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n // Use first detected agent as the representative\n const firstAgent = agentTypes[0] ?? (Object.keys(agents) as AgentType[])[0]!\n for (const name of entries) {\n const dir = join(sharedDir, name)\n if (lock?.skills[name]) {\n yield { name, dir, agent: firstAgent, info: lock.skills[name], scope: 'local' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: firstAgent, info, scope: 'local' }\n }\n }\n }\n }\n\n for (const agentType of agentTypes) {\n const agent = agents[agentType]\n\n // Local skills (skip if already yielded from shared dir)\n if (!yieldedLocal && (scope === 'local' || scope === 'all')) {\n const localDir = join(cwd, agent.skillsDir)\n if (existsSync(localDir)) {\n const lock = readLock(localDir)\n const entries = readdirSync(localDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n for (const name of entries) {\n const dir = join(localDir, name)\n // Only track skills in lockfile OR with generator: \"skilld\"\n if (lock?.skills[name]) {\n yield { name, dir, agent: agentType, info: lock.skills[name], scope: 'local' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: agentType, info, scope: 'local' }\n }\n }\n }\n }\n }\n\n // Global skills\n if ((scope === 'global' || scope === 'all') && agent.globalSkillsDir) {\n const globalDir = agent.globalSkillsDir\n if (existsSync(globalDir)) {\n const lock = readLock(globalDir)\n const entries = readdirSync(globalDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n for (const name of entries) {\n const dir = join(globalDir, name)\n // Only track skills in lockfile OR with generator: \"skilld\"\n if (lock?.skills[name]) {\n yield { name, dir, agent: agentType, info: lock.skills[name], scope: 'global' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: agentType, info, scope: 'global' }\n }\n }\n }\n }\n }\n }\n}\n\nexport function isOutdated(skill: SkillEntry, depVersion: string): boolean {\n if (!skill.info?.version)\n return true\n\n const depClean = depVersion.replace(/^[\\^~]/, '')\n\n return semverGt(depClean, skill.info.version)\n}\n\nexport async function getProjectState(cwd: string = process.cwd()): Promise<ProjectState> {\n const skills = [...iterateSkills({ scope: 'local', cwd })]\n\n // Get package.json deps\n const localDeps = await readLocalDependencies(cwd).catch(() => [])\n const deps = new Map(localDeps.map(d => [d.name, d.version]))\n\n // Build skill name -> entry map (for lookup by package name)\n const skillByName = new Map(skills.map(s => [s.name, s]))\n\n // Secondary lookup: packageName from lockfile (shipped skills have different names)\n // Also includes all packages from multi-package skills\n const skillByPkgName = new Map<string, SkillEntry>()\n for (const s of skills) {\n if (s.info?.packageName)\n skillByPkgName.set(s.info.packageName, s)\n for (const pkg of parsePackages(s.info?.packages))\n skillByPkgName.set(pkg.name, s)\n }\n\n const missing: string[] = []\n const outdated: SkillEntry[] = []\n const synced: SkillEntry[] = []\n const matchedSkillNames = new Set<string>()\n\n for (const [pkgName, version] of deps) {\n // Normalize package name (e.g., @scope/pkg -> scope-pkg)\n const normalizedName = pkgName.replace(/^@/, '').replace(/\\//g, '-')\n const skill = skillByName.get(`${normalizedName}-skilld`) || skillByName.get(normalizedName) || skillByName.get(pkgName) || skillByPkgName.get(pkgName)\n\n if (!skill) {\n missing.push(pkgName)\n }\n else {\n matchedSkillNames.add(skill.name)\n if (isOutdated(skill, version)) {\n outdated.push({ ...skill, packageName: pkgName, latestVersion: version })\n }\n else {\n synced.push({ ...skill, packageName: pkgName, latestVersion: version })\n }\n }\n }\n\n // Skills in lockfile but not matched to any local dep\n const unmatched = skills.filter(s => !matchedSkillNames.has(s.name))\n\n return { skills, deps, missing, outdated, synced, unmatched }\n}\n\nexport function getSkillsDir(agent: AgentType, scope: 'local' | 'global', cwd: string = process.cwd()): string {\n const agentConfig = agents[agent]\n if (scope === 'global') {\n if (!agentConfig.globalSkillsDir) {\n throw new Error(`Agent ${agent} does not support global skills`)\n }\n return agentConfig.globalSkillsDir\n }\n return getSharedSkillsDir(cwd) || join(cwd, agentConfig.skillsDir)\n}\n"],"mappings":"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"}
|
package/dist/_chunks/sources.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
14
14
|
import pLimit from "p-limit";
|
|
15
15
|
import { Writable } from "node:stream";
|
|
16
16
|
import { resolvePathSync } from "mlly";
|
|
17
|
+
//#region src/sources/github-common.ts
|
|
17
18
|
/**
|
|
18
19
|
* Shared constants and helpers for GitHub source modules (issues, discussions, releases)
|
|
19
20
|
*/
|
|
@@ -33,6 +34,8 @@ function buildFrontmatter(fields) {
|
|
|
33
34
|
lines.push("---");
|
|
34
35
|
return lines.join("\n");
|
|
35
36
|
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/sources/issues.ts
|
|
36
39
|
/**
|
|
37
40
|
* GitHub issues fetching via gh CLI Search API
|
|
38
41
|
* Freshness-weighted scoring, type quotas, comment quality filtering
|
|
@@ -434,6 +437,8 @@ function generateIssueIndex(issues) {
|
|
|
434
437
|
}
|
|
435
438
|
return sections.join("\n");
|
|
436
439
|
}
|
|
440
|
+
//#endregion
|
|
441
|
+
//#region src/sources/utils.ts
|
|
437
442
|
/**
|
|
438
443
|
* Shared utilities for doc resolution
|
|
439
444
|
*/
|
|
@@ -540,6 +545,8 @@ function extractBranchHint(url) {
|
|
|
540
545
|
if (!fragment || fragment === "readme") return void 0;
|
|
541
546
|
return fragment;
|
|
542
547
|
}
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/sources/releases.ts
|
|
543
550
|
/**
|
|
544
551
|
* GitHub release notes fetching via gh CLI (preferred) with ungh.cc fallback
|
|
545
552
|
*/
|
|
@@ -788,6 +795,8 @@ async function fetchReleaseNotes(owner, repo, installedVersion, gitRef, packageN
|
|
|
788
795
|
content: changelog
|
|
789
796
|
}];
|
|
790
797
|
}
|
|
798
|
+
//#endregion
|
|
799
|
+
//#region src/sources/blog-releases.ts
|
|
791
800
|
/**
|
|
792
801
|
* Format a blog release as markdown with YAML frontmatter
|
|
793
802
|
*/
|
|
@@ -878,6 +887,8 @@ async function fetchBlogReleases(packageName, installedVersion) {
|
|
|
878
887
|
content: formatBlogRelease(r)
|
|
879
888
|
}));
|
|
880
889
|
}
|
|
890
|
+
//#endregion
|
|
891
|
+
//#region src/sources/crawl.ts
|
|
881
892
|
/**
|
|
882
893
|
* Website crawl doc source — fetches docs by crawling a URL pattern
|
|
883
894
|
*/
|
|
@@ -892,13 +903,19 @@ async function fetchBlogReleases(packageName, installedVersion) {
|
|
|
892
903
|
async function fetchCrawledDocs(url, onProgress, maxPages = 200) {
|
|
893
904
|
const outputDir = join(tmpdir(), "skilld-crawl", Date.now().toString());
|
|
894
905
|
onProgress?.(`Crawling ${url}`);
|
|
906
|
+
const userLang = getUserLang();
|
|
907
|
+
const foreignUrls = /* @__PURE__ */ new Set();
|
|
895
908
|
const doCrawl = () => crawlAndGenerate({
|
|
896
909
|
urls: [url],
|
|
897
910
|
outputDir,
|
|
898
911
|
driver: "http",
|
|
899
912
|
generateLlmsTxt: false,
|
|
900
|
-
generateIndividualMd:
|
|
901
|
-
maxRequestsPerCrawl: maxPages
|
|
913
|
+
generateIndividualMd: true,
|
|
914
|
+
maxRequestsPerCrawl: maxPages,
|
|
915
|
+
onPage: (page) => {
|
|
916
|
+
const lang = extractHtmlLang(page.html);
|
|
917
|
+
if (lang && !lang.startsWith("en") && !lang.startsWith(userLang)) foreignUrls.add(page.url);
|
|
918
|
+
}
|
|
902
919
|
}, (progress) => {
|
|
903
920
|
if (progress.crawling.status === "processing" && progress.crawling.total > 0) onProgress?.(`Crawling ${progress.crawling.processed}/${progress.crawling.total} pages`);
|
|
904
921
|
});
|
|
@@ -915,21 +932,74 @@ async function fetchCrawledDocs(url, onProgress, maxPages = 200) {
|
|
|
915
932
|
force: true
|
|
916
933
|
});
|
|
917
934
|
const docs = [];
|
|
935
|
+
let localeFiltered = 0;
|
|
918
936
|
for (const result of results) {
|
|
919
937
|
if (!result.success || !result.content) continue;
|
|
920
|
-
|
|
938
|
+
if (foreignUrls.has(result.url)) {
|
|
939
|
+
localeFiltered++;
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
const segments = (new URL(result.url).pathname.replace(/\/$/, "") || "/index").split("/").filter(Boolean);
|
|
943
|
+
if (isForeignPathPrefix(segments[0], userLang)) {
|
|
944
|
+
localeFiltered++;
|
|
945
|
+
continue;
|
|
946
|
+
}
|
|
947
|
+
const path = `docs/${segments.join("/")}.md`;
|
|
921
948
|
docs.push({
|
|
922
949
|
path,
|
|
923
950
|
content: result.content
|
|
924
951
|
});
|
|
925
952
|
}
|
|
953
|
+
if (localeFiltered > 0) onProgress?.(`Filtered ${localeFiltered} foreign locale pages`);
|
|
926
954
|
onProgress?.(`Crawled ${docs.length} pages`);
|
|
927
955
|
return docs;
|
|
928
956
|
}
|
|
957
|
+
const HTML_LANG_RE = /<html[^>]*\slang=["']([^"']+)["']/i;
|
|
958
|
+
/** Extract lang attribute from <html> tag */
|
|
959
|
+
function extractHtmlLang(html) {
|
|
960
|
+
return HTML_LANG_RE.exec(html)?.[1]?.toLowerCase();
|
|
961
|
+
}
|
|
962
|
+
/** Common ISO 639-1 locale codes for i18n'd doc sites */
|
|
963
|
+
const LOCALE_CODES = new Set([
|
|
964
|
+
"ar",
|
|
965
|
+
"de",
|
|
966
|
+
"es",
|
|
967
|
+
"fr",
|
|
968
|
+
"id",
|
|
969
|
+
"it",
|
|
970
|
+
"ja",
|
|
971
|
+
"ko",
|
|
972
|
+
"nl",
|
|
973
|
+
"pl",
|
|
974
|
+
"pt",
|
|
975
|
+
"pt-br",
|
|
976
|
+
"ru",
|
|
977
|
+
"th",
|
|
978
|
+
"tr",
|
|
979
|
+
"uk",
|
|
980
|
+
"vi",
|
|
981
|
+
"zh",
|
|
982
|
+
"zh-cn",
|
|
983
|
+
"zh-tw"
|
|
984
|
+
]);
|
|
985
|
+
/** Check if a URL path segment is a known locale prefix foreign to both English and user's locale */
|
|
986
|
+
function isForeignPathPrefix(segment, userLang) {
|
|
987
|
+
if (!segment) return false;
|
|
988
|
+
const lower = segment.toLowerCase();
|
|
989
|
+
if (lower === "en" || lower.startsWith(userLang)) return false;
|
|
990
|
+
return LOCALE_CODES.has(lower);
|
|
991
|
+
}
|
|
992
|
+
/** Detect user's 2-letter language code from env (e.g. 'ja' from LANG=ja_JP.UTF-8) */
|
|
993
|
+
function getUserLang() {
|
|
994
|
+
const code = (process.env.LC_ALL || process.env.LANG || process.env.LANGUAGE || "").split(/[_.:-]/)[0]?.toLowerCase() || "";
|
|
995
|
+
return code.length >= 2 ? code.slice(0, 2) : "en";
|
|
996
|
+
}
|
|
929
997
|
/** Append glob pattern to a docs URL for crawling */
|
|
930
998
|
function toCrawlPattern(docsUrl) {
|
|
931
999
|
return `${docsUrl.replace(/\/+$/, "")}/**`;
|
|
932
1000
|
}
|
|
1001
|
+
//#endregion
|
|
1002
|
+
//#region src/sources/discussions.ts
|
|
933
1003
|
/**
|
|
934
1004
|
* GitHub discussions fetching via gh CLI GraphQL
|
|
935
1005
|
* Prioritizes Q&A and Help categories, includes accepted answers
|
|
@@ -1163,6 +1233,8 @@ function generateDiscussionIndex(discussions) {
|
|
|
1163
1233
|
}
|
|
1164
1234
|
return sections.join("\n");
|
|
1165
1235
|
}
|
|
1236
|
+
//#endregion
|
|
1237
|
+
//#region src/sources/docs.ts
|
|
1166
1238
|
/**
|
|
1167
1239
|
* Docs index generation — creates _INDEX.md for docs directory
|
|
1168
1240
|
*/
|
|
@@ -1215,6 +1287,8 @@ function generateDocsIndex(docs) {
|
|
|
1215
1287
|
}
|
|
1216
1288
|
return sections.join("\n");
|
|
1217
1289
|
}
|
|
1290
|
+
//#endregion
|
|
1291
|
+
//#region src/sources/entries.ts
|
|
1218
1292
|
/**
|
|
1219
1293
|
* Globs .d.ts type definition files from a package for search indexing.
|
|
1220
1294
|
* Only types — source code is too verbose.
|
|
@@ -1275,6 +1349,8 @@ async function resolveEntryFiles(packageDir) {
|
|
|
1275
1349
|
}
|
|
1276
1350
|
return entries;
|
|
1277
1351
|
}
|
|
1352
|
+
//#endregion
|
|
1353
|
+
//#region src/sources/git-skills.ts
|
|
1278
1354
|
/**
|
|
1279
1355
|
* Git repo skill source — parse inputs + fetch pre-authored skills from repos
|
|
1280
1356
|
*
|
|
@@ -1521,6 +1597,8 @@ async function fetchGitLabSkills(source, onProgress) {
|
|
|
1521
1597
|
});
|
|
1522
1598
|
}
|
|
1523
1599
|
}
|
|
1600
|
+
//#endregion
|
|
1601
|
+
//#region src/sources/llms.ts
|
|
1524
1602
|
/**
|
|
1525
1603
|
* Check for llms.txt at a docs URL, returns the llms.txt URL if found
|
|
1526
1604
|
*/
|
|
@@ -1612,10 +1690,12 @@ function extractSections(content, patterns) {
|
|
|
1612
1690
|
if (sections.length === 0) return null;
|
|
1613
1691
|
return sections.join("\n\n---\n\n");
|
|
1614
1692
|
}
|
|
1693
|
+
//#endregion
|
|
1694
|
+
//#region src/sources/github.ts
|
|
1615
1695
|
/** Minimum git-doc file count to prefer over llms.txt */
|
|
1616
1696
|
const MIN_GIT_DOCS = 5;
|
|
1617
1697
|
/** True when git-docs exist but are too few to be useful (< MIN_GIT_DOCS) */
|
|
1618
|
-
const isShallowGitDocs = (n) => n > 0 && n <
|
|
1698
|
+
const isShallowGitDocs = (n) => n > 0 && n < 5;
|
|
1619
1699
|
/**
|
|
1620
1700
|
* List files at a git ref using ungh (no rate limits)
|
|
1621
1701
|
*/
|
|
@@ -1804,7 +1884,7 @@ function discoverDocFiles(allFiles, packageName) {
|
|
|
1804
1884
|
mapInsert(dirGroups, file.slice(0, lastSlash + 1), () => []).push(file);
|
|
1805
1885
|
}
|
|
1806
1886
|
if (dirGroups.size === 0) return null;
|
|
1807
|
-
const scored =
|
|
1887
|
+
const scored = Array.from(dirGroups.entries(), ([dir, files]) => ({
|
|
1808
1888
|
dir,
|
|
1809
1889
|
files,
|
|
1810
1890
|
score: scoreDocDir(dir, files.length)
|
|
@@ -2103,6 +2183,8 @@ async function resolveGitHubRepo(owner, repo, onProgress) {
|
|
|
2103
2183
|
llmsUrl
|
|
2104
2184
|
};
|
|
2105
2185
|
}
|
|
2186
|
+
//#endregion
|
|
2187
|
+
//#region src/sources/npm.ts
|
|
2106
2188
|
/**
|
|
2107
2189
|
* Search npm registry for packages matching a query.
|
|
2108
2190
|
* Used as a fallback when direct package lookup fails.
|
|
@@ -2545,6 +2627,7 @@ function getInstalledSkillVersion(skillDir) {
|
|
|
2545
2627
|
if (!existsSync(skillPath)) return null;
|
|
2546
2628
|
return readFileSync(skillPath, "utf-8").match(/^version:\s*"?([^"\n]+)"?/m)?.[1] || null;
|
|
2547
2629
|
}
|
|
2630
|
+
//#endregion
|
|
2548
2631
|
export { fetchGitHubIssues as $, parseGitSkillInput as A, compareSemver as B, downloadLlmsDocs as C, normalizeLlmsLinks as D, fetchLlmsUrl as E, formatDiscussionAsMarkdown as F, $fetch as G, generateReleaseIndex as H, generateDiscussionIndex as I, isGitHubRepoUrl as J, extractBranchHint as K, fetchCrawledDocs as L, resolveEntryFiles as M, generateDocsIndex as N, parseMarkdownLinks as O, fetchGitHubDiscussions as P, verifyUrl as Q, toCrawlPattern as R, validateGitDocsWithLlms as S, fetchLlmsTxt as T, isPrerelease as U, fetchReleaseNotes as V, parseSemver as W, parseGitHubUrl as X, normalizeRepoUrl as Y, parsePackageSpec as Z, fetchReadme as _, getInstalledSkillVersion as a, isShallowGitDocs as b, readLocalPackageInfo as c, resolvePackageDocs as d, formatIssueAsMarkdown as et, resolvePackageDocsWithAttempts as f, fetchGitHubRepoMeta as g, fetchGitDocs as h, fetchPkgDist as i, parseSkillFrontmatterName as j, fetchGitSkills as k, resolveInstalledVersion as l, MIN_GIT_DOCS as m, fetchNpmPackage as n, isGhAvailable as nt, parseVersionSpecifier as o, searchNpmPackages as p, fetchText as q, fetchNpmRegistryMeta as r, readLocalDependencies as s, fetchLatestVersion as t, generateIssueIndex as tt, resolveLocalPackageDocs as u, fetchReadmeContent as v, extractSections as w, resolveGitHubRepo as x, filterFrameworkDocs as y, fetchBlogReleases as z };
|
|
2549
2632
|
|
|
2550
2633
|
//# sourceMappingURL=sources.mjs.map
|