skilld 1.7.2 → 1.7.3
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.map +1 -1
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author-group.mjs.map +1 -1
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/cli-helpers.mjs.map +1 -1
- package/dist/_chunks/config.mjs.map +1 -1
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/embedding-cache2.mjs.map +1 -1
- package/dist/_chunks/index3.d.mts.map +1 -1
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/pool2.mjs +6 -1
- package/dist/_chunks/pool2.mjs.map +1 -1
- package/dist/_chunks/prefix.mjs.map +1 -1
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/retriv.mjs.map +1 -1
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/setup.mjs.map +1 -1
- package/dist/_chunks/shared.mjs.map +1 -1
- package/dist/_chunks/skill.mjs.map +1 -1
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/sources.mjs +21 -9
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync-registry.mjs.map +1 -1
- package/dist/_chunks/sync-shared2.mjs.map +1 -1
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/upload.mjs.map +1 -1
- package/dist/_chunks/validate.mjs.map +1 -1
- package/dist/_chunks/version.mjs.map +1 -1
- package/dist/_chunks/wizard.mjs.map +1 -1
- package/dist/_chunks/yaml.mjs.map +1 -1
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/worker.d.mts +1 -0
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +2 -1
- package/dist/retriv/worker.mjs.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uninstall.mjs","names":["agents"],"sources":["../../src/commands/uninstall.ts"],"sourcesContent":["import type { AgentType } from '../agent/index.ts'\nimport { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { agents } from '../agent/index.ts'\nimport { CACHE_DIR } from '../cache/index.ts'\nimport { isInteractive, sharedArgs } from '../cli-helpers.ts'\nimport { getRegisteredProjects, unregisterProject } from '../core/config.ts'\nimport { readLock } from '../core/lockfile.ts'\nimport { mapInsert, SHARED_SKILLS_DIR } from '../core/shared.ts'\nimport { SKILLD_MARKER_END, SKILLD_MARKER_START } from './sync.ts'\n\n/**\n * Remove the skilld marker block from an agent's instruction file.\n * For .mdc files (dedicated skilld files), delete the entire file.\n * Also cleans up legacy .cursorrules markers for backwards compat.\n */\nfunction removeAgentInstructions(agent: AgentType, projectPath: string): boolean {\n const agentConfig = agents[agent]\n if (!agentConfig.instructionFile)\n return false\n\n let removed = false\n\n // Handle current instruction file\n const filePath = join(projectPath, agentConfig.instructionFile)\n if (agentConfig.instructionFile.endsWith('.mdc')) {\n // MDC files are dedicated skilld files - just delete\n if (existsSync(filePath)) {\n rmSync(filePath)\n removed = true\n }\n // Also clean up legacy .cursorrules markers (cursor-specific)\n if (agent === 'cursor')\n removed = removeMarkerBlock(join(projectPath, '.cursorrules')) || removed\n }\n else if (existsSync(filePath)) {\n removed = removeMarkerBlock(filePath)\n }\n\n return removed\n}\n\nfunction removeMarkerBlock(filePath: string): boolean {\n if (!existsSync(filePath))\n return false\n\n const content = readFileSync(filePath, 'utf-8')\n const startIdx = content.indexOf(SKILLD_MARKER_START)\n if (startIdx === -1)\n return false\n\n const endIdx = content.indexOf(SKILLD_MARKER_END, startIdx)\n if (endIdx === -1)\n return false\n\n // Remove marker block plus surrounding blank lines\n const before = content.slice(0, startIdx).replace(/\\n+$/, '')\n const after = content.slice(endIdx + SKILLD_MARKER_END.length).replace(/^\\n+/, '')\n const updated = before + (before && after ? '\\n' : '') + after\n\n if (updated.trim() === '') {\n rmSync(filePath)\n }\n else {\n writeFileSync(filePath, updated.endsWith('\\n') ? updated : `${updated}\\n`)\n }\n return true\n}\n\nexport interface UninstallOptions {\n scope?: 'project' | 'all'\n agent?: AgentType\n yes: boolean\n}\n\n/**\n * Uninstall skilld skills by scope:\n * - project: Remove project skills (cwd)\n * - all: All registered projects + global skills + cache\n */\nexport async function uninstallCommand(opts: UninstallOptions): Promise<void> {\n let scope = opts.scope\n const registeredProjects = getRegisteredProjects()\n\n // Prompt for scope if not provided\n if (!scope) {\n if (!isInteractive()) {\n scope = 'project'\n }\n else {\n const allHint = registeredProjects.length > 0\n ? `${registeredProjects.length} projects + global + cache`\n : 'global skills + cache'\n\n const selected = await p.select({\n message: 'What do you want to uninstall?',\n options: [\n { label: 'This project', value: 'project', hint: 'current project only' },\n { label: 'Everything', value: 'all', hint: allHint },\n ],\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Cancelled')\n return\n }\n scope = selected as 'project' | 'all'\n }\n }\n\n interface RemoveItem { label: string, path: string, version?: string }\n const toRemove: RemoveItem[] = []\n const seenPaths = new Set<string>()\n const projectsToUnregister: string[] = []\n const agentFilter = opts.agent ? [opts.agent] : undefined\n\n const addToRemove = (label: string, path: string, version?: string) => {\n if (seenPaths.has(path))\n return\n seenPaths.add(path)\n toRemove.push({ label, path, version })\n }\n\n // Helper to add skills from a lockfile\n const addSkillsFromLock = (skillsDir: string, label: string): string[] => {\n const trackedNames: string[] = []\n const lock = readLock(skillsDir)\n\n if (lock?.skills) {\n for (const [skillName, info] of Object.entries(lock.skills)) {\n trackedNames.push(skillName)\n const skillDir = join(skillsDir, skillName)\n if (existsSync(skillDir)) {\n const version = info.version ? `${info.version.split('.').slice(0, 2).join('.')}.x` : undefined\n addToRemove(`${label}: ${skillName}`, skillDir, version)\n }\n }\n\n // Also add the lockfile itself\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n if (existsSync(lockPath)) {\n addToRemove(`${label}: skilld-lock.yaml`, lockPath)\n }\n }\n\n return trackedNames\n }\n\n // Helper to find untracked skills in a directory\n const findUntrackedSkills = (skillsDir: string, trackedNames: string[]): string[] => {\n if (!existsSync(skillsDir))\n return []\n const tracked = new Set(trackedNames)\n return readdirSync(skillsDir)\n .filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml' && !tracked.has(f))\n }\n\n // Track untracked skills per directory (dedupe by path)\n const untrackedByDir = new Map<string, { label: string, skills: string[] }>()\n const processedDirs = new Set<string>()\n\n // Helper to process a skills directory (with deduping)\n const processSkillsDir = (skillsDir: string, label: string) => {\n if (processedDirs.has(skillsDir))\n return\n processedDirs.add(skillsDir)\n\n const tracked = addSkillsFromLock(skillsDir, label)\n const untracked = findUntrackedSkills(skillsDir, tracked)\n if (untracked.length > 0) {\n untrackedByDir.set(skillsDir, { label, skills: untracked })\n }\n }\n\n // Project skills\n if (scope === 'project') {\n // Shared dir\n const sharedDir = join(process.cwd(), SHARED_SKILLS_DIR)\n if (existsSync(sharedDir))\n processSkillsDir(sharedDir, 'project (.skills)')\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n processSkillsDir(join(process.cwd(), agent.skillsDir), 'project')\n }\n projectsToUnregister.push(process.cwd())\n }\n\n // All registered projects + global\n if (scope === 'all') {\n const projectPaths = registeredProjects.length > 0 ? registeredProjects : [process.cwd()]\n\n // Show which projects will be affected\n if (registeredProjects.length > 0) {\n p.log.info('Projects to uninstall from:')\n for (const proj of projectPaths) {\n p.log.message(` ${proj}`)\n }\n }\n\n // Project skills from lockfiles\n for (const projectPath of projectPaths) {\n if (!existsSync(projectPath))\n continue\n\n const shortPath = projectPath.replace(process.env.HOME || '', '~')\n\n // Shared dir\n const sharedDir = join(projectPath, SHARED_SKILLS_DIR)\n if (existsSync(sharedDir))\n processSkillsDir(sharedDir, `${shortPath} (.skills)`)\n\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n processSkillsDir(join(projectPath, agent.skillsDir), shortPath)\n }\n\n projectsToUnregister.push(projectPath)\n }\n\n // Global skills from lockfiles\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n if (!agent.globalSkillsDir)\n continue\n processSkillsDir(agent.globalSkillsDir, 'user')\n }\n\n // Cache directory\n if (existsSync(CACHE_DIR)) {\n addToRemove('~/.skilld cache', CACHE_DIR)\n }\n }\n\n // Warn about untracked skills that will remain (grouped by label, deduped)\n if (untrackedByDir.size > 0) {\n const groupedUntracked = new Map<string, Set<string>>()\n for (const [_dir, { label, skills }] of untrackedByDir) {\n const set = mapInsert(groupedUntracked, label, () => new Set())\n for (const s of skills) set.add(s)\n }\n\n const totalUntracked = [...groupedUntracked.values()].reduce((sum, s) => sum + s.size, 0)\n p.log.warn(`${totalUntracked} untracked skill(s) will remain (not managed by skilld):`)\n for (const [label, skills] of groupedUntracked) {\n p.log.message(` ${label}: ${[...skills].join(', ')}`)\n }\n }\n\n if (toRemove.length === 0) {\n p.log.info('Nothing to uninstall')\n return\n }\n\n // Group by prefix for display\n const groups = new Map<string, Array<{ name: string, version?: string }>>()\n for (const item of toRemove) {\n const [prefix, name] = item.label.includes(': ')\n ? item.label.split(': ', 2)\n : ['other', item.label]\n mapInsert(groups, prefix!, () => []).push({ name: name!, version: item.version })\n }\n\n const formatGroup = (items: Array<{ name: string, version?: string }>) =>\n items.map(i => i.version ? `${i.name}@${i.version}` : i.name).join(', ')\n\n p.log.info(`Will remove ${toRemove.length} items:`)\n for (const [prefix, items] of groups) {\n p.log.message(` ${prefix}: ${formatGroup(items)}`)\n }\n\n if (!opts.yes && isInteractive()) {\n const confirmed = await p.confirm({\n message: 'Proceed with uninstall?',\n })\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Cancelled')\n return\n }\n }\n\n // Remove all items\n for (const item of toRemove) {\n rmSync(item.path, { recursive: true, force: true })\n }\n\n // Show grouped removal summary\n for (const [prefix, items] of groups) {\n p.log.success(`Removed ${prefix}: ${formatGroup(items)}`)\n }\n\n // Remove skilld instructions from agent instruction files\n const agentTypes = agentFilter || (Object.keys(agents) as AgentType[])\n for (const proj of projectsToUnregister) {\n for (const agent of agentTypes) {\n if (removeAgentInstructions(agent, proj)) {\n const file = agents[agent].instructionFile!\n p.log.success(`Cleaned ${file}`)\n }\n }\n }\n\n // Unregister projects from config (skip if cache dir was removed — config is gone)\n if (scope !== 'all') {\n for (const proj of projectsToUnregister) {\n unregisterProject(proj)\n }\n }\n\n p.outro('skilld uninstalled')\n}\n\nexport const uninstallCommandDef = defineCommand({\n meta: { name: 'uninstall', description: 'Remove skilld data' },\n args: {\n ...sharedArgs,\n },\n async run({ args }) {\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m uninstall`)\n return uninstallCommand({\n scope: args.global ? 'all' : undefined,\n agent: args.agent as AgentType | undefined,\n yes: args.yes,\n })\n },\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"uninstall.mjs","names":["agents"],"sources":["../../src/commands/uninstall.ts"],"sourcesContent":["import type { AgentType } from '../agent/index.ts'\nimport { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { agents } from '../agent/index.ts'\nimport { CACHE_DIR } from '../cache/index.ts'\nimport { isInteractive, sharedArgs } from '../cli-helpers.ts'\nimport { getRegisteredProjects, unregisterProject } from '../core/config.ts'\nimport { readLock } from '../core/lockfile.ts'\nimport { mapInsert, SHARED_SKILLS_DIR } from '../core/shared.ts'\nimport { SKILLD_MARKER_END, SKILLD_MARKER_START } from './sync.ts'\n\n/**\n * Remove the skilld marker block from an agent's instruction file.\n * For .mdc files (dedicated skilld files), delete the entire file.\n * Also cleans up legacy .cursorrules markers for backwards compat.\n */\nfunction removeAgentInstructions(agent: AgentType, projectPath: string): boolean {\n const agentConfig = agents[agent]\n if (!agentConfig.instructionFile)\n return false\n\n let removed = false\n\n // Handle current instruction file\n const filePath = join(projectPath, agentConfig.instructionFile)\n if (agentConfig.instructionFile.endsWith('.mdc')) {\n // MDC files are dedicated skilld files - just delete\n if (existsSync(filePath)) {\n rmSync(filePath)\n removed = true\n }\n // Also clean up legacy .cursorrules markers (cursor-specific)\n if (agent === 'cursor')\n removed = removeMarkerBlock(join(projectPath, '.cursorrules')) || removed\n }\n else if (existsSync(filePath)) {\n removed = removeMarkerBlock(filePath)\n }\n\n return removed\n}\n\nfunction removeMarkerBlock(filePath: string): boolean {\n if (!existsSync(filePath))\n return false\n\n const content = readFileSync(filePath, 'utf-8')\n const startIdx = content.indexOf(SKILLD_MARKER_START)\n if (startIdx === -1)\n return false\n\n const endIdx = content.indexOf(SKILLD_MARKER_END, startIdx)\n if (endIdx === -1)\n return false\n\n // Remove marker block plus surrounding blank lines\n const before = content.slice(0, startIdx).replace(/\\n+$/, '')\n const after = content.slice(endIdx + SKILLD_MARKER_END.length).replace(/^\\n+/, '')\n const updated = before + (before && after ? '\\n' : '') + after\n\n if (updated.trim() === '') {\n rmSync(filePath)\n }\n else {\n writeFileSync(filePath, updated.endsWith('\\n') ? updated : `${updated}\\n`)\n }\n return true\n}\n\nexport interface UninstallOptions {\n scope?: 'project' | 'all'\n agent?: AgentType\n yes: boolean\n}\n\n/**\n * Uninstall skilld skills by scope:\n * - project: Remove project skills (cwd)\n * - all: All registered projects + global skills + cache\n */\nexport async function uninstallCommand(opts: UninstallOptions): Promise<void> {\n let scope = opts.scope\n const registeredProjects = getRegisteredProjects()\n\n // Prompt for scope if not provided\n if (!scope) {\n if (!isInteractive()) {\n scope = 'project'\n }\n else {\n const allHint = registeredProjects.length > 0\n ? `${registeredProjects.length} projects + global + cache`\n : 'global skills + cache'\n\n const selected = await p.select({\n message: 'What do you want to uninstall?',\n options: [\n { label: 'This project', value: 'project', hint: 'current project only' },\n { label: 'Everything', value: 'all', hint: allHint },\n ],\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Cancelled')\n return\n }\n scope = selected as 'project' | 'all'\n }\n }\n\n interface RemoveItem { label: string, path: string, version?: string }\n const toRemove: RemoveItem[] = []\n const seenPaths = new Set<string>()\n const projectsToUnregister: string[] = []\n const agentFilter = opts.agent ? [opts.agent] : undefined\n\n const addToRemove = (label: string, path: string, version?: string) => {\n if (seenPaths.has(path))\n return\n seenPaths.add(path)\n toRemove.push({ label, path, version })\n }\n\n // Helper to add skills from a lockfile\n const addSkillsFromLock = (skillsDir: string, label: string): string[] => {\n const trackedNames: string[] = []\n const lock = readLock(skillsDir)\n\n if (lock?.skills) {\n for (const [skillName, info] of Object.entries(lock.skills)) {\n trackedNames.push(skillName)\n const skillDir = join(skillsDir, skillName)\n if (existsSync(skillDir)) {\n const version = info.version ? `${info.version.split('.').slice(0, 2).join('.')}.x` : undefined\n addToRemove(`${label}: ${skillName}`, skillDir, version)\n }\n }\n\n // Also add the lockfile itself\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n if (existsSync(lockPath)) {\n addToRemove(`${label}: skilld-lock.yaml`, lockPath)\n }\n }\n\n return trackedNames\n }\n\n // Helper to find untracked skills in a directory\n const findUntrackedSkills = (skillsDir: string, trackedNames: string[]): string[] => {\n if (!existsSync(skillsDir))\n return []\n const tracked = new Set(trackedNames)\n return readdirSync(skillsDir)\n .filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml' && !tracked.has(f))\n }\n\n // Track untracked skills per directory (dedupe by path)\n const untrackedByDir = new Map<string, { label: string, skills: string[] }>()\n const processedDirs = new Set<string>()\n\n // Helper to process a skills directory (with deduping)\n const processSkillsDir = (skillsDir: string, label: string) => {\n if (processedDirs.has(skillsDir))\n return\n processedDirs.add(skillsDir)\n\n const tracked = addSkillsFromLock(skillsDir, label)\n const untracked = findUntrackedSkills(skillsDir, tracked)\n if (untracked.length > 0) {\n untrackedByDir.set(skillsDir, { label, skills: untracked })\n }\n }\n\n // Project skills\n if (scope === 'project') {\n // Shared dir\n const sharedDir = join(process.cwd(), SHARED_SKILLS_DIR)\n if (existsSync(sharedDir))\n processSkillsDir(sharedDir, 'project (.skills)')\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n processSkillsDir(join(process.cwd(), agent.skillsDir), 'project')\n }\n projectsToUnregister.push(process.cwd())\n }\n\n // All registered projects + global\n if (scope === 'all') {\n const projectPaths = registeredProjects.length > 0 ? registeredProjects : [process.cwd()]\n\n // Show which projects will be affected\n if (registeredProjects.length > 0) {\n p.log.info('Projects to uninstall from:')\n for (const proj of projectPaths) {\n p.log.message(` ${proj}`)\n }\n }\n\n // Project skills from lockfiles\n for (const projectPath of projectPaths) {\n if (!existsSync(projectPath))\n continue\n\n const shortPath = projectPath.replace(process.env.HOME || '', '~')\n\n // Shared dir\n const sharedDir = join(projectPath, SHARED_SKILLS_DIR)\n if (existsSync(sharedDir))\n processSkillsDir(sharedDir, `${shortPath} (.skills)`)\n\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n processSkillsDir(join(projectPath, agent.skillsDir), shortPath)\n }\n\n projectsToUnregister.push(projectPath)\n }\n\n // Global skills from lockfiles\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n if (!agent.globalSkillsDir)\n continue\n processSkillsDir(agent.globalSkillsDir, 'user')\n }\n\n // Cache directory\n if (existsSync(CACHE_DIR)) {\n addToRemove('~/.skilld cache', CACHE_DIR)\n }\n }\n\n // Warn about untracked skills that will remain (grouped by label, deduped)\n if (untrackedByDir.size > 0) {\n const groupedUntracked = new Map<string, Set<string>>()\n for (const [_dir, { label, skills }] of untrackedByDir) {\n const set = mapInsert(groupedUntracked, label, () => new Set())\n for (const s of skills) set.add(s)\n }\n\n const totalUntracked = [...groupedUntracked.values()].reduce((sum, s) => sum + s.size, 0)\n p.log.warn(`${totalUntracked} untracked skill(s) will remain (not managed by skilld):`)\n for (const [label, skills] of groupedUntracked) {\n p.log.message(` ${label}: ${[...skills].join(', ')}`)\n }\n }\n\n if (toRemove.length === 0) {\n p.log.info('Nothing to uninstall')\n return\n }\n\n // Group by prefix for display\n const groups = new Map<string, Array<{ name: string, version?: string }>>()\n for (const item of toRemove) {\n const [prefix, name] = item.label.includes(': ')\n ? item.label.split(': ', 2)\n : ['other', item.label]\n mapInsert(groups, prefix!, () => []).push({ name: name!, version: item.version })\n }\n\n const formatGroup = (items: Array<{ name: string, version?: string }>) =>\n items.map(i => i.version ? `${i.name}@${i.version}` : i.name).join(', ')\n\n p.log.info(`Will remove ${toRemove.length} items:`)\n for (const [prefix, items] of groups) {\n p.log.message(` ${prefix}: ${formatGroup(items)}`)\n }\n\n if (!opts.yes && isInteractive()) {\n const confirmed = await p.confirm({\n message: 'Proceed with uninstall?',\n })\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Cancelled')\n return\n }\n }\n\n // Remove all items\n for (const item of toRemove) {\n rmSync(item.path, { recursive: true, force: true })\n }\n\n // Show grouped removal summary\n for (const [prefix, items] of groups) {\n p.log.success(`Removed ${prefix}: ${formatGroup(items)}`)\n }\n\n // Remove skilld instructions from agent instruction files\n const agentTypes = agentFilter || (Object.keys(agents) as AgentType[])\n for (const proj of projectsToUnregister) {\n for (const agent of agentTypes) {\n if (removeAgentInstructions(agent, proj)) {\n const file = agents[agent].instructionFile!\n p.log.success(`Cleaned ${file}`)\n }\n }\n }\n\n // Unregister projects from config (skip if cache dir was removed — config is gone)\n if (scope !== 'all') {\n for (const proj of projectsToUnregister) {\n unregisterProject(proj)\n }\n }\n\n p.outro('skilld uninstalled')\n}\n\nexport const uninstallCommandDef = defineCommand({\n meta: { name: 'uninstall', description: 'Remove skilld data' },\n args: {\n ...sharedArgs,\n },\n async run({ args }) {\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m uninstall`)\n return uninstallCommand({\n scope: args.global ? 'all' : undefined,\n agent: args.agent as AgentType | undefined,\n yes: args.yes,\n })\n },\n})\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.mjs","names":[],"sources":["../../src/commands/upload.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { multiselect } from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { colorize } from 'consola/utils'\nimport { ofetch } from 'ofetch'\nimport { join } from 'pathe'\nimport { readLock } from '../core/lockfile.ts'\nimport { parseFrontmatter } from '../core/markdown.ts'\n\nconst UPLOAD_URL = 'https://skilld.dev/api/collections/import'\n\ninterface DiscoveredSkill {\n name: string\n description?: string\n version?: string\n repo?: string\n generator?: string\n source: 'local' | 'global' | 'plugin'\n}\n\nfunction readSkillsFromDir(dir: string, source: 'local' | 'global', extraLockDirs?: string[]): DiscoveredSkill[] {\n if (!existsSync(dir))\n return []\n\n // Merge lockfiles: primary dir + any extra dirs (e.g. ~/.skilld/skills/ for global)\n let lock = readLock(dir)\n if (!lock && extraLockDirs) {\n for (const d of extraLockDirs) {\n lock = readLock(d)\n if (lock)\n break\n }\n }\n const entries = readdirSync(dir).filter((f) => {\n if (f.startsWith('.') || f.endsWith('.yaml') || f.endsWith('.yml'))\n return false\n const full = join(dir, f)\n return statSync(full).isDirectory()\n })\n\n const skills: DiscoveredSkill[] = []\n for (const dirName of entries) {\n const skillMd = join(dir, dirName, 'SKILL.md')\n if (!existsSync(skillMd))\n continue\n const content = readFileSync(skillMd, 'utf-8')\n const fm = parseFrontmatter(content)\n const lockInfo = lock?.skills[dirName]\n skills.push({\n name: fm.name || dirName,\n description: fm.description,\n version: fm.version || lockInfo?.version,\n repo: lockInfo?.repo,\n generator: lockInfo?.generator,\n source,\n })\n }\n\n return skills\n}\n\ninterface MarketplaceInfo {\n source: { source: string, repo: string }\n}\n\nfunction readPlugins(configDir: string): DiscoveredSkill[] {\n const settingsPath = join(configDir, 'settings.json')\n if (!existsSync(settingsPath))\n return []\n\n const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'))\n const enabledPlugins = settings.enabledPlugins as Record<string, boolean> | undefined\n if (!enabledPlugins)\n return []\n\n // Load marketplace repos for GitHub links\n const marketplacesPath = join(configDir, 'plugins', 'known_marketplaces.json')\n const marketplaces: Record<string, MarketplaceInfo> = existsSync(marketplacesPath)\n ? JSON.parse(readFileSync(marketplacesPath, 'utf-8'))\n : {}\n\n // Load installed plugins for version info\n const installedPath = join(configDir, 'plugins', 'installed_plugins.json')\n const installed: { plugins: Record<string, Array<{ version?: string }>> } = existsSync(installedPath)\n ? JSON.parse(readFileSync(installedPath, 'utf-8'))\n : { plugins: {} }\n\n return Object.entries(enabledPlugins)\n .filter(([, enabled]) => enabled)\n .map(([id]) => {\n const marketplace = id.split('@')[1]\n const pluginName = id.split('@')[0]\n const marketplaceInfo = marketplace ? marketplaces[marketplace] : undefined\n const repo = marketplaceInfo?.source?.repo\n const versions = installed.plugins[id]\n const version = versions?.[0]?.version !== 'unknown' ? versions?.[0]?.version : undefined\n\n return {\n name: pluginName!,\n version,\n repo: repo ? `${repo}` : undefined,\n source: 'plugin' as const,\n }\n })\n}\n\nfunction discoverAllSkills(cwd: string): DiscoveredSkill[] {\n const claudeHome = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude')\n const localDir = join(cwd, '.claude', 'skills')\n const globalDir = join(claudeHome, 'skills')\n\n const skilldGlobalDir = join(homedir(), '.skilld', 'skills')\n const local = readSkillsFromDir(localDir, 'local')\n const global = readSkillsFromDir(globalDir, 'global', [skilldGlobalDir])\n const plugins = readPlugins(claudeHome)\n\n // Filter out skilld-generated skills, deduplicate by repo\n const seenRepos = new Set<string>()\n const all: DiscoveredSkill[] = []\n for (const skill of [...local, ...global, ...plugins]) {\n if (!skill.repo || seenRepos.has(skill.repo))\n continue\n if (skill.generator === 'skilld')\n continue\n seenRepos.add(skill.repo)\n all.push(skill)\n }\n return all\n}\n\nconst SOURCE_COLORS: Record<string, string> = {\n local: 'green',\n global: 'blue',\n plugin: 'magenta',\n}\n\nexport async function uploadCommand(options?: { dryRun?: boolean }): Promise<void> {\n const skills = discoverAllSkills(process.cwd())\n\n if (skills.length === 0) {\n process.stdout.write('No skills found.\\n')\n return\n }\n\n if (options?.dryRun) {\n process.stdout.write(`Found ${colorize('bold', String(skills.length))} skill${skills.length === 1 ? '' : 's'}:\\n\\n`)\n for (const skill of skills) {\n const version = skill.version ? colorize('dim', ` v${skill.version}`) : ''\n const tag = colorize((SOURCE_COLORS[skill.source] || 'dim') as 'dim', skill.source)\n const repo = skill.repo ? colorize('dim', ` github.com/${skill.repo}`) : ''\n process.stdout.write(` ${colorize('cyan', skill.name)}${version} ${tag}${repo}\\n`)\n }\n process.stdout.write(`\\n${colorize('dim', 'Dry run complete. No requests were made.')}\\n`)\n return\n }\n\n const selected = await multiselect({\n message: `Select skills to upload (${skills.length} found)`,\n options: skills.map((s) => {\n const version = s.version ? ` v${s.version}` : ''\n const repo = s.repo ? ` github.com/${s.repo}` : ''\n return {\n value: s.name,\n label: `${s.name}${version}`,\n hint: `${s.source}${repo}`,\n }\n }),\n initialValues: [],\n })\n\n if (typeof selected === 'symbol' || selected.length === 0)\n return\n\n const selectedSet = new Set(selected)\n const payload = skills\n .filter(s => selectedSet.has(s.name))\n .map(s => ({\n name: s.name,\n version: s.version,\n repo: s.repo,\n source: s.source,\n }))\n\n const { token, expires } = await ofetch<{ token: string, expires: string }>(UPLOAD_URL, {\n method: 'POST',\n body: { skills: payload },\n })\n\n const expiresDate = new Date(expires)\n const minutesLeft = Math.round((expiresDate.getTime() - Date.now()) / 60000)\n\n process.stdout.write(`\\nToken: ${colorize('green', token)}\\n\\n`)\n process.stdout.write(`Paste this token at: ${colorize('cyan', 'https://skilld.dev/people/YOUR_HANDLE/edit-skills')}\\n`)\n process.stdout.write(colorize('dim', `Token expires in ${minutesLeft} minutes.\\n`))\n}\n\nexport const uploadCommandDef = defineCommand({\n meta: { name: 'publish', description: 'Publish your skill list to skilld.dev' },\n args: {\n dryRun: {\n type: 'boolean',\n alias: 'd',\n description: 'Show what would be uploaded without making any requests',\n default: false,\n },\n },\n run({ args }) {\n return uploadCommand({ dryRun: args.dryRun })\n },\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"upload.mjs","names":[],"sources":["../../src/commands/upload.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { multiselect } from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { colorize } from 'consola/utils'\nimport { ofetch } from 'ofetch'\nimport { join } from 'pathe'\nimport { readLock } from '../core/lockfile.ts'\nimport { parseFrontmatter } from '../core/markdown.ts'\n\nconst UPLOAD_URL = 'https://skilld.dev/api/collections/import'\n\ninterface DiscoveredSkill {\n name: string\n description?: string\n version?: string\n repo?: string\n generator?: string\n source: 'local' | 'global' | 'plugin'\n}\n\nfunction readSkillsFromDir(dir: string, source: 'local' | 'global', extraLockDirs?: string[]): DiscoveredSkill[] {\n if (!existsSync(dir))\n return []\n\n // Merge lockfiles: primary dir + any extra dirs (e.g. ~/.skilld/skills/ for global)\n let lock = readLock(dir)\n if (!lock && extraLockDirs) {\n for (const d of extraLockDirs) {\n lock = readLock(d)\n if (lock)\n break\n }\n }\n const entries = readdirSync(dir).filter((f) => {\n if (f.startsWith('.') || f.endsWith('.yaml') || f.endsWith('.yml'))\n return false\n const full = join(dir, f)\n return statSync(full).isDirectory()\n })\n\n const skills: DiscoveredSkill[] = []\n for (const dirName of entries) {\n const skillMd = join(dir, dirName, 'SKILL.md')\n if (!existsSync(skillMd))\n continue\n const content = readFileSync(skillMd, 'utf-8')\n const fm = parseFrontmatter(content)\n const lockInfo = lock?.skills[dirName]\n skills.push({\n name: fm.name || dirName,\n description: fm.description,\n version: fm.version || lockInfo?.version,\n repo: lockInfo?.repo,\n generator: lockInfo?.generator,\n source,\n })\n }\n\n return skills\n}\n\ninterface MarketplaceInfo {\n source: { source: string, repo: string }\n}\n\nfunction readPlugins(configDir: string): DiscoveredSkill[] {\n const settingsPath = join(configDir, 'settings.json')\n if (!existsSync(settingsPath))\n return []\n\n const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'))\n const enabledPlugins = settings.enabledPlugins as Record<string, boolean> | undefined\n if (!enabledPlugins)\n return []\n\n // Load marketplace repos for GitHub links\n const marketplacesPath = join(configDir, 'plugins', 'known_marketplaces.json')\n const marketplaces: Record<string, MarketplaceInfo> = existsSync(marketplacesPath)\n ? JSON.parse(readFileSync(marketplacesPath, 'utf-8'))\n : {}\n\n // Load installed plugins for version info\n const installedPath = join(configDir, 'plugins', 'installed_plugins.json')\n const installed: { plugins: Record<string, Array<{ version?: string }>> } = existsSync(installedPath)\n ? JSON.parse(readFileSync(installedPath, 'utf-8'))\n : { plugins: {} }\n\n return Object.entries(enabledPlugins)\n .filter(([, enabled]) => enabled)\n .map(([id]) => {\n const marketplace = id.split('@')[1]\n const pluginName = id.split('@')[0]\n const marketplaceInfo = marketplace ? marketplaces[marketplace] : undefined\n const repo = marketplaceInfo?.source?.repo\n const versions = installed.plugins[id]\n const version = versions?.[0]?.version !== 'unknown' ? versions?.[0]?.version : undefined\n\n return {\n name: pluginName!,\n version,\n repo: repo ? `${repo}` : undefined,\n source: 'plugin' as const,\n }\n })\n}\n\nfunction discoverAllSkills(cwd: string): DiscoveredSkill[] {\n const claudeHome = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude')\n const localDir = join(cwd, '.claude', 'skills')\n const globalDir = join(claudeHome, 'skills')\n\n const skilldGlobalDir = join(homedir(), '.skilld', 'skills')\n const local = readSkillsFromDir(localDir, 'local')\n const global = readSkillsFromDir(globalDir, 'global', [skilldGlobalDir])\n const plugins = readPlugins(claudeHome)\n\n // Filter out skilld-generated skills, deduplicate by repo\n const seenRepos = new Set<string>()\n const all: DiscoveredSkill[] = []\n for (const skill of [...local, ...global, ...plugins]) {\n if (!skill.repo || seenRepos.has(skill.repo))\n continue\n if (skill.generator === 'skilld')\n continue\n seenRepos.add(skill.repo)\n all.push(skill)\n }\n return all\n}\n\nconst SOURCE_COLORS: Record<string, string> = {\n local: 'green',\n global: 'blue',\n plugin: 'magenta',\n}\n\nexport async function uploadCommand(options?: { dryRun?: boolean }): Promise<void> {\n const skills = discoverAllSkills(process.cwd())\n\n if (skills.length === 0) {\n process.stdout.write('No skills found.\\n')\n return\n }\n\n if (options?.dryRun) {\n process.stdout.write(`Found ${colorize('bold', String(skills.length))} skill${skills.length === 1 ? '' : 's'}:\\n\\n`)\n for (const skill of skills) {\n const version = skill.version ? colorize('dim', ` v${skill.version}`) : ''\n const tag = colorize((SOURCE_COLORS[skill.source] || 'dim') as 'dim', skill.source)\n const repo = skill.repo ? colorize('dim', ` github.com/${skill.repo}`) : ''\n process.stdout.write(` ${colorize('cyan', skill.name)}${version} ${tag}${repo}\\n`)\n }\n process.stdout.write(`\\n${colorize('dim', 'Dry run complete. No requests were made.')}\\n`)\n return\n }\n\n const selected = await multiselect({\n message: `Select skills to upload (${skills.length} found)`,\n options: skills.map((s) => {\n const version = s.version ? ` v${s.version}` : ''\n const repo = s.repo ? ` github.com/${s.repo}` : ''\n return {\n value: s.name,\n label: `${s.name}${version}`,\n hint: `${s.source}${repo}`,\n }\n }),\n initialValues: [],\n })\n\n if (typeof selected === 'symbol' || selected.length === 0)\n return\n\n const selectedSet = new Set(selected)\n const payload = skills\n .filter(s => selectedSet.has(s.name))\n .map(s => ({\n name: s.name,\n version: s.version,\n repo: s.repo,\n source: s.source,\n }))\n\n const { token, expires } = await ofetch<{ token: string, expires: string }>(UPLOAD_URL, {\n method: 'POST',\n body: { skills: payload },\n })\n\n const expiresDate = new Date(expires)\n const minutesLeft = Math.round((expiresDate.getTime() - Date.now()) / 60000)\n\n process.stdout.write(`\\nToken: ${colorize('green', token)}\\n\\n`)\n process.stdout.write(`Paste this token at: ${colorize('cyan', 'https://skilld.dev/people/YOUR_HANDLE/edit-skills')}\\n`)\n process.stdout.write(colorize('dim', `Token expires in ${minutesLeft} minutes.\\n`))\n}\n\nexport const uploadCommandDef = defineCommand({\n meta: { name: 'publish', description: 'Publish your skill list to skilld.dev' },\n args: {\n dryRun: {\n type: 'boolean',\n alias: 'd',\n description: 'Show what would be uploaded without making any requests',\n default: false,\n },\n },\n run({ args }) {\n return uploadCommand({ dryRun: args.dryRun })\n },\n})\n"],"mappings":";;;;;;;;;AAUA,MAAM,aAAa;AAWnB,SAAS,kBAAkB,KAAa,QAA4B,eAA6C;CAC/G,IAAI,CAAC,WAAW,IAAI,EAClB,OAAO,EAAE;CAGX,IAAI,OAAO,SAAS,IAAI;CACxB,IAAI,CAAC,QAAQ,eACX,KAAK,MAAM,KAAK,eAAe;EAC7B,OAAO,SAAS,EAAE;EAClB,IAAI,MACF;;CAGN,MAAM,UAAU,YAAY,IAAI,CAAC,QAAQ,MAAM;EAC7C,IAAI,EAAE,WAAW,IAAI,IAAI,EAAE,SAAS,QAAQ,IAAI,EAAE,SAAS,OAAO,EAChE,OAAO;EAET,OAAO,SADM,KAAK,KAAK,EACH,CAAC,CAAC,aAAa;GACnC;CAEF,MAAM,SAA4B,EAAE;CACpC,KAAK,MAAM,WAAW,SAAS;EAC7B,MAAM,UAAU,KAAK,KAAK,SAAS,WAAW;EAC9C,IAAI,CAAC,WAAW,QAAQ,EACtB;EAEF,MAAM,KAAK,iBADK,aAAa,SAAS,QACH,CAAC;EACpC,MAAM,WAAW,MAAM,OAAO;EAC9B,OAAO,KAAK;GACV,MAAM,GAAG,QAAQ;GACjB,aAAa,GAAG;GAChB,SAAS,GAAG,WAAW,UAAU;GACjC,MAAM,UAAU;GAChB,WAAW,UAAU;GACrB;GACD,CAAC;;CAGJ,OAAO;;AAOT,SAAS,YAAY,WAAsC;CACzD,MAAM,eAAe,KAAK,WAAW,gBAAgB;CACrD,IAAI,CAAC,WAAW,aAAa,EAC3B,OAAO,EAAE;CAGX,MAAM,iBADW,KAAK,MAAM,aAAa,cAAc,QAAQ,CAChC,CAAC;CAChC,IAAI,CAAC,gBACH,OAAO,EAAE;CAGX,MAAM,mBAAmB,KAAK,WAAW,WAAW,0BAA0B;CAC9E,MAAM,eAAgD,WAAW,iBAAiB,GAC9E,KAAK,MAAM,aAAa,kBAAkB,QAAQ,CAAC,GACnD,EAAE;CAGN,MAAM,gBAAgB,KAAK,WAAW,WAAW,yBAAyB;CAC1E,MAAM,YAAsE,WAAW,cAAc,GACjG,KAAK,MAAM,aAAa,eAAe,QAAQ,CAAC,GAChD,EAAE,SAAS,EAAE,EAAE;CAEnB,OAAO,OAAO,QAAQ,eAAe,CAClC,QAAQ,GAAG,aAAa,QAAQ,CAChC,KAAK,CAAC,QAAQ;EACb,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC;EAClC,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC;EAEjC,MAAM,QADkB,cAAc,aAAa,eAAe,KAAA,IACpC,QAAQ;EACtC,MAAM,WAAW,UAAU,QAAQ;EAGnC,OAAO;GACL,MAAM;GACN,SAJc,WAAW,IAAI,YAAY,YAAY,WAAW,IAAI,UAAU,KAAA;GAK9E,MAAM,OAAO,GAAG,SAAS,KAAA;GACzB,QAAQ;GACT;GACD;;AAGN,SAAS,kBAAkB,KAAgC;CACzD,MAAM,aAAa,QAAQ,IAAI,qBAAqB,KAAK,SAAS,EAAE,UAAU;CAC9E,MAAM,WAAW,KAAK,KAAK,WAAW,SAAS;CAC/C,MAAM,YAAY,KAAK,YAAY,SAAS;CAE5C,MAAM,kBAAkB,KAAK,SAAS,EAAE,WAAW,SAAS;CAC5D,MAAM,QAAQ,kBAAkB,UAAU,QAAQ;CAClD,MAAM,SAAS,kBAAkB,WAAW,UAAU,CAAC,gBAAgB,CAAC;CACxE,MAAM,UAAU,YAAY,WAAW;CAGvC,MAAM,4BAAY,IAAI,KAAa;CACnC,MAAM,MAAyB,EAAE;CACjC,KAAK,MAAM,SAAS;EAAC,GAAG;EAAO,GAAG;EAAQ,GAAG;EAAQ,EAAE;EACrD,IAAI,CAAC,MAAM,QAAQ,UAAU,IAAI,MAAM,KAAK,EAC1C;EACF,IAAI,MAAM,cAAc,UACtB;EACF,UAAU,IAAI,MAAM,KAAK;EACzB,IAAI,KAAK,MAAM;;CAEjB,OAAO;;AAGT,MAAM,gBAAwC;CAC5C,OAAO;CACP,QAAQ;CACR,QAAQ;CACT;AAED,eAAsB,cAAc,SAA+C;CACjF,MAAM,SAAS,kBAAkB,QAAQ,KAAK,CAAC;CAE/C,IAAI,OAAO,WAAW,GAAG;EACvB,QAAQ,OAAO,MAAM,qBAAqB;EAC1C;;CAGF,IAAI,SAAS,QAAQ;EACnB,QAAQ,OAAO,MAAM,SAAS,SAAS,QAAQ,OAAO,OAAO,OAAO,CAAC,CAAC,QAAQ,OAAO,WAAW,IAAI,KAAK,IAAI,OAAO;EACpH,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,UAAU,MAAM,UAAU,SAAS,OAAO,KAAK,MAAM,UAAU,GAAG;GACxE,MAAM,MAAM,SAAU,cAAc,MAAM,WAAW,OAAiB,MAAM,OAAO;GACnF,MAAM,OAAO,MAAM,OAAO,SAAS,OAAO,eAAe,MAAM,OAAO,GAAG;GACzE,QAAQ,OAAO,MAAM,KAAK,SAAS,QAAQ,MAAM,KAAK,GAAG,QAAQ,GAAG,MAAM,KAAK,IAAI;;EAErF,QAAQ,OAAO,MAAM,KAAK,SAAS,OAAO,2CAA2C,CAAC,IAAI;EAC1F;;CAGF,MAAM,WAAW,MAAM,YAAY;EACjC,SAAS,4BAA4B,OAAO,OAAO;EACnD,SAAS,OAAO,KAAK,MAAM;GACzB,MAAM,UAAU,EAAE,UAAU,KAAK,EAAE,YAAY;GAC/C,MAAM,OAAO,EAAE,OAAO,eAAe,EAAE,SAAS;GAChD,OAAO;IACL,OAAO,EAAE;IACT,OAAO,GAAG,EAAE,OAAO;IACnB,MAAM,GAAG,EAAE,SAAS;IACrB;IACD;EACF,eAAe,EAAE;EAClB,CAAC;CAEF,IAAI,OAAO,aAAa,YAAY,SAAS,WAAW,GACtD;CAEF,MAAM,cAAc,IAAI,IAAI,SAAS;CAUrC,MAAM,EAAE,OAAO,YAAY,MAAM,OAA2C,YAAY;EACtF,QAAQ;EACR,MAAM,EAAE,QAXM,OACb,QAAO,MAAK,YAAY,IAAI,EAAE,KAAK,CAAC,CACpC,KAAI,OAAM;GACT,MAAM,EAAE;GACR,SAAS,EAAE;GACX,MAAM,EAAE;GACR,QAAQ,EAAE;GACX,EAIsB,EAAE;EAC1B,CAAC;CAEF,MAAM,cAAc,IAAI,KAAK,QAAQ;CACrC,MAAM,cAAc,KAAK,OAAO,YAAY,SAAS,GAAG,KAAK,KAAK,IAAI,IAAM;CAE5E,QAAQ,OAAO,MAAM,YAAY,SAAS,SAAS,MAAM,CAAC,MAAM;CAChE,QAAQ,OAAO,MAAM,wBAAwB,SAAS,QAAQ,oDAAoD,CAAC,IAAI;CACvH,QAAQ,OAAO,MAAM,SAAS,OAAO,oBAAoB,YAAY,aAAa,CAAC;;AAGrF,MAAa,mBAAmB,cAAc;CAC5C,MAAM;EAAE,MAAM;EAAW,aAAa;EAAyC;CAC/E,MAAM,EACJ,QAAQ;EACN,MAAM;EACN,OAAO;EACP,aAAa;EACb,SAAS;EACV,EACF;CACD,IAAI,EAAE,QAAQ;EACZ,OAAO,cAAc,EAAE,QAAQ,KAAK,QAAQ,CAAC;;CAEhD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.mjs","names":[],"sources":["../../src/commands/validate.ts"],"sourcesContent":["/**\n * skilld validate <file> [--section <type>]\n *\n * Validates a generated skill section file against quality heuristics.\n * Exits non-zero on warnings so the LLM agent detects issues via exit code.\n */\n\nimport type { SkillSection } from '../agent/prompts/index.ts'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { defineCommand } from 'citty'\nimport { getSectionValidator } from '../agent/prompts/index.ts'\n\nconst SECTION_HEADINGS: Record<string, SkillSection> = {\n '## API Changes': 'api-changes',\n '## Best Practices': 'best-practices',\n}\n\n/** Infer section type from content headings */\nfunction inferSection(content: string): SkillSection | null {\n for (const [heading, section] of Object.entries(SECTION_HEADINGS)) {\n if (content.includes(heading))\n return section\n }\n // Custom sections don't have a fixed heading — fall back\n return 'custom'\n}\n\nexport const validateCommandDef = defineCommand({\n meta: { name: 'validate', description: 'Validate a generated skill section' },\n args: {\n file: {\n type: 'positional',\n description: 'Path to the section file to validate',\n required: true,\n },\n section: {\n type: 'string',\n description: 'Section type (api-changes, best-practices, custom). Auto-detected from heading if omitted.',\n },\n },\n\n /* eslint-disable no-console */\n async run({ args }) {\n const filePath = args.file as string\n if (!existsSync(filePath)) {\n console.error(`File not found: ${filePath}`)\n process.exit(1)\n }\n\n const content = readFileSync(filePath, 'utf-8').trim()\n if (!content) {\n console.error('File is empty')\n process.exit(1)\n }\n\n const section = (args.section as SkillSection) || inferSection(content)\n if (!section) {\n console.error('Could not infer section type — use --section flag')\n process.exit(1)\n }\n\n const validator = getSectionValidator(section)\n if (!validator) {\n console.log('OK: No validator for section type:', section)\n process.exit(0)\n }\n\n const warnings = validator(content)\n\n if (warnings.length === 0) {\n console.log('OK: No validation warnings')\n process.exit(0)\n }\n\n for (const w of warnings)\n console.log(`WARNING: ${w.warning}`)\n\n process.exit(1)\n },\n})\n"],"mappings":";;;AAYA,MAAM,mBAAiD;CACrD,kBAAkB;CAClB,qBAAqB;CACtB;AAGD,SAAS,aAAa,SAAsC;
|
|
1
|
+
{"version":3,"file":"validate.mjs","names":[],"sources":["../../src/commands/validate.ts"],"sourcesContent":["/**\n * skilld validate <file> [--section <type>]\n *\n * Validates a generated skill section file against quality heuristics.\n * Exits non-zero on warnings so the LLM agent detects issues via exit code.\n */\n\nimport type { SkillSection } from '../agent/prompts/index.ts'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { defineCommand } from 'citty'\nimport { getSectionValidator } from '../agent/prompts/index.ts'\n\nconst SECTION_HEADINGS: Record<string, SkillSection> = {\n '## API Changes': 'api-changes',\n '## Best Practices': 'best-practices',\n}\n\n/** Infer section type from content headings */\nfunction inferSection(content: string): SkillSection | null {\n for (const [heading, section] of Object.entries(SECTION_HEADINGS)) {\n if (content.includes(heading))\n return section\n }\n // Custom sections don't have a fixed heading — fall back\n return 'custom'\n}\n\nexport const validateCommandDef = defineCommand({\n meta: { name: 'validate', description: 'Validate a generated skill section' },\n args: {\n file: {\n type: 'positional',\n description: 'Path to the section file to validate',\n required: true,\n },\n section: {\n type: 'string',\n description: 'Section type (api-changes, best-practices, custom). Auto-detected from heading if omitted.',\n },\n },\n\n /* eslint-disable no-console */\n async run({ args }) {\n const filePath = args.file as string\n if (!existsSync(filePath)) {\n console.error(`File not found: ${filePath}`)\n process.exit(1)\n }\n\n const content = readFileSync(filePath, 'utf-8').trim()\n if (!content) {\n console.error('File is empty')\n process.exit(1)\n }\n\n const section = (args.section as SkillSection) || inferSection(content)\n if (!section) {\n console.error('Could not infer section type — use --section flag')\n process.exit(1)\n }\n\n const validator = getSectionValidator(section)\n if (!validator) {\n console.log('OK: No validator for section type:', section)\n process.exit(0)\n }\n\n const warnings = validator(content)\n\n if (warnings.length === 0) {\n console.log('OK: No validation warnings')\n process.exit(0)\n }\n\n for (const w of warnings)\n console.log(`WARNING: ${w.warning}`)\n\n process.exit(1)\n },\n})\n"],"mappings":";;;AAYA,MAAM,mBAAiD;CACrD,kBAAkB;CAClB,qBAAqB;CACtB;AAGD,SAAS,aAAa,SAAsC;CAC1D,KAAK,MAAM,CAAC,SAAS,YAAY,OAAO,QAAQ,iBAAiB,EAC/D,IAAI,QAAQ,SAAS,QAAQ,EAC3B,OAAO;CAGX,OAAO;;AAGT,MAAa,qBAAqB,cAAc;CAC9C,MAAM;EAAE,MAAM;EAAY,aAAa;EAAsC;CAC7E,MAAM;EACJ,MAAM;GACJ,MAAM;GACN,aAAa;GACb,UAAU;GACX;EACD,SAAS;GACP,MAAM;GACN,aAAa;GACd;EACF;CAGD,MAAM,IAAI,EAAE,QAAQ;EAClB,MAAM,WAAW,KAAK;EACtB,IAAI,CAAC,WAAW,SAAS,EAAE;GACzB,QAAQ,MAAM,mBAAmB,WAAW;GAC5C,QAAQ,KAAK,EAAE;;EAGjB,MAAM,UAAU,aAAa,UAAU,QAAQ,CAAC,MAAM;EACtD,IAAI,CAAC,SAAS;GACZ,QAAQ,MAAM,gBAAgB;GAC9B,QAAQ,KAAK,EAAE;;EAGjB,MAAM,UAAW,KAAK,WAA4B,aAAa,QAAQ;EACvE,IAAI,CAAC,SAAS;GACZ,QAAQ,MAAM,oDAAoD;GAClE,QAAQ,KAAK,EAAE;;EAGjB,MAAM,YAAY,oBAAoB,QAAQ;EAC9C,IAAI,CAAC,WAAW;GACd,QAAQ,IAAI,sCAAsC,QAAQ;GAC1D,QAAQ,KAAK,EAAE;;EAGjB,MAAM,WAAW,UAAU,QAAQ;EAEnC,IAAI,SAAS,WAAW,GAAG;GACzB,QAAQ,IAAI,6BAA6B;GACzC,QAAQ,KAAK,EAAE;;EAGjB,KAAK,MAAM,KAAK,UACd,QAAQ,IAAI,YAAY,EAAE,UAAU;EAEtC,QAAQ,KAAK,EAAE;;CAElB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.mjs","names":[],"sources":["../../src/cache/config.ts","../../src/cache/version.ts"],"sourcesContent":["/**\n * Cache configuration\n */\n\nimport { homedir } from 'node:os'\nimport { join } from 'pathe'\n\n/** Global cache directory */\nexport const CACHE_DIR = join(homedir(), '.skilld')\n\n/** References subdirectory */\nexport const REFERENCES_DIR = join(CACHE_DIR, 'references')\n\n/** Repo-level cache (issues, discussions, releases shared across monorepo packages) */\nexport const REPOS_DIR = join(CACHE_DIR, 'repos')\n\n/** Get repo cache dir for owner/repo with path traversal validation */\nexport function getRepoCacheDir(owner: string, repo: string): string {\n if (owner.includes('..') || repo.includes('..') || owner.includes('/') || repo.includes('/'))\n throw new Error(`Invalid repo path: ${owner}/${repo}`)\n return join(REPOS_DIR, owner, repo)\n}\n\n/** Get search DB path for a specific package@version */\nexport function getPackageDbPath(name: string, version: string): string {\n return join(REFERENCES_DIR, `${name}@${version}`, 'search.db')\n}\n","/**\n * Version utilities\n */\n\nimport { resolve } from 'pathe'\nimport { REFERENCES_DIR } from './config.ts'\n\n/** Validate npm package name (scoped or unscoped) */\nconst VALID_PKG_NAME = /^(?:@[a-z0-9][-a-z0-9._]*\\/)?[a-z0-9][-a-z0-9._]*$/\n\n/** Validate version string (semver-ish, no path separators) */\nconst VALID_VERSION = /^[a-z0-9][-\\w.+]*$/i\n\n/**\n * Get exact version key for cache keying\n */\nexport function getVersionKey(version: string): string {\n return version\n}\n\n/**\n * Get cache key for a package: name@version\n */\nexport function getCacheKey(name: string, version: string): string {\n return `${name}@${getVersionKey(version)}`\n}\n\n/**\n * Get path to cached package references.\n * Validates name/version to prevent path traversal.\n */\nexport function getCacheDir(name: string, version: string): string {\n if (!VALID_PKG_NAME.test(name))\n throw new Error(`Invalid package name: ${name}`)\n if (!VALID_VERSION.test(version))\n throw new Error(`Invalid version: ${version}`)\n\n const dir = resolve(REFERENCES_DIR, getCacheKey(name, version))\n if (!dir.startsWith(REFERENCES_DIR))\n throw new Error(`Path traversal detected: ${dir}`)\n return dir\n}\n"],"mappings":";;;AAQA,MAAa,iBAAiB,KAAA,WAAW,aAAU;AAGnD,MAAa,YAAA,KAAiB,WAAK,QAAW;AAG9C,SAAa,gBAAiB,OAAA,MAAW;;
|
|
1
|
+
{"version":3,"file":"version.mjs","names":[],"sources":["../../src/cache/config.ts","../../src/cache/version.ts"],"sourcesContent":["/**\n * Cache configuration\n */\n\nimport { homedir } from 'node:os'\nimport { join } from 'pathe'\n\n/** Global cache directory */\nexport const CACHE_DIR = join(homedir(), '.skilld')\n\n/** References subdirectory */\nexport const REFERENCES_DIR = join(CACHE_DIR, 'references')\n\n/** Repo-level cache (issues, discussions, releases shared across monorepo packages) */\nexport const REPOS_DIR = join(CACHE_DIR, 'repos')\n\n/** Get repo cache dir for owner/repo with path traversal validation */\nexport function getRepoCacheDir(owner: string, repo: string): string {\n if (owner.includes('..') || repo.includes('..') || owner.includes('/') || repo.includes('/'))\n throw new Error(`Invalid repo path: ${owner}/${repo}`)\n return join(REPOS_DIR, owner, repo)\n}\n\n/** Get search DB path for a specific package@version */\nexport function getPackageDbPath(name: string, version: string): string {\n return join(REFERENCES_DIR, `${name}@${version}`, 'search.db')\n}\n","/**\n * Version utilities\n */\n\nimport { resolve } from 'pathe'\nimport { REFERENCES_DIR } from './config.ts'\n\n/** Validate npm package name (scoped or unscoped) */\nconst VALID_PKG_NAME = /^(?:@[a-z0-9][-a-z0-9._]*\\/)?[a-z0-9][-a-z0-9._]*$/\n\n/** Validate version string (semver-ish, no path separators) */\nconst VALID_VERSION = /^[a-z0-9][-\\w.+]*$/i\n\n/**\n * Get exact version key for cache keying\n */\nexport function getVersionKey(version: string): string {\n return version\n}\n\n/**\n * Get cache key for a package: name@version\n */\nexport function getCacheKey(name: string, version: string): string {\n return `${name}@${getVersionKey(version)}`\n}\n\n/**\n * Get path to cached package references.\n * Validates name/version to prevent path traversal.\n */\nexport function getCacheDir(name: string, version: string): string {\n if (!VALID_PKG_NAME.test(name))\n throw new Error(`Invalid package name: ${name}`)\n if (!VALID_VERSION.test(version))\n throw new Error(`Invalid version: ${version}`)\n\n const dir = resolve(REFERENCES_DIR, getCacheKey(name, version))\n if (!dir.startsWith(REFERENCES_DIR))\n throw new Error(`Path traversal detected: ${dir}`)\n return dir\n}\n"],"mappings":";;;AAQA,MAAa,iBAAiB,KAAA,WAAW,aAAU;AAGnD,MAAa,YAAA,KAAiB,WAAK,QAAW;AAG9C,SAAa,gBAAiB,OAAA,MAAW;;CAGzC,OAAA,KAAgB,WAAA,OAAgB,KAAe;;;;;;;ACT/C,SAAM,cAAiB,SAAA;;;;;;;;;;CAevB,IAAA,CAAA,IAAgB,WAAY,eAAuC,EAAA,MAAA,IAAA,MAAA,4BAAA,MAAA;CACjE,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard.mjs","names":["agents"],"sources":["../../src/commands/wizard.ts"],"sourcesContent":["import type { AgentType, OptimizeModel } from '../agent/index.ts'\nimport type { FeaturesConfig } from '../core/config.ts'\nimport { execSync } from 'node:child_process'\nimport * as p from '@clack/prompts'\nimport { getOAuthProviderList, loginOAuthProvider } from '../agent/clis/pi-ai.ts'\nimport { agents, getAvailableModels, getModelName } from '../agent/index.ts'\nimport { isInteractive, NO_MODELS_MESSAGE, OAUTH_NOTE, pickModel } from '../cli-helpers.ts'\nimport { defaultFeatures, updateConfig } from '../core/config.ts'\n\nfunction hasGhCli(): boolean {\n if (process.env.SKILLD_NO_GH)\n return false\n try {\n execSync('gh --version', { stdio: 'ignore' })\n return true\n }\n catch {\n return false\n }\n}\n\nexport interface WizardOptions {\n /** Resolved target agent, if known */\n agent?: AgentType\n /** Show next-steps outro when done (default: true) */\n showOutro?: boolean\n}\n\nexport async function runWizard(opts: WizardOptions = {}): Promise<boolean> {\n if (!isInteractive())\n return false\n\n const agentLabel = opts.agent ? agents[opts.agent].displayName : null\n const skillsDir = opts.agent ? agents[opts.agent].skillsDir : '.claude/skills'\n const agentLine = agentLabel\n ? `\\n\\x1B[90mTarget agent: ${agentLabel}\\x1B[0m`\n : ''\n\n p.note(\n `Your AI agent reads docs from its training data - but APIs change,\\n`\n + `versions drift, and patterns go stale. Skilld fixes this.\\n`\n + `\\n`\n + `It generates a \\x1B[1mSKILL.md\\x1B[0m - a markdown reference card built from\\n`\n + `the \\x1B[1mactual docs, issues, and release notes\\x1B[0m for the exact\\n`\n + `package versions in your project. Your agent reads this file\\n`\n + `every session - no hallucinated APIs.\\n`\n + `\\n`\n + `\\x1B[1mHow it works:\\x1B[0m\\n`\n + ` 1. Fetch docs, issues, and types for your packages\\n`\n + ` 2. Optionally compress with an LLM into a concise cheat sheet\\n`\n + `\\n`\n + `\\x1B[90mExample: \\`skilld add vue\\` creates ${skillsDir}/vue-skilld/SKILL.md\\n`\n + `Your agent then knows the right APIs, gotchas, and patterns\\n`\n + `for your exact version.\\x1B[0m${\n agentLine}`,\n 'Welcome to skilld',\n )\n\n const ghInstalled = hasGhCli()\n\n if (ghInstalled) {\n p.log.success(\n 'GitHub CLI detected — will use it to pull issues and discussions.',\n )\n }\n else {\n p.log.info(\n '\\x1B[90mGitHub CLI not installed — issues and discussions disabled.\\n'\n + ' Install later to enable: \\x1B[36mhttps://cli.github.com\\x1B[0m',\n )\n }\n\n // Feature toggles\n const selected = await p.multiselect({\n message: 'What data sources should skills include?',\n options: [\n { label: 'Local search', value: 'search' as const, hint: 'query engine for `skilld search` across all skill docs' },\n { label: 'Release notes', value: 'releases' as const, hint: 'changelogs and migration notes per version' },\n { label: 'GitHub issues', value: 'issues' as const, hint: 'common bugs, workarounds, and solutions', disabled: !ghInstalled },\n { label: 'GitHub discussions', value: 'discussions' as const, hint: 'community Q&A and usage examples', disabled: !ghInstalled },\n ],\n initialValues: [\n ...Object.entries(defaultFeatures)\n .filter(([, v]) => v)\n .map(([k]) => k),\n ...(ghInstalled ? ['issues', 'discussions'] as const : []),\n ] as Array<keyof FeaturesConfig>,\n required: false,\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Setup cancelled')\n return false\n }\n\n const features: FeaturesConfig = {\n search: selected.includes('search'),\n issues: selected.includes('issues'),\n discussions: selected.includes('discussions'),\n releases: selected.includes('releases'),\n }\n\n // Enhancement model - optional, independent of target agent\n p.note(\n 'An LLM can optionally summarize raw docs into a focused reference\\n'\n + 'highlighting best practices, gotchas, and migrations.\\n'\n + '\\n'\n + '\\x1B[1mWithout LLM:\\x1B[0m ~2 KB skill with package metadata, types, and links\\n'\n + '\\x1B[1mWith LLM:\\x1B[0m ~5 KB skill with curated gotchas, patterns, and migration notes\\n'\n + '\\n'\n + '\\x1B[1mThis is a one-time build step\\x1B[0m - it generates the SKILL.md, then your\\n'\n + 'coding agent reads the result every session. Can be a different model.\\n'\n + '\\n'\n + '\\x1B[90mWorks with API keys (ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENAI_API_KEY)\\n'\n + 'or CLI tools (claude, gemini, codex).\\x1B[0m',\n 'Enhancement model (optional)',\n )\n\n let modelId: OptimizeModel | undefined\n let skippedEnhancement = false\n let oauthJustConnected = false\n\n // Loop so user can connect OAuth then come back to pick a model\n while (true) {\n const allModels = process.env.SKILLD_NO_AGENTS ? [] : await getAvailableModels()\n\n if (allModels.length === 0) {\n p.log.warn(NO_MODELS_MESSAGE)\n }\n else if (oauthJustConnected) {\n p.log.step(`${allModels.length} models now available. Select one below.`)\n }\n else {\n // Show which providers were found by name (e.g. \"Anthropic via CLI, OpenAI via API key\")\n const providers = new Set<string>()\n for (const m of allModels) {\n const vendor = m.vendorGroup ?? m.providerName\n if (!m.id.startsWith('pi:'))\n providers.add(`${vendor} via CLI`)\n else if (m.hint?.includes('API key'))\n providers.add(`${vendor} via API key`)\n else if (m.hint?.includes('OAuth'))\n providers.add(`${vendor} via OAuth`)\n }\n if (providers.size > 0)\n p.log.success(`Found: ${[...providers].join(', ')}`)\n }\n\n const oauthProviders = getOAuthProviderList()\n const afterOptions = oauthProviders.length > 0\n ? [\n { label: '⚠ Connect OAuth provider...', value: '_connect', hint: 'may violate provider ToS' },\n { label: 'Skip enhancement', value: '_skip', hint: 'base skill with docs, issues, and types, add LLM later via `skilld config`' },\n ]\n : [\n { label: 'Skip enhancement', value: '_skip', hint: 'base skill with docs, issues, and types, add LLM later via `skilld config`' },\n ]\n\n const choice = await pickModel(allModels, {\n before: allModels.length > 0\n ? [{ label: 'Auto', value: '_auto', hint: 'picks best available model from connected providers' }]\n : [],\n after: afterOptions,\n })\n\n if (choice === null) {\n p.cancel('Setup cancelled')\n return false\n }\n\n if (choice === '_connect') {\n await wizardConnectProvider()\n oauthJustConnected = true\n continue\n }\n\n if (choice === '_skip') {\n skippedEnhancement = true\n break\n }\n if (choice === '_auto')\n break\n\n modelId = choice as OptimizeModel\n break\n }\n\n updateConfig({\n features,\n ...(modelId\n ? { model: modelId, skipLlm: false }\n : { model: undefined, skipLlm: skippedEnhancement }),\n })\n\n // Summary of what was saved\n const modelSummary = modelId\n ? getModelName(modelId)\n : skippedEnhancement\n ? 'none (raw docs)'\n : 'auto'\n const featureList = Object.entries(features).filter(([, v]) => v).map(([k]) => k).join(', ') || 'none'\n p.log.success(`Model: ${modelSummary} · Features: ${featureList}`)\n\n if (opts.showOutro !== false) {\n p.note(\n 'Run \\x1B[36mskilld add <pkg>\\x1B[0m to generate skills for specific packages\\n'\n + 'Run \\x1B[36mskilld\\x1B[0m to scan your project and pick packages interactively\\n'\n + 'Run \\x1B[36mskilld config\\x1B[0m to change settings later',\n 'Setup complete',\n )\n }\n return true\n}\n\nasync function wizardConnectProvider(): Promise<void> {\n p.note(OAUTH_NOTE, 'How OAuth works')\n\n const providers = getOAuthProviderList()\n const provider = await p.select({\n message: 'Connect provider',\n options: providers.map(pr => ({\n label: pr.name,\n value: pr.id,\n hint: pr.loggedIn ? 'connected' : undefined,\n })),\n })\n\n if (p.isCancel(provider))\n return\n\n const spinner = p.spinner()\n spinner.start('Connecting...')\n\n const success = await loginOAuthProvider(provider as string, {\n onAuth: (url, instructions) => {\n spinner.stop('Open this URL in your browser:')\n p.log.info(` \\x1B[36m${url}\\x1B[0m`)\n if (instructions)\n p.log.info(` \\x1B[90m${instructions}\\x1B[0m`)\n spinner.start('Waiting for authentication...')\n },\n onPrompt: async (message, placeholder) => {\n const value = await p.text({ message, placeholder })\n if (p.isCancel(value))\n return ''\n return value as string\n },\n onProgress: msg => p.log.step(msg),\n }).catch((err: Error) => {\n spinner.stop(`Login failed: ${err.message}`)\n return false\n })\n\n spinner.stop()\n\n if (success) {\n const name = providers.find(pr => pr.id === provider)?.name ?? provider\n p.log.success(`Connected to ${name}`)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wizard.mjs","names":["agents"],"sources":["../../src/commands/wizard.ts"],"sourcesContent":["import type { AgentType, OptimizeModel } from '../agent/index.ts'\nimport type { FeaturesConfig } from '../core/config.ts'\nimport { execSync } from 'node:child_process'\nimport * as p from '@clack/prompts'\nimport { getOAuthProviderList, loginOAuthProvider } from '../agent/clis/pi-ai.ts'\nimport { agents, getAvailableModels, getModelName } from '../agent/index.ts'\nimport { isInteractive, NO_MODELS_MESSAGE, OAUTH_NOTE, pickModel } from '../cli-helpers.ts'\nimport { defaultFeatures, updateConfig } from '../core/config.ts'\n\nfunction hasGhCli(): boolean {\n if (process.env.SKILLD_NO_GH)\n return false\n try {\n execSync('gh --version', { stdio: 'ignore' })\n return true\n }\n catch {\n return false\n }\n}\n\nexport interface WizardOptions {\n /** Resolved target agent, if known */\n agent?: AgentType\n /** Show next-steps outro when done (default: true) */\n showOutro?: boolean\n}\n\nexport async function runWizard(opts: WizardOptions = {}): Promise<boolean> {\n if (!isInteractive())\n return false\n\n const agentLabel = opts.agent ? agents[opts.agent].displayName : null\n const skillsDir = opts.agent ? agents[opts.agent].skillsDir : '.claude/skills'\n const agentLine = agentLabel\n ? `\\n\\x1B[90mTarget agent: ${agentLabel}\\x1B[0m`\n : ''\n\n p.note(\n `Your AI agent reads docs from its training data - but APIs change,\\n`\n + `versions drift, and patterns go stale. Skilld fixes this.\\n`\n + `\\n`\n + `It generates a \\x1B[1mSKILL.md\\x1B[0m - a markdown reference card built from\\n`\n + `the \\x1B[1mactual docs, issues, and release notes\\x1B[0m for the exact\\n`\n + `package versions in your project. Your agent reads this file\\n`\n + `every session - no hallucinated APIs.\\n`\n + `\\n`\n + `\\x1B[1mHow it works:\\x1B[0m\\n`\n + ` 1. Fetch docs, issues, and types for your packages\\n`\n + ` 2. Optionally compress with an LLM into a concise cheat sheet\\n`\n + `\\n`\n + `\\x1B[90mExample: \\`skilld add vue\\` creates ${skillsDir}/vue-skilld/SKILL.md\\n`\n + `Your agent then knows the right APIs, gotchas, and patterns\\n`\n + `for your exact version.\\x1B[0m${\n agentLine}`,\n 'Welcome to skilld',\n )\n\n const ghInstalled = hasGhCli()\n\n if (ghInstalled) {\n p.log.success(\n 'GitHub CLI detected — will use it to pull issues and discussions.',\n )\n }\n else {\n p.log.info(\n '\\x1B[90mGitHub CLI not installed — issues and discussions disabled.\\n'\n + ' Install later to enable: \\x1B[36mhttps://cli.github.com\\x1B[0m',\n )\n }\n\n // Feature toggles\n const selected = await p.multiselect({\n message: 'What data sources should skills include?',\n options: [\n { label: 'Local search', value: 'search' as const, hint: 'query engine for `skilld search` across all skill docs' },\n { label: 'Release notes', value: 'releases' as const, hint: 'changelogs and migration notes per version' },\n { label: 'GitHub issues', value: 'issues' as const, hint: 'common bugs, workarounds, and solutions', disabled: !ghInstalled },\n { label: 'GitHub discussions', value: 'discussions' as const, hint: 'community Q&A and usage examples', disabled: !ghInstalled },\n ],\n initialValues: [\n ...Object.entries(defaultFeatures)\n .filter(([, v]) => v)\n .map(([k]) => k),\n ...(ghInstalled ? ['issues', 'discussions'] as const : []),\n ] as Array<keyof FeaturesConfig>,\n required: false,\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Setup cancelled')\n return false\n }\n\n const features: FeaturesConfig = {\n search: selected.includes('search'),\n issues: selected.includes('issues'),\n discussions: selected.includes('discussions'),\n releases: selected.includes('releases'),\n }\n\n // Enhancement model - optional, independent of target agent\n p.note(\n 'An LLM can optionally summarize raw docs into a focused reference\\n'\n + 'highlighting best practices, gotchas, and migrations.\\n'\n + '\\n'\n + '\\x1B[1mWithout LLM:\\x1B[0m ~2 KB skill with package metadata, types, and links\\n'\n + '\\x1B[1mWith LLM:\\x1B[0m ~5 KB skill with curated gotchas, patterns, and migration notes\\n'\n + '\\n'\n + '\\x1B[1mThis is a one-time build step\\x1B[0m - it generates the SKILL.md, then your\\n'\n + 'coding agent reads the result every session. Can be a different model.\\n'\n + '\\n'\n + '\\x1B[90mWorks with API keys (ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENAI_API_KEY)\\n'\n + 'or CLI tools (claude, gemini, codex).\\x1B[0m',\n 'Enhancement model (optional)',\n )\n\n let modelId: OptimizeModel | undefined\n let skippedEnhancement = false\n let oauthJustConnected = false\n\n // Loop so user can connect OAuth then come back to pick a model\n while (true) {\n const allModels = process.env.SKILLD_NO_AGENTS ? [] : await getAvailableModels()\n\n if (allModels.length === 0) {\n p.log.warn(NO_MODELS_MESSAGE)\n }\n else if (oauthJustConnected) {\n p.log.step(`${allModels.length} models now available. Select one below.`)\n }\n else {\n // Show which providers were found by name (e.g. \"Anthropic via CLI, OpenAI via API key\")\n const providers = new Set<string>()\n for (const m of allModels) {\n const vendor = m.vendorGroup ?? m.providerName\n if (!m.id.startsWith('pi:'))\n providers.add(`${vendor} via CLI`)\n else if (m.hint?.includes('API key'))\n providers.add(`${vendor} via API key`)\n else if (m.hint?.includes('OAuth'))\n providers.add(`${vendor} via OAuth`)\n }\n if (providers.size > 0)\n p.log.success(`Found: ${[...providers].join(', ')}`)\n }\n\n const oauthProviders = getOAuthProviderList()\n const afterOptions = oauthProviders.length > 0\n ? [\n { label: '⚠ Connect OAuth provider...', value: '_connect', hint: 'may violate provider ToS' },\n { label: 'Skip enhancement', value: '_skip', hint: 'base skill with docs, issues, and types, add LLM later via `skilld config`' },\n ]\n : [\n { label: 'Skip enhancement', value: '_skip', hint: 'base skill with docs, issues, and types, add LLM later via `skilld config`' },\n ]\n\n const choice = await pickModel(allModels, {\n before: allModels.length > 0\n ? [{ label: 'Auto', value: '_auto', hint: 'picks best available model from connected providers' }]\n : [],\n after: afterOptions,\n })\n\n if (choice === null) {\n p.cancel('Setup cancelled')\n return false\n }\n\n if (choice === '_connect') {\n await wizardConnectProvider()\n oauthJustConnected = true\n continue\n }\n\n if (choice === '_skip') {\n skippedEnhancement = true\n break\n }\n if (choice === '_auto')\n break\n\n modelId = choice as OptimizeModel\n break\n }\n\n updateConfig({\n features,\n ...(modelId\n ? { model: modelId, skipLlm: false }\n : { model: undefined, skipLlm: skippedEnhancement }),\n })\n\n // Summary of what was saved\n const modelSummary = modelId\n ? getModelName(modelId)\n : skippedEnhancement\n ? 'none (raw docs)'\n : 'auto'\n const featureList = Object.entries(features).filter(([, v]) => v).map(([k]) => k).join(', ') || 'none'\n p.log.success(`Model: ${modelSummary} · Features: ${featureList}`)\n\n if (opts.showOutro !== false) {\n p.note(\n 'Run \\x1B[36mskilld add <pkg>\\x1B[0m to generate skills for specific packages\\n'\n + 'Run \\x1B[36mskilld\\x1B[0m to scan your project and pick packages interactively\\n'\n + 'Run \\x1B[36mskilld config\\x1B[0m to change settings later',\n 'Setup complete',\n )\n }\n return true\n}\n\nasync function wizardConnectProvider(): Promise<void> {\n p.note(OAUTH_NOTE, 'How OAuth works')\n\n const providers = getOAuthProviderList()\n const provider = await p.select({\n message: 'Connect provider',\n options: providers.map(pr => ({\n label: pr.name,\n value: pr.id,\n hint: pr.loggedIn ? 'connected' : undefined,\n })),\n })\n\n if (p.isCancel(provider))\n return\n\n const spinner = p.spinner()\n spinner.start('Connecting...')\n\n const success = await loginOAuthProvider(provider as string, {\n onAuth: (url, instructions) => {\n spinner.stop('Open this URL in your browser:')\n p.log.info(` \\x1B[36m${url}\\x1B[0m`)\n if (instructions)\n p.log.info(` \\x1B[90m${instructions}\\x1B[0m`)\n spinner.start('Waiting for authentication...')\n },\n onPrompt: async (message, placeholder) => {\n const value = await p.text({ message, placeholder })\n if (p.isCancel(value))\n return ''\n return value as string\n },\n onProgress: msg => p.log.step(msg),\n }).catch((err: Error) => {\n spinner.stop(`Login failed: ${err.message}`)\n return false\n })\n\n spinner.stop()\n\n if (success) {\n const name = providers.find(pr => pr.id === provider)?.name ?? provider\n p.log.success(`Connected to ${name}`)\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml.mjs","names":[],"sources":["../../src/core/yaml.ts"],"sourcesContent":["/**\n * Minimal YAML value escaping/unescaping for our hand-rolled parsers.\n *\n * Handles the characters that break naive `:` splitting and quote stripping:\n * colons, quotes, newlines, backslashes.\n */\n\n/** Characters that require double-quoting in YAML values */\nconst NEEDS_QUOTING = /[:\"'\\\\\\n\\r\\t#{}[\\],&*!|>%@`]/\n\n/**\n * Escape a value for safe YAML emission. Always double-quotes if the value\n * contains any special characters; returns unquoted for simple values.\n */\nexport function yamlEscape(value: string): string {\n if (!NEEDS_QUOTING.test(value))\n return value\n // Escape backslashes first, then double quotes, then control chars\n const escaped = value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\t/g, '\\\\t')\n return `\"${escaped}\"`\n}\n\n/**\n * Parse a raw YAML value string back to its actual value.\n * Handles double-quoted (with escapes), single-quoted, and unquoted values.\n */\nexport function yamlUnescape(raw: string): string {\n const trimmed = raw.trim()\n if (!trimmed)\n return ''\n\n // Double-quoted: single-pass escape processing to handle backslashes correctly\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return trimmed.slice(1, -1)\n .replace(/\\\\([\\\\nrt\"])/g, (_, c) => {\n switch (c) {\n case '\\\\': return '\\\\'\n case 'n': return '\\n'\n case 'r': return '\\r'\n case 't': return '\\t'\n case '\"': return '\"'\n default: return c\n }\n })\n }\n\n // Single-quoted: no escape processing, just strip quotes\n if (trimmed.startsWith('\\'') && trimmed.endsWith('\\''))\n return trimmed.slice(1, -1)\n\n return trimmed\n}\n\n/**\n * Parse a YAML `key: value` line, correctly handling colons inside quoted values.\n * Returns [key, value] or null if not a valid KV line.\n */\nexport function yamlParseKV(line: string): [string, string] | null {\n const trimmed = line.trim()\n // Find the first `: ` or `:\\n` or `:$` — the YAML key-value separator\n const colonIdx = trimmed.indexOf(':')\n if (colonIdx === -1)\n return null\n const key = trimmed.slice(0, colonIdx).trim()\n const rawValue = trimmed.slice(colonIdx + 1)\n if (!key)\n return null\n return [key, yamlUnescape(rawValue)]\n}\n"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"yaml.mjs","names":[],"sources":["../../src/core/yaml.ts"],"sourcesContent":["/**\n * Minimal YAML value escaping/unescaping for our hand-rolled parsers.\n *\n * Handles the characters that break naive `:` splitting and quote stripping:\n * colons, quotes, newlines, backslashes.\n */\n\n/** Characters that require double-quoting in YAML values */\nconst NEEDS_QUOTING = /[:\"'\\\\\\n\\r\\t#{}[\\],&*!|>%@`]/\n\n/**\n * Escape a value for safe YAML emission. Always double-quotes if the value\n * contains any special characters; returns unquoted for simple values.\n */\nexport function yamlEscape(value: string): string {\n if (!NEEDS_QUOTING.test(value))\n return value\n // Escape backslashes first, then double quotes, then control chars\n const escaped = value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\t/g, '\\\\t')\n return `\"${escaped}\"`\n}\n\n/**\n * Parse a raw YAML value string back to its actual value.\n * Handles double-quoted (with escapes), single-quoted, and unquoted values.\n */\nexport function yamlUnescape(raw: string): string {\n const trimmed = raw.trim()\n if (!trimmed)\n return ''\n\n // Double-quoted: single-pass escape processing to handle backslashes correctly\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return trimmed.slice(1, -1)\n .replace(/\\\\([\\\\nrt\"])/g, (_, c) => {\n switch (c) {\n case '\\\\': return '\\\\'\n case 'n': return '\\n'\n case 'r': return '\\r'\n case 't': return '\\t'\n case '\"': return '\"'\n default: return c\n }\n })\n }\n\n // Single-quoted: no escape processing, just strip quotes\n if (trimmed.startsWith('\\'') && trimmed.endsWith('\\''))\n return trimmed.slice(1, -1)\n\n return trimmed\n}\n\n/**\n * Parse a YAML `key: value` line, correctly handling colons inside quoted values.\n * Returns [key, value] or null if not a valid KV line.\n */\nexport function yamlParseKV(line: string): [string, string] | null {\n const trimmed = line.trim()\n // Find the first `: ` or `:\\n` or `:$` — the YAML key-value separator\n const colonIdx = trimmed.indexOf(':')\n if (colonIdx === -1)\n return null\n const key = trimmed.slice(0, colonIdx).trim()\n const rawValue = trimmed.slice(colonIdx + 1)\n if (!key)\n return null\n return [key, yamlUnescape(rawValue)]\n}\n"],"mappings":";;;;;;;;CAcA,IAAA,QAAgB,WAAW,KAAuB,IAAA,QAAA,SAAA,KAAA,EAAA,OAAA,QAAA,MAAA,GAAA,GAAA,CAAA,QAAA,kBAAA,GAAA,MAAA;EAChD,QAAK,GAAL;GASA,KAAO,MANS,OACb;;;;;;;GAaH;CACA,IAAI,QAAC,WACI,IAAA,IAAA,QAAA,SAAA,IAAA,EAAA,OAAA,QAAA,MAAA,GAAA,GAAA;CAGT,OAAI;;SAKS,YAAY,MAAA;OACjB,UAAU,KAAO,MAAA;OACjB,WAAU,QAAO,QAAA,IAAA;KACjB,aAAU,IAAO,OAAA;OACjB,MAAS,QAAO,MAAA,GAAA,SAAA,CAAA,MAAA;;KAElB,CAAA,KAAA,OAAA;CAIN,OAAI,CAAA,KAAQ,aAAW,SAAS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/core/config.ts","../../src/agent/prompts/optional/types.ts","../../src/agent/prompts/prompt.ts","../../src/agent/prompts/skill.ts","../../src/agent/types.ts","../../src/agent/clis/types.ts","../../src/agent/clis/index.ts","../../src/agent/detect-imports.ts","../../src/agent/detect.ts","../../src/agent/install.ts","../../src/agent/targets/types.ts","../../src/agent/targets/registry.ts"],"mappings":"UAMiB,cAAA;EACf,MAAA;EACA,MAAA;EACA,WAAA;EACA,QAAA;AAAA;AAAA,UCCe,wBAAA;EACf,OAAA;AAAA;AAAA,UAiCe,YAAA;EACf,OAAA;EACA,IAAA;AAAA;AAAA,KCpCU,YAAA;;cAGC,oBAAA,EAAsB,MAAA,CAAO,YAAA;;cAO7B,mBAAA,EAAqB,YAAA;;iBAGlB,WAAA,CAAY,OAAA,EAAS,YAAA,EAAc,OAAA;;iBAKnC,qBAAA,CAAsB,EAAA,WAAa,GAAA,CAAI,YAAA;EAAgB,KAAA;EAAe,GAAA;AAAA;AAAA,UAarE,uBAAA;EACf,WAAA;EDGA;ECDA,QAAA;;EAEA,OAAA;EApCsB;EAsCtB,SAAA;EAtCsB;EAwCtB,cAAA;EArCW;EAuCX,WAAA;;EAEA,YAAA;EAzCoD;EA2CpD,QAAA;EApC4F;EAsC5F,QAAA;EAtCgC;EAwChC,cAAA;EArCc;EAuCd,YAAA,GAAe,YAAA;;EAEf,QAAA,GAAW,cAAA;EAzCwB;EA2CnC,mBAAA;EA3CiD;EA6CjD,QAAA;EA7CgE;EA+ChE,aAAA;AAAA;;;;;iBAgHc,mBAAA,CAAoB,OAAA,EAAS,YAAA,KAAiB,OAAA,aAAoB,wBAAA;;;;iBAWlE,kBAAA,CAAmB,IAAA,EAAM,uBAAA;EAA4B,OAAA,EAAS,YAAA;AAAA;;;;iBAkE9D,sBAAA,CAAuB,IAAA,EAAM,uBAAA;EAA4B,QAAA,EAAU,YAAA;AAAA,IAAmB,GAAA,CAAI,YAAA;;;;;;;;;iBAkB1F,iBAAA,CAAkB,MAAA,UAAgB,OAAA,GAAU,YAAA;AAAA,UCxQ3C,YAAA;EACf,IAAA;EACA,OAAA;EACA,UAAA
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/core/config.ts","../../src/agent/prompts/optional/types.ts","../../src/agent/prompts/prompt.ts","../../src/agent/prompts/skill.ts","../../src/agent/types.ts","../../src/agent/clis/types.ts","../../src/agent/clis/index.ts","../../src/agent/detect-imports.ts","../../src/agent/detect.ts","../../src/agent/install.ts","../../src/agent/targets/types.ts","../../src/agent/targets/registry.ts"],"mappings":"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"}
|