|
| 1 | +import type { SkillHandler } from "../../types.js"; |
| 2 | +import { streamQuery } from "../../handler-utils.js"; |
| 3 | + |
| 4 | +const SYSTEM_PROMPT = `You are an expert at creating dex CLI skills. Your job is to generate a complete, working skill based on the user's description. |
| 5 | +
|
| 6 | +A dex skill consists of two files in a directory: |
| 7 | +
|
| 8 | +## 1. manifest.json |
| 9 | +
|
| 10 | +\`\`\`json |
| 11 | +{ |
| 12 | + "name": "skill-name", |
| 13 | + "version": "1.0.0", |
| 14 | + "description": "What this skill does", |
| 15 | + "inputs": { |
| 16 | + "args": [ |
| 17 | + { "name": "file", "description": "Target file", "required": true } |
| 18 | + ], |
| 19 | + "flags": [ |
| 20 | + { "name": "verbose", "short": "v", "type": "boolean", "default": false } |
| 21 | + ], |
| 22 | + "context": ["current-file", "git-diff", "git-diff-staged", "git-log", "file-tree", "package-json", "stdin"] |
| 23 | + }, |
| 24 | + "agent": { |
| 25 | + "maxTurns": 5, |
| 26 | + "allowedTools": ["bash", "read_file", "write_file", "list_files", "search_files", "apply_diff"] |
| 27 | + }, |
| 28 | + "aliases": ["short-name"] |
| 29 | +} |
| 30 | +\`\`\` |
| 31 | +
|
| 32 | +Rules: |
| 33 | +- "name" must be lowercase with hyphens |
| 34 | +- Only include "args", "flags", "context" that the skill actually needs |
| 35 | +- Only include "agent.allowedTools" if the skill needs to read/write files or run commands |
| 36 | +- Omit "agent" entirely for simple single-turn skills (review, explain, etc.) |
| 37 | +
|
| 38 | +## 2. handler.ts |
| 39 | +
|
| 40 | +\`\`\`typescript |
| 41 | +import type { SkillHandler } from "../../types.js"; |
| 42 | +import { streamQuery } from "../../handler-utils.js"; |
| 43 | +
|
| 44 | +const SYSTEM_PROMPT = \\\`Your system prompt here\\\`; |
| 45 | +
|
| 46 | +const handler: SkillHandler = async (ctx) => { |
| 47 | + // Access inputs: |
| 48 | + // ctx.args.file — positional arg |
| 49 | + // ctx.flags.verbose — flag value |
| 50 | + // ctx.context.gitDiff — context data |
| 51 | + // ctx.context.currentFile?.content — file content |
| 52 | + // ctx.context.stdin — piped input |
| 53 | + // ctx.context.cwd — working directory |
| 54 | +
|
| 55 | + const prompt = \\\`Your prompt with \${ctx.context.currentFile?.content}\\\`; |
| 56 | + await streamQuery(ctx.agent, prompt, { systemPrompt: SYSTEM_PROMPT }); |
| 57 | +}; |
| 58 | +
|
| 59 | +export default handler; |
| 60 | +\`\`\` |
| 61 | +
|
| 62 | +## Your workflow: |
| 63 | +
|
| 64 | +1. Understand what the user wants |
| 65 | +2. Design the manifest (what inputs, context, and tools are needed) |
| 66 | +3. Write the handler with a good system prompt |
| 67 | +4. Create the skill directory with write_file |
| 68 | +5. If the user wants it installed, run: \`dex skill add ./<name>\` |
| 69 | +
|
| 70 | +Keep skills simple and focused. One skill = one job.`; |
| 71 | + |
| 72 | +const handler: SkillHandler = async (ctx) => { |
| 73 | + const name = ctx.args.name; |
| 74 | + const description = ctx.flags.description as string | undefined; |
| 75 | + const install = ctx.flags.install as boolean; |
| 76 | + |
| 77 | + if (!name) { |
| 78 | + throw new Error("Skill name is required. Usage: dex create-skill <name> -d 'what it does'"); |
| 79 | + } |
| 80 | + |
| 81 | + const prompt = `Create a new dex skill called "${name}" in the directory "./${name}/". |
| 82 | +
|
| 83 | +${description ? `Description: ${description}` : "Ask me what this skill should do, then create it."} |
| 84 | +
|
| 85 | +${install ? "After creating the files, install it by running: dex skill add ./" + name : ""} |
| 86 | +
|
| 87 | +${ctx.context.fileTree ? `Current project structure for reference:\n\`\`\`\n${ctx.context.fileTree}\n\`\`\`` : ""} |
| 88 | +
|
| 89 | +Create the manifest.json and handler.ts files now.`; |
| 90 | + |
| 91 | + await streamQuery(ctx.agent, prompt, { systemPrompt: SYSTEM_PROMPT }); |
| 92 | +}; |
| 93 | + |
| 94 | +export default handler; |
0 commit comments