Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:51:59 +08:00
commit 38e80921c8
89 changed files with 20480 additions and 0 deletions

View File

@@ -0,0 +1,430 @@
#!/usr/bin/env python3
"""
Command Generator - Generate Navigator slash command markdown files
Generates properly structured command files following Navigator conventions.
"""
from typing import Dict, List, Optional
from datetime import datetime
def generate_command(
name: str,
description: str,
complexity: str = "medium",
sections: Optional[Dict] = None
) -> str:
"""
Generate complete Navigator command markdown file.
Args:
name: Command name (kebab-case, without /nav: prefix)
description: One-line purpose description
complexity: Command complexity level ("simple", "medium", "complex")
sections: Dictionary of section content (optional, uses templates if not provided)
Returns:
Complete markdown content for the command file
Example:
>>> content = generate_command(
... name="example",
... description="Example command for testing",
... complexity="simple"
... )
>>> "---" in content and "description:" in content
True
"""
if sections is None:
sections = {}
# Validate inputs
valid, error = validate_command_name(name)
if not valid:
raise ValueError(f"Invalid command name: {error}")
if complexity not in ["simple", "medium", "complex"]:
raise ValueError(f"Complexity must be 'simple', 'medium', or 'complex', got: {complexity}")
# Generate frontmatter
frontmatter = f"""---
description: {description}
---"""
# Generate title
title = f"# {format_title(name)}"
# Generate content based on complexity
if complexity == "simple":
content = generate_simple_command(name, description, sections)
elif complexity == "medium":
content = generate_medium_command(name, description, sections)
else: # complex
content = generate_complex_command(name, description, sections)
# Combine all parts
return f"{frontmatter}\n\n{title}\n\n{content}"
def generate_simple_command(name: str, description: str, sections: Dict) -> str:
"""Generate content for a simple command."""
what_this_does = sections.get("what_this_does", f"[Explain what /nav:{name} does in 2-3 sentences]")
usage = sections.get("usage", f"/nav:{name}")
when_to_use = sections.get("when_to_use", [
"Scenario 1",
"Scenario 2",
"Scenario 3"
])
output_format = sections.get("output_format", "[Example output]")
troubleshooting = sections.get("troubleshooting", {
"Issue 1": "Solution 1",
"Issue 2": "Solution 2"
})
# Build when_to_use section
when_to_use_content = "\n\n".join([
f"**{scenario}**:\n```\n[Example]\n```" for scenario in when_to_use
])
# Build troubleshooting section
troubleshooting_content = "\n\n".join([
f"### {issue}\n\n**Problem**: [Description]\n\n**Solution**:\n{solution}"
for issue, solution in troubleshooting.items()
])
return f"""## What This Does
{what_this_does}
---
## Usage
```bash
{usage}
```
---
## When to Use
{when_to_use_content}
---
## Output Format
```
{output_format}
```
---
## Troubleshooting
{troubleshooting_content}
---
**[Closing statement about the command]** 🚀"""
def generate_medium_command(name: str, description: str, sections: Dict) -> str:
"""Generate content for a medium complexity command."""
overview = sections.get("overview", f"You are using Navigator's `/nav:{name}` command.\n\n[Explain context and purpose]")
what_this_does = sections.get("what_this_does", "[Detailed explanation with comparisons]")
when_to_use = sections.get("when_to_use", [f"Scenario {i+1}" for i in range(5)])
execution_steps = sections.get("execution_steps", [f"Step {i+1}" for i in range(3)])
troubleshooting = sections.get("troubleshooting", {f"Issue {i+1}": f"Solution {i+1}" for i in range(4)})
# Build when_to_use section
when_to_use_content = "\n\n".join([
f"**{scenario}**:\n```\n[Example]\n```" for scenario in when_to_use
])
# Build execution steps
execution_content = "\n\n".join([
f"### {step}\n\n[Instructions for this step]\n\n**Expected outcome**: [What happens]"
for step in execution_steps
])
# Build troubleshooting
troubleshooting_content = "\n\n".join([
f"### {issue}\n\n**Problem**: [Description]\n\n**Solutions**:\n1. {solution}\n2. [Additional solution]\n3. [Additional solution]"
for issue, solution in troubleshooting.items()
])
return f"""{overview}
---
## What This Does
{what_this_does}
---
## When to Use
{when_to_use_content}
---
## Execution Steps
{execution_content}
---
## Output Format
```
[Expected output format]
```
---
## Best Practices
- [Best practice 1]
- [Best practice 2]
- [Best practice 3]
---
## Troubleshooting
{troubleshooting_content}
---
**[Closing statement emphasizing key benefit]** 🚀"""
def generate_complex_command(name: str, description: str, sections: Dict) -> str:
"""Generate content for a complex command."""
return f"""You are executing the `/nav:{name}` command.
[Comprehensive overview explaining the command's role in Navigator workflow]
---
## What This Does
[Detailed explanation with comparisons to alternative approaches]
**Traditional approach**: [Manual process]
**With `/nav:{name}`**:
- [Benefit 1]
- [Benefit 2]
- [Benefit 3]
---
## EXECUTION PLAN
You will execute these steps in order. Each step has explicit outcomes.
---
### Step 1: Pre-Flight Checks
[Validation and preparation steps]
**Checks**:
- [ ] Check 1
- [ ] Check 2
- [ ] Check 3
---
### Step 2: [Main Operation]
[Detailed implementation instructions]
**Process**:
1. [Substep 1]
2. [Substep 2]
3. [Substep 3]
**Expected outcome**: [What should happen]
---
### Step 3: Validation
[Verification steps]
**Verify**:
- [ ] Verification 1
- [ ] Verification 2
- [ ] Verification 3
---
### Step 4: Completion
[Finalization and user feedback]
**Show summary**:
```
✅ [Success message]
[Summary of what was accomplished]
```
---
## Integration Notes
[How this command integrates with other Navigator features or external tools]
---
## Success Criteria
**This command succeeds when**:
- [ ] Criterion 1
- [ ] Criterion 2
- [ ] Criterion 3
- [ ] Criterion 4
---
## Troubleshooting
### Common Issue 1
**Error**: [Error message or symptom]
**Solution**:
[Detailed solution with commands]
### Common Issue 2
**Error**: [Error message or symptom]
**Solution**:
[Detailed solution]
### Edge Case 1
**Scenario**: [When this happens]
**Handling**:
[How to handle this case]
---
## Performance Notes
[Any performance considerations, optimization tips, or scalability notes]
---
**[Comprehensive closing statement]** 🚀"""
def validate_command_name(name: str) -> tuple[bool, Optional[str]]:
"""
Validate command name follows Navigator conventions.
Args:
name: Command name to validate
Returns:
Tuple of (is_valid, error_message)
Example:
>>> validate_command_name("my-command")
(True, None)
>>> validate_command_name("MyCommand")
(False, 'Command name must be kebab-case')
"""
import re
if not name:
return False, "Command name cannot be empty"
if not re.match(r'^[a-z][a-z0-9]*(-[a-z0-9]+)*$', name):
return False, "Command name must be kebab-case (lowercase, hyphens only)"
if len(name) > 50:
return False, "Command name too long (max 50 characters)"
# Reserved names
reserved = ["help", "clear", "reset"]
if name in reserved:
return False, f"Command name '{name}' is reserved"
return True, None
def format_title(name: str) -> str:
"""
Format command name as title.
Args:
name: Command name (kebab-case)
Returns:
Formatted title string
Example:
>>> format_title("update-doc")
'Update Doc - Navigator'
>>> format_title("marker")
'Marker - Navigator'
"""
# Convert kebab-case to Title Case
title = name.replace('-', ' ').title()
# Add Navigator branding
return f"{title} - Navigator"
def generate_description(name: str, purpose: str) -> str:
"""
Generate command description for YAML frontmatter.
Args:
name: Command name
purpose: Brief purpose statement
Returns:
Formatted description (under 100 chars)
Example:
>>> desc = generate_description("marker", "save conversation state")
>>> len(desc) < 100
True
"""
# Ensure it starts with a verb and is concise
if len(purpose) > 90:
purpose = purpose[:87] + "..."
return purpose
if __name__ == "__main__":
# Example usage
print("Generating simple command...")
simple = generate_command(
name="example",
description="Example command for demonstration",
complexity="simple"
)
print("\n" + "=" * 50)
print(simple[:500] + "...")
print("=" * 50)
# Validate names
test_names = ["my-command", "MyCommand", "my_command", "valid-name-123"]
print("\nValidation Tests:")
for name in test_names:
valid, error = validate_command_name(name)
status = "" if valid else ""
print(f"{status} {name}: {error or 'Valid'}")

View File

@@ -0,0 +1,323 @@
#!/usr/bin/env python3
"""
Command Validator - Validate Navigator slash command files
Validates command markdown files follow Navigator conventions and standards.
"""
import re
from typing import List, Tuple, Optional
from pathlib import Path
def validate_command_file(file_path: str) -> Tuple[bool, List[str]]:
"""
Validate complete command markdown file.
Args:
file_path: Path to command .md file
Returns:
Tuple of (is_valid, list_of_errors)
Example:
>>> valid, errors = validate_command_file("commands/marker.md")
>>> valid or len(errors) > 0
True
"""
errors = []
# Check file exists
path = Path(file_path)
if not path.exists():
return False, [f"File not found: {file_path}"]
# Read content
try:
content = path.read_text()
except Exception as e:
return False, [f"Cannot read file: {e}"]
# Validate sections
errors.extend(validate_frontmatter(content))
errors.extend(validate_structure(content))
errors.extend(validate_formatting(content))
errors.extend(validate_style(content))
return len(errors) == 0, errors
def validate_frontmatter(content: str) -> List[str]:
"""
Validate YAML frontmatter.
Args:
content: File content
Returns:
List of errors (empty if valid)
"""
errors = []
# Check frontmatter exists
if not content.startswith("---"):
errors.append("Missing YAML frontmatter (must start with '---')")
return errors
# Extract frontmatter
parts = content.split("---", 2)
if len(parts) < 3:
errors.append("Invalid frontmatter structure (must be surrounded by '---')")
return errors
frontmatter = parts[1].strip()
# Check description field
if "description:" not in frontmatter:
errors.append("Missing 'description' field in frontmatter")
else:
# Extract description value
desc_match = re.search(r'description:\s*(.+)', frontmatter)
if desc_match:
desc = desc_match.group(1).strip()
if not desc:
errors.append("Description field is empty")
elif len(desc) > 150:
errors.append(f"Description too long ({len(desc)} chars, max 150)")
else:
errors.append("Cannot parse description field")
# Check for invalid fields (Navigator commands use minimal frontmatter)
valid_fields = ["description", "author", "version", "deprecated"]
for line in frontmatter.split("\n"):
if ":" in line:
field = line.split(":")[0].strip()
if field and field not in valid_fields:
errors.append(f"Unexpected frontmatter field: '{field}'")
return errors
def validate_structure(content: str) -> List[str]:
"""
Validate document structure and required sections.
Args:
content: File content
Returns:
List of errors (empty if valid)
"""
errors = []
# Extract markdown body (after frontmatter)
parts = content.split("---", 2)
if len(parts) < 3:
return ["Cannot extract markdown body"]
body = parts[2].strip()
# Check for title (# heading)
if not body.startswith("#"):
errors.append("Missing main title (must start with # heading)")
else:
title_match = re.match(r'^#\s+(.+)$', body.split("\n")[0])
if not title_match:
errors.append("Invalid title format")
else:
title = title_match.group(1)
# Navigator commands typically end with " - Navigator" or context
if "navigator" not in title.lower() and "jitd" not in title.lower():
errors.append(f"Title should include Navigator branding: '{title}'")
# Check for required sections (vary by complexity, so we check for minimum)
required_keywords = ["what", "usage", "when"]
for keyword in required_keywords:
if keyword.lower() not in body.lower():
errors.append(f"Missing section with '{keyword}' (recommended sections: What This Does, Usage, When to Use)")
# Check for code blocks (commands should have examples)
if "```" not in body:
errors.append("No code blocks found (commands should include examples)")
# Check for closing statement
last_line = body.strip().split("\n")[-1]
if not last_line.startswith("**") or not last_line.endswith("**"):
errors.append("Missing closing statement (should be bold text at end)")
return errors
def validate_formatting(content: str) -> List[str]:
"""
Validate markdown formatting and syntax.
Args:
content: File content
Returns:
List of errors (empty if valid)
"""
errors = []
# Check for proper heading hierarchy
headings = re.findall(r'^(#{1,6})\s+(.+)$', content, re.MULTILINE)
prev_level = 0
for heading, text in headings:
level = len(heading)
if level > prev_level + 1:
errors.append(f"Heading hierarchy skip: {heading} {text} (jumped from h{prev_level} to h{level})")
prev_level = level
# Check for unclosed code blocks
code_block_count = content.count("```")
if code_block_count % 2 != 0:
errors.append(f"Unclosed code block (found {code_block_count} backticks, must be even)")
# Check for proper list formatting
lines = content.split("\n")
in_list = False
for i, line in enumerate(lines, 1):
if re.match(r'^\s*[-*+]\s+', line):
in_list = True
# Check indentation consistency
if not re.match(r'^( |\t)?[-*+]\s+\S', line):
errors.append(f"Line {i}: Improper list item format (needs space after bullet)")
elif in_list and line.strip() and not line.startswith(" ") and not line.startswith("\t"):
in_list = False
# Check for broken links (markdown links with empty href)
broken_links = re.findall(r'\[([^\]]+)\]\(\s*\)', content)
if broken_links:
errors.append(f"Broken markdown links found: {broken_links}")
return errors
def validate_style(content: str) -> List[str]:
"""
Validate Navigator style conventions.
Args:
content: File content
Returns:
List of errors (empty if valid)
"""
errors = []
# Check for 2nd person perspective (Navigator style)
first_person = ["I am", "I will", "I have", "we are", "we will", "we have"]
for phrase in first_person:
if phrase.lower() in content.lower():
errors.append(f"Use 2nd person perspective ('you are') not 1st person ('{phrase}')")
# Check emoji usage (Navigator commands use emojis sparingly)
# Common Navigator emojis: ✅ ❌ 📖 🚀 ⚠️ 💡 🔹
emoji_count = len(re.findall(r'[\U0001F300-\U0001F9FF]', content))
if emoji_count > 15:
errors.append(f"Too many emojis ({emoji_count} found, keep under 15 for professionalism)")
# Check for proper bash/shell syntax in code blocks
bash_blocks = re.findall(r'```(?:bash|shell|sh)\n(.*?)\n```', content, re.DOTALL)
for block in bash_blocks:
if "$(" in block and not re.search(r'\)\s*$', block, re.MULTILINE):
errors.append("Potential unclosed command substitution in bash block")
# Check for Navigator command references (should use /nav: prefix)
nav_cmds = re.findall(r'`/(?:jitd|nav):([a-z-]+)`', content)
jitd_cmds = re.findall(r'`/jitd:([a-z-]+)`', content)
if len(jitd_cmds) > len(nav_cmds) * 0.5: # More than 50% use old prefix
errors.append("Prefer /nav: prefix over /jitd: (for consistency)")
return errors
def validate_example_realism(content: str) -> List[str]:
"""
Check if examples are realistic (not placeholders).
Args:
content: File content
Returns:
List of warnings (empty if examples look good)
"""
warnings = []
# Check for common placeholder patterns
placeholders = [
r'\[.*?\]', # [placeholder]
r'<.*?>', # <placeholder>
r'\.\.\.+', # ...
r'TODO',
r'FIXME',
r'XXX',
]
code_blocks = re.findall(r'```.*?\n(.*?)\n```', content, re.DOTALL)
for block in code_blocks:
for pattern in placeholders:
if re.search(pattern, block):
warnings.append(f"Code block contains placeholder-like content: {pattern}")
break # One warning per block
return warnings
def quick_validate(file_path: str) -> bool:
"""
Quick validation check (returns only boolean).
Args:
file_path: Path to command file
Returns:
True if valid, False otherwise
"""
valid, _ = validate_command_file(file_path)
return valid
def print_validation_report(file_path: str):
"""
Print formatted validation report.
Args:
file_path: Path to command file
"""
valid, errors = validate_command_file(file_path)
print(f"\n{'='*60}")
print(f"Validation Report: {Path(file_path).name}")
print(f"{'='*60}\n")
if valid:
print("✅ All validations passed!")
print("\nFile is ready to use.")
else:
print(f"❌ Found {len(errors)} issue(s):\n")
for i, error in enumerate(errors, 1):
print(f"{i}. {error}")
print("\n" + "="*60)
print("Fix these issues before using the command.")
print()
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python command_validator.py <command-file.md>")
print("\nExample:")
print(" python command_validator.py commands/marker.md")
sys.exit(1)
file_path = sys.argv[1]
print_validation_report(file_path)
# Exit with error code if validation failed
if not quick_validate(file_path):
sys.exit(1)