mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-18 18:48:48 +08:00
feat: enhance search, ranking, reranker and CLI tooling across ccw and codex-lens
Major improvements to smart-search, chain-search cascade, ranking pipeline, reranker factory, CLI history store, codex-lens integration, and uv-manager. Simplify command-generator skill by inlining phases. Add comprehensive tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,190 +1,307 @@
|
||||
---
|
||||
name: command-generator
|
||||
description: Command file generator - 5 phase workflow for creating Claude Code command files with YAML frontmatter. Generates .md command files for project or user scope. Triggers on "create command", "new command", "command generator".
|
||||
allowed-tools: Read, Write, Edit, Bash, Glob
|
||||
allowed-tools: Read, Write, Edit, Bash, Glob, AskUserQuestion
|
||||
---
|
||||
|
||||
# Command Generator
|
||||
<purpose>
|
||||
Generate Claude Code command .md files with concrete, domain-specific content in GSD style. Produces command files at project-level (`.claude/commands/`) or user-level (`~/.claude/commands/`) with YAML frontmatter, XML semantic tags (`<purpose>`, `<process>`, `<step>`, `<error_codes>`, `<success_criteria>`), and actionable execution logic — NOT empty placeholders.
|
||||
|
||||
CLI-based command file generator producing Claude Code command .md files through a structured 5-phase workflow. Supports both project-level (`.claude/commands/`) and user-level (`~/.claude/commands/`) command locations.
|
||||
Invoked when user requests "create command", "new command", or "command generator".
|
||||
</purpose>
|
||||
|
||||
## Architecture Overview
|
||||
<required_reading>
|
||||
- @.claude/skills/command-generator/specs/command-design-spec.md
|
||||
- @.claude/skills/command-generator/templates/command-md.md
|
||||
</required_reading>
|
||||
|
||||
<process>
|
||||
|
||||
<step name="validate_params" priority="first">
|
||||
**Parse and validate all input parameters.**
|
||||
|
||||
Extract from `$ARGUMENTS` or skill args:
|
||||
|
||||
| Parameter | Required | Validation | Example |
|
||||
|-----------|----------|------------|---------|
|
||||
| `$SKILL_NAME` | Yes | `/^[a-z][a-z0-9-]*$/`, min 1 char | `deploy`, `create` |
|
||||
| `$DESCRIPTION` | Yes | min 10 chars | `"Deploy application to production"` |
|
||||
| `$LOCATION` | Yes | `"project"` or `"user"` | `project` |
|
||||
| `$GROUP` | No | `/^[a-z][a-z0-9-]*$/` or null | `issue`, `workflow` |
|
||||
| `$ARGUMENT_HINT` | No | any string or empty | `"<url> [--priority 1-5]"` |
|
||||
|
||||
**Validation rules:**
|
||||
- Missing required param → Error with specific message (e.g., `"skillName is required"`)
|
||||
- Invalid `$SKILL_NAME` pattern → Error: `"skillName must be lowercase alphanumeric with hyphens, starting with a letter"`
|
||||
- Invalid `$LOCATION` → Error: `"location must be 'project' or 'user'"`
|
||||
- Invalid `$GROUP` pattern → Warning, continue
|
||||
|
||||
**Normalize:** trim + lowercase for `$SKILL_NAME`, `$LOCATION`, `$GROUP`.
|
||||
</step>
|
||||
|
||||
<step name="resolve_target_path">
|
||||
**Resolve target file path based on location and group.**
|
||||
|
||||
Path mapping:
|
||||
|
||||
| Location | Base Directory |
|
||||
|----------|---------------|
|
||||
| `project` | `.claude/commands` |
|
||||
| `user` | `~/.claude/commands` (expand `~` to `$HOME`) |
|
||||
|
||||
Path construction:
|
||||
|
||||
```
|
||||
+-----------------------------------------------------------+
|
||||
| Command Generator |
|
||||
| |
|
||||
| Input: skillName, description, location, [group], [hint] |
|
||||
| | |
|
||||
| +-------------------------------------------------+ |
|
||||
| | Phase 1-5: Sequential Pipeline | |
|
||||
| | | |
|
||||
| | [P1] --> [P2] --> [P3] --> [P4] --> [P5] | |
|
||||
| | Param Target Template Content File | |
|
||||
| | Valid Path Loading Format Gen | |
|
||||
| +-------------------------------------------------+ |
|
||||
| | |
|
||||
| Output: {scope}/.claude/commands/{group}/{name}.md |
|
||||
| |
|
||||
+-----------------------------------------------------------+
|
||||
If $GROUP:
|
||||
$TARGET_DIR = {base}/{$GROUP}
|
||||
$TARGET_PATH = {base}/{$GROUP}/{$SKILL_NAME}.md
|
||||
Else:
|
||||
$TARGET_DIR = {base}
|
||||
$TARGET_PATH = {base}/{$SKILL_NAME}.md
|
||||
```
|
||||
|
||||
## Key Design Principles
|
||||
Check if `$TARGET_PATH` already exists → store as `$FILE_EXISTS` (true/false).
|
||||
</step>
|
||||
|
||||
1. **Single Responsibility**: Generates one command file per invocation
|
||||
2. **Scope Awareness**: Supports project and user-level command locations
|
||||
3. **Template-Driven**: Uses consistent template for all generated commands
|
||||
4. **Validation First**: Validates all required parameters before file operations
|
||||
5. **Non-Destructive**: Warns if command file already exists
|
||||
<step name="gather_requirements">
|
||||
**Gather domain-specific requirements to generate concrete content.**
|
||||
|
||||
Infer the command's domain from `$SKILL_NAME`, `$DESCRIPTION`, and `$ARGUMENT_HINT`:
|
||||
|
||||
| Signal | Extract |
|
||||
|--------|---------|
|
||||
| `$SKILL_NAME` | Action verb (deploy, create, analyze, sync) → step naming |
|
||||
| `$DESCRIPTION` | Domain keywords → execution logic, error scenarios |
|
||||
| `$ARGUMENT_HINT` | Flags/args → parse_input step details, validation rules |
|
||||
| `$GROUP` | Command family → related commands, shared patterns |
|
||||
|
||||
**Determine command complexity:**
|
||||
|
||||
| Complexity | Criteria | Steps to Generate |
|
||||
|------------|----------|-------------------|
|
||||
| Simple | Single action, no flags | 2-3 steps |
|
||||
| Standard | 1-2 flags, clear workflow | 3-4 steps |
|
||||
| Complex | Multiple flags, multi-phase | 4-6 steps |
|
||||
|
||||
**If complexity is unclear**, ask user:
|
||||
|
||||
```
|
||||
AskUserQuestion(
|
||||
header: "Command Scope",
|
||||
question: "What are the main execution steps for this command?",
|
||||
options: [
|
||||
{ label: "Simple", description: "Single action: validate → execute → report" },
|
||||
{ label: "Standard", description: "Multi-step: parse → process → verify → report" },
|
||||
{ label: "Complex", description: "Full workflow: parse → explore → execute → verify → report" },
|
||||
{ label: "I'll describe", description: "Let me specify the steps" }
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
Store as `$COMMAND_STEPS`, `$ERROR_SCENARIOS`, `$SUCCESS_CONDITIONS`.
|
||||
</step>
|
||||
|
||||
<step name="draft_content">
|
||||
**Generate concrete, domain-specific command content in GSD style.**
|
||||
|
||||
This is the core generation step. Draft the COMPLETE command file — not a template with placeholders — using the gathered requirements.
|
||||
|
||||
**YAML Frontmatter:**
|
||||
```yaml
|
||||
---
|
||||
|
||||
## Execution Flow
|
||||
|
||||
```
|
||||
Phase 1: Parameter Validation
|
||||
- Ref: phases/01-parameter-validation.md
|
||||
- Validate: skillName (required), description (required), location (required)
|
||||
- Optional: group, argumentHint
|
||||
- Output: validated params object
|
||||
|
||||
Phase 2: Target Path Resolution
|
||||
- Ref: phases/02-target-path-resolution.md
|
||||
- Resolve: location -> target commands directory
|
||||
- Support: project (.claude/commands/) vs user (~/.claude/commands/)
|
||||
- Handle: group subdirectory if provided
|
||||
- Output: targetPath string
|
||||
|
||||
Phase 3: Template Loading
|
||||
- Ref: phases/03-template-loading.md
|
||||
- Load: templates/command-md.md
|
||||
- Template contains YAML frontmatter with placeholders
|
||||
- Output: templateContent string
|
||||
|
||||
Phase 4: Content Formatting
|
||||
- Ref: phases/04-content-formatting.md
|
||||
- Substitute: {{name}}, {{description}}, {{group}}, {{argumentHint}}
|
||||
- Handle: optional fields (group, argumentHint)
|
||||
- Output: formattedContent string
|
||||
|
||||
Phase 5: File Generation
|
||||
- Ref: phases/05-file-generation.md
|
||||
- Check: file existence (warn if exists)
|
||||
- Write: formatted content to target path
|
||||
- Output: success confirmation with file path
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Command (Project Scope)
|
||||
```javascript
|
||||
Skill(skill="command-generator", args={
|
||||
skillName: "deploy",
|
||||
description: "Deploy application to production environment",
|
||||
location: "project"
|
||||
})
|
||||
// Output: .claude/commands/deploy.md
|
||||
```
|
||||
|
||||
### Grouped Command with Argument Hint
|
||||
```javascript
|
||||
Skill(skill="command-generator", args={
|
||||
skillName: "create",
|
||||
description: "Create new issue from GitHub URL or text",
|
||||
location: "project",
|
||||
group: "issue",
|
||||
argumentHint: "[-y|--yes] <github-url | text-description> [--priority 1-5]"
|
||||
})
|
||||
// Output: .claude/commands/issue/create.md
|
||||
```
|
||||
|
||||
### User-Level Command
|
||||
```javascript
|
||||
Skill(skill="command-generator", args={
|
||||
skillName: "global-status",
|
||||
description: "Show global Claude Code status",
|
||||
location: "user"
|
||||
})
|
||||
// Output: ~/.claude/commands/global-status.md
|
||||
```
|
||||
|
||||
name: $SKILL_NAME
|
||||
description: $DESCRIPTION
|
||||
argument-hint: $ARGUMENT_HINT # only if provided
|
||||
---
|
||||
```
|
||||
|
||||
## Reference Documents by Phase
|
||||
**`<purpose>` section:** Write 2-3 sentences describing:
|
||||
- What the command does (action + target)
|
||||
- When it's invoked (trigger conditions)
|
||||
- What it produces (output artifacts or effects)
|
||||
|
||||
### Phase 1: Parameter Validation
|
||||
| Document | Purpose | When to Use |
|
||||
|----------|---------|-------------|
|
||||
| [phases/01-parameter-validation.md](phases/01-parameter-validation.md) | Validate required parameters | Phase 1 execution |
|
||||
**`<required_reading>` section:** Infer from domain:
|
||||
- If command reads config → `@.claude/CLAUDE.md` or relevant config files
|
||||
- If command modifies code → relevant source directories
|
||||
- If command is part of a group → other commands in the same group
|
||||
|
||||
### Phase 2: Target Path Resolution
|
||||
| Document | Purpose | When to Use |
|
||||
|----------|---------|-------------|
|
||||
| [phases/02-target-path-resolution.md](phases/02-target-path-resolution.md) | Resolve target directory | Phase 2 execution |
|
||||
**`<process>` section with `<step>` blocks:**
|
||||
|
||||
### Phase 3: Template Loading
|
||||
| Document | Purpose | When to Use |
|
||||
|----------|---------|-------------|
|
||||
| [phases/03-template-loading.md](phases/03-template-loading.md) | Load command template | Phase 3 execution |
|
||||
| [templates/command-md.md](templates/command-md.md) | Command file template | Template reference |
|
||||
For each step in `$COMMAND_STEPS`, generate a `<step name="snake_case">` block containing:
|
||||
|
||||
### Phase 4: Content Formatting
|
||||
| Document | Purpose | When to Use |
|
||||
|----------|---------|-------------|
|
||||
| [phases/04-content-formatting.md](phases/04-content-formatting.md) | Format content with params | Phase 4 execution |
|
||||
1. **`parse_input`** (always first, `priority="first"`):
|
||||
- Parse `$ARGUMENTS` for flags and positional args derived from `$ARGUMENT_HINT`
|
||||
- Include specific flag detection logic (e.g., `if arguments contain "--env"`)
|
||||
- Include validation with specific error messages
|
||||
- Include decision routing table if multiple modes exist
|
||||
|
||||
### Phase 5: File Generation
|
||||
| Document | Purpose | When to Use |
|
||||
|----------|---------|-------------|
|
||||
| [phases/05-file-generation.md](phases/05-file-generation.md) | Write final file | Phase 5 execution |
|
||||
2. **Domain-specific execution steps** (2-4 steps):
|
||||
- Each step has a **bold action description**
|
||||
- Include concrete shell commands, file operations, or tool calls
|
||||
- Use `$UPPER_CASE` variables for user input, `${computed}` for derived values
|
||||
- Include conditional logic with specific conditions (not generic)
|
||||
- Reference actual file paths and tool names
|
||||
|
||||
### Design Specifications
|
||||
| Document | Purpose | When to Use |
|
||||
|----------|---------|-------------|
|
||||
| [specs/command-design-spec.md](specs/command-design-spec.md) | Command design guidelines | Understanding best practices |
|
||||
3. **`report`** (always last):
|
||||
- Format output with banner and status
|
||||
- Include file paths, timestamps, next step suggestions
|
||||
|
||||
---
|
||||
**Shell Correctness Checklist (MANDATORY for every shell block):**
|
||||
|
||||
## Output Structure
|
||||
| Rule | Wrong | Correct |
|
||||
|------|-------|---------|
|
||||
| Multi-line output | `echo "{ ... }"` (unquoted multi-line) | `cat <<'EOF' > file`...`EOF` (heredoc) |
|
||||
| Variable init | Use `$VAR` after conditional | `VAR="default"` BEFORE any conditional that sets it |
|
||||
| Error exit | `echo "Error: ..."` (no exit) | `echo "Error: ..." # (see code: E00X)` + `exit 1` |
|
||||
| Quoting | `$VAR` in commands | `"$VAR"` (double-quoted in all expansions) |
|
||||
| Exit on fail | Command chain without checks | `set -e` or explicit `|| { echo "Failed"; exit 1; }` |
|
||||
| Command from var | `$CMD --flag` (word-split fragile) | `eval "$CMD" --flag` or use array: `cmd=(...); "${cmd[@]}"` |
|
||||
| Prerequisites | Implicit `git`/`curl` usage | Declare in `<prerequisites>` section |
|
||||
|
||||
### Generated Command File
|
||||
**Golden Example — a correctly-written execution step:**
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: {skillName}
|
||||
description: {description}
|
||||
{group} {argumentHint}
|
||||
---
|
||||
<step name="run_deployment">
|
||||
**Execute deployment to target environment.**
|
||||
|
||||
# {skillName} Command
|
||||
$DEPLOY_STATUS="pending" # Initialize before conditional
|
||||
|
||||
## Overview
|
||||
{Auto-generated placeholder for command overview}
|
||||
```bash
|
||||
# Save current state for rollback
|
||||
cp .deploy/latest.json .deploy/previous.json 2>/dev/null || true
|
||||
|
||||
## Usage
|
||||
{Auto-generated placeholder for usage examples}
|
||||
# Write deployment manifest via heredoc
|
||||
cat <<EOF > .deploy/latest.json
|
||||
{
|
||||
"env": "$ENV",
|
||||
"tag": "$DEPLOY_TAG",
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||||
"commit": "$(git rev-parse --short HEAD)",
|
||||
"status": "deploying"
|
||||
}
|
||||
EOF
|
||||
|
||||
## Execution Flow
|
||||
{Auto-generated placeholder for execution steps}
|
||||
# Execute deployment
|
||||
if ! deploy_cmd --env "$ENV" --tag "$DEPLOY_TAG" 2>&1 | tee .deploy/latest.log; then
|
||||
echo "Error: Deployment to $ENV failed" # (see code: E004)
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$DEPLOY_STATUS="success"
|
||||
```
|
||||
|
||||
---
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| Deploy succeeds | Update status → `"deployed"`, continue to verify |
|
||||
| Deploy fails | Log error `# (see code: E004)`, exit 1 |
|
||||
| `$ROLLBACK_MODE` | Load `.deploy/previous.json`, redeploy prior version |
|
||||
</step>
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
**Optional `<prerequisites>` section** (include when command uses external tools):
|
||||
|
||||
| Error | Stage | Action |
|
||||
|-------|-------|--------|
|
||||
| Missing skillName | Phase 1 | Error: "skillName is required" |
|
||||
| Missing description | Phase 1 | Error: "description is required" |
|
||||
| Missing location | Phase 1 | Error: "location is required (project or user)" |
|
||||
| Invalid location | Phase 2 | Error: "location must be 'project' or 'user'" |
|
||||
| Template not found | Phase 3 | Error: "Command template not found" |
|
||||
| File exists | Phase 5 | Warning: "Command file already exists, will overwrite" |
|
||||
| Write failure | Phase 5 | Error: "Failed to write command file" |
|
||||
```markdown
|
||||
<prerequisites>
|
||||
- git (2.20+) — version control operations
|
||||
- curl — health check endpoints
|
||||
- jq — JSON processing (optional)
|
||||
</prerequisites>
|
||||
```
|
||||
|
||||
---
|
||||
**`<error_codes>` table:** Generate 3-6 specific error codes:
|
||||
- Derive from `$ARGUMENT_HINT` validation failures (E001-E003)
|
||||
- Derive from domain-specific failure modes (E004+)
|
||||
- Include 1-2 warnings (W001+)
|
||||
- Each code has: Code, Severity, Description, **Stage** (which step triggers it)
|
||||
- **Cross-reference rule**: Every `# (see code: E00X)` comment in `<process>` MUST have a matching row in `<error_codes>`, and every error code row MUST be referenced by at least one inline comment
|
||||
|
||||
## Related Skills
|
||||
**`<success_criteria>` checkboxes:** Generate 4-8 verifiable conditions:
|
||||
- Input validation passed
|
||||
- Each execution step completed its action
|
||||
- Output artifacts exist / effects applied
|
||||
- Report displayed
|
||||
|
||||
- **skill-generator**: Create complete skills with phases, templates, and specs
|
||||
- **flow-coordinator**: Orchestrate multi-step command workflows
|
||||
**Quality rules for generated content:**
|
||||
- NO bracket placeholders (`[Describe...]`, `[List...]`) — all content must be concrete
|
||||
- Steps must contain actionable logic, not descriptions of what to do
|
||||
- Error codes must reference specific failure conditions from this command's domain
|
||||
- Success criteria must be verifiable (not "command works correctly")
|
||||
- Every shell block must pass the Shell Correctness Checklist above
|
||||
- Follow patterns from @.claude/skills/command-generator/templates/command-md.md for structural reference only
|
||||
</step>
|
||||
|
||||
<step name="write_file">
|
||||
**Write generated content to target path.**
|
||||
|
||||
**If `$FILE_EXISTS`:** Warn: `"Command file already exists at {path}. Will overwrite."`
|
||||
|
||||
```bash
|
||||
mkdir -p "$TARGET_DIR"
|
||||
```
|
||||
|
||||
Write the drafted content to `$TARGET_PATH` using Write tool.
|
||||
|
||||
**Verify:** Read back the file and confirm:
|
||||
- File exists and is non-empty
|
||||
- Contains `<purpose>` tag with concrete content (no placeholders)
|
||||
- Contains at least 2 `<step name=` blocks with shell code or tool calls
|
||||
- Contains `<error_codes>` with at least 3 rows including Stage column
|
||||
- Contains `<success_criteria>` with at least 4 checkboxes
|
||||
- No unresolved `{{...}}` or `[...]` placeholders remain
|
||||
- Every `# (see code: E0XX)` has a matching `<error_codes>` row (cross-ref check)
|
||||
- Every shell block uses heredoc for multi-line output (no bare multi-line echo)
|
||||
- All state variables initialized before conditional use
|
||||
- All error paths include `exit 1` after error message
|
||||
|
||||
**If verification fails:** Fix the content in-place using Edit tool.
|
||||
|
||||
**Report completion:**
|
||||
|
||||
```
|
||||
Command generated successfully!
|
||||
|
||||
File: {$TARGET_PATH}
|
||||
Name: {$SKILL_NAME}
|
||||
Description: {$DESCRIPTION}
|
||||
Location: {$LOCATION}
|
||||
Group: {$GROUP or "(none)"}
|
||||
Steps: {number of <step> blocks generated}
|
||||
Error codes: {number of error codes}
|
||||
|
||||
Next Steps:
|
||||
1. Review and customize {$TARGET_PATH}
|
||||
2. Test: /{$GROUP}:{$SKILL_NAME} or /{$SKILL_NAME}
|
||||
```
|
||||
</step>
|
||||
|
||||
</process>
|
||||
|
||||
<error_codes>
|
||||
|
||||
| Code | Severity | Description | Stage |
|
||||
|------|----------|-------------|-------|
|
||||
| E001 | error | skillName is required | validate_params |
|
||||
| E002 | error | description is required (min 10 chars) | validate_params |
|
||||
| E003 | error | location is required ("project" or "user") | validate_params |
|
||||
| E004 | error | skillName must be lowercase alphanumeric with hyphens | validate_params |
|
||||
| E005 | error | Failed to infer command domain from description | gather_requirements |
|
||||
| E006 | error | Failed to write command file | write_file |
|
||||
| E007 | error | Generated content contains unresolved placeholders | write_file |
|
||||
| W001 | warning | group must be lowercase alphanumeric with hyphens | validate_params |
|
||||
| W002 | warning | Command file already exists, will overwrite | write_file |
|
||||
| W003 | warning | Could not infer required_reading, using defaults | draft_content |
|
||||
|
||||
</error_codes>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] All required parameters validated ($SKILL_NAME, $DESCRIPTION, $LOCATION)
|
||||
- [ ] Target path resolved with correct scope (project vs user) and group
|
||||
- [ ] Command domain inferred from description and argument hint
|
||||
- [ ] Concrete `<purpose>` drafted (no placeholders)
|
||||
- [ ] 2-6 `<step>` blocks generated with domain-specific logic
|
||||
- [ ] `<error_codes>` table generated with 3+ specific codes
|
||||
- [ ] `<success_criteria>` generated with 4+ verifiable checkboxes
|
||||
- [ ] File written to $TARGET_PATH and verified
|
||||
- [ ] Zero bracket placeholders in final output
|
||||
- [ ] Completion report displayed
|
||||
</success_criteria>
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
# Phase 1: Parameter Validation
|
||||
|
||||
Validate all required parameters for command generation.
|
||||
|
||||
## Objective
|
||||
|
||||
Ensure all required parameters are provided before proceeding with command generation:
|
||||
- **skillName**: Command identifier (required)
|
||||
- **description**: Command description (required)
|
||||
- **location**: Target scope - "project" or "user" (required)
|
||||
- **group**: Optional grouping subdirectory
|
||||
- **argumentHint**: Optional argument hint string
|
||||
|
||||
## Input
|
||||
|
||||
Parameters received from skill invocation:
|
||||
- `skillName`: string (required)
|
||||
- `description`: string (required)
|
||||
- `location`: "project" | "user" (required)
|
||||
- `group`: string (optional)
|
||||
- `argumentHint`: string (optional)
|
||||
|
||||
## Validation Rules
|
||||
|
||||
### Required Parameters
|
||||
|
||||
```javascript
|
||||
const requiredParams = {
|
||||
skillName: {
|
||||
type: 'string',
|
||||
minLength: 1,
|
||||
pattern: /^[a-z][a-z0-9-]*$/, // lowercase, alphanumeric, hyphens
|
||||
error: 'skillName must be lowercase alphanumeric with hyphens, starting with a letter'
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
minLength: 10,
|
||||
error: 'description must be at least 10 characters'
|
||||
},
|
||||
location: {
|
||||
type: 'string',
|
||||
enum: ['project', 'user'],
|
||||
error: 'location must be "project" or "user"'
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Optional Parameters
|
||||
|
||||
```javascript
|
||||
const optionalParams = {
|
||||
group: {
|
||||
type: 'string',
|
||||
pattern: /^[a-z][a-z0-9-]*$/,
|
||||
default: null,
|
||||
error: 'group must be lowercase alphanumeric with hyphens'
|
||||
},
|
||||
argumentHint: {
|
||||
type: 'string',
|
||||
default: '',
|
||||
error: 'argumentHint must be a string'
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Extract Parameters
|
||||
|
||||
```javascript
|
||||
// Extract from skill args
|
||||
const params = {
|
||||
skillName: args.skillName,
|
||||
description: args.description,
|
||||
location: args.location,
|
||||
group: args.group || null,
|
||||
argumentHint: args.argumentHint || ''
|
||||
};
|
||||
```
|
||||
|
||||
### Step 2: Validate Required Parameters
|
||||
|
||||
```javascript
|
||||
function validateRequired(params, rules) {
|
||||
const errors = [];
|
||||
|
||||
for (const [key, rule] of Object.entries(rules)) {
|
||||
const value = params[key];
|
||||
|
||||
// Check existence
|
||||
if (value === undefined || value === null || value === '') {
|
||||
errors.push(`${key} is required`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check type
|
||||
if (typeof value !== rule.type) {
|
||||
errors.push(`${key} must be a ${rule.type}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check minLength
|
||||
if (rule.minLength && value.length < rule.minLength) {
|
||||
errors.push(`${key} must be at least ${rule.minLength} characters`);
|
||||
}
|
||||
|
||||
// Check pattern
|
||||
if (rule.pattern && !rule.pattern.test(value)) {
|
||||
errors.push(rule.error);
|
||||
}
|
||||
|
||||
// Check enum
|
||||
if (rule.enum && !rule.enum.includes(value)) {
|
||||
errors.push(`${key} must be one of: ${rule.enum.join(', ')}`);
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
const requiredErrors = validateRequired(params, requiredParams);
|
||||
if (requiredErrors.length > 0) {
|
||||
throw new Error(`Validation failed:\n${requiredErrors.join('\n')}`);
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Validate Optional Parameters
|
||||
|
||||
```javascript
|
||||
function validateOptional(params, rules) {
|
||||
const warnings = [];
|
||||
|
||||
for (const [key, rule] of Object.entries(rules)) {
|
||||
const value = params[key];
|
||||
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
if (rule.pattern && !rule.pattern.test(value)) {
|
||||
warnings.push(`${key}: ${rule.error}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
const optionalWarnings = validateOptional(params, optionalParams);
|
||||
// Log warnings but continue
|
||||
```
|
||||
|
||||
### Step 4: Normalize Parameters
|
||||
|
||||
```javascript
|
||||
const validatedParams = {
|
||||
skillName: params.skillName.trim().toLowerCase(),
|
||||
description: params.description.trim(),
|
||||
location: params.location.trim().toLowerCase(),
|
||||
group: params.group ? params.group.trim().toLowerCase() : null,
|
||||
argumentHint: params.argumentHint ? params.argumentHint.trim() : ''
|
||||
};
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: 'validated',
|
||||
params: validatedParams,
|
||||
warnings: optionalWarnings
|
||||
}
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 2: Target Path Resolution](02-target-path-resolution.md) with `validatedParams`.
|
||||
@@ -1,171 +0,0 @@
|
||||
# Phase 2: Target Path Resolution
|
||||
|
||||
Resolve the target commands directory based on location parameter.
|
||||
|
||||
## Objective
|
||||
|
||||
Determine the correct target path for the command file based on:
|
||||
- **location**: "project" or "user" scope
|
||||
- **group**: Optional subdirectory for command organization
|
||||
- **skillName**: Command filename (with .md extension)
|
||||
|
||||
## Input
|
||||
|
||||
From Phase 1 validation:
|
||||
```javascript
|
||||
{
|
||||
skillName: string, // e.g., "create"
|
||||
description: string,
|
||||
location: "project" | "user",
|
||||
group: string | null, // e.g., "issue"
|
||||
argumentHint: string
|
||||
}
|
||||
```
|
||||
|
||||
## Path Resolution Rules
|
||||
|
||||
### Location Mapping
|
||||
|
||||
```javascript
|
||||
const locationMap = {
|
||||
project: '.claude/commands',
|
||||
user: '~/.claude/commands' // Expands to user home directory
|
||||
};
|
||||
```
|
||||
|
||||
### Path Construction
|
||||
|
||||
```javascript
|
||||
function resolveTargetPath(params) {
|
||||
const baseDir = locationMap[params.location];
|
||||
|
||||
if (!baseDir) {
|
||||
throw new Error(`Invalid location: ${params.location}. Must be "project" or "user".`);
|
||||
}
|
||||
|
||||
// Expand ~ to user home if present
|
||||
const expandedBase = baseDir.startsWith('~')
|
||||
? path.join(os.homedir(), baseDir.slice(1))
|
||||
: baseDir;
|
||||
|
||||
// Build full path
|
||||
let targetPath;
|
||||
if (params.group) {
|
||||
// Grouped command: .claude/commands/{group}/{skillName}.md
|
||||
targetPath = path.join(expandedBase, params.group, `${params.skillName}.md`);
|
||||
} else {
|
||||
// Top-level command: .claude/commands/{skillName}.md
|
||||
targetPath = path.join(expandedBase, `${params.skillName}.md`);
|
||||
}
|
||||
|
||||
return targetPath;
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Get Base Directory
|
||||
|
||||
```javascript
|
||||
const location = validatedParams.location;
|
||||
const baseDir = locationMap[location];
|
||||
|
||||
if (!baseDir) {
|
||||
throw new Error(`Invalid location: ${location}. Must be "project" or "user".`);
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Expand User Path (if applicable)
|
||||
|
||||
```javascript
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
let expandedBase = baseDir;
|
||||
if (baseDir.startsWith('~')) {
|
||||
expandedBase = path.join(os.homedir(), baseDir.slice(1));
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Construct Full Path
|
||||
|
||||
```javascript
|
||||
let targetPath;
|
||||
let targetDir;
|
||||
|
||||
if (validatedParams.group) {
|
||||
// Command with group subdirectory
|
||||
targetDir = path.join(expandedBase, validatedParams.group);
|
||||
targetPath = path.join(targetDir, `${validatedParams.skillName}.md`);
|
||||
} else {
|
||||
// Top-level command
|
||||
targetDir = expandedBase;
|
||||
targetPath = path.join(targetDir, `${validatedParams.skillName}.md`);
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Ensure Target Directory Exists
|
||||
|
||||
```javascript
|
||||
// Check and create directory if needed
|
||||
Bash(`mkdir -p "${targetDir}"`);
|
||||
```
|
||||
|
||||
### Step 5: Check File Existence
|
||||
|
||||
```javascript
|
||||
const fileExists = Bash(`test -f "${targetPath}" && echo "EXISTS" || echo "NOT_FOUND"`);
|
||||
|
||||
if (fileExists.includes('EXISTS')) {
|
||||
console.warn(`Warning: Command file already exists at ${targetPath}. Will overwrite.`);
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: 'resolved',
|
||||
targetPath: targetPath, // Full path to command file
|
||||
targetDir: targetDir, // Directory containing command
|
||||
fileName: `${skillName}.md`,
|
||||
fileExists: fileExists.includes('EXISTS'),
|
||||
params: validatedParams // Pass through to next phase
|
||||
}
|
||||
```
|
||||
|
||||
## Path Examples
|
||||
|
||||
### Project Scope (No Group)
|
||||
```
|
||||
location: "project"
|
||||
skillName: "deploy"
|
||||
-> .claude/commands/deploy.md
|
||||
```
|
||||
|
||||
### Project Scope (With Group)
|
||||
```
|
||||
location: "project"
|
||||
skillName: "create"
|
||||
group: "issue"
|
||||
-> .claude/commands/issue/create.md
|
||||
```
|
||||
|
||||
### User Scope (No Group)
|
||||
```
|
||||
location: "user"
|
||||
skillName: "global-status"
|
||||
-> ~/.claude/commands/global-status.md
|
||||
```
|
||||
|
||||
### User Scope (With Group)
|
||||
```
|
||||
location: "user"
|
||||
skillName: "sync"
|
||||
group: "session"
|
||||
-> ~/.claude/commands/session/sync.md
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 3: Template Loading](03-template-loading.md) with `targetPath` and `params`.
|
||||
@@ -1,123 +0,0 @@
|
||||
# Phase 3: Template Loading
|
||||
|
||||
Load the command template file for content generation.
|
||||
|
||||
## Objective
|
||||
|
||||
Load the command template from the skill's templates directory. The template provides:
|
||||
- YAML frontmatter structure
|
||||
- Placeholder variables for substitution
|
||||
- Standard command file sections
|
||||
|
||||
## Input
|
||||
|
||||
From Phase 2:
|
||||
```javascript
|
||||
{
|
||||
targetPath: string,
|
||||
targetDir: string,
|
||||
fileName: string,
|
||||
fileExists: boolean,
|
||||
params: {
|
||||
skillName: string,
|
||||
description: string,
|
||||
location: string,
|
||||
group: string | null,
|
||||
argumentHint: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Template Location
|
||||
|
||||
```
|
||||
.claude/skills/command-generator/templates/command-md.md
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Locate Template File
|
||||
|
||||
```javascript
|
||||
// Template is located in the skill's templates directory
|
||||
const skillDir = '.claude/skills/command-generator';
|
||||
const templatePath = `${skillDir}/templates/command-md.md`;
|
||||
```
|
||||
|
||||
### Step 2: Read Template Content
|
||||
|
||||
```javascript
|
||||
const templateContent = Read(templatePath);
|
||||
|
||||
if (!templateContent) {
|
||||
throw new Error(`Command template not found at ${templatePath}`);
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Validate Template Structure
|
||||
|
||||
```javascript
|
||||
// Verify template contains expected placeholders
|
||||
const requiredPlaceholders = ['{{name}}', '{{description}}'];
|
||||
const optionalPlaceholders = ['{{group}}', '{{argumentHint}}'];
|
||||
|
||||
for (const placeholder of requiredPlaceholders) {
|
||||
if (!templateContent.includes(placeholder)) {
|
||||
throw new Error(`Template missing required placeholder: ${placeholder}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Store Template for Next Phase
|
||||
|
||||
```javascript
|
||||
const template = {
|
||||
content: templateContent,
|
||||
requiredPlaceholders: requiredPlaceholders,
|
||||
optionalPlaceholders: optionalPlaceholders
|
||||
};
|
||||
```
|
||||
|
||||
## Template Format Reference
|
||||
|
||||
The template should follow this structure:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: {{name}}
|
||||
description: {{description}}
|
||||
{{#if group}}group: {{group}}{{/if}}
|
||||
{{#if argumentHint}}argument-hint: {{argumentHint}}{{/if}}
|
||||
---
|
||||
|
||||
# {{name}} Command
|
||||
|
||||
[Template content with placeholders]
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: 'loaded',
|
||||
template: {
|
||||
content: templateContent,
|
||||
requiredPlaceholders: requiredPlaceholders,
|
||||
optionalPlaceholders: optionalPlaceholders
|
||||
},
|
||||
targetPath: targetPath,
|
||||
params: params
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Action |
|
||||
|-------|--------|
|
||||
| Template file not found | Throw error with path |
|
||||
| Missing required placeholder | Throw error with missing placeholder name |
|
||||
| Empty template | Throw error |
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 4: Content Formatting](04-content-formatting.md) with `template`, `targetPath`, and `params`.
|
||||
@@ -1,184 +0,0 @@
|
||||
# Phase 4: Content Formatting
|
||||
|
||||
Format template content by substituting placeholders with parameter values.
|
||||
|
||||
## Objective
|
||||
|
||||
Replace all placeholder variables in the template with validated parameter values:
|
||||
- `{{name}}` -> skillName
|
||||
- `{{description}}` -> description
|
||||
- `{{group}}` -> group (if provided)
|
||||
- `{{argumentHint}}` -> argumentHint (if provided)
|
||||
|
||||
## Input
|
||||
|
||||
From Phase 3:
|
||||
```javascript
|
||||
{
|
||||
template: {
|
||||
content: string,
|
||||
requiredPlaceholders: string[],
|
||||
optionalPlaceholders: string[]
|
||||
},
|
||||
targetPath: string,
|
||||
params: {
|
||||
skillName: string,
|
||||
description: string,
|
||||
location: string,
|
||||
group: string | null,
|
||||
argumentHint: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Placeholder Mapping
|
||||
|
||||
```javascript
|
||||
const placeholderMap = {
|
||||
'{{name}}': params.skillName,
|
||||
'{{description}}': params.description,
|
||||
'{{group}}': params.group || '',
|
||||
'{{argumentHint}}': params.argumentHint || ''
|
||||
};
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Initialize Content
|
||||
|
||||
```javascript
|
||||
let formattedContent = template.content;
|
||||
```
|
||||
|
||||
### Step 2: Substitute Required Placeholders
|
||||
|
||||
```javascript
|
||||
// These must always be replaced
|
||||
formattedContent = formattedContent.replace(/\{\{name\}\}/g, params.skillName);
|
||||
formattedContent = formattedContent.replace(/\{\{description\}\}/g, params.description);
|
||||
```
|
||||
|
||||
### Step 3: Handle Optional Placeholders
|
||||
|
||||
```javascript
|
||||
// Group placeholder
|
||||
if (params.group) {
|
||||
formattedContent = formattedContent.replace(/\{\{group\}\}/g, params.group);
|
||||
} else {
|
||||
// Remove group line if not provided
|
||||
formattedContent = formattedContent.replace(/^group: \{\{group\}\}\n?/gm, '');
|
||||
formattedContent = formattedContent.replace(/\{\{group\}\}/g, '');
|
||||
}
|
||||
|
||||
// Argument hint placeholder
|
||||
if (params.argumentHint) {
|
||||
formattedContent = formattedContent.replace(/\{\{argumentHint\}\}/g, params.argumentHint);
|
||||
} else {
|
||||
// Remove argument-hint line if not provided
|
||||
formattedContent = formattedContent.replace(/^argument-hint: \{\{argumentHint\}\}\n?/gm, '');
|
||||
formattedContent = formattedContent.replace(/\{\{argumentHint\}\}/g, '');
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Handle Conditional Sections
|
||||
|
||||
```javascript
|
||||
// Remove empty frontmatter lines (caused by missing optional fields)
|
||||
formattedContent = formattedContent.replace(/\n{3,}/g, '\n\n');
|
||||
|
||||
// Handle {{#if group}} style conditionals
|
||||
if (formattedContent.includes('{{#if')) {
|
||||
// Process group conditional
|
||||
if (params.group) {
|
||||
formattedContent = formattedContent.replace(/\{\{#if group\}\}([\s\S]*?)\{\{\/if\}\}/g, '$1');
|
||||
} else {
|
||||
formattedContent = formattedContent.replace(/\{\{#if group\}\}[\s\S]*?\{\{\/if\}\}/g, '');
|
||||
}
|
||||
|
||||
// Process argumentHint conditional
|
||||
if (params.argumentHint) {
|
||||
formattedContent = formattedContent.replace(/\{\{#if argumentHint\}\}([\s\S]*?)\{\{\/if\}\}/g, '$1');
|
||||
} else {
|
||||
formattedContent = formattedContent.replace(/\{\{#if argumentHint\}\}[\s\S]*?\{\{\/if\}\}/g, '');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Validate Final Content
|
||||
|
||||
```javascript
|
||||
// Ensure no unresolved placeholders remain
|
||||
const unresolvedPlaceholders = formattedContent.match(/\{\{[^}]+\}\}/g);
|
||||
if (unresolvedPlaceholders) {
|
||||
console.warn(`Warning: Unresolved placeholders found: ${unresolvedPlaceholders.join(', ')}`);
|
||||
}
|
||||
|
||||
// Ensure frontmatter is valid
|
||||
const frontmatterMatch = formattedContent.match(/^---\n([\s\S]*?)\n---/);
|
||||
if (!frontmatterMatch) {
|
||||
throw new Error('Generated content has invalid frontmatter structure');
|
||||
}
|
||||
```
|
||||
|
||||
### Step 6: Generate Summary
|
||||
|
||||
```javascript
|
||||
const summary = {
|
||||
name: params.skillName,
|
||||
description: params.description.substring(0, 50) + (params.description.length > 50 ? '...' : ''),
|
||||
location: params.location,
|
||||
group: params.group,
|
||||
hasArgumentHint: !!params.argumentHint
|
||||
};
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: 'formatted',
|
||||
content: formattedContent,
|
||||
targetPath: targetPath,
|
||||
summary: summary
|
||||
}
|
||||
```
|
||||
|
||||
## Content Example
|
||||
|
||||
### Input Template
|
||||
```markdown
|
||||
---
|
||||
name: {{name}}
|
||||
description: {{description}}
|
||||
{{#if group}}group: {{group}}{{/if}}
|
||||
{{#if argumentHint}}argument-hint: {{argumentHint}}{{/if}}
|
||||
---
|
||||
|
||||
# {{name}} Command
|
||||
```
|
||||
|
||||
### Output (with all fields)
|
||||
```markdown
|
||||
---
|
||||
name: create
|
||||
description: Create structured issue from GitHub URL or text description
|
||||
group: issue
|
||||
argument-hint: [-y|--yes] <github-url | text-description> [--priority 1-5]
|
||||
---
|
||||
|
||||
# create Command
|
||||
```
|
||||
|
||||
### Output (minimal fields)
|
||||
```markdown
|
||||
---
|
||||
name: deploy
|
||||
description: Deploy application to production environment
|
||||
---
|
||||
|
||||
# deploy Command
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 5: File Generation](05-file-generation.md) with `content` and `targetPath`.
|
||||
@@ -1,185 +0,0 @@
|
||||
# Phase 5: File Generation
|
||||
|
||||
Write the formatted content to the target command file.
|
||||
|
||||
## Objective
|
||||
|
||||
Generate the final command file by:
|
||||
1. Checking for existing file (warn if present)
|
||||
2. Writing formatted content to target path
|
||||
3. Confirming successful generation
|
||||
|
||||
## Input
|
||||
|
||||
From Phase 4:
|
||||
```javascript
|
||||
{
|
||||
status: 'formatted',
|
||||
content: string,
|
||||
targetPath: string,
|
||||
summary: {
|
||||
name: string,
|
||||
description: string,
|
||||
location: string,
|
||||
group: string | null,
|
||||
hasArgumentHint: boolean
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Pre-Write Check
|
||||
|
||||
```javascript
|
||||
// Check if file already exists
|
||||
const fileExists = Bash(`test -f "${targetPath}" && echo "EXISTS" || echo "NOT_FOUND"`);
|
||||
|
||||
if (fileExists.includes('EXISTS')) {
|
||||
console.warn(`
|
||||
WARNING: Command file already exists at: ${targetPath}
|
||||
The file will be overwritten with new content.
|
||||
`);
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Ensure Directory Exists
|
||||
|
||||
```javascript
|
||||
// Get directory from target path
|
||||
const targetDir = path.dirname(targetPath);
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
Bash(`mkdir -p "${targetDir}"`);
|
||||
```
|
||||
|
||||
### Step 3: Write File
|
||||
|
||||
```javascript
|
||||
// Write the formatted content
|
||||
Write(targetPath, content);
|
||||
```
|
||||
|
||||
### Step 4: Verify Write
|
||||
|
||||
```javascript
|
||||
// Confirm file was created
|
||||
const verifyExists = Bash(`test -f "${targetPath}" && echo "SUCCESS" || echo "FAILED"`);
|
||||
|
||||
if (!verifyExists.includes('SUCCESS')) {
|
||||
throw new Error(`Failed to create command file at ${targetPath}`);
|
||||
}
|
||||
|
||||
// Verify content was written
|
||||
const writtenContent = Read(targetPath);
|
||||
if (!writtenContent || writtenContent.length === 0) {
|
||||
throw new Error(`Command file created but appears to be empty`);
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Generate Success Report
|
||||
|
||||
```javascript
|
||||
const report = {
|
||||
status: 'completed',
|
||||
file: {
|
||||
path: targetPath,
|
||||
name: summary.name,
|
||||
location: summary.location,
|
||||
group: summary.group,
|
||||
size: writtenContent.length,
|
||||
created: new Date().toISOString()
|
||||
},
|
||||
command: {
|
||||
name: summary.name,
|
||||
description: summary.description,
|
||||
hasArgumentHint: summary.hasArgumentHint
|
||||
},
|
||||
nextSteps: [
|
||||
`Edit ${targetPath} to add implementation details`,
|
||||
'Add usage examples and execution flow',
|
||||
'Test the command with Claude Code'
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
### Success Output
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: 'completed',
|
||||
file: {
|
||||
path: '.claude/commands/issue/create.md',
|
||||
name: 'create',
|
||||
location: 'project',
|
||||
group: 'issue',
|
||||
size: 1234,
|
||||
created: '2026-02-27T12:00:00.000Z'
|
||||
},
|
||||
command: {
|
||||
name: 'create',
|
||||
description: 'Create structured issue from GitHub URL...',
|
||||
hasArgumentHint: true
|
||||
},
|
||||
nextSteps: [
|
||||
'Edit .claude/commands/issue/create.md to add implementation details',
|
||||
'Add usage examples and execution flow',
|
||||
'Test the command with Claude Code'
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Console Output
|
||||
|
||||
```
|
||||
Command generated successfully!
|
||||
|
||||
File: .claude/commands/issue/create.md
|
||||
Name: create
|
||||
Description: Create structured issue from GitHub URL...
|
||||
Location: project
|
||||
Group: issue
|
||||
|
||||
Next Steps:
|
||||
1. Edit .claude/commands/issue/create.md to add implementation details
|
||||
2. Add usage examples and execution flow
|
||||
3. Test the command with Claude Code
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Action |
|
||||
|-------|--------|
|
||||
| Directory creation failed | Throw error with directory path |
|
||||
| File write failed | Throw error with target path |
|
||||
| Empty file detected | Throw error and attempt cleanup |
|
||||
| Permission denied | Throw error with permission hint |
|
||||
|
||||
## Cleanup on Failure
|
||||
|
||||
```javascript
|
||||
// If any step fails, attempt to clean up partial artifacts
|
||||
function cleanup(targetPath) {
|
||||
try {
|
||||
Bash(`rm -f "${targetPath}"`);
|
||||
} catch (e) {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
The command file has been successfully generated. The skill execution is complete.
|
||||
|
||||
### Usage Example
|
||||
|
||||
```bash
|
||||
# Use the generated command
|
||||
/issue:create https://github.com/owner/repo/issues/123
|
||||
|
||||
# Or with the group prefix
|
||||
/issue:create "Login fails with special chars"
|
||||
```
|
||||
@@ -1,160 +1,65 @@
|
||||
# Command Design Specification
|
||||
|
||||
Guidelines and best practices for designing Claude Code command files.
|
||||
Guidelines for Claude Code command files generated by command-generator.
|
||||
|
||||
## Command File Structure
|
||||
|
||||
### YAML Frontmatter
|
||||
|
||||
Every command file must start with YAML frontmatter containing:
|
||||
## YAML Frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: command-name # Required: Command identifier (lowercase, hyphens)
|
||||
description: Description # Required: Brief description of command purpose
|
||||
argument-hint: "[args]" # Optional: Argument format hint
|
||||
allowed-tools: Tool1, Tool2 # Optional: Restricted tool set
|
||||
examples: # Optional: Usage examples
|
||||
- /command:example1
|
||||
- /command:example2 --flag
|
||||
name: command-name # Required: lowercase with hyphens
|
||||
description: Description # Required: brief purpose
|
||||
argument-hint: "[args]" # Optional: argument format hint
|
||||
allowed-tools: Tool1, Tool2 # Optional: restricted tool set
|
||||
---
|
||||
```
|
||||
|
||||
### Frontmatter Fields
|
||||
|
||||
| Field | Required | Description |
|
||||
|-------|----------|-------------|
|
||||
| `name` | Yes | Command identifier, lowercase with hyphens |
|
||||
| `description` | Yes | Brief description, appears in command listings |
|
||||
| `argument-hint` | No | Usage hint for arguments (shown in help) |
|
||||
| `allowed-tools` | No | Restrict available tools for this command |
|
||||
| `examples` | No | Array of usage examples |
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
### Command Names
|
||||
| Element | Convention | Examples |
|
||||
|---------|-----------|----------|
|
||||
| Command name | lowercase, hyphens, 2-3 words max | `deploy`, `create-issue` |
|
||||
| Group name | singular noun | `issue`, `session`, `workflow` |
|
||||
| Verbs for actions | imperative | `deploy`, `create`, `analyze` |
|
||||
|
||||
- Use lowercase letters only
|
||||
- Separate words with hyphens (`create-issue`, not `createIssue`)
|
||||
- Keep names short but descriptive (2-3 words max)
|
||||
- Use verbs for actions (`deploy`, `create`, `analyze`)
|
||||
|
||||
### Group Names
|
||||
|
||||
- Groups organize related commands
|
||||
- Use singular nouns (`issue`, `session`, `workflow`)
|
||||
- Common groups: `issue`, `workflow`, `session`, `memory`, `cli`
|
||||
|
||||
### Path Examples
|
||||
## Path Structure
|
||||
|
||||
```
|
||||
.claude/commands/deploy.md # Top-level command
|
||||
.claude/commands/issue/create.md # Grouped command
|
||||
.claude/commands/workflow/init.md # Grouped command
|
||||
~/.claude/commands/global-status.md # User-level command
|
||||
```
|
||||
|
||||
## Content Sections
|
||||
## Content Structure (GSD Style)
|
||||
|
||||
### Required Sections
|
||||
Generated commands should use XML semantic tags:
|
||||
|
||||
1. **Overview**: Brief description of command purpose
|
||||
2. **Usage**: Command syntax and examples
|
||||
3. **Execution Flow**: High-level process diagram
|
||||
| Tag | Required | Purpose |
|
||||
|-----|----------|---------|
|
||||
| `<purpose>` | Yes | What the command does, when invoked, what it produces |
|
||||
| `<required_reading>` | Yes | Files to read before execution (@ notation) |
|
||||
| `<process>` | Yes | Container for execution steps |
|
||||
| `<step name="...">` | Yes | Individual execution steps with snake_case names |
|
||||
| `<error_codes>` | No | Error code table with severity and description |
|
||||
| `<success_criteria>` | Yes | Checkbox list of verifiable completion conditions |
|
||||
|
||||
### Recommended Sections
|
||||
## Step Naming
|
||||
|
||||
4. **Implementation**: Code examples for each phase
|
||||
5. **Error Handling**: Error cases and recovery
|
||||
6. **Related Commands**: Links to related functionality
|
||||
- Use snake_case: `parse_input`, `validate_config`, `write_output`
|
||||
- Use action verbs: `discover`, `validate`, `spawn`, `collect`, `report`
|
||||
- First step gets `priority="first"` attribute
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Clear Purpose
|
||||
|
||||
Each command should do one thing well:
|
||||
## Error Messages
|
||||
|
||||
```
|
||||
Good: /issue:create - Create a new issue
|
||||
Bad: /issue:manage - Create, update, delete issues (too broad)
|
||||
```
|
||||
Good: Error: GitHub issue URL required
|
||||
Usage: /issue:create <github-url>
|
||||
|
||||
### 2. Consistent Structure
|
||||
|
||||
Follow the same pattern across all commands in a group:
|
||||
|
||||
```markdown
|
||||
# All issue commands should have:
|
||||
- Overview
|
||||
- Usage with examples
|
||||
- Phase-based implementation
|
||||
- Error handling table
|
||||
```
|
||||
|
||||
### 3. Progressive Detail
|
||||
|
||||
Start simple, add detail in phases:
|
||||
|
||||
```
|
||||
Phase 1: Quick overview
|
||||
Phase 2: Implementation details
|
||||
Phase 3: Edge cases and errors
|
||||
```
|
||||
|
||||
### 4. Reusable Patterns
|
||||
|
||||
Use consistent patterns for common operations:
|
||||
|
||||
```javascript
|
||||
// Input parsing pattern
|
||||
const args = parseArguments($ARGUMENTS);
|
||||
const flags = parseFlags($ARGUMENTS);
|
||||
|
||||
// Validation pattern
|
||||
if (!args.required) {
|
||||
throw new Error('Required argument missing');
|
||||
}
|
||||
Bad: Error: Invalid input
|
||||
```
|
||||
|
||||
## Scope Guidelines
|
||||
|
||||
### Project Commands (`.claude/commands/`)
|
||||
|
||||
- Project-specific workflows
|
||||
- Team conventions
|
||||
- Integration with project tools
|
||||
|
||||
### User Commands (`~/.claude/commands/`)
|
||||
|
||||
- Personal productivity tools
|
||||
- Cross-project utilities
|
||||
- Global configuration
|
||||
|
||||
## Error Messages
|
||||
|
||||
### Good Error Messages
|
||||
|
||||
```
|
||||
Error: GitHub issue URL required
|
||||
Usage: /issue:create <github-url>
|
||||
Example: /issue:create https://github.com/owner/repo/issues/123
|
||||
```
|
||||
|
||||
### Bad Error Messages
|
||||
|
||||
```
|
||||
Error: Invalid input
|
||||
```
|
||||
|
||||
## Testing Commands
|
||||
|
||||
After creating a command, test:
|
||||
|
||||
1. **Basic invocation**: Does it run without arguments?
|
||||
2. **Argument parsing**: Does it handle valid arguments?
|
||||
3. **Error cases**: Does it show helpful errors for invalid input?
|
||||
4. **Help text**: Is the usage clear?
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [SKILL-DESIGN-SPEC.md](../_shared/SKILL-DESIGN-SPEC.md) - Full skill design specification
|
||||
- [../skill-generator/SKILL.md](../skill-generator/SKILL.md) - Meta-skill for creating skills
|
||||
| Scope | Location | Use For |
|
||||
|-------|----------|---------|
|
||||
| Project | `.claude/commands/` | Team workflows, project integrations |
|
||||
| User | `~/.claude/commands/` | Personal tools, cross-project utilities |
|
||||
|
||||
@@ -1,75 +1,112 @@
|
||||
# Command Template — Structural Reference
|
||||
|
||||
This template defines the **structural pattern** for generated commands. The `draft_content` step uses this as a guide to generate concrete, domain-specific content — NOT as a literal copy target.
|
||||
|
||||
## Required Structure
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: {$SKILL_NAME}
|
||||
description: {$DESCRIPTION}
|
||||
argument-hint: {$ARGUMENT_HINT} # omit line if empty
|
||||
---
|
||||
name: {{name}}
|
||||
description: {{description}}
|
||||
{{#if argumentHint}}argument-hint: {{argumentHint}}
|
||||
{{/if}}---
|
||||
|
||||
# {{name}} Command
|
||||
<purpose>
|
||||
{2-3 concrete sentences: what it does + when invoked + what it produces}
|
||||
</purpose>
|
||||
|
||||
## Overview
|
||||
<required_reading>
|
||||
{@ references to files this command needs before execution}
|
||||
</required_reading>
|
||||
|
||||
[Describe the command purpose and what it does]
|
||||
<prerequisites> <!-- include when command uses external CLI tools -->
|
||||
- {tool} ({version}+) — {what it's used for}
|
||||
</prerequisites>
|
||||
|
||||
## Usage
|
||||
<process>
|
||||
|
||||
<step name="parse_input" priority="first">
|
||||
**Parse arguments and validate input.**
|
||||
|
||||
Parse `$ARGUMENTS` for:
|
||||
- {specific flags from $ARGUMENT_HINT}
|
||||
- {positional args}
|
||||
|
||||
{Decision routing table if multiple modes:}
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| flag present | set variable |
|
||||
| missing required | Error: "message" `# (see code: E001)` + `exit 1` |
|
||||
|
||||
</step>
|
||||
|
||||
<step name="{domain_action_1}">
|
||||
**{Concrete action description.}**
|
||||
|
||||
$STATE_VAR="default" <!-- Initialize BEFORE conditional -->
|
||||
|
||||
```bash
|
||||
/{{#if group}}{{group}}:{{/if}}{{name}} [arguments]
|
||||
# Use heredoc for multi-line output
|
||||
cat <<EOF > output-file
|
||||
{structured content with $VARIABLES}
|
||||
EOF
|
||||
|
||||
# Every error path: message + code ref + exit
|
||||
if [ ! -f "$REQUIRED_FILE" ]; then
|
||||
echo "Error: Required file missing" # (see code: E003)
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
**Examples**:
|
||||
```bash
|
||||
# Example 1: Basic usage
|
||||
/{{#if group}}{{group}}:{{/if}}{{name}}
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| success | Continue to next step |
|
||||
| failure | Error `# (see code: E0XX)`, exit 1 |
|
||||
</step>
|
||||
|
||||
# Example 2: With arguments
|
||||
/{{#if group}}{{group}}:{{/if}}{{name}} --option value
|
||||
<step name="report">
|
||||
**Format and display results.**
|
||||
|
||||
{Banner with status, file paths, next steps}
|
||||
</step>
|
||||
|
||||
</process>
|
||||
|
||||
<error_codes>
|
||||
|
||||
| Code | Severity | Description | Stage |
|
||||
|------|----------|-------------|-------|
|
||||
| E001 | error | {specific to parse_input validation} | parse_input |
|
||||
| E002 | error | {specific to domain action failure} | {step_name} |
|
||||
| W001 | warning | {specific recoverable condition} | {step_name} |
|
||||
|
||||
<!-- Every code MUST be referenced by `# (see code: EXXX)` in <process> -->
|
||||
</error_codes>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] {Input validated}
|
||||
- [ ] {Domain action 1 completed}
|
||||
- [ ] {Domain action 2 completed}
|
||||
- [ ] {Output produced / effect applied}
|
||||
</success_criteria>
|
||||
```
|
||||
|
||||
## Execution Flow
|
||||
## Content Quality Rules
|
||||
|
||||
```
|
||||
Phase 1: Input Parsing
|
||||
- Parse arguments and flags
|
||||
- Validate input parameters
|
||||
| Rule | Bad Example | Good Example |
|
||||
|------|-------------|--------------|
|
||||
| No bracket placeholders | `[Describe purpose]` | `Deploy to target environment with rollback on failure.` |
|
||||
| Concrete step names | `execute` | `run_deployment`, `validate_config` |
|
||||
| Specific error codes | `E001: Invalid input` | `E001: --env must be "prod" or "staging"` |
|
||||
| Verifiable criteria | `Command works` | `Deployment log written to .deploy/latest.log` |
|
||||
| Real shell commands | `# TODO: implement` | `kubectl apply -f $MANIFEST_PATH` |
|
||||
|
||||
Phase 2: Core Processing
|
||||
- Execute main logic
|
||||
- Handle edge cases
|
||||
## Step Naming Conventions
|
||||
|
||||
Phase 3: Output Generation
|
||||
- Format results
|
||||
- Display to user
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Phase 1: Input Parsing
|
||||
|
||||
```javascript
|
||||
// Parse command arguments
|
||||
const args = parseArguments($ARGUMENTS);
|
||||
```
|
||||
|
||||
### Phase 2: Core Processing
|
||||
|
||||
```javascript
|
||||
// TODO: Implement core logic
|
||||
```
|
||||
|
||||
### Phase 3: Output Generation
|
||||
|
||||
```javascript
|
||||
// TODO: Format and display output
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Action |
|
||||
|-------|--------|
|
||||
| Invalid input | Show usage and error message |
|
||||
| Processing failure | Log error and suggest recovery |
|
||||
|
||||
## Related Commands
|
||||
|
||||
- [Related command 1]
|
||||
- [Related command 2]
|
||||
| Domain | Typical Steps |
|
||||
|--------|--------------|
|
||||
| Deploy/Release | `validate_config`, `run_deployment`, `verify_health`, `report` |
|
||||
| CRUD operations | `parse_input`, `validate_entity`, `persist_changes`, `report` |
|
||||
| Analysis/Review | `parse_input`, `gather_context`, `run_analysis`, `present_findings` |
|
||||
| Sync/Migration | `parse_input`, `detect_changes`, `apply_sync`, `verify_state` |
|
||||
| Build/Generate | `parse_input`, `resolve_dependencies`, `run_build`, `write_output` |
|
||||
|
||||
Reference in New Issue
Block a user