{"version":3,"file":"skills-command.mjs","names":[],"sources":["../../../src/commands/skills-command.ts"],"sourcesContent":["/**\n * Skills command — browse, search, enable/disable the unified skill registry.\n *\n * /skills                — List all skills with status indicators\n * /skills <name>         — Show full content of a specific skill\n * /skills search <q>     — Search skills by keyword\n * /skills enable <name>  — Re-enable a disabled skill\n * /skills disable <name> — Disable a skill (saves prompt tokens)\n */\n\nimport type { SkillEntry } from '../services/skill-registry.js';\nimport { getSkillRegistry } from '../services/skill-registry.js';\n\n/** Format a single skill line with status indicators. */\nfunction formatSkillLine(s: SkillEntry, registry: ReturnType<typeof getSkillRegistry>): string {\n  const missing = registry.missingEnv(s);\n  const tags: string[] = [];\n\n  if (s.disabled)       tags.push('[disabled]');\n  if (missing.length)   tags.push(`[env not set: ${missing.join(', ')}]`);\n  if (s.source === 'learned') tags.push('(learned)');\n\n  const suffix = tags.length > 0 ? `  ${tags.join(' ')}` : '';\n  return `  **${s.name}** — ${s.description.slice(0, 90)}${s.description.length > 90 ? '...' : ''}${suffix}`;\n}\n\nexport const skillsCommand = {\n  name: 'skills',\n  description: 'Browse crypto skills: /skills, /skills <name>, /skills search|enable|disable <name>',\n  acceptsArgs: true,\n  requireAuth: true,\n  handler: async (ctx?: any) => {\n    const rawArgs = (ctx?.args ?? '').trim();\n    const registry = getSkillRegistry();\n\n    // ── No args: list all skills ─────────────────────────────────\n    if (!rawArgs) {\n      const all = registry.listAll();\n      if (all.length === 0) {\n        return { text: 'No skills found. Check that `extensions/crypto/skills/` exists and contains skill directories.' };\n      }\n\n      const enabled = all.filter(s => !s.disabled);\n      const disabled = all.filter(s => s.disabled);\n\n      const lines: string[] = [\n        `**Skills** (${enabled.length} active, ${all.length} total)`,\n        '',\n      ];\n\n      // Group by source\n      const staticSkills = all.filter(s => s.source === 'static');\n      const learnedSkills = all.filter(s => s.source === 'learned');\n\n      if (staticSkills.length > 0) {\n        lines.push(`**Built-in** (${staticSkills.length}):`);\n        for (const s of staticSkills) {\n          lines.push(formatSkillLine(s, registry));\n        }\n        lines.push('');\n      }\n\n      if (learnedSkills.length > 0) {\n        lines.push(`**Learned** (${learnedSkills.length}):`);\n        for (const s of learnedSkills) {\n          lines.push(formatSkillLine(s, registry));\n        }\n        lines.push('');\n      }\n\n      lines.push('---');\n      lines.push('`/skills <name>` view | `/skills search <q>` search');\n      lines.push('`/skills disable <name>` | `/skills enable <name>`');\n\n      if (disabled.length === 0 && all.length > 10) {\n        lines.push('');\n        lines.push('*Tip: disable skills you don\\'t use to save prompt tokens.*');\n      }\n\n      return { text: lines.join('\\n') };\n    }\n\n    // ── \"enable <name>\" ──────────────────────────────────────────\n    if (rawArgs.startsWith('enable ')) {\n      const name = rawArgs.slice(7).trim().toLowerCase().replace(/[^a-z0-9-]/g, '');\n      if (!name) return { text: 'Usage: `/skills enable <name>`' };\n\n      const skill = registry.get(name);\n      if (!skill) return { text: `Skill \"${name}\" not found. Use \\`/skills\\` to list all.` };\n      if (!skill.disabled) return { text: `**${name}** is already enabled.` };\n\n      registry.enable(name);\n      return { text: `Enabled **${name}**. It will now appear in prompts and matching.` };\n    }\n\n    // ── \"disable <name>\" ─────────────────────────────────────────\n    if (rawArgs.startsWith('disable ')) {\n      const name = rawArgs.slice(8).trim().toLowerCase().replace(/[^a-z0-9-]/g, '');\n      if (!name) return { text: 'Usage: `/skills disable <name>`' };\n\n      const skill = registry.get(name);\n      if (!skill) return { text: `Skill \"${name}\" not found. Use \\`/skills\\` to list all.` };\n      if (skill.disabled) return { text: `**${name}** is already disabled.` };\n\n      registry.disable(name);\n      return { text: `Disabled **${name}**. It won't be injected into prompts (saves tokens). Re-enable with \\`/skills enable ${name}\\`.` };\n    }\n\n    // ── \"search <query>\": keyword search ─────────────────────────\n    if (rawArgs.startsWith('search ')) {\n      const query = rawArgs.slice(7).trim();\n      if (!query) return { text: 'Usage: `/skills search <query>`' };\n\n      const matches = registry.match(query, { minScore: 1, maxResults: 10 });\n      if (matches.length === 0) {\n        return { text: `No skills matching \"${query}\". Use \\`/skills\\` to list all.` };\n      }\n\n      const lines = [`**Skills matching \"${query}\"** (${matches.length} result${matches.length > 1 ? 's' : ''})`, ''];\n      for (const m of matches) {\n        lines.push(formatSkillLine(m.skill, registry));\n      }\n      lines.push('', 'Use `/skills <name>` to view full content.');\n      return { text: lines.join('\\n') };\n    }\n\n    // ── \"<name>\": show full content ──────────────────────────────\n    const name = rawArgs.toLowerCase().replace(/[^a-z0-9-]/g, '');\n    const content = registry.readContent(name);\n    if (!content) {\n      // Try fuzzy: search for the name\n      const matches = registry.match(rawArgs, { minScore: 1, maxResults: 3 });\n      if (matches.length > 0) {\n        const suggestions = matches.map(m => `\\`${m.skill.name}\\``).join(', ');\n        return { text: `Skill \"${name}\" not found. Did you mean: ${suggestions}?` };\n      }\n      return { text: `Skill \"${name}\" not found. Use \\`/skills\\` to list all available skills.` };\n    }\n\n    // Show status header for the skill\n    const skill = registry.get(name)!;\n    const missing = registry.missingEnv(skill);\n    const statusParts: string[] = [];\n    if (skill.disabled) statusParts.push('DISABLED');\n    if (missing.length) statusParts.push(`env not set: ${missing.join(', ')}`);\n    const statusLine = statusParts.length > 0 ? `\\n**Status:** ${statusParts.join(' | ')}\\n` : '';\n\n    // Cap output at 4000 chars for chat readability\n    const MAX_DISPLAY = 4000;\n    const display = content.length > MAX_DISPLAY\n      ? content.slice(0, MAX_DISPLAY) + `\\n\\n[...truncated at ${MAX_DISPLAY} chars. Full content available via skill_evolve(action: \"view\", name: \"${name}\")]`\n      : content;\n\n    return { text: `**Skill: ${name}**${statusLine}\\n${display}` };\n  },\n};\n"],"mappings":"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"}