Add /diff and /template commands
- /diff command to compare config with backups - Shows added/removed/changed files - JSON-aware comparison for config files - List available backups - /template command for session templates - Built-in templates: daily-standup, code-review, troubleshoot, deploy - Each template includes checklist, initial commands, prompt - Create custom templates interactively or non-interactively - Updated shell completions with 21 aliases total - Test suite now covers 29 tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
257
automation/session-template.py
Executable file
257
automation/session-template.py
Executable file
@@ -0,0 +1,257 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Manage session templates for common workflows.
|
||||
Usage: python3 session-template.py [--list|--create NAME|--use NAME|--delete NAME]
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
CLAUDE_DIR = Path.home() / ".claude"
|
||||
TEMPLATES_DIR = CLAUDE_DIR / "state" / "personal-assistant" / "templates"
|
||||
|
||||
|
||||
def ensure_templates_dir():
|
||||
"""Ensure templates directory exists."""
|
||||
TEMPLATES_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def load_template(name: str) -> Optional[Dict]:
|
||||
"""Load a template by name."""
|
||||
template_file = TEMPLATES_DIR / f"{name}.json"
|
||||
try:
|
||||
with open(template_file) as f:
|
||||
return json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
return None
|
||||
|
||||
|
||||
def save_template(name: str, template: Dict):
|
||||
"""Save a template."""
|
||||
ensure_templates_dir()
|
||||
template_file = TEMPLATES_DIR / f"{name}.json"
|
||||
with open(template_file, "w") as f:
|
||||
json.dump(template, f, indent=2)
|
||||
|
||||
|
||||
def list_templates():
|
||||
"""List available templates."""
|
||||
ensure_templates_dir()
|
||||
|
||||
templates = list(TEMPLATES_DIR.glob("*.json"))
|
||||
|
||||
if not templates:
|
||||
print("\nNo templates found. Create one with --create <name>")
|
||||
print("\nBuilt-in templates you can create:")
|
||||
print(" - daily-standup: Morning status check and planning")
|
||||
print(" - code-review: Review code changes")
|
||||
print(" - troubleshoot: Debug an issue")
|
||||
print(" - deploy: Deployment workflow")
|
||||
return
|
||||
|
||||
print(f"\n📋 Session Templates ({len(templates)})\n")
|
||||
|
||||
for t in sorted(templates):
|
||||
template = load_template(t.stem)
|
||||
if template:
|
||||
desc = template.get("description", "No description")
|
||||
category = template.get("category", "general")
|
||||
print(f" {t.stem}")
|
||||
print(f" Category: {category}")
|
||||
print(f" {desc}")
|
||||
print("")
|
||||
|
||||
|
||||
def create_template(name: str, interactive: bool = True):
|
||||
"""Create a new template."""
|
||||
ensure_templates_dir()
|
||||
|
||||
# Check for built-in templates
|
||||
builtin_templates = {
|
||||
"daily-standup": {
|
||||
"name": "daily-standup",
|
||||
"description": "Morning status check and planning",
|
||||
"category": "routine",
|
||||
"context_level": "moderate",
|
||||
"initial_commands": ["/status"],
|
||||
"checklist": [
|
||||
"Check system health",
|
||||
"Review pending items",
|
||||
"Check calendar",
|
||||
"Plan priorities"
|
||||
],
|
||||
"prompt_template": "Good morning! Let's start with a quick status check and plan the day."
|
||||
},
|
||||
"code-review": {
|
||||
"name": "code-review",
|
||||
"description": "Review code changes in a project",
|
||||
"category": "development",
|
||||
"context_level": "comprehensive",
|
||||
"initial_commands": [],
|
||||
"checklist": [
|
||||
"Understand the change scope",
|
||||
"Check for issues",
|
||||
"Verify tests",
|
||||
"Suggest improvements"
|
||||
],
|
||||
"prompt_template": "Please review the recent changes in {project}. Focus on {focus_areas}."
|
||||
},
|
||||
"troubleshoot": {
|
||||
"name": "troubleshoot",
|
||||
"description": "Debug an issue systematically",
|
||||
"category": "debugging",
|
||||
"context_level": "comprehensive",
|
||||
"initial_commands": ["/debug"],
|
||||
"checklist": [
|
||||
"Gather symptoms",
|
||||
"Check logs",
|
||||
"Identify root cause",
|
||||
"Implement fix",
|
||||
"Verify resolution"
|
||||
],
|
||||
"prompt_template": "I'm experiencing {issue}. Let's debug this systematically."
|
||||
},
|
||||
"deploy": {
|
||||
"name": "deploy",
|
||||
"description": "Deploy application to environment",
|
||||
"category": "operations",
|
||||
"context_level": "moderate",
|
||||
"initial_commands": ["/k8s:cluster-status"],
|
||||
"checklist": [
|
||||
"Verify cluster health",
|
||||
"Check application readiness",
|
||||
"Perform deployment",
|
||||
"Verify deployment",
|
||||
"Monitor for issues"
|
||||
],
|
||||
"prompt_template": "Deploy {app} to {environment}."
|
||||
}
|
||||
}
|
||||
|
||||
if name in builtin_templates:
|
||||
template = builtin_templates[name]
|
||||
save_template(name, template)
|
||||
print(f"✓ Created template from built-in: {name}")
|
||||
print(f" {template['description']}")
|
||||
return
|
||||
|
||||
if interactive:
|
||||
print(f"\nCreating new template: {name}\n")
|
||||
|
||||
template = {
|
||||
"name": name,
|
||||
"created": datetime.now().isoformat(),
|
||||
}
|
||||
|
||||
# Get details interactively
|
||||
template["description"] = input("Description: ").strip() or "No description"
|
||||
template["category"] = input("Category [general]: ").strip() or "general"
|
||||
template["context_level"] = input("Context level [moderate]: ").strip() or "moderate"
|
||||
|
||||
print("Initial commands (comma-separated, e.g., /status,/debug): ")
|
||||
commands = input("> ").strip()
|
||||
template["initial_commands"] = [c.strip() for c in commands.split(",") if c.strip()]
|
||||
|
||||
print("Checklist items (one per line, empty line to finish):")
|
||||
checklist = []
|
||||
while True:
|
||||
item = input(" - ").strip()
|
||||
if not item:
|
||||
break
|
||||
checklist.append(item)
|
||||
template["checklist"] = checklist
|
||||
|
||||
template["prompt_template"] = input("Prompt template: ").strip()
|
||||
|
||||
save_template(name, template)
|
||||
print(f"\n✓ Template '{name}' created successfully")
|
||||
else:
|
||||
# Create minimal template
|
||||
template = {
|
||||
"name": name,
|
||||
"description": "Custom template",
|
||||
"category": "custom",
|
||||
"context_level": "moderate",
|
||||
"initial_commands": [],
|
||||
"checklist": [],
|
||||
"prompt_template": "",
|
||||
"created": datetime.now().isoformat()
|
||||
}
|
||||
save_template(name, template)
|
||||
print(f"✓ Created empty template: {name}")
|
||||
print(f" Edit: {TEMPLATES_DIR / f'{name}.json'}")
|
||||
|
||||
|
||||
def use_template(name: str):
|
||||
"""Display template for use."""
|
||||
template = load_template(name)
|
||||
|
||||
if not template:
|
||||
print(f"Template '{name}' not found.")
|
||||
list_templates()
|
||||
return
|
||||
|
||||
print(f"\n📋 Template: {name}\n")
|
||||
print(f"Description: {template.get('description', 'No description')}")
|
||||
print(f"Category: {template.get('category', 'general')}")
|
||||
print(f"Context: {template.get('context_level', 'moderate')}")
|
||||
|
||||
commands = template.get("initial_commands", [])
|
||||
if commands:
|
||||
print(f"\nInitial commands:")
|
||||
for cmd in commands:
|
||||
print(f" {cmd}")
|
||||
|
||||
checklist = template.get("checklist", [])
|
||||
if checklist:
|
||||
print(f"\nChecklist:")
|
||||
for i, item in enumerate(checklist, 1):
|
||||
print(f" [ ] {item}")
|
||||
|
||||
prompt = template.get("prompt_template", "")
|
||||
if prompt:
|
||||
print(f"\nPrompt template:")
|
||||
print(f" {prompt}")
|
||||
|
||||
print("")
|
||||
|
||||
|
||||
def delete_template(name: str):
|
||||
"""Delete a template."""
|
||||
template_file = TEMPLATES_DIR / f"{name}.json"
|
||||
|
||||
if not template_file.exists():
|
||||
print(f"Template '{name}' not found.")
|
||||
return
|
||||
|
||||
template_file.unlink()
|
||||
print(f"✓ Deleted template: {name}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Manage session templates")
|
||||
parser.add_argument("--list", "-l", action="store_true", help="List templates")
|
||||
parser.add_argument("--create", "-c", type=str, help="Create a template")
|
||||
parser.add_argument("--use", "-u", type=str, help="Use a template")
|
||||
parser.add_argument("--delete", "-d", type=str, help="Delete a template")
|
||||
parser.add_argument("--non-interactive", "-n", action="store_true",
|
||||
help="Non-interactive mode for --create")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.create:
|
||||
create_template(args.create, interactive=not args.non_interactive)
|
||||
elif args.use:
|
||||
use_template(args.use)
|
||||
elif args.delete:
|
||||
delete_template(args.delete)
|
||||
else:
|
||||
list_templates()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user