skilldb 0.1.3 → 0.1.5

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/cli.js CHANGED
@@ -105,8 +105,9 @@ var SkillDBClient = class {
105
105
  /** Validate that the configured API key works. */
106
106
  async validate() {
107
107
  try {
108
- await this.list({ limit: 1 });
109
- return true;
108
+ const url = `${this.baseUrl}/keys/usage`;
109
+ const res = await fetch(url, { headers: this.headers() });
110
+ return res.ok;
110
111
  } catch {
111
112
  return false;
112
113
  }
@@ -433,8 +434,9 @@ function getIntegrationSnippet(ide) {
433
434
  ## SkillDB Skills
434
435
 
435
436
  Local skills are available in \`.skilldb/skills/\`. Use them as reference when working on tasks.
436
- To add more skills: \`npx skilldb add <pack-name>\`
437
- Browse available skills: \`npx skilldb search <query>\`
437
+ Search: \`skilldb search react server components\` (supports multiple words)
438
+ Download a skill: \`skilldb get <pack>/<skill>\` (e.g. \`skilldb get software-skills/code-review\`)
439
+ Download a full pack: \`skilldb add <pack>\`
438
440
  `.trim();
439
441
  return `
440
442
 
@@ -493,9 +495,10 @@ async function initCommand() {
493
495
  console.log(`Added SkillDB snippet to ${pc6.cyan(path3.basename(configFile))}`);
494
496
  }
495
497
  console.log(pc6.green("\nDone! Next steps:"));
496
- console.log(` ${pc6.dim("$")} skilldb login ${pc6.dim("# save your API key")}`);
497
- console.log(` ${pc6.dim("$")} skilldb search testing ${pc6.dim("# find skills")}`);
498
- console.log(` ${pc6.dim("$")} skilldb add <pack> ${pc6.dim("# install a skill pack")}`);
498
+ console.log(` ${pc6.dim("$")} skilldb login ${pc6.dim("# save your API key")}`);
499
+ console.log(` ${pc6.dim("$")} skilldb search react server components ${pc6.dim("# multi-word search")}`);
500
+ console.log(` ${pc6.dim("$")} skilldb get software-skills/code-review ${pc6.dim("# download one skill")}`);
501
+ console.log(` ${pc6.dim("$")} skilldb add game-design-skills ${pc6.dim("# download full pack")}`);
499
502
  }
500
503
 
501
504
  // src/commands/login.ts
@@ -537,7 +540,7 @@ async function loginCommand() {
537
540
 
538
541
  // src/cli.ts
539
542
  var program = new Command();
540
- program.name("skilldb").description("SkillDB CLI \u2014 discover, install, and manage AI agent skills").version("0.1.0");
543
+ program.name("skilldb").description("SkillDB CLI \u2014 discover, install, and manage AI agent skills").version("0.1.5");
541
544
  program.command("init").description("Initialize SkillDB in this project (detect IDE, create .skilldb/)").action(initCommand);
542
545
  program.command("login").description("Save your SkillDB API key").action(loginCommand);
543
546
  program.command("search <query...>").description("Search skills by keyword(s)").option("-c, --category <name>", "Filter by category").option("-l, --limit <n>", "Max results", "20").action((queryParts, options) => {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/commands/search.ts","../src/config.ts","../src/client.ts","../src/commands/list.ts","../src/commands/add.ts","../src/cache.ts","../src/commands/get.ts","../src/commands/info.ts","../src/commands/init.ts","../src/commands/login.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { searchCommand } from './commands/search.js';\nimport { listCommand } from './commands/list.js';\nimport { addCommand } from './commands/add.js';\nimport { getCommand } from './commands/get.js';\nimport { infoCommand } from './commands/info.js';\nimport { initCommand } from './commands/init.js';\nimport { loginCommand } from './commands/login.js';\n\nconst program = new Command();\n\nprogram\n .name('skilldb')\n .description('SkillDB CLI — discover, install, and manage AI agent skills')\n .version('0.1.0');\n\nprogram\n .command('init')\n .description('Initialize SkillDB in this project (detect IDE, create .skilldb/)')\n .action(initCommand);\n\nprogram\n .command('login')\n .description('Save your SkillDB API key')\n .action(loginCommand);\n\nprogram\n .command('search <query...>')\n .description('Search skills by keyword(s)')\n .option('-c, --category <name>', 'Filter by category')\n .option('-l, --limit <n>', 'Max results', '20')\n .action((queryParts: string[], options: { category?: string; limit?: string }) => {\n searchCommand(queryParts.join(' '), options);\n });\n\nprogram\n .command('list')\n .description('List skills, optionally filtered')\n .option('-c, --category <name>', 'Filter by category')\n .option('-p, --pack <name>', 'Filter by pack')\n .option('-l, --limit <n>', 'Max results', '50')\n .action(listCommand);\n\nprogram\n .command('get <id>')\n .description('Download a single skill to .skilldb/skills/ (e.g. \"software-skills/code-review\")')\n .action(getCommand);\n\nprogram\n .command('add <pack>')\n .description('Download an entire skill pack to local .skilldb/skills/ cache')\n .action(addCommand);\n\nprogram\n .command('info <id>')\n .description('Show metadata and preview for a skill (e.g. \"software-skills/code-review\")')\n .action(infoCommand);\n\nprogram.parse();\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\n\nexport async function searchCommand(query: string, options: { category?: string; limit?: string }): Promise<void> {\n const client = new SkillDBClient();\n const limit = options.limit ? parseInt(options.limit) : 20;\n\n try {\n const res = await client.search(query, { category: options.category, limit });\n\n if (res.skills.length === 0) {\n console.log(pc.yellow(`No skills found for \"${query}\"`));\n return;\n }\n\n console.log(pc.bold(`Found ${res.pagination.total} skill${res.pagination.total === 1 ? '' : 's'} for \"${query}\":\\n`));\n\n // Column widths\n const idW = 42;\n const nameW = 28;\n const descW = 44;\n\n console.log(\n pc.dim(\n pad('ID', idW) + pad('SKILL', nameW) + 'DESCRIPTION'\n )\n );\n console.log(pc.dim('─'.repeat(idW + nameW + descW)));\n\n for (const s of res.skills) {\n const id = truncate(s.id.replace('.md', ''), idW - 2);\n const name = truncate(s.title, nameW - 2);\n const desc = truncate(s.description, descW);\n console.log(\n pc.white(pad(id, idW)) + pc.cyan(pad(name, nameW)) + pc.dim(desc)\n );\n }\n\n if (res.pagination.hasMore) {\n console.log(pc.dim(`\\n... and ${res.pagination.total - res.skills.length} more. Use --limit to see more.`));\n }\n\n console.log(pc.dim(`\\nTo download a skill: `) + pc.cyan(`skilldb get <pack>/<skill-name>`));\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n\nfunction pad(str: string, width: number): string {\n return str.length >= width ? str.slice(0, width) : str + ' '.repeat(width - str.length);\n}\n\nfunction truncate(str: string, max: number): string {\n return str.length <= max ? str : str.slice(0, max - 1) + '…';\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nconst RC_FILE = '.skilldbrc';\n\nexport const DEFAULT_BASE_URL = 'https://skilldb.dev/api/v1';\n\ninterface RcConfig {\n apiKey?: string;\n}\n\nfunction readJson(filePath: string): RcConfig | null {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return JSON.parse(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve API key from (in priority order):\n * 1. SKILLDB_API_KEY env var\n * 2. .skilldbrc in project root (cwd)\n * 3. ~/.skilldbrc in home dir\n */\nexport function resolveApiKey(): string | undefined {\n if (process.env.SKILLDB_API_KEY) {\n return process.env.SKILLDB_API_KEY;\n }\n\n const projectRc = path.join(process.cwd(), RC_FILE);\n const projectConfig = readJson(projectRc);\n if (projectConfig?.apiKey) return projectConfig.apiKey;\n\n const homeRc = path.join(os.homedir(), RC_FILE);\n const homeConfig = readJson(homeRc);\n if (homeConfig?.apiKey) return homeConfig.apiKey;\n\n return undefined;\n}\n\n/**\n * Resolve base URL from env or default.\n */\nexport function resolveBaseUrl(): string {\n return process.env.SKILLDB_API_URL || DEFAULT_BASE_URL;\n}\n\n/**\n * Save API key to ~/.skilldbrc (user-wide) or project .skilldbrc.\n */\nexport function saveApiKey(apiKey: string, global = true): string {\n const target = global\n ? path.join(os.homedir(), RC_FILE)\n : path.join(process.cwd(), RC_FILE);\n\n const existing = readJson(target) || {};\n fs.writeFileSync(target, JSON.stringify({ ...existing, apiKey }, null, 2) + '\\n', 'utf-8');\n return target;\n}\n","import type { ClientConfig, Skill, SkillsResponse, SearchOptions } from './types.js';\nimport { resolveApiKey, resolveBaseUrl } from './config.js';\n\nexport class SkillDBClient {\n private apiKey?: string;\n private baseUrl: string;\n\n constructor(config?: ClientConfig) {\n this.apiKey = config?.apiKey ?? resolveApiKey();\n this.baseUrl = config?.baseUrl ?? resolveBaseUrl();\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.apiKey) {\n h['Authorization'] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async request<T>(endpoint: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== '') url.searchParams.set(k, v);\n }\n }\n\n const res = await fetch(url.toString(), { headers: this.headers() });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n const msg = (body as Record<string, string>).error || `HTTP ${res.status}`;\n throw new Error(msg);\n }\n\n return res.json() as Promise<T>;\n }\n\n /** Search skills by keyword. */\n async search(query: string, options?: Omit<SearchOptions, 'search'>): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n search: query,\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n limit: String(options?.limit ?? 20),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** List skills with optional filters. */\n async list(options?: SearchOptions): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n search: options?.search ?? '',\n limit: String(options?.limit ?? 50),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** Get a single skill by ID (e.g. \"software-skills/code-review.md\"). */\n async get(id: string): Promise<Skill> {\n const encoded = encodeURIComponent(id);\n const res = await this.request<Skill | { skill: Skill }>(`/skills/${encoded}`, {\n include_content: 'true',\n });\n // Handle both direct and wrapped responses\n return 'skill' in res ? res.skill : res;\n }\n\n /** Validate that the configured API key works. */\n async validate(): Promise<boolean> {\n try {\n await this.list({ limit: 1 });\n return true;\n } catch {\n return false;\n }\n }\n}\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\n\nexport async function listCommand(options: { category?: string; pack?: string; limit?: string }): Promise<void> {\n const client = new SkillDBClient();\n const limit = options.limit ? parseInt(options.limit) : 50;\n\n try {\n const res = await client.list({ category: options.category, pack: options.pack, limit });\n\n if (res.skills.length === 0) {\n console.log(pc.yellow('No skills found.'));\n return;\n }\n\n // If no filter, show categories overview\n if (!options.category && !options.pack) {\n console.log(pc.bold('Categories:'));\n for (const cat of res.meta.categories) {\n console.log(` ${pc.cyan(cat)}`);\n }\n console.log(`\\n${pc.dim(`${res.meta.totalPacks} packs, ${res.pagination.total} skills total`)}`);\n console.log(pc.dim('Use --category or --pack to filter.\\n'));\n }\n\n // Print skills\n const nameW = 30;\n const packW = 24;\n const catW = 20;\n\n console.log(pc.dim(pad('SKILL', nameW) + pad('PACK', packW) + 'CATEGORY'));\n console.log(pc.dim('─'.repeat(nameW + packW + catW)));\n\n for (const s of res.skills) {\n console.log(\n pc.cyan(pad(truncate(s.title, nameW - 2), nameW)) +\n pc.white(pad(truncate(s.packLabel, packW - 2), packW)) +\n pc.dim(s.category)\n );\n }\n\n if (res.pagination.hasMore) {\n console.log(pc.dim(`\\nShowing ${res.skills.length} of ${res.pagination.total}. Use --limit to see more.`));\n }\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n\nfunction pad(str: string, width: number): string {\n return str.length >= width ? str.slice(0, width) : str + ' '.repeat(width - str.length);\n}\n\nfunction truncate(str: string, max: number): string {\n return str.length <= max ? str : str.slice(0, max - 1) + '…';\n}\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\nimport { initCache, cacheSkill, isCached } from '../cache.js';\n\nexport async function addCommand(packName: string): Promise<void> {\n const client = new SkillDBClient();\n\n console.log(pc.bold(`Adding pack: ${packName}`));\n initCache();\n\n try {\n // Fetch all skills in the pack\n const res = await client.list({ pack: packName, limit: 500, includeContent: true });\n\n if (res.skills.length === 0) {\n console.error(pc.red(`Pack \"${packName}\" not found or empty.`));\n process.exit(1);\n }\n\n let added = 0;\n let skipped = 0;\n\n for (const skill of res.skills) {\n if (isCached(skill.id)) {\n skipped++;\n console.log(pc.dim(` skip ${skill.id} (already cached)`));\n continue;\n }\n\n const filePath = cacheSkill(skill);\n added++;\n console.log(pc.green(` add ${skill.id}`) + pc.dim(` → ${filePath}`));\n }\n\n console.log(\n `\\n${pc.green(`${added} skill${added === 1 ? '' : 's'} added`)}` +\n (skipped > 0 ? pc.dim(`, ${skipped} skipped`) : '')\n );\n\n if (res.skills.some(s => !s.content)) {\n console.log(pc.yellow('\\nNote: Some skills were cached without content (metadata only).'));\n console.log(pc.yellow('Run \"skilldb login\" with a Pro key to download full content.'));\n }\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Manifest, Skill } from './types.js';\n\nconst SKILLDB_DIR = '.skilldb';\nconst SKILLS_DIR = 'skills';\nconst MANIFEST_FILE = 'manifest.json';\n\nfunction ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n}\n\nfunction skilldbRoot(cwd?: string): string {\n return path.join(cwd ?? process.cwd(), SKILLDB_DIR);\n}\n\n/** Ensure .skilldb/ directory structure exists. */\nexport function initCache(cwd?: string): string {\n const root = skilldbRoot(cwd);\n ensureDir(path.join(root, SKILLS_DIR));\n\n const manifestPath = path.join(root, MANIFEST_FILE);\n if (!fs.existsSync(manifestPath)) {\n fs.writeFileSync(manifestPath, JSON.stringify({ installed: {} }, null, 2) + '\\n');\n }\n\n return root;\n}\n\n/** Read the local manifest. */\nexport function readManifest(cwd?: string): Manifest {\n const manifestPath = path.join(skilldbRoot(cwd), MANIFEST_FILE);\n try {\n return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n } catch {\n return { installed: {} };\n }\n}\n\n/** Write the local manifest. */\nexport function writeManifest(manifest: Manifest, cwd?: string): void {\n const root = skilldbRoot(cwd);\n ensureDir(root);\n fs.writeFileSync(\n path.join(root, MANIFEST_FILE),\n JSON.stringify(manifest, null, 2) + '\\n'\n );\n}\n\n/** Save a skill to the local cache. */\nexport function cacheSkill(skill: Skill, cwd?: string): string {\n const root = skilldbRoot(cwd);\n const skillDir = path.join(root, SKILLS_DIR, skill.pack);\n ensureDir(skillDir);\n\n const safeName = skill.name.replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skillDir, `${safeName}.md`);\n fs.writeFileSync(filePath, skill.content ?? `# ${skill.title}\\n\\n${skill.description}\\n`);\n\n // Update manifest\n const manifest = readManifest(cwd);\n manifest.installed[skill.id] = {\n addedAt: new Date().toISOString(),\n lines: skill.lines,\n };\n writeManifest(manifest, cwd);\n\n return filePath;\n}\n\n/** Check if a skill is already cached. */\nexport function isCached(skillId: string, cwd?: string): boolean {\n const manifest = readManifest(cwd);\n return skillId in manifest.installed;\n}\n\n/** Get the local path for a cached skill. */\nexport function getCachedPath(skillId: string, cwd?: string): string | null {\n if (!isCached(skillId, cwd)) return null;\n const [pack, file] = skillId.split('/');\n const name = file.replace('.md', '').replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skilldbRoot(cwd), SKILLS_DIR, pack, `${name}.md`);\n return fs.existsSync(filePath) ? filePath : null;\n}\n\n/** List all cached skills. */\nexport function listCached(cwd?: string): Manifest {\n return readManifest(cwd);\n}\n\n/** Ensure .skilldb/ and .skilldbrc are in .gitignore. */\nexport function updateGitignore(cwd?: string): void {\n const root = cwd ?? process.cwd();\n const gitignorePath = path.join(root, '.gitignore');\n\n const entries = ['.skilldb/', '.skilldbrc'];\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n const toAdd = entries.filter(e => !content.includes(e));\n if (toAdd.length === 0) return;\n\n const suffix = (content && !content.endsWith('\\n') ? '\\n' : '') +\n '\\n# SkillDB\\n' + toAdd.join('\\n') + '\\n';\n\n fs.writeFileSync(gitignorePath, content + suffix);\n}\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\nimport { initCache, cacheSkill, isCached, getCachedPath } from '../cache.js';\n\nexport async function getCommand(id: string): Promise<void> {\n const client = new SkillDBClient();\n\n // Normalize: accept \"pack/skill\" without .md\n if (!id.includes('.md')) {\n id = id + '.md';\n }\n\n // Check if already cached\n if (isCached(id)) {\n const cachedPath = getCachedPath(id);\n console.log(pc.dim(`Already cached: ${cachedPath}`));\n return;\n }\n\n console.log(pc.dim(`Fetching ${id}...`));\n initCache();\n\n try {\n const skill = await client.get(id);\n\n if (!skill.content) {\n console.log(pc.yellow('Skill fetched (metadata only — no content without API key).'));\n console.log(pc.yellow('Run \"skilldb login\" with a Pro key to download full content.'));\n }\n\n const filePath = cacheSkill(skill);\n console.log(pc.green(`✓ Saved ${skill.title}`) + pc.dim(` → ${filePath}`));\n console.log(pc.dim(` ${skill.lines} lines | ${skill.packLabel} | ${skill.category}`));\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\n\nexport async function infoCommand(id: string): Promise<void> {\n const client = new SkillDBClient();\n\n // Normalize: accept \"pack/skill\" without .md\n if (!id.includes('.md')) {\n id = id + '.md';\n }\n\n try {\n const skill = await client.get(id);\n\n console.log(pc.bold(skill.title));\n console.log(pc.dim('─'.repeat(50)));\n console.log(`${pc.cyan('ID:')} ${skill.id}`);\n console.log(`${pc.cyan('Pack:')} ${skill.packLabel} (${skill.pack})`);\n console.log(`${pc.cyan('Category:')} ${skill.category}`);\n console.log(`${pc.cyan('Lines:')} ${skill.lines}`);\n console.log(`${pc.cyan('Description:')} ${skill.description}`);\n\n if (skill.content) {\n console.log(pc.dim('\\n─── Preview ───────────────────────────────────'));\n const preview = skill.content.split('\\n').slice(0, 20).join('\\n');\n console.log(preview);\n if (skill.content.split('\\n').length > 20) {\n console.log(pc.dim(`\\n... ${skill.lines - 20} more lines`));\n }\n }\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\nimport readline from 'node:readline';\nimport { initCache, updateGitignore } from '../cache.js';\n\ntype IDE = 'claude-code' | 'cursor' | 'codex';\n\ninterface Detection {\n ide: IDE;\n label: string;\n configFile: string;\n}\n\nfunction prompt(question: string): Promise<string> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return new Promise(resolve => {\n rl.question(question, answer => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nfunction detectIDE(cwd: string): Detection | null {\n // Claude Code\n if (fs.existsSync(path.join(cwd, 'CLAUDE.md')) || fs.existsSync(path.join(cwd, '.claude'))) {\n return {\n ide: 'claude-code',\n label: 'Claude Code',\n configFile: path.join(cwd, 'CLAUDE.md'),\n };\n }\n\n // Cursor\n if (fs.existsSync(path.join(cwd, '.cursor')) || fs.existsSync(path.join(cwd, '.cursorrules'))) {\n return {\n ide: 'cursor',\n label: 'Cursor',\n configFile: fs.existsSync(path.join(cwd, '.cursorrules'))\n ? path.join(cwd, '.cursorrules')\n : path.join(cwd, '.cursor', 'rules'),\n };\n }\n\n // Codex\n if (fs.existsSync(path.join(cwd, 'codex.md')) || fs.existsSync(path.join(cwd, '.codex'))) {\n return {\n ide: 'codex',\n label: 'Codex CLI',\n configFile: path.join(cwd, 'codex.md'),\n };\n }\n\n return null;\n}\n\nfunction getIntegrationSnippet(ide: IDE): string {\n const marker = '<!-- skilldb:start -->';\n const endMarker = '<!-- skilldb:end -->';\n\n const content = `\n## SkillDB Skills\n\nLocal skills are available in \\`.skilldb/skills/\\`. Use them as reference when working on tasks.\nTo add more skills: \\`npx skilldb add <pack-name>\\`\nBrowse available skills: \\`npx skilldb search <query>\\`\n`.trim();\n\n return `\\n\\n${marker}\\n${content}\\n${endMarker}\\n`;\n}\n\nexport async function initCommand(): Promise<void> {\n const cwd = process.cwd();\n console.log(pc.bold('SkillDB Init\\n'));\n\n // Detect IDE\n let detection = detectIDE(cwd);\n\n if (detection) {\n console.log(`Detected: ${pc.cyan(detection.label)}`);\n } else {\n console.log('No IDE config detected. Which are you using?');\n console.log(' 1) Claude Code');\n console.log(' 2) Cursor');\n console.log(' 3) Codex CLI');\n const choice = await prompt('\\nChoice (1-3): ');\n\n const ideMap: Record<string, IDE> = { '1': 'claude-code', '2': 'cursor', '3': 'codex' };\n const ide = ideMap[choice];\n if (!ide) {\n console.log(pc.red('Invalid choice.'));\n process.exit(1);\n }\n\n const configFiles: Record<IDE, string> = {\n 'claude-code': path.join(cwd, 'CLAUDE.md'),\n 'cursor': path.join(cwd, '.cursorrules'),\n 'codex': path.join(cwd, 'codex.md'),\n };\n\n detection = {\n ide,\n label: ide === 'claude-code' ? 'Claude Code' : ide === 'cursor' ? 'Cursor' : 'Codex CLI',\n configFile: configFiles[ide],\n };\n }\n\n // Create .skilldb/ directory\n const cacheDir = initCache(cwd);\n console.log(`Created ${pc.dim(cacheDir)}`);\n\n // Update .gitignore\n updateGitignore(cwd);\n console.log(`Updated ${pc.dim('.gitignore')}`);\n\n // Write integration snippet\n const snippet = getIntegrationSnippet(detection.ide);\n const configFile = detection.configFile;\n\n let existing = '';\n if (fs.existsSync(configFile)) {\n existing = fs.readFileSync(configFile, 'utf-8');\n }\n\n if (existing.includes('<!-- skilldb:start -->')) {\n console.log(pc.dim(`${path.basename(configFile)} already has SkillDB integration.`));\n } else {\n // Ensure parent dir exists\n const dir = path.dirname(configFile);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(configFile, existing + snippet);\n console.log(`Added SkillDB snippet to ${pc.cyan(path.basename(configFile))}`);\n }\n\n console.log(pc.green('\\nDone! Next steps:'));\n console.log(` ${pc.dim('$')} skilldb login ${pc.dim('# save your API key')}`);\n console.log(` ${pc.dim('$')} skilldb search testing ${pc.dim('# find skills')}`);\n console.log(` ${pc.dim('$')} skilldb add <pack> ${pc.dim('# install a skill pack')}`);\n}\n","import pc from 'picocolors';\nimport { saveApiKey } from '../config.js';\nimport { SkillDBClient } from '../client.js';\nimport readline from 'node:readline';\n\nfunction prompt(question: string): Promise<string> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return new Promise(resolve => {\n rl.question(question, answer => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nexport async function loginCommand(): Promise<void> {\n console.log(pc.bold('SkillDB Login'));\n console.log('Get your API key at https://skilldb.dev/api-access\\n');\n\n const apiKey = await prompt('API key: ');\n\n if (!apiKey) {\n console.log(pc.red('No API key provided.'));\n process.exit(1);\n }\n\n if (!apiKey.startsWith('sk_')) {\n console.log(pc.yellow('Warning: API key should start with \"sk_\". Saving anyway.'));\n }\n\n // Validate the key\n process.stdout.write('Validating... ');\n const client = new SkillDBClient({ apiKey });\n const valid = await client.validate();\n\n if (valid) {\n const savedTo = saveApiKey(apiKey);\n console.log(pc.green('valid!'));\n console.log(`Saved to ${pc.dim(savedTo)}`);\n } else {\n console.log(pc.yellow('could not validate (saved anyway)'));\n const savedTo = saveApiKey(apiKey);\n console.log(`Saved to ${pc.dim(savedTo)}`);\n }\n}\n"],"mappings":"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","names":["pc","pc","pad","truncate","pc","fs","path","path","fs","pc","pc","pc","pc","pc","fs","path","pc","fs","path","pc","pc","readline","prompt","pc"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/search.ts","../src/config.ts","../src/client.ts","../src/commands/list.ts","../src/commands/add.ts","../src/cache.ts","../src/commands/get.ts","../src/commands/info.ts","../src/commands/init.ts","../src/commands/login.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { searchCommand } from './commands/search.js';\nimport { listCommand } from './commands/list.js';\nimport { addCommand } from './commands/add.js';\nimport { getCommand } from './commands/get.js';\nimport { infoCommand } from './commands/info.js';\nimport { initCommand } from './commands/init.js';\nimport { loginCommand } from './commands/login.js';\n\nconst program = new Command();\n\nprogram\n .name('skilldb')\n .description('SkillDB CLI — discover, install, and manage AI agent skills')\n .version('0.1.5');\n\nprogram\n .command('init')\n .description('Initialize SkillDB in this project (detect IDE, create .skilldb/)')\n .action(initCommand);\n\nprogram\n .command('login')\n .description('Save your SkillDB API key')\n .action(loginCommand);\n\nprogram\n .command('search <query...>')\n .description('Search skills by keyword(s)')\n .option('-c, --category <name>', 'Filter by category')\n .option('-l, --limit <n>', 'Max results', '20')\n .action((queryParts: string[], options: { category?: string; limit?: string }) => {\n searchCommand(queryParts.join(' '), options);\n });\n\nprogram\n .command('list')\n .description('List skills, optionally filtered')\n .option('-c, --category <name>', 'Filter by category')\n .option('-p, --pack <name>', 'Filter by pack')\n .option('-l, --limit <n>', 'Max results', '50')\n .action(listCommand);\n\nprogram\n .command('get <id>')\n .description('Download a single skill to .skilldb/skills/ (e.g. \"software-skills/code-review\")')\n .action(getCommand);\n\nprogram\n .command('add <pack>')\n .description('Download an entire skill pack to local .skilldb/skills/ cache')\n .action(addCommand);\n\nprogram\n .command('info <id>')\n .description('Show metadata and preview for a skill (e.g. \"software-skills/code-review\")')\n .action(infoCommand);\n\nprogram.parse();\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\n\nexport async function searchCommand(query: string, options: { category?: string; limit?: string }): Promise<void> {\n const client = new SkillDBClient();\n const limit = options.limit ? parseInt(options.limit) : 20;\n\n try {\n const res = await client.search(query, { category: options.category, limit });\n\n if (res.skills.length === 0) {\n console.log(pc.yellow(`No skills found for \"${query}\"`));\n return;\n }\n\n console.log(pc.bold(`Found ${res.pagination.total} skill${res.pagination.total === 1 ? '' : 's'} for \"${query}\":\\n`));\n\n // Column widths\n const idW = 42;\n const nameW = 28;\n const descW = 44;\n\n console.log(\n pc.dim(\n pad('ID', idW) + pad('SKILL', nameW) + 'DESCRIPTION'\n )\n );\n console.log(pc.dim('─'.repeat(idW + nameW + descW)));\n\n for (const s of res.skills) {\n const id = truncate(s.id.replace('.md', ''), idW - 2);\n const name = truncate(s.title, nameW - 2);\n const desc = truncate(s.description, descW);\n console.log(\n pc.white(pad(id, idW)) + pc.cyan(pad(name, nameW)) + pc.dim(desc)\n );\n }\n\n if (res.pagination.hasMore) {\n console.log(pc.dim(`\\n... and ${res.pagination.total - res.skills.length} more. Use --limit to see more.`));\n }\n\n console.log(pc.dim(`\\nTo download a skill: `) + pc.cyan(`skilldb get <pack>/<skill-name>`));\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n\nfunction pad(str: string, width: number): string {\n return str.length >= width ? str.slice(0, width) : str + ' '.repeat(width - str.length);\n}\n\nfunction truncate(str: string, max: number): string {\n return str.length <= max ? str : str.slice(0, max - 1) + '…';\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nconst RC_FILE = '.skilldbrc';\n\nexport const DEFAULT_BASE_URL = 'https://skilldb.dev/api/v1';\n\ninterface RcConfig {\n apiKey?: string;\n}\n\nfunction readJson(filePath: string): RcConfig | null {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return JSON.parse(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve API key from (in priority order):\n * 1. SKILLDB_API_KEY env var\n * 2. .skilldbrc in project root (cwd)\n * 3. ~/.skilldbrc in home dir\n */\nexport function resolveApiKey(): string | undefined {\n if (process.env.SKILLDB_API_KEY) {\n return process.env.SKILLDB_API_KEY;\n }\n\n const projectRc = path.join(process.cwd(), RC_FILE);\n const projectConfig = readJson(projectRc);\n if (projectConfig?.apiKey) return projectConfig.apiKey;\n\n const homeRc = path.join(os.homedir(), RC_FILE);\n const homeConfig = readJson(homeRc);\n if (homeConfig?.apiKey) return homeConfig.apiKey;\n\n return undefined;\n}\n\n/**\n * Resolve base URL from env or default.\n */\nexport function resolveBaseUrl(): string {\n return process.env.SKILLDB_API_URL || DEFAULT_BASE_URL;\n}\n\n/**\n * Save API key to ~/.skilldbrc (user-wide) or project .skilldbrc.\n */\nexport function saveApiKey(apiKey: string, global = true): string {\n const target = global\n ? path.join(os.homedir(), RC_FILE)\n : path.join(process.cwd(), RC_FILE);\n\n const existing = readJson(target) || {};\n fs.writeFileSync(target, JSON.stringify({ ...existing, apiKey }, null, 2) + '\\n', 'utf-8');\n return target;\n}\n","import type { ClientConfig, Skill, SkillsResponse, SearchOptions } from './types.js';\nimport { resolveApiKey, resolveBaseUrl } from './config.js';\n\nexport class SkillDBClient {\n private apiKey?: string;\n private baseUrl: string;\n\n constructor(config?: ClientConfig) {\n this.apiKey = config?.apiKey ?? resolveApiKey();\n this.baseUrl = config?.baseUrl ?? resolveBaseUrl();\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.apiKey) {\n h['Authorization'] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async request<T>(endpoint: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== '') url.searchParams.set(k, v);\n }\n }\n\n const res = await fetch(url.toString(), { headers: this.headers() });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n const msg = (body as Record<string, string>).error || `HTTP ${res.status}`;\n throw new Error(msg);\n }\n\n return res.json() as Promise<T>;\n }\n\n /** Search skills by keyword. */\n async search(query: string, options?: Omit<SearchOptions, 'search'>): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n search: query,\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n limit: String(options?.limit ?? 20),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** List skills with optional filters. */\n async list(options?: SearchOptions): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n search: options?.search ?? '',\n limit: String(options?.limit ?? 50),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** Get a single skill by ID (e.g. \"software-skills/code-review.md\"). */\n async get(id: string): Promise<Skill> {\n const encoded = encodeURIComponent(id);\n const res = await this.request<Skill | { skill: Skill }>(`/skills/${encoded}`, {\n include_content: 'true',\n });\n // Handle both direct and wrapped responses\n return 'skill' in res ? res.skill : res;\n }\n\n /** Validate that the configured API key works. */\n async validate(): Promise<boolean> {\n try {\n const url = `${this.baseUrl}/keys/usage`;\n const res = await fetch(url, { headers: this.headers() });\n return res.ok;\n } catch {\n // Network error — key might still be valid, just can't reach server\n return false;\n }\n }\n}\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\n\nexport async function listCommand(options: { category?: string; pack?: string; limit?: string }): Promise<void> {\n const client = new SkillDBClient();\n const limit = options.limit ? parseInt(options.limit) : 50;\n\n try {\n const res = await client.list({ category: options.category, pack: options.pack, limit });\n\n if (res.skills.length === 0) {\n console.log(pc.yellow('No skills found.'));\n return;\n }\n\n // If no filter, show categories overview\n if (!options.category && !options.pack) {\n console.log(pc.bold('Categories:'));\n for (const cat of res.meta.categories) {\n console.log(` ${pc.cyan(cat)}`);\n }\n console.log(`\\n${pc.dim(`${res.meta.totalPacks} packs, ${res.pagination.total} skills total`)}`);\n console.log(pc.dim('Use --category or --pack to filter.\\n'));\n }\n\n // Print skills\n const nameW = 30;\n const packW = 24;\n const catW = 20;\n\n console.log(pc.dim(pad('SKILL', nameW) + pad('PACK', packW) + 'CATEGORY'));\n console.log(pc.dim('─'.repeat(nameW + packW + catW)));\n\n for (const s of res.skills) {\n console.log(\n pc.cyan(pad(truncate(s.title, nameW - 2), nameW)) +\n pc.white(pad(truncate(s.packLabel, packW - 2), packW)) +\n pc.dim(s.category)\n );\n }\n\n if (res.pagination.hasMore) {\n console.log(pc.dim(`\\nShowing ${res.skills.length} of ${res.pagination.total}. Use --limit to see more.`));\n }\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n\nfunction pad(str: string, width: number): string {\n return str.length >= width ? str.slice(0, width) : str + ' '.repeat(width - str.length);\n}\n\nfunction truncate(str: string, max: number): string {\n return str.length <= max ? str : str.slice(0, max - 1) + '…';\n}\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\nimport { initCache, cacheSkill, isCached } from '../cache.js';\n\nexport async function addCommand(packName: string): Promise<void> {\n const client = new SkillDBClient();\n\n console.log(pc.bold(`Adding pack: ${packName}`));\n initCache();\n\n try {\n // Fetch all skills in the pack\n const res = await client.list({ pack: packName, limit: 500, includeContent: true });\n\n if (res.skills.length === 0) {\n console.error(pc.red(`Pack \"${packName}\" not found or empty.`));\n process.exit(1);\n }\n\n let added = 0;\n let skipped = 0;\n\n for (const skill of res.skills) {\n if (isCached(skill.id)) {\n skipped++;\n console.log(pc.dim(` skip ${skill.id} (already cached)`));\n continue;\n }\n\n const filePath = cacheSkill(skill);\n added++;\n console.log(pc.green(` add ${skill.id}`) + pc.dim(` → ${filePath}`));\n }\n\n console.log(\n `\\n${pc.green(`${added} skill${added === 1 ? '' : 's'} added`)}` +\n (skipped > 0 ? pc.dim(`, ${skipped} skipped`) : '')\n );\n\n if (res.skills.some(s => !s.content)) {\n console.log(pc.yellow('\\nNote: Some skills were cached without content (metadata only).'));\n console.log(pc.yellow('Run \"skilldb login\" with a Pro key to download full content.'));\n }\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Manifest, Skill } from './types.js';\n\nconst SKILLDB_DIR = '.skilldb';\nconst SKILLS_DIR = 'skills';\nconst MANIFEST_FILE = 'manifest.json';\n\nfunction ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n}\n\nfunction skilldbRoot(cwd?: string): string {\n return path.join(cwd ?? process.cwd(), SKILLDB_DIR);\n}\n\n/** Ensure .skilldb/ directory structure exists. */\nexport function initCache(cwd?: string): string {\n const root = skilldbRoot(cwd);\n ensureDir(path.join(root, SKILLS_DIR));\n\n const manifestPath = path.join(root, MANIFEST_FILE);\n if (!fs.existsSync(manifestPath)) {\n fs.writeFileSync(manifestPath, JSON.stringify({ installed: {} }, null, 2) + '\\n');\n }\n\n return root;\n}\n\n/** Read the local manifest. */\nexport function readManifest(cwd?: string): Manifest {\n const manifestPath = path.join(skilldbRoot(cwd), MANIFEST_FILE);\n try {\n return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n } catch {\n return { installed: {} };\n }\n}\n\n/** Write the local manifest. */\nexport function writeManifest(manifest: Manifest, cwd?: string): void {\n const root = skilldbRoot(cwd);\n ensureDir(root);\n fs.writeFileSync(\n path.join(root, MANIFEST_FILE),\n JSON.stringify(manifest, null, 2) + '\\n'\n );\n}\n\n/** Save a skill to the local cache. */\nexport function cacheSkill(skill: Skill, cwd?: string): string {\n const root = skilldbRoot(cwd);\n const skillDir = path.join(root, SKILLS_DIR, skill.pack);\n ensureDir(skillDir);\n\n const safeName = skill.name.replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skillDir, `${safeName}.md`);\n fs.writeFileSync(filePath, skill.content ?? `# ${skill.title}\\n\\n${skill.description}\\n`);\n\n // Update manifest\n const manifest = readManifest(cwd);\n manifest.installed[skill.id] = {\n addedAt: new Date().toISOString(),\n lines: skill.lines,\n };\n writeManifest(manifest, cwd);\n\n return filePath;\n}\n\n/** Check if a skill is already cached. */\nexport function isCached(skillId: string, cwd?: string): boolean {\n const manifest = readManifest(cwd);\n return skillId in manifest.installed;\n}\n\n/** Get the local path for a cached skill. */\nexport function getCachedPath(skillId: string, cwd?: string): string | null {\n if (!isCached(skillId, cwd)) return null;\n const [pack, file] = skillId.split('/');\n const name = file.replace('.md', '').replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skilldbRoot(cwd), SKILLS_DIR, pack, `${name}.md`);\n return fs.existsSync(filePath) ? filePath : null;\n}\n\n/** List all cached skills. */\nexport function listCached(cwd?: string): Manifest {\n return readManifest(cwd);\n}\n\n/** Ensure .skilldb/ and .skilldbrc are in .gitignore. */\nexport function updateGitignore(cwd?: string): void {\n const root = cwd ?? process.cwd();\n const gitignorePath = path.join(root, '.gitignore');\n\n const entries = ['.skilldb/', '.skilldbrc'];\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n const toAdd = entries.filter(e => !content.includes(e));\n if (toAdd.length === 0) return;\n\n const suffix = (content && !content.endsWith('\\n') ? '\\n' : '') +\n '\\n# SkillDB\\n' + toAdd.join('\\n') + '\\n';\n\n fs.writeFileSync(gitignorePath, content + suffix);\n}\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\nimport { initCache, cacheSkill, isCached, getCachedPath } from '../cache.js';\n\nexport async function getCommand(id: string): Promise<void> {\n const client = new SkillDBClient();\n\n // Normalize: accept \"pack/skill\" without .md\n if (!id.includes('.md')) {\n id = id + '.md';\n }\n\n // Check if already cached\n if (isCached(id)) {\n const cachedPath = getCachedPath(id);\n console.log(pc.dim(`Already cached: ${cachedPath}`));\n return;\n }\n\n console.log(pc.dim(`Fetching ${id}...`));\n initCache();\n\n try {\n const skill = await client.get(id);\n\n if (!skill.content) {\n console.log(pc.yellow('Skill fetched (metadata only — no content without API key).'));\n console.log(pc.yellow('Run \"skilldb login\" with a Pro key to download full content.'));\n }\n\n const filePath = cacheSkill(skill);\n console.log(pc.green(`✓ Saved ${skill.title}`) + pc.dim(` → ${filePath}`));\n console.log(pc.dim(` ${skill.lines} lines | ${skill.packLabel} | ${skill.category}`));\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n","import pc from 'picocolors';\nimport { SkillDBClient } from '../client.js';\n\nexport async function infoCommand(id: string): Promise<void> {\n const client = new SkillDBClient();\n\n // Normalize: accept \"pack/skill\" without .md\n if (!id.includes('.md')) {\n id = id + '.md';\n }\n\n try {\n const skill = await client.get(id);\n\n console.log(pc.bold(skill.title));\n console.log(pc.dim('─'.repeat(50)));\n console.log(`${pc.cyan('ID:')} ${skill.id}`);\n console.log(`${pc.cyan('Pack:')} ${skill.packLabel} (${skill.pack})`);\n console.log(`${pc.cyan('Category:')} ${skill.category}`);\n console.log(`${pc.cyan('Lines:')} ${skill.lines}`);\n console.log(`${pc.cyan('Description:')} ${skill.description}`);\n\n if (skill.content) {\n console.log(pc.dim('\\n─── Preview ───────────────────────────────────'));\n const preview = skill.content.split('\\n').slice(0, 20).join('\\n');\n console.log(preview);\n if (skill.content.split('\\n').length > 20) {\n console.log(pc.dim(`\\n... ${skill.lines - 20} more lines`));\n }\n }\n } catch (err) {\n console.error(pc.red(`Error: ${(err as Error).message}`));\n process.exit(1);\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\nimport readline from 'node:readline';\nimport { initCache, updateGitignore } from '../cache.js';\n\ntype IDE = 'claude-code' | 'cursor' | 'codex';\n\ninterface Detection {\n ide: IDE;\n label: string;\n configFile: string;\n}\n\nfunction prompt(question: string): Promise<string> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return new Promise(resolve => {\n rl.question(question, answer => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nfunction detectIDE(cwd: string): Detection | null {\n // Claude Code\n if (fs.existsSync(path.join(cwd, 'CLAUDE.md')) || fs.existsSync(path.join(cwd, '.claude'))) {\n return {\n ide: 'claude-code',\n label: 'Claude Code',\n configFile: path.join(cwd, 'CLAUDE.md'),\n };\n }\n\n // Cursor\n if (fs.existsSync(path.join(cwd, '.cursor')) || fs.existsSync(path.join(cwd, '.cursorrules'))) {\n return {\n ide: 'cursor',\n label: 'Cursor',\n configFile: fs.existsSync(path.join(cwd, '.cursorrules'))\n ? path.join(cwd, '.cursorrules')\n : path.join(cwd, '.cursor', 'rules'),\n };\n }\n\n // Codex\n if (fs.existsSync(path.join(cwd, 'codex.md')) || fs.existsSync(path.join(cwd, '.codex'))) {\n return {\n ide: 'codex',\n label: 'Codex CLI',\n configFile: path.join(cwd, 'codex.md'),\n };\n }\n\n return null;\n}\n\nfunction getIntegrationSnippet(ide: IDE): string {\n const marker = '<!-- skilldb:start -->';\n const endMarker = '<!-- skilldb:end -->';\n\n const content = `\n## SkillDB Skills\n\nLocal skills are available in \\`.skilldb/skills/\\`. Use them as reference when working on tasks.\nSearch: \\`skilldb search react server components\\` (supports multiple words)\nDownload a skill: \\`skilldb get <pack>/<skill>\\` (e.g. \\`skilldb get software-skills/code-review\\`)\nDownload a full pack: \\`skilldb add <pack>\\`\n`.trim();\n\n return `\\n\\n${marker}\\n${content}\\n${endMarker}\\n`;\n}\n\nexport async function initCommand(): Promise<void> {\n const cwd = process.cwd();\n console.log(pc.bold('SkillDB Init\\n'));\n\n // Detect IDE\n let detection = detectIDE(cwd);\n\n if (detection) {\n console.log(`Detected: ${pc.cyan(detection.label)}`);\n } else {\n console.log('No IDE config detected. Which are you using?');\n console.log(' 1) Claude Code');\n console.log(' 2) Cursor');\n console.log(' 3) Codex CLI');\n const choice = await prompt('\\nChoice (1-3): ');\n\n const ideMap: Record<string, IDE> = { '1': 'claude-code', '2': 'cursor', '3': 'codex' };\n const ide = ideMap[choice];\n if (!ide) {\n console.log(pc.red('Invalid choice.'));\n process.exit(1);\n }\n\n const configFiles: Record<IDE, string> = {\n 'claude-code': path.join(cwd, 'CLAUDE.md'),\n 'cursor': path.join(cwd, '.cursorrules'),\n 'codex': path.join(cwd, 'codex.md'),\n };\n\n detection = {\n ide,\n label: ide === 'claude-code' ? 'Claude Code' : ide === 'cursor' ? 'Cursor' : 'Codex CLI',\n configFile: configFiles[ide],\n };\n }\n\n // Create .skilldb/ directory\n const cacheDir = initCache(cwd);\n console.log(`Created ${pc.dim(cacheDir)}`);\n\n // Update .gitignore\n updateGitignore(cwd);\n console.log(`Updated ${pc.dim('.gitignore')}`);\n\n // Write integration snippet\n const snippet = getIntegrationSnippet(detection.ide);\n const configFile = detection.configFile;\n\n let existing = '';\n if (fs.existsSync(configFile)) {\n existing = fs.readFileSync(configFile, 'utf-8');\n }\n\n if (existing.includes('<!-- skilldb:start -->')) {\n console.log(pc.dim(`${path.basename(configFile)} already has SkillDB integration.`));\n } else {\n // Ensure parent dir exists\n const dir = path.dirname(configFile);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(configFile, existing + snippet);\n console.log(`Added SkillDB snippet to ${pc.cyan(path.basename(configFile))}`);\n }\n\n console.log(pc.green('\\nDone! Next steps:'));\n console.log(` ${pc.dim('$')} skilldb login ${pc.dim('# save your API key')}`);\n console.log(` ${pc.dim('$')} skilldb search react server components ${pc.dim('# multi-word search')}`);\n console.log(` ${pc.dim('$')} skilldb get software-skills/code-review ${pc.dim('# download one skill')}`);\n console.log(` ${pc.dim('$')} skilldb add game-design-skills ${pc.dim('# download full pack')}`);\n}\n","import pc from 'picocolors';\nimport { saveApiKey } from '../config.js';\nimport { SkillDBClient } from '../client.js';\nimport readline from 'node:readline';\n\nfunction prompt(question: string): Promise<string> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return new Promise(resolve => {\n rl.question(question, answer => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nexport async function loginCommand(): Promise<void> {\n console.log(pc.bold('SkillDB Login'));\n console.log('Get your API key at https://skilldb.dev/api-access\\n');\n\n const apiKey = await prompt('API key: ');\n\n if (!apiKey) {\n console.log(pc.red('No API key provided.'));\n process.exit(1);\n }\n\n if (!apiKey.startsWith('sk_')) {\n console.log(pc.yellow('Warning: API key should start with \"sk_\". Saving anyway.'));\n }\n\n // Validate the key\n process.stdout.write('Validating... ');\n const client = new SkillDBClient({ apiKey });\n const valid = await client.validate();\n\n if (valid) {\n const savedTo = saveApiKey(apiKey);\n console.log(pc.green('valid!'));\n console.log(`Saved to ${pc.dim(savedTo)}`);\n } else {\n console.log(pc.yellow('could not validate (saved anyway)'));\n const savedTo = saveApiKey(apiKey);\n console.log(`Saved to ${pc.dim(savedTo)}`);\n }\n}\n"],"mappings":"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","names":["pc","pc","pad","truncate","pc","fs","path","path","fs","pc","pc","pc","pc","pc","fs","path","pc","fs","path","pc","pc","readline","prompt","pc"]}
package/dist/index.cjs CHANGED
@@ -142,8 +142,9 @@ var SkillDBClient = class {
142
142
  /** Validate that the configured API key works. */
143
143
  async validate() {
144
144
  try {
145
- await this.list({ limit: 1 });
146
- return true;
145
+ const url = `${this.baseUrl}/keys/usage`;
146
+ const res = await fetch(url, { headers: this.headers() });
147
+ return res.ok;
147
148
  } catch {
148
149
  return false;
149
150
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/client.ts","../src/cache.ts"],"sourcesContent":["export { SkillDBClient } from './client.js';\nexport type {\n Skill,\n PackInfo,\n CategoryInfo,\n SkillsResponse,\n SearchOptions,\n ClientConfig,\n Manifest,\n} from './types.js';\nexport { resolveApiKey, resolveBaseUrl, saveApiKey } from './config.js';\nexport { initCache, cacheSkill, isCached, getCachedPath, listCached } from './cache.js';\n\nimport type { ClientConfig } from './types.js';\nimport { SkillDBClient } from './client.js';\n\n/** Create a SkillDB client. Auto-loads API key from env/config. */\nexport function createClient(config?: ClientConfig): SkillDBClient {\n return new SkillDBClient(config);\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nconst RC_FILE = '.skilldbrc';\n\nexport const DEFAULT_BASE_URL = 'https://skilldb.dev/api/v1';\n\ninterface RcConfig {\n apiKey?: string;\n}\n\nfunction readJson(filePath: string): RcConfig | null {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return JSON.parse(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve API key from (in priority order):\n * 1. SKILLDB_API_KEY env var\n * 2. .skilldbrc in project root (cwd)\n * 3. ~/.skilldbrc in home dir\n */\nexport function resolveApiKey(): string | undefined {\n if (process.env.SKILLDB_API_KEY) {\n return process.env.SKILLDB_API_KEY;\n }\n\n const projectRc = path.join(process.cwd(), RC_FILE);\n const projectConfig = readJson(projectRc);\n if (projectConfig?.apiKey) return projectConfig.apiKey;\n\n const homeRc = path.join(os.homedir(), RC_FILE);\n const homeConfig = readJson(homeRc);\n if (homeConfig?.apiKey) return homeConfig.apiKey;\n\n return undefined;\n}\n\n/**\n * Resolve base URL from env or default.\n */\nexport function resolveBaseUrl(): string {\n return process.env.SKILLDB_API_URL || DEFAULT_BASE_URL;\n}\n\n/**\n * Save API key to ~/.skilldbrc (user-wide) or project .skilldbrc.\n */\nexport function saveApiKey(apiKey: string, global = true): string {\n const target = global\n ? path.join(os.homedir(), RC_FILE)\n : path.join(process.cwd(), RC_FILE);\n\n const existing = readJson(target) || {};\n fs.writeFileSync(target, JSON.stringify({ ...existing, apiKey }, null, 2) + '\\n', 'utf-8');\n return target;\n}\n","import type { ClientConfig, Skill, SkillsResponse, SearchOptions } from './types.js';\nimport { resolveApiKey, resolveBaseUrl } from './config.js';\n\nexport class SkillDBClient {\n private apiKey?: string;\n private baseUrl: string;\n\n constructor(config?: ClientConfig) {\n this.apiKey = config?.apiKey ?? resolveApiKey();\n this.baseUrl = config?.baseUrl ?? resolveBaseUrl();\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.apiKey) {\n h['Authorization'] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async request<T>(endpoint: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== '') url.searchParams.set(k, v);\n }\n }\n\n const res = await fetch(url.toString(), { headers: this.headers() });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n const msg = (body as Record<string, string>).error || `HTTP ${res.status}`;\n throw new Error(msg);\n }\n\n return res.json() as Promise<T>;\n }\n\n /** Search skills by keyword. */\n async search(query: string, options?: Omit<SearchOptions, 'search'>): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n search: query,\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n limit: String(options?.limit ?? 20),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** List skills with optional filters. */\n async list(options?: SearchOptions): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n search: options?.search ?? '',\n limit: String(options?.limit ?? 50),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** Get a single skill by ID (e.g. \"software-skills/code-review.md\"). */\n async get(id: string): Promise<Skill> {\n const encoded = encodeURIComponent(id);\n const res = await this.request<Skill | { skill: Skill }>(`/skills/${encoded}`, {\n include_content: 'true',\n });\n // Handle both direct and wrapped responses\n return 'skill' in res ? res.skill : res;\n }\n\n /** Validate that the configured API key works. */\n async validate(): Promise<boolean> {\n try {\n await this.list({ limit: 1 });\n return true;\n } catch {\n return false;\n }\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Manifest, Skill } from './types.js';\n\nconst SKILLDB_DIR = '.skilldb';\nconst SKILLS_DIR = 'skills';\nconst MANIFEST_FILE = 'manifest.json';\n\nfunction ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n}\n\nfunction skilldbRoot(cwd?: string): string {\n return path.join(cwd ?? process.cwd(), SKILLDB_DIR);\n}\n\n/** Ensure .skilldb/ directory structure exists. */\nexport function initCache(cwd?: string): string {\n const root = skilldbRoot(cwd);\n ensureDir(path.join(root, SKILLS_DIR));\n\n const manifestPath = path.join(root, MANIFEST_FILE);\n if (!fs.existsSync(manifestPath)) {\n fs.writeFileSync(manifestPath, JSON.stringify({ installed: {} }, null, 2) + '\\n');\n }\n\n return root;\n}\n\n/** Read the local manifest. */\nexport function readManifest(cwd?: string): Manifest {\n const manifestPath = path.join(skilldbRoot(cwd), MANIFEST_FILE);\n try {\n return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n } catch {\n return { installed: {} };\n }\n}\n\n/** Write the local manifest. */\nexport function writeManifest(manifest: Manifest, cwd?: string): void {\n const root = skilldbRoot(cwd);\n ensureDir(root);\n fs.writeFileSync(\n path.join(root, MANIFEST_FILE),\n JSON.stringify(manifest, null, 2) + '\\n'\n );\n}\n\n/** Save a skill to the local cache. */\nexport function cacheSkill(skill: Skill, cwd?: string): string {\n const root = skilldbRoot(cwd);\n const skillDir = path.join(root, SKILLS_DIR, skill.pack);\n ensureDir(skillDir);\n\n const safeName = skill.name.replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skillDir, `${safeName}.md`);\n fs.writeFileSync(filePath, skill.content ?? `# ${skill.title}\\n\\n${skill.description}\\n`);\n\n // Update manifest\n const manifest = readManifest(cwd);\n manifest.installed[skill.id] = {\n addedAt: new Date().toISOString(),\n lines: skill.lines,\n };\n writeManifest(manifest, cwd);\n\n return filePath;\n}\n\n/** Check if a skill is already cached. */\nexport function isCached(skillId: string, cwd?: string): boolean {\n const manifest = readManifest(cwd);\n return skillId in manifest.installed;\n}\n\n/** Get the local path for a cached skill. */\nexport function getCachedPath(skillId: string, cwd?: string): string | null {\n if (!isCached(skillId, cwd)) return null;\n const [pack, file] = skillId.split('/');\n const name = file.replace('.md', '').replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skilldbRoot(cwd), SKILLS_DIR, pack, `${name}.md`);\n return fs.existsSync(filePath) ? filePath : null;\n}\n\n/** List all cached skills. */\nexport function listCached(cwd?: string): Manifest {\n return readManifest(cwd);\n}\n\n/** Ensure .skilldb/ and .skilldbrc are in .gitignore. */\nexport function updateGitignore(cwd?: string): void {\n const root = cwd ?? process.cwd();\n const gitignorePath = path.join(root, '.gitignore');\n\n const entries = ['.skilldb/', '.skilldbrc'];\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n const toAdd = entries.filter(e => !content.includes(e));\n if (toAdd.length === 0) return;\n\n const suffix = (content && !content.endsWith('\\n') ? '\\n' : '') +\n '\\n# SkillDB\\n' + toAdd.join('\\n') + '\\n';\n\n fs.writeFileSync(gitignorePath, content + suffix);\n}\n"],"mappings":"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","names":["fs","path","os","import_node_fs","import_node_path","fs","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/client.ts","../src/cache.ts"],"sourcesContent":["export { SkillDBClient } from './client.js';\nexport type {\n Skill,\n PackInfo,\n CategoryInfo,\n SkillsResponse,\n SearchOptions,\n ClientConfig,\n Manifest,\n} from './types.js';\nexport { resolveApiKey, resolveBaseUrl, saveApiKey } from './config.js';\nexport { initCache, cacheSkill, isCached, getCachedPath, listCached } from './cache.js';\n\nimport type { ClientConfig } from './types.js';\nimport { SkillDBClient } from './client.js';\n\n/** Create a SkillDB client. Auto-loads API key from env/config. */\nexport function createClient(config?: ClientConfig): SkillDBClient {\n return new SkillDBClient(config);\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nconst RC_FILE = '.skilldbrc';\n\nexport const DEFAULT_BASE_URL = 'https://skilldb.dev/api/v1';\n\ninterface RcConfig {\n apiKey?: string;\n}\n\nfunction readJson(filePath: string): RcConfig | null {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return JSON.parse(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve API key from (in priority order):\n * 1. SKILLDB_API_KEY env var\n * 2. .skilldbrc in project root (cwd)\n * 3. ~/.skilldbrc in home dir\n */\nexport function resolveApiKey(): string | undefined {\n if (process.env.SKILLDB_API_KEY) {\n return process.env.SKILLDB_API_KEY;\n }\n\n const projectRc = path.join(process.cwd(), RC_FILE);\n const projectConfig = readJson(projectRc);\n if (projectConfig?.apiKey) return projectConfig.apiKey;\n\n const homeRc = path.join(os.homedir(), RC_FILE);\n const homeConfig = readJson(homeRc);\n if (homeConfig?.apiKey) return homeConfig.apiKey;\n\n return undefined;\n}\n\n/**\n * Resolve base URL from env or default.\n */\nexport function resolveBaseUrl(): string {\n return process.env.SKILLDB_API_URL || DEFAULT_BASE_URL;\n}\n\n/**\n * Save API key to ~/.skilldbrc (user-wide) or project .skilldbrc.\n */\nexport function saveApiKey(apiKey: string, global = true): string {\n const target = global\n ? path.join(os.homedir(), RC_FILE)\n : path.join(process.cwd(), RC_FILE);\n\n const existing = readJson(target) || {};\n fs.writeFileSync(target, JSON.stringify({ ...existing, apiKey }, null, 2) + '\\n', 'utf-8');\n return target;\n}\n","import type { ClientConfig, Skill, SkillsResponse, SearchOptions } from './types.js';\nimport { resolveApiKey, resolveBaseUrl } from './config.js';\n\nexport class SkillDBClient {\n private apiKey?: string;\n private baseUrl: string;\n\n constructor(config?: ClientConfig) {\n this.apiKey = config?.apiKey ?? resolveApiKey();\n this.baseUrl = config?.baseUrl ?? resolveBaseUrl();\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.apiKey) {\n h['Authorization'] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async request<T>(endpoint: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== '') url.searchParams.set(k, v);\n }\n }\n\n const res = await fetch(url.toString(), { headers: this.headers() });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n const msg = (body as Record<string, string>).error || `HTTP ${res.status}`;\n throw new Error(msg);\n }\n\n return res.json() as Promise<T>;\n }\n\n /** Search skills by keyword. */\n async search(query: string, options?: Omit<SearchOptions, 'search'>): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n search: query,\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n limit: String(options?.limit ?? 20),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** List skills with optional filters. */\n async list(options?: SearchOptions): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n search: options?.search ?? '',\n limit: String(options?.limit ?? 50),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** Get a single skill by ID (e.g. \"software-skills/code-review.md\"). */\n async get(id: string): Promise<Skill> {\n const encoded = encodeURIComponent(id);\n const res = await this.request<Skill | { skill: Skill }>(`/skills/${encoded}`, {\n include_content: 'true',\n });\n // Handle both direct and wrapped responses\n return 'skill' in res ? res.skill : res;\n }\n\n /** Validate that the configured API key works. */\n async validate(): Promise<boolean> {\n try {\n const url = `${this.baseUrl}/keys/usage`;\n const res = await fetch(url, { headers: this.headers() });\n return res.ok;\n } catch {\n // Network error — key might still be valid, just can't reach server\n return false;\n }\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Manifest, Skill } from './types.js';\n\nconst SKILLDB_DIR = '.skilldb';\nconst SKILLS_DIR = 'skills';\nconst MANIFEST_FILE = 'manifest.json';\n\nfunction ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n}\n\nfunction skilldbRoot(cwd?: string): string {\n return path.join(cwd ?? process.cwd(), SKILLDB_DIR);\n}\n\n/** Ensure .skilldb/ directory structure exists. */\nexport function initCache(cwd?: string): string {\n const root = skilldbRoot(cwd);\n ensureDir(path.join(root, SKILLS_DIR));\n\n const manifestPath = path.join(root, MANIFEST_FILE);\n if (!fs.existsSync(manifestPath)) {\n fs.writeFileSync(manifestPath, JSON.stringify({ installed: {} }, null, 2) + '\\n');\n }\n\n return root;\n}\n\n/** Read the local manifest. */\nexport function readManifest(cwd?: string): Manifest {\n const manifestPath = path.join(skilldbRoot(cwd), MANIFEST_FILE);\n try {\n return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n } catch {\n return { installed: {} };\n }\n}\n\n/** Write the local manifest. */\nexport function writeManifest(manifest: Manifest, cwd?: string): void {\n const root = skilldbRoot(cwd);\n ensureDir(root);\n fs.writeFileSync(\n path.join(root, MANIFEST_FILE),\n JSON.stringify(manifest, null, 2) + '\\n'\n );\n}\n\n/** Save a skill to the local cache. */\nexport function cacheSkill(skill: Skill, cwd?: string): string {\n const root = skilldbRoot(cwd);\n const skillDir = path.join(root, SKILLS_DIR, skill.pack);\n ensureDir(skillDir);\n\n const safeName = skill.name.replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skillDir, `${safeName}.md`);\n fs.writeFileSync(filePath, skill.content ?? `# ${skill.title}\\n\\n${skill.description}\\n`);\n\n // Update manifest\n const manifest = readManifest(cwd);\n manifest.installed[skill.id] = {\n addedAt: new Date().toISOString(),\n lines: skill.lines,\n };\n writeManifest(manifest, cwd);\n\n return filePath;\n}\n\n/** Check if a skill is already cached. */\nexport function isCached(skillId: string, cwd?: string): boolean {\n const manifest = readManifest(cwd);\n return skillId in manifest.installed;\n}\n\n/** Get the local path for a cached skill. */\nexport function getCachedPath(skillId: string, cwd?: string): string | null {\n if (!isCached(skillId, cwd)) return null;\n const [pack, file] = skillId.split('/');\n const name = file.replace('.md', '').replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skilldbRoot(cwd), SKILLS_DIR, pack, `${name}.md`);\n return fs.existsSync(filePath) ? filePath : null;\n}\n\n/** List all cached skills. */\nexport function listCached(cwd?: string): Manifest {\n return readManifest(cwd);\n}\n\n/** Ensure .skilldb/ and .skilldbrc are in .gitignore. */\nexport function updateGitignore(cwd?: string): void {\n const root = cwd ?? process.cwd();\n const gitignorePath = path.join(root, '.gitignore');\n\n const entries = ['.skilldb/', '.skilldbrc'];\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n const toAdd = entries.filter(e => !content.includes(e));\n if (toAdd.length === 0) return;\n\n const suffix = (content && !content.endsWith('\\n') ? '\\n' : '') +\n '\\n# SkillDB\\n' + toAdd.join('\\n') + '\\n';\n\n fs.writeFileSync(gitignorePath, content + suffix);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,qBAAe;AACf,uBAAiB;AACjB,qBAAe;AAEf,IAAM,UAAU;AAET,IAAM,mBAAmB;AAMhC,SAAS,SAAS,UAAmC;AACnD,MAAI;AACF,UAAM,MAAM,eAAAA,QAAG,aAAa,UAAU,OAAO;AAC7C,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQO,SAAS,gBAAoC;AAClD,MAAI,QAAQ,IAAI,iBAAiB;AAC/B,WAAO,QAAQ,IAAI;AAAA,EACrB;AAEA,QAAM,YAAY,iBAAAC,QAAK,KAAK,QAAQ,IAAI,GAAG,OAAO;AAClD,QAAM,gBAAgB,SAAS,SAAS;AACxC,MAAI,eAAe,OAAQ,QAAO,cAAc;AAEhD,QAAM,SAAS,iBAAAA,QAAK,KAAK,eAAAC,QAAG,QAAQ,GAAG,OAAO;AAC9C,QAAM,aAAa,SAAS,MAAM;AAClC,MAAI,YAAY,OAAQ,QAAO,WAAW;AAE1C,SAAO;AACT;AAKO,SAAS,iBAAyB;AACvC,SAAO,QAAQ,IAAI,mBAAmB;AACxC;AAKO,SAAS,WAAW,QAAgB,SAAS,MAAc;AAChE,QAAM,SAAS,SACX,iBAAAD,QAAK,KAAK,eAAAC,QAAG,QAAQ,GAAG,OAAO,IAC/B,iBAAAD,QAAK,KAAK,QAAQ,IAAI,GAAG,OAAO;AAEpC,QAAM,WAAW,SAAS,MAAM,KAAK,CAAC;AACtC,iBAAAD,QAAG,cAAc,QAAQ,KAAK,UAAU,EAAE,GAAG,UAAU,OAAO,GAAG,MAAM,CAAC,IAAI,MAAM,OAAO;AACzF,SAAO;AACT;;;AC1DO,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EACA;AAAA,EAER,YAAY,QAAuB;AACjC,SAAK,SAAS,QAAQ,UAAU,cAAc;AAC9C,SAAK,UAAU,QAAQ,WAAW,eAAe;AAAA,EACnD;AAAA,EAEQ,UAAkC;AACxC,UAAM,IAA4B,EAAE,gBAAgB,mBAAmB;AACvE,QAAI,KAAK,QAAQ;AACf,QAAE,eAAe,IAAI,UAAU,KAAK,MAAM;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,QAAW,UAAkB,QAA6C;AACtF,UAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,GAAG,QAAQ,EAAE;AAChD,QAAI,QAAQ;AACV,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,YAAI,MAAM,UAAa,MAAM,GAAI,KAAI,aAAa,IAAI,GAAG,CAAC;AAAA,MAC5D;AAAA,IACF;AAEA,UAAM,MAAM,MAAM,MAAM,IAAI,SAAS,GAAG,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC;AAEnE,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,YAAM,MAAO,KAAgC,SAAS,QAAQ,IAAI,MAAM;AACxE,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,OAAO,OAAe,SAAkE;AAC5F,WAAO,KAAK,QAAwB,WAAW;AAAA,MAC7C,QAAQ;AAAA,MACR,UAAU,SAAS,YAAY;AAAA,MAC/B,MAAM,SAAS,QAAQ;AAAA,MACvB,OAAO,OAAO,SAAS,SAAS,EAAE;AAAA,MAClC,QAAQ,OAAO,SAAS,UAAU,CAAC;AAAA,MACnC,iBAAiB,SAAS,iBAAiB,SAAS;AAAA,IACtD,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,KAAK,SAAkD;AAC3D,WAAO,KAAK,QAAwB,WAAW;AAAA,MAC7C,UAAU,SAAS,YAAY;AAAA,MAC/B,MAAM,SAAS,QAAQ;AAAA,MACvB,QAAQ,SAAS,UAAU;AAAA,MAC3B,OAAO,OAAO,SAAS,SAAS,EAAE;AAAA,MAClC,QAAQ,OAAO,SAAS,UAAU,CAAC;AAAA,MACnC,iBAAiB,SAAS,iBAAiB,SAAS;AAAA,IACtD,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,IAAI,IAA4B;AACpC,UAAM,UAAU,mBAAmB,EAAE;AACrC,UAAM,MAAM,MAAM,KAAK,QAAkC,WAAW,OAAO,IAAI;AAAA,MAC7E,iBAAiB;AAAA,IACnB,CAAC;AAED,WAAO,WAAW,MAAM,IAAI,QAAQ;AAAA,EACtC;AAAA;AAAA,EAGA,MAAM,WAA6B;AACjC,QAAI;AACF,YAAM,MAAM,GAAG,KAAK,OAAO;AAC3B,YAAM,MAAM,MAAM,MAAM,KAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC;AACxD,aAAO,IAAI;AAAA,IACb,QAAQ;AAEN,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACpFA,IAAAG,kBAAe;AACf,IAAAC,oBAAiB;AAGjB,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,gBAAgB;AAEtB,SAAS,UAAU,KAAmB;AACpC,MAAI,CAAC,gBAAAC,QAAG,WAAW,GAAG,GAAG;AACvB,oBAAAA,QAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AACF;AAEA,SAAS,YAAY,KAAsB;AACzC,SAAO,kBAAAC,QAAK,KAAK,OAAO,QAAQ,IAAI,GAAG,WAAW;AACpD;AAGO,SAAS,UAAU,KAAsB;AAC9C,QAAM,OAAO,YAAY,GAAG;AAC5B,YAAU,kBAAAA,QAAK,KAAK,MAAM,UAAU,CAAC;AAErC,QAAM,eAAe,kBAAAA,QAAK,KAAK,MAAM,aAAa;AAClD,MAAI,CAAC,gBAAAD,QAAG,WAAW,YAAY,GAAG;AAChC,oBAAAA,QAAG,cAAc,cAAc,KAAK,UAAU,EAAE,WAAW,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,IAAI;AAAA,EAClF;AAEA,SAAO;AACT;AAGO,SAAS,aAAa,KAAwB;AACnD,QAAM,eAAe,kBAAAC,QAAK,KAAK,YAAY,GAAG,GAAG,aAAa;AAC9D,MAAI;AACF,WAAO,KAAK,MAAM,gBAAAD,QAAG,aAAa,cAAc,OAAO,CAAC;AAAA,EAC1D,QAAQ;AACN,WAAO,EAAE,WAAW,CAAC,EAAE;AAAA,EACzB;AACF;AAGO,SAAS,cAAc,UAAoB,KAAoB;AACpE,QAAM,OAAO,YAAY,GAAG;AAC5B,YAAU,IAAI;AACd,kBAAAA,QAAG;AAAA,IACD,kBAAAC,QAAK,KAAK,MAAM,aAAa;AAAA,IAC7B,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI;AAAA,EACtC;AACF;AAGO,SAAS,WAAW,OAAc,KAAsB;AAC7D,QAAM,OAAO,YAAY,GAAG;AAC5B,QAAM,WAAW,kBAAAA,QAAK,KAAK,MAAM,YAAY,MAAM,IAAI;AACvD,YAAU,QAAQ;AAElB,QAAM,WAAW,MAAM,KAAK,QAAQ,iBAAiB,GAAG;AACxD,QAAM,WAAW,kBAAAA,QAAK,KAAK,UAAU,GAAG,QAAQ,KAAK;AACrD,kBAAAD,QAAG,cAAc,UAAU,MAAM,WAAW,KAAK,MAAM,KAAK;AAAA;AAAA,EAAO,MAAM,WAAW;AAAA,CAAI;AAGxF,QAAM,WAAW,aAAa,GAAG;AACjC,WAAS,UAAU,MAAM,EAAE,IAAI;AAAA,IAC7B,UAAS,oBAAI,KAAK,GAAE,YAAY;AAAA,IAChC,OAAO,MAAM;AAAA,EACf;AACA,gBAAc,UAAU,GAAG;AAE3B,SAAO;AACT;AAGO,SAAS,SAAS,SAAiB,KAAuB;AAC/D,QAAM,WAAW,aAAa,GAAG;AACjC,SAAO,WAAW,SAAS;AAC7B;AAGO,SAAS,cAAc,SAAiB,KAA6B;AAC1E,MAAI,CAAC,SAAS,SAAS,GAAG,EAAG,QAAO;AACpC,QAAM,CAAC,MAAM,IAAI,IAAI,QAAQ,MAAM,GAAG;AACtC,QAAM,OAAO,KAAK,QAAQ,OAAO,EAAE,EAAE,QAAQ,iBAAiB,GAAG;AACjE,QAAM,WAAW,kBAAAC,QAAK,KAAK,YAAY,GAAG,GAAG,YAAY,MAAM,GAAG,IAAI,KAAK;AAC3E,SAAO,gBAAAD,QAAG,WAAW,QAAQ,IAAI,WAAW;AAC9C;AAGO,SAAS,WAAW,KAAwB;AACjD,SAAO,aAAa,GAAG;AACzB;;;AHzEO,SAAS,aAAa,QAAsC;AACjE,SAAO,IAAI,cAAc,MAAM;AACjC;","names":["fs","path","os","import_node_fs","import_node_path","fs","path"]}
package/dist/index.js CHANGED
@@ -97,8 +97,9 @@ var SkillDBClient = class {
97
97
  /** Validate that the configured API key works. */
98
98
  async validate() {
99
99
  try {
100
- await this.list({ limit: 1 });
101
- return true;
100
+ const url = `${this.baseUrl}/keys/usage`;
101
+ const res = await fetch(url, { headers: this.headers() });
102
+ return res.ok;
102
103
  } catch {
103
104
  return false;
104
105
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/client.ts","../src/cache.ts","../src/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nconst RC_FILE = '.skilldbrc';\n\nexport const DEFAULT_BASE_URL = 'https://skilldb.dev/api/v1';\n\ninterface RcConfig {\n apiKey?: string;\n}\n\nfunction readJson(filePath: string): RcConfig | null {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return JSON.parse(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve API key from (in priority order):\n * 1. SKILLDB_API_KEY env var\n * 2. .skilldbrc in project root (cwd)\n * 3. ~/.skilldbrc in home dir\n */\nexport function resolveApiKey(): string | undefined {\n if (process.env.SKILLDB_API_KEY) {\n return process.env.SKILLDB_API_KEY;\n }\n\n const projectRc = path.join(process.cwd(), RC_FILE);\n const projectConfig = readJson(projectRc);\n if (projectConfig?.apiKey) return projectConfig.apiKey;\n\n const homeRc = path.join(os.homedir(), RC_FILE);\n const homeConfig = readJson(homeRc);\n if (homeConfig?.apiKey) return homeConfig.apiKey;\n\n return undefined;\n}\n\n/**\n * Resolve base URL from env or default.\n */\nexport function resolveBaseUrl(): string {\n return process.env.SKILLDB_API_URL || DEFAULT_BASE_URL;\n}\n\n/**\n * Save API key to ~/.skilldbrc (user-wide) or project .skilldbrc.\n */\nexport function saveApiKey(apiKey: string, global = true): string {\n const target = global\n ? path.join(os.homedir(), RC_FILE)\n : path.join(process.cwd(), RC_FILE);\n\n const existing = readJson(target) || {};\n fs.writeFileSync(target, JSON.stringify({ ...existing, apiKey }, null, 2) + '\\n', 'utf-8');\n return target;\n}\n","import type { ClientConfig, Skill, SkillsResponse, SearchOptions } from './types.js';\nimport { resolveApiKey, resolveBaseUrl } from './config.js';\n\nexport class SkillDBClient {\n private apiKey?: string;\n private baseUrl: string;\n\n constructor(config?: ClientConfig) {\n this.apiKey = config?.apiKey ?? resolveApiKey();\n this.baseUrl = config?.baseUrl ?? resolveBaseUrl();\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.apiKey) {\n h['Authorization'] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async request<T>(endpoint: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== '') url.searchParams.set(k, v);\n }\n }\n\n const res = await fetch(url.toString(), { headers: this.headers() });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n const msg = (body as Record<string, string>).error || `HTTP ${res.status}`;\n throw new Error(msg);\n }\n\n return res.json() as Promise<T>;\n }\n\n /** Search skills by keyword. */\n async search(query: string, options?: Omit<SearchOptions, 'search'>): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n search: query,\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n limit: String(options?.limit ?? 20),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** List skills with optional filters. */\n async list(options?: SearchOptions): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n search: options?.search ?? '',\n limit: String(options?.limit ?? 50),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** Get a single skill by ID (e.g. \"software-skills/code-review.md\"). */\n async get(id: string): Promise<Skill> {\n const encoded = encodeURIComponent(id);\n const res = await this.request<Skill | { skill: Skill }>(`/skills/${encoded}`, {\n include_content: 'true',\n });\n // Handle both direct and wrapped responses\n return 'skill' in res ? res.skill : res;\n }\n\n /** Validate that the configured API key works. */\n async validate(): Promise<boolean> {\n try {\n await this.list({ limit: 1 });\n return true;\n } catch {\n return false;\n }\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Manifest, Skill } from './types.js';\n\nconst SKILLDB_DIR = '.skilldb';\nconst SKILLS_DIR = 'skills';\nconst MANIFEST_FILE = 'manifest.json';\n\nfunction ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n}\n\nfunction skilldbRoot(cwd?: string): string {\n return path.join(cwd ?? process.cwd(), SKILLDB_DIR);\n}\n\n/** Ensure .skilldb/ directory structure exists. */\nexport function initCache(cwd?: string): string {\n const root = skilldbRoot(cwd);\n ensureDir(path.join(root, SKILLS_DIR));\n\n const manifestPath = path.join(root, MANIFEST_FILE);\n if (!fs.existsSync(manifestPath)) {\n fs.writeFileSync(manifestPath, JSON.stringify({ installed: {} }, null, 2) + '\\n');\n }\n\n return root;\n}\n\n/** Read the local manifest. */\nexport function readManifest(cwd?: string): Manifest {\n const manifestPath = path.join(skilldbRoot(cwd), MANIFEST_FILE);\n try {\n return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n } catch {\n return { installed: {} };\n }\n}\n\n/** Write the local manifest. */\nexport function writeManifest(manifest: Manifest, cwd?: string): void {\n const root = skilldbRoot(cwd);\n ensureDir(root);\n fs.writeFileSync(\n path.join(root, MANIFEST_FILE),\n JSON.stringify(manifest, null, 2) + '\\n'\n );\n}\n\n/** Save a skill to the local cache. */\nexport function cacheSkill(skill: Skill, cwd?: string): string {\n const root = skilldbRoot(cwd);\n const skillDir = path.join(root, SKILLS_DIR, skill.pack);\n ensureDir(skillDir);\n\n const safeName = skill.name.replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skillDir, `${safeName}.md`);\n fs.writeFileSync(filePath, skill.content ?? `# ${skill.title}\\n\\n${skill.description}\\n`);\n\n // Update manifest\n const manifest = readManifest(cwd);\n manifest.installed[skill.id] = {\n addedAt: new Date().toISOString(),\n lines: skill.lines,\n };\n writeManifest(manifest, cwd);\n\n return filePath;\n}\n\n/** Check if a skill is already cached. */\nexport function isCached(skillId: string, cwd?: string): boolean {\n const manifest = readManifest(cwd);\n return skillId in manifest.installed;\n}\n\n/** Get the local path for a cached skill. */\nexport function getCachedPath(skillId: string, cwd?: string): string | null {\n if (!isCached(skillId, cwd)) return null;\n const [pack, file] = skillId.split('/');\n const name = file.replace('.md', '').replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skilldbRoot(cwd), SKILLS_DIR, pack, `${name}.md`);\n return fs.existsSync(filePath) ? filePath : null;\n}\n\n/** List all cached skills. */\nexport function listCached(cwd?: string): Manifest {\n return readManifest(cwd);\n}\n\n/** Ensure .skilldb/ and .skilldbrc are in .gitignore. */\nexport function updateGitignore(cwd?: string): void {\n const root = cwd ?? process.cwd();\n const gitignorePath = path.join(root, '.gitignore');\n\n const entries = ['.skilldb/', '.skilldbrc'];\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n const toAdd = entries.filter(e => !content.includes(e));\n if (toAdd.length === 0) return;\n\n const suffix = (content && !content.endsWith('\\n') ? '\\n' : '') +\n '\\n# SkillDB\\n' + toAdd.join('\\n') + '\\n';\n\n fs.writeFileSync(gitignorePath, content + suffix);\n}\n","export { SkillDBClient } from './client.js';\nexport type {\n Skill,\n PackInfo,\n CategoryInfo,\n SkillsResponse,\n SearchOptions,\n ClientConfig,\n Manifest,\n} from './types.js';\nexport { resolveApiKey, resolveBaseUrl, saveApiKey } from './config.js';\nexport { initCache, cacheSkill, isCached, getCachedPath, listCached } from './cache.js';\n\nimport type { ClientConfig } from './types.js';\nimport { SkillDBClient } from './client.js';\n\n/** Create a SkillDB client. Auto-loads API key from env/config. */\nexport function createClient(config?: ClientConfig): SkillDBClient {\n return new SkillDBClient(config);\n}\n"],"mappings":"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","names":["fs","path"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/client.ts","../src/cache.ts","../src/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nconst RC_FILE = '.skilldbrc';\n\nexport const DEFAULT_BASE_URL = 'https://skilldb.dev/api/v1';\n\ninterface RcConfig {\n apiKey?: string;\n}\n\nfunction readJson(filePath: string): RcConfig | null {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return JSON.parse(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve API key from (in priority order):\n * 1. SKILLDB_API_KEY env var\n * 2. .skilldbrc in project root (cwd)\n * 3. ~/.skilldbrc in home dir\n */\nexport function resolveApiKey(): string | undefined {\n if (process.env.SKILLDB_API_KEY) {\n return process.env.SKILLDB_API_KEY;\n }\n\n const projectRc = path.join(process.cwd(), RC_FILE);\n const projectConfig = readJson(projectRc);\n if (projectConfig?.apiKey) return projectConfig.apiKey;\n\n const homeRc = path.join(os.homedir(), RC_FILE);\n const homeConfig = readJson(homeRc);\n if (homeConfig?.apiKey) return homeConfig.apiKey;\n\n return undefined;\n}\n\n/**\n * Resolve base URL from env or default.\n */\nexport function resolveBaseUrl(): string {\n return process.env.SKILLDB_API_URL || DEFAULT_BASE_URL;\n}\n\n/**\n * Save API key to ~/.skilldbrc (user-wide) or project .skilldbrc.\n */\nexport function saveApiKey(apiKey: string, global = true): string {\n const target = global\n ? path.join(os.homedir(), RC_FILE)\n : path.join(process.cwd(), RC_FILE);\n\n const existing = readJson(target) || {};\n fs.writeFileSync(target, JSON.stringify({ ...existing, apiKey }, null, 2) + '\\n', 'utf-8');\n return target;\n}\n","import type { ClientConfig, Skill, SkillsResponse, SearchOptions } from './types.js';\nimport { resolveApiKey, resolveBaseUrl } from './config.js';\n\nexport class SkillDBClient {\n private apiKey?: string;\n private baseUrl: string;\n\n constructor(config?: ClientConfig) {\n this.apiKey = config?.apiKey ?? resolveApiKey();\n this.baseUrl = config?.baseUrl ?? resolveBaseUrl();\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.apiKey) {\n h['Authorization'] = `Bearer ${this.apiKey}`;\n }\n return h;\n }\n\n private async request<T>(endpoint: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== '') url.searchParams.set(k, v);\n }\n }\n\n const res = await fetch(url.toString(), { headers: this.headers() });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n const msg = (body as Record<string, string>).error || `HTTP ${res.status}`;\n throw new Error(msg);\n }\n\n return res.json() as Promise<T>;\n }\n\n /** Search skills by keyword. */\n async search(query: string, options?: Omit<SearchOptions, 'search'>): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n search: query,\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n limit: String(options?.limit ?? 20),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** List skills with optional filters. */\n async list(options?: SearchOptions): Promise<SkillsResponse> {\n return this.request<SkillsResponse>('/skills', {\n category: options?.category ?? '',\n pack: options?.pack ?? '',\n search: options?.search ?? '',\n limit: String(options?.limit ?? 50),\n offset: String(options?.offset ?? 0),\n include_content: options?.includeContent ? 'true' : '',\n });\n }\n\n /** Get a single skill by ID (e.g. \"software-skills/code-review.md\"). */\n async get(id: string): Promise<Skill> {\n const encoded = encodeURIComponent(id);\n const res = await this.request<Skill | { skill: Skill }>(`/skills/${encoded}`, {\n include_content: 'true',\n });\n // Handle both direct and wrapped responses\n return 'skill' in res ? res.skill : res;\n }\n\n /** Validate that the configured API key works. */\n async validate(): Promise<boolean> {\n try {\n const url = `${this.baseUrl}/keys/usage`;\n const res = await fetch(url, { headers: this.headers() });\n return res.ok;\n } catch {\n // Network error — key might still be valid, just can't reach server\n return false;\n }\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Manifest, Skill } from './types.js';\n\nconst SKILLDB_DIR = '.skilldb';\nconst SKILLS_DIR = 'skills';\nconst MANIFEST_FILE = 'manifest.json';\n\nfunction ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n}\n\nfunction skilldbRoot(cwd?: string): string {\n return path.join(cwd ?? process.cwd(), SKILLDB_DIR);\n}\n\n/** Ensure .skilldb/ directory structure exists. */\nexport function initCache(cwd?: string): string {\n const root = skilldbRoot(cwd);\n ensureDir(path.join(root, SKILLS_DIR));\n\n const manifestPath = path.join(root, MANIFEST_FILE);\n if (!fs.existsSync(manifestPath)) {\n fs.writeFileSync(manifestPath, JSON.stringify({ installed: {} }, null, 2) + '\\n');\n }\n\n return root;\n}\n\n/** Read the local manifest. */\nexport function readManifest(cwd?: string): Manifest {\n const manifestPath = path.join(skilldbRoot(cwd), MANIFEST_FILE);\n try {\n return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n } catch {\n return { installed: {} };\n }\n}\n\n/** Write the local manifest. */\nexport function writeManifest(manifest: Manifest, cwd?: string): void {\n const root = skilldbRoot(cwd);\n ensureDir(root);\n fs.writeFileSync(\n path.join(root, MANIFEST_FILE),\n JSON.stringify(manifest, null, 2) + '\\n'\n );\n}\n\n/** Save a skill to the local cache. */\nexport function cacheSkill(skill: Skill, cwd?: string): string {\n const root = skilldbRoot(cwd);\n const skillDir = path.join(root, SKILLS_DIR, skill.pack);\n ensureDir(skillDir);\n\n const safeName = skill.name.replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skillDir, `${safeName}.md`);\n fs.writeFileSync(filePath, skill.content ?? `# ${skill.title}\\n\\n${skill.description}\\n`);\n\n // Update manifest\n const manifest = readManifest(cwd);\n manifest.installed[skill.id] = {\n addedAt: new Date().toISOString(),\n lines: skill.lines,\n };\n writeManifest(manifest, cwd);\n\n return filePath;\n}\n\n/** Check if a skill is already cached. */\nexport function isCached(skillId: string, cwd?: string): boolean {\n const manifest = readManifest(cwd);\n return skillId in manifest.installed;\n}\n\n/** Get the local path for a cached skill. */\nexport function getCachedPath(skillId: string, cwd?: string): string | null {\n if (!isCached(skillId, cwd)) return null;\n const [pack, file] = skillId.split('/');\n const name = file.replace('.md', '').replace(/[/\\\\:*?\"<>|]/g, '-');\n const filePath = path.join(skilldbRoot(cwd), SKILLS_DIR, pack, `${name}.md`);\n return fs.existsSync(filePath) ? filePath : null;\n}\n\n/** List all cached skills. */\nexport function listCached(cwd?: string): Manifest {\n return readManifest(cwd);\n}\n\n/** Ensure .skilldb/ and .skilldbrc are in .gitignore. */\nexport function updateGitignore(cwd?: string): void {\n const root = cwd ?? process.cwd();\n const gitignorePath = path.join(root, '.gitignore');\n\n const entries = ['.skilldb/', '.skilldbrc'];\n let content = '';\n\n if (fs.existsSync(gitignorePath)) {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n }\n\n const toAdd = entries.filter(e => !content.includes(e));\n if (toAdd.length === 0) return;\n\n const suffix = (content && !content.endsWith('\\n') ? '\\n' : '') +\n '\\n# SkillDB\\n' + toAdd.join('\\n') + '\\n';\n\n fs.writeFileSync(gitignorePath, content + suffix);\n}\n","export { SkillDBClient } from './client.js';\nexport type {\n Skill,\n PackInfo,\n CategoryInfo,\n SkillsResponse,\n SearchOptions,\n ClientConfig,\n Manifest,\n} from './types.js';\nexport { resolveApiKey, resolveBaseUrl, saveApiKey } from './config.js';\nexport { initCache, cacheSkill, isCached, getCachedPath, listCached } from './cache.js';\n\nimport type { ClientConfig } from './types.js';\nimport { SkillDBClient } from './client.js';\n\n/** Create a SkillDB client. Auto-loads API key from env/config. */\nexport function createClient(config?: ClientConfig): SkillDBClient {\n return new SkillDBClient(config);\n}\n"],"mappings":"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","names":["fs","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skilldb",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "SDK and CLI for SkillDB — discover, install, and manage AI agent skills",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",