panopticon-cli 0.4.6 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/skills/beads/README.md +120 -0
- package/skills/beads/SKILL.md +214 -0
- package/skills/beads/adr/0001-bd-prime-as-source-of-truth.md +59 -0
- package/skills/beads/resources/AGENTS.md +62 -0
- package/skills/beads/resources/ASYNC_GATES.md +168 -0
- package/skills/beads/resources/BOUNDARIES.md +469 -0
- package/skills/beads/resources/CHEMISTRY_PATTERNS.md +197 -0
- package/skills/beads/resources/CLI_REFERENCE.md +558 -0
- package/skills/beads/resources/DEPENDENCIES.md +747 -0
- package/skills/beads/resources/INTEGRATION_PATTERNS.md +407 -0
- package/skills/beads/resources/ISSUE_CREATION.md +139 -0
- package/skills/beads/resources/MOLECULES.md +354 -0
- package/skills/beads/resources/PATTERNS.md +341 -0
- package/skills/beads/resources/RESUMABILITY.md +207 -0
- package/skills/beads/resources/STATIC_DATA.md +54 -0
- package/skills/beads/resources/TROUBLESHOOTING.md +489 -0
- package/skills/beads/resources/WORKFLOWS.md +623 -0
- package/skills/beads/resources/WORKTREES.md +94 -0
- package/skills/beads-completion-check/SKILL.md +90 -0
- package/skills/beads-panopticon-guide/SKILL.md +171 -0
- package/skills/bug-fix/SKILL.md +32 -0
- package/skills/clear-writing/SKILL.md +105 -0
- package/skills/clear-writing/references/elements-of-style/01-introductory.md +3 -0
- package/skills/clear-writing/references/elements-of-style/02-elementary-rules-of-usage.md +214 -0
- package/skills/clear-writing/references/elements-of-style/03-elementary-principles-of-composition.md +398 -0
- package/skills/clear-writing/references/elements-of-style/04-a-few-matters-of-form.md +89 -0
- package/skills/clear-writing/references/elements-of-style/05-words-and-expressions-commonly-misused.md +342 -0
- package/skills/clear-writing/references/signs-of-ai-writing.md +901 -0
- package/skills/code-review/SKILL.md +37 -0
- package/skills/code-review-performance/SKILL.md +53 -0
- package/skills/code-review-security/SKILL.md +35 -0
- package/skills/dependency-update/SKILL.md +30 -0
- package/skills/feature-work/SKILL.md +39 -0
- package/skills/incident-response/SKILL.md +32 -0
- package/skills/knowledge-capture/SKILL.md +463 -0
- package/skills/onboard-codebase/SKILL.md +34 -0
- package/skills/opus-plan/SKILL.md +400 -0
- package/skills/pan-approve/SKILL.md +136 -0
- package/skills/pan-code-review/SKILL.md +249 -0
- package/skills/pan-config/SKILL.md +164 -0
- package/skills/pan-convoy-synthesis/SKILL.md +249 -0
- package/skills/pan-diagnose/SKILL.md +360 -0
- package/skills/pan-docker/SKILL.md +279 -0
- package/skills/pan-docs/SKILL.md +113 -0
- package/skills/pan-down/SKILL.md +434 -0
- package/skills/pan-health/SKILL.md +240 -0
- package/skills/pan-help/SKILL.md +237 -0
- package/skills/pan-install/SKILL.md +339 -0
- package/skills/pan-issue/SKILL.md +596 -0
- package/skills/pan-kill/SKILL.md +172 -0
- package/skills/pan-logs/SKILL.md +255 -0
- package/skills/pan-network/SKILL.md +320 -0
- package/skills/pan-oversee/SKILL.md +290 -0
- package/skills/pan-plan/SKILL.md +521 -0
- package/skills/pan-projects/SKILL.md +239 -0
- package/skills/pan-quickstart/SKILL.md +440 -0
- package/skills/pan-reload/SKILL.md +44 -0
- package/skills/pan-rescue/SKILL.md +271 -0
- package/skills/pan-restart/SKILL.md +53 -0
- package/skills/pan-setup/SKILL.md +478 -0
- package/skills/pan-skill-creator/SKILL.md +168 -0
- package/skills/pan-skill-creator/references/output-patterns.md +141 -0
- package/skills/pan-skill-creator/references/workflows.md +90 -0
- package/skills/pan-skill-creator/scripts/init_skill.py +176 -0
- package/skills/pan-status/SKILL.md +493 -0
- package/skills/pan-subagent-creator/SKILL.md +295 -0
- package/skills/pan-subagent-creator/assets/validate-readonly-query.sh +35 -0
- package/skills/pan-subagent-creator/references/example-agents.md +308 -0
- package/skills/pan-subagent-creator/scripts/init_agent.py +126 -0
- package/skills/pan-sync/SKILL.md +272 -0
- package/skills/pan-tell/SKILL.md +157 -0
- package/skills/pan-test-config/SKILL.md +208 -0
- package/skills/pan-tracker/SKILL.md +288 -0
- package/skills/pan-up/SKILL.md +458 -0
- package/skills/pan-workspace-config/SKILL.md +303 -0
- package/skills/refactor/SKILL.md +30 -0
- package/skills/refactor-radar/SKILL.md +475 -0
- package/skills/release/SKILL.md +25 -0
- package/skills/send-feedback-to-agent/SKILL.md +98 -0
- package/skills/session-health/SKILL.md +76 -0
- package/skills/session-health/scripts/check_sessions.py +166 -0
- package/skills/skill-creator/SKILL.md +92 -0
- package/skills/skill-creator/scripts/init_skill.py +152 -0
- package/skills/skill-creator/scripts/package_skill.py +123 -0
- package/skills/stitch-design-md/README.md +34 -0
- package/skills/stitch-design-md/SKILL.md +172 -0
- package/skills/stitch-design-md/examples/DESIGN.md +154 -0
- package/skills/stitch-react-components/README.md +36 -0
- package/skills/stitch-react-components/SKILL.md +47 -0
- package/skills/stitch-react-components/examples/gold-standard-card.tsx +80 -0
- package/skills/stitch-react-components/package-lock.json +231 -0
- package/skills/stitch-react-components/package.json +16 -0
- package/skills/stitch-react-components/resources/architecture-checklist.md +15 -0
- package/skills/stitch-react-components/resources/component-template.tsx +37 -0
- package/skills/stitch-react-components/resources/stitch-api-reference.md +14 -0
- package/skills/stitch-react-components/resources/style-guide.json +27 -0
- package/skills/stitch-react-components/scripts/fetch-stitch.sh +30 -0
- package/skills/stitch-react-components/scripts/validate.js +68 -0
- package/skills/stitch-setup/SKILL.md +94 -0
- package/skills/web-design-guidelines/SKILL.md +39 -0
- package/skills/work-complete/SKILL.md +79 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Session Health Checker - Detects stuck/corrupted Claude Code sessions
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python check_sessions.py [--fix] [--path PATH]
|
|
7
|
+
|
|
8
|
+
Detects:
|
|
9
|
+
- Warmup sidechain loops (tool calls returning "Warmup" errors)
|
|
10
|
+
- Excessive message counts (>500 messages)
|
|
11
|
+
- Infinite retry patterns (same command repeated >10 times)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import json
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
from collections import Counter
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def analyze_session(jsonl_path: Path) -> dict:
|
|
24
|
+
"""Analyze a single session file for health issues."""
|
|
25
|
+
issues = []
|
|
26
|
+
stats = {
|
|
27
|
+
"path": str(jsonl_path),
|
|
28
|
+
"name": jsonl_path.name,
|
|
29
|
+
"size_kb": jsonl_path.stat().st_size / 1024,
|
|
30
|
+
"message_count": 0,
|
|
31
|
+
"warmup_errors": 0,
|
|
32
|
+
"tool_calls": Counter(),
|
|
33
|
+
"is_sidechain": False,
|
|
34
|
+
"issues": [],
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
with open(jsonl_path, 'r') as f:
|
|
39
|
+
for line in f:
|
|
40
|
+
stats["message_count"] += 1
|
|
41
|
+
try:
|
|
42
|
+
msg = json.loads(line)
|
|
43
|
+
|
|
44
|
+
# Check if sidechain
|
|
45
|
+
if msg.get("isSidechain"):
|
|
46
|
+
stats["is_sidechain"] = True
|
|
47
|
+
|
|
48
|
+
# Check for warmup errors
|
|
49
|
+
if msg.get("type") == "user":
|
|
50
|
+
content = msg.get("message", {}).get("content", [])
|
|
51
|
+
if isinstance(content, list):
|
|
52
|
+
for item in content:
|
|
53
|
+
if isinstance(item, dict):
|
|
54
|
+
if item.get("content") == "Warmup" and item.get("is_error"):
|
|
55
|
+
stats["warmup_errors"] += 1
|
|
56
|
+
|
|
57
|
+
# Track tool calls
|
|
58
|
+
if msg.get("type") == "assistant":
|
|
59
|
+
content = msg.get("message", {}).get("content", [])
|
|
60
|
+
if isinstance(content, list):
|
|
61
|
+
for item in content:
|
|
62
|
+
if isinstance(item, dict) and item.get("type") == "tool_use":
|
|
63
|
+
tool_input = item.get("input", {})
|
|
64
|
+
if isinstance(tool_input, dict):
|
|
65
|
+
cmd = tool_input.get("command", item.get("name", "unknown"))
|
|
66
|
+
stats["tool_calls"][cmd] += 1
|
|
67
|
+
|
|
68
|
+
except json.JSONDecodeError:
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
except Exception as e:
|
|
72
|
+
stats["issues"].append(f"Error reading file: {e}")
|
|
73
|
+
return stats
|
|
74
|
+
|
|
75
|
+
# Detect issues
|
|
76
|
+
if stats["warmup_errors"] > 10:
|
|
77
|
+
stats["issues"].append(f"CRITICAL: Warmup loop detected ({stats['warmup_errors']} warmup errors)")
|
|
78
|
+
|
|
79
|
+
if stats["message_count"] > 500:
|
|
80
|
+
stats["issues"].append(f"WARNING: Excessive messages ({stats['message_count']})")
|
|
81
|
+
|
|
82
|
+
# Check for repeated commands
|
|
83
|
+
for cmd, count in stats["tool_calls"].most_common(5):
|
|
84
|
+
if count > 50:
|
|
85
|
+
stats["issues"].append(f"WARNING: Command repeated {count}x: {cmd[:50]}...")
|
|
86
|
+
|
|
87
|
+
if stats["size_kb"] > 2000: # > 2MB
|
|
88
|
+
stats["issues"].append(f"WARNING: Large session file ({stats['size_kb']:.0f}KB)")
|
|
89
|
+
|
|
90
|
+
return stats
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def find_sessions(base_path: Path) -> list:
|
|
94
|
+
"""Find all session files."""
|
|
95
|
+
sessions = []
|
|
96
|
+
for jsonl in base_path.rglob("*.jsonl"):
|
|
97
|
+
sessions.append(jsonl)
|
|
98
|
+
return sessions
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def main():
|
|
102
|
+
parser = argparse.ArgumentParser(description="Check Claude Code session health")
|
|
103
|
+
parser.add_argument("--fix", action="store_true", help="Remove problematic sessions")
|
|
104
|
+
parser.add_argument("--path", default=os.path.expanduser("~/.claude/projects"),
|
|
105
|
+
help="Path to projects directory")
|
|
106
|
+
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
107
|
+
args = parser.parse_args()
|
|
108
|
+
|
|
109
|
+
base_path = Path(args.path)
|
|
110
|
+
if not base_path.exists():
|
|
111
|
+
print(f"Path not found: {base_path}")
|
|
112
|
+
sys.exit(1)
|
|
113
|
+
|
|
114
|
+
sessions = find_sessions(base_path)
|
|
115
|
+
results = []
|
|
116
|
+
problematic = []
|
|
117
|
+
|
|
118
|
+
for session_path in sessions:
|
|
119
|
+
stats = analyze_session(session_path)
|
|
120
|
+
results.append(stats)
|
|
121
|
+
if stats["issues"]:
|
|
122
|
+
problematic.append(stats)
|
|
123
|
+
|
|
124
|
+
if args.json:
|
|
125
|
+
print(json.dumps(results, indent=2, default=str))
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
# Summary
|
|
129
|
+
print(f"\n{'='*60}")
|
|
130
|
+
print(f"SESSION HEALTH CHECK")
|
|
131
|
+
print(f"{'='*60}")
|
|
132
|
+
print(f"Total sessions: {len(sessions)}")
|
|
133
|
+
print(f"Problematic: {len(problematic)}")
|
|
134
|
+
|
|
135
|
+
if problematic:
|
|
136
|
+
print(f"\n{'='*60}")
|
|
137
|
+
print("ISSUES FOUND:")
|
|
138
|
+
print(f"{'='*60}")
|
|
139
|
+
|
|
140
|
+
for stats in problematic:
|
|
141
|
+
print(f"\n{stats['name']}")
|
|
142
|
+
print(f" Size: {stats['size_kb']:.0f}KB | Messages: {stats['message_count']}")
|
|
143
|
+
print(f" Warmup errors: {stats['warmup_errors']}")
|
|
144
|
+
print(f" Sidechain: {stats['is_sidechain']}")
|
|
145
|
+
for issue in stats["issues"]:
|
|
146
|
+
print(f" -> {issue}")
|
|
147
|
+
|
|
148
|
+
if args.fix:
|
|
149
|
+
print(f"\n{'='*60}")
|
|
150
|
+
print("CLEANING UP...")
|
|
151
|
+
print(f"{'='*60}")
|
|
152
|
+
for stats in problematic:
|
|
153
|
+
if any("CRITICAL" in i for i in stats["issues"]):
|
|
154
|
+
try:
|
|
155
|
+
os.remove(stats["path"])
|
|
156
|
+
print(f"Removed: {stats['name']}")
|
|
157
|
+
except Exception as e:
|
|
158
|
+
print(f"Failed to remove {stats['name']}: {e}")
|
|
159
|
+
else:
|
|
160
|
+
print("\nAll sessions healthy!")
|
|
161
|
+
|
|
162
|
+
return len(problematic)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
if __name__ == "__main__":
|
|
166
|
+
sys.exit(main())
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-creator
|
|
3
|
+
description: Guide for creating effective Claude Code skills. Use when users want to create a new skill, update an existing skill, or need guidance on skill best practices. Triggers on requests like "create a skill", "make a new skill", "help me build a skill", "skill development", or "extend Claude's capabilities".
|
|
4
|
+
license: Apache 2.0 (based on Anthropic's skills repo)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill Creator
|
|
8
|
+
|
|
9
|
+
Create effective skills that extend Claude's capabilities with specialized knowledge, workflows, and tools.
|
|
10
|
+
|
|
11
|
+
## Core Principles
|
|
12
|
+
|
|
13
|
+
### Concise is Key
|
|
14
|
+
The context window is shared. Only add what Claude doesn't already know. Challenge each piece: "Does this justify its token cost?"
|
|
15
|
+
|
|
16
|
+
### Degrees of Freedom
|
|
17
|
+
- **High freedom** (text instructions): Multiple valid approaches, context-dependent decisions
|
|
18
|
+
- **Medium freedom** (pseudocode/parameterized scripts): Preferred pattern exists, some variation OK
|
|
19
|
+
- **Low freedom** (specific scripts): Fragile operations, consistency critical
|
|
20
|
+
|
|
21
|
+
## Skill Anatomy
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
skill-name/
|
|
25
|
+
├── SKILL.md (required)
|
|
26
|
+
│ ├── YAML frontmatter (name, description - REQUIRED)
|
|
27
|
+
│ └── Markdown instructions
|
|
28
|
+
└── Bundled Resources (optional)
|
|
29
|
+
├── scripts/ - Executable code (deterministic, reusable)
|
|
30
|
+
├── references/ - Documentation loaded into context as needed
|
|
31
|
+
└── assets/ - Files used in output (templates, images)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Frontmatter (Critical)
|
|
35
|
+
```yaml
|
|
36
|
+
---
|
|
37
|
+
name: my-skill
|
|
38
|
+
description: What it does AND when to use it. This is the ONLY thing Claude sees to decide if the skill triggers. Be comprehensive.
|
|
39
|
+
---
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Progressive Disclosure
|
|
43
|
+
1. **Metadata** (~100 words) - Always in context
|
|
44
|
+
2. **SKILL.md body** (<5k words) - When skill triggers
|
|
45
|
+
3. **Bundled resources** - As needed
|
|
46
|
+
|
|
47
|
+
Keep SKILL.md under 500 lines. Split into references when approaching limit.
|
|
48
|
+
|
|
49
|
+
## Creation Process
|
|
50
|
+
|
|
51
|
+
### Step 1: Understand with Examples
|
|
52
|
+
- What functionality should this skill support?
|
|
53
|
+
- What would users say to trigger it?
|
|
54
|
+
- Can you give concrete usage examples?
|
|
55
|
+
|
|
56
|
+
### Step 2: Plan Reusable Contents
|
|
57
|
+
For each example, identify:
|
|
58
|
+
- Scripts for repetitive code
|
|
59
|
+
- References for documentation/schemas
|
|
60
|
+
- Assets for templates/boilerplate
|
|
61
|
+
|
|
62
|
+
### Step 3: Initialize
|
|
63
|
+
```bash
|
|
64
|
+
python scripts/init_skill.py <skill-name> --path <output-directory>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Step 4: Implement
|
|
68
|
+
1. Create scripts/, references/, assets/ files
|
|
69
|
+
2. Test scripts by actually running them
|
|
70
|
+
3. Write SKILL.md with:
|
|
71
|
+
- Comprehensive description in frontmatter
|
|
72
|
+
- Instructions referencing bundled resources
|
|
73
|
+
- Use imperative form ("Do X", not "You should do X")
|
|
74
|
+
|
|
75
|
+
### Step 5: Package
|
|
76
|
+
```bash
|
|
77
|
+
python scripts/package_skill.py <path/to/skill-folder> [output-dir]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 6: Iterate
|
|
81
|
+
Use skill on real tasks → Notice struggles → Update → Test again
|
|
82
|
+
|
|
83
|
+
## What NOT to Include
|
|
84
|
+
- README.md, CHANGELOG.md, INSTALLATION_GUIDE.md
|
|
85
|
+
- Setup/testing procedures
|
|
86
|
+
- User-facing documentation
|
|
87
|
+
- Anything not needed by the AI agent
|
|
88
|
+
|
|
89
|
+
## Reference Files
|
|
90
|
+
|
|
91
|
+
- See `references/workflows.md` for multi-step process patterns
|
|
92
|
+
- See `references/output-patterns.md` for output format patterns
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Skill Initializer - Creates a new skill from template
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python init_skill.py <skill-name> --path <output-directory>
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
python init_skill.py pdf-editor --path ./skills
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import re
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
SKILL_MD_TEMPLATE = '''---
|
|
18
|
+
name: {skill_name}
|
|
19
|
+
description: TODO - Describe what this skill does AND when to use it. Include trigger phrases.
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# {skill_title}
|
|
23
|
+
|
|
24
|
+
TODO: Write instructions for using this skill.
|
|
25
|
+
|
|
26
|
+
## Overview
|
|
27
|
+
|
|
28
|
+
TODO: Brief description of what this skill does.
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
TODO: How to use this skill.
|
|
33
|
+
|
|
34
|
+
## Resources
|
|
35
|
+
|
|
36
|
+
- `scripts/` - Executable automation scripts
|
|
37
|
+
- `references/` - Documentation loaded as needed
|
|
38
|
+
- `assets/` - Templates and files for output
|
|
39
|
+
'''
|
|
40
|
+
|
|
41
|
+
EXAMPLE_SCRIPT = '''#!/usr/bin/env python3
|
|
42
|
+
"""
|
|
43
|
+
Example script - replace with your actual script.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def main():
|
|
47
|
+
print("Hello from {skill_name}!")
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
main()
|
|
51
|
+
'''
|
|
52
|
+
|
|
53
|
+
EXAMPLE_REFERENCE = '''# {skill_title} Reference
|
|
54
|
+
|
|
55
|
+
This is an example reference file. Replace with actual documentation.
|
|
56
|
+
|
|
57
|
+
## Section 1
|
|
58
|
+
|
|
59
|
+
TODO: Add reference content here.
|
|
60
|
+
'''
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def validate_skill_name(name: str) -> bool:
|
|
64
|
+
"""Validate skill name follows conventions."""
|
|
65
|
+
if not re.match(r'^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$', name):
|
|
66
|
+
return False
|
|
67
|
+
if len(name) > 40:
|
|
68
|
+
return False
|
|
69
|
+
if '--' in name:
|
|
70
|
+
return False
|
|
71
|
+
return True
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def to_title(skill_name: str) -> str:
|
|
75
|
+
"""Convert skill-name to Skill Name."""
|
|
76
|
+
return ' '.join(word.capitalize() for word in skill_name.split('-'))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def init_skill(skill_name: str, output_path: Path) -> bool:
|
|
80
|
+
"""Initialize a new skill directory structure."""
|
|
81
|
+
|
|
82
|
+
if not validate_skill_name(skill_name):
|
|
83
|
+
print(f"Error: Invalid skill name '{skill_name}'")
|
|
84
|
+
print(" - Use lowercase letters, digits, and hyphens only")
|
|
85
|
+
print(" - Must start and end with letter or digit")
|
|
86
|
+
print(" - Maximum 40 characters")
|
|
87
|
+
print(" - No consecutive hyphens")
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
skill_dir = output_path / skill_name
|
|
91
|
+
|
|
92
|
+
if skill_dir.exists():
|
|
93
|
+
print(f"Error: Directory already exists: {skill_dir}")
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
skill_title = to_title(skill_name)
|
|
97
|
+
|
|
98
|
+
# Create directories
|
|
99
|
+
skill_dir.mkdir(parents=True)
|
|
100
|
+
(skill_dir / 'scripts').mkdir()
|
|
101
|
+
(skill_dir / 'references').mkdir()
|
|
102
|
+
(skill_dir / 'assets').mkdir()
|
|
103
|
+
|
|
104
|
+
# Create SKILL.md
|
|
105
|
+
skill_md = skill_dir / 'SKILL.md'
|
|
106
|
+
skill_md.write_text(SKILL_MD_TEMPLATE.format(
|
|
107
|
+
skill_name=skill_name,
|
|
108
|
+
skill_title=skill_title
|
|
109
|
+
))
|
|
110
|
+
|
|
111
|
+
# Create example script
|
|
112
|
+
example_script = skill_dir / 'scripts' / 'example.py'
|
|
113
|
+
example_script.write_text(EXAMPLE_SCRIPT.format(skill_name=skill_name))
|
|
114
|
+
example_script.chmod(0o755)
|
|
115
|
+
|
|
116
|
+
# Create example reference
|
|
117
|
+
example_ref = skill_dir / 'references' / 'example.md'
|
|
118
|
+
example_ref.write_text(EXAMPLE_REFERENCE.format(skill_title=skill_title))
|
|
119
|
+
|
|
120
|
+
# Create .gitkeep in assets
|
|
121
|
+
(skill_dir / 'assets' / '.gitkeep').touch()
|
|
122
|
+
|
|
123
|
+
print(f"Created skill: {skill_dir}")
|
|
124
|
+
print()
|
|
125
|
+
print("Next steps:")
|
|
126
|
+
print(f" 1. Edit {skill_dir}/SKILL.md")
|
|
127
|
+
print(f" 2. Add scripts to {skill_dir}/scripts/")
|
|
128
|
+
print(f" 3. Add references to {skill_dir}/references/")
|
|
129
|
+
print(f" 4. Add assets to {skill_dir}/assets/")
|
|
130
|
+
print(f" 5. Delete example files you don't need")
|
|
131
|
+
|
|
132
|
+
return True
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def main():
|
|
136
|
+
parser = argparse.ArgumentParser(description='Initialize a new skill')
|
|
137
|
+
parser.add_argument('skill_name', help='Name of the skill (hyphen-case)')
|
|
138
|
+
parser.add_argument('--path', required=True, help='Output directory')
|
|
139
|
+
|
|
140
|
+
args = parser.parse_args()
|
|
141
|
+
|
|
142
|
+
output_path = Path(args.path).resolve()
|
|
143
|
+
|
|
144
|
+
if not output_path.exists():
|
|
145
|
+
output_path.mkdir(parents=True)
|
|
146
|
+
|
|
147
|
+
success = init_skill(args.skill_name, output_path)
|
|
148
|
+
sys.exit(0 if success else 1)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if __name__ == "__main__":
|
|
152
|
+
main()
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Skill Packager - Creates a distributable .skill file
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python package_skill.py <path/to/skill-folder> [output-directory]
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
python package_skill.py ./my-skill
|
|
10
|
+
python package_skill.py ./my-skill ./dist
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
import zipfile
|
|
15
|
+
import re
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def validate_skill(skill_path: Path) -> tuple[bool, str]:
|
|
20
|
+
"""Validate skill structure and contents."""
|
|
21
|
+
|
|
22
|
+
skill_md = skill_path / "SKILL.md"
|
|
23
|
+
if not skill_md.exists():
|
|
24
|
+
return False, "SKILL.md not found"
|
|
25
|
+
|
|
26
|
+
content = skill_md.read_text()
|
|
27
|
+
|
|
28
|
+
# Check frontmatter
|
|
29
|
+
if not content.startswith('---'):
|
|
30
|
+
return False, "SKILL.md must start with YAML frontmatter (---)"
|
|
31
|
+
|
|
32
|
+
# Extract frontmatter
|
|
33
|
+
parts = content.split('---', 2)
|
|
34
|
+
if len(parts) < 3:
|
|
35
|
+
return False, "Invalid frontmatter format"
|
|
36
|
+
|
|
37
|
+
frontmatter = parts[1]
|
|
38
|
+
|
|
39
|
+
# Check required fields
|
|
40
|
+
if 'name:' not in frontmatter:
|
|
41
|
+
return False, "Frontmatter missing 'name' field"
|
|
42
|
+
if 'description:' not in frontmatter:
|
|
43
|
+
return False, "Frontmatter missing 'description' field"
|
|
44
|
+
|
|
45
|
+
# Check description isn't a TODO
|
|
46
|
+
if 'TODO' in frontmatter:
|
|
47
|
+
return False, "Frontmatter contains TODO - please complete the description"
|
|
48
|
+
|
|
49
|
+
# Check for body content
|
|
50
|
+
body = parts[2].strip()
|
|
51
|
+
if len(body) < 50:
|
|
52
|
+
return False, "SKILL.md body is too short"
|
|
53
|
+
|
|
54
|
+
return True, "Skill is valid"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def package_skill(skill_path: Path, output_dir: Path = None) -> Path:
|
|
58
|
+
"""Package a skill folder into a .skill file."""
|
|
59
|
+
|
|
60
|
+
if not skill_path.exists():
|
|
61
|
+
print(f"Error: Skill folder not found: {skill_path}")
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
if not skill_path.is_dir():
|
|
65
|
+
print(f"Error: Path is not a directory: {skill_path}")
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
# Validate
|
|
69
|
+
print("Validating skill...")
|
|
70
|
+
valid, message = validate_skill(skill_path)
|
|
71
|
+
if not valid:
|
|
72
|
+
print(f"Validation failed: {message}")
|
|
73
|
+
return None
|
|
74
|
+
print(f" {message}")
|
|
75
|
+
|
|
76
|
+
# Determine output
|
|
77
|
+
skill_name = skill_path.name
|
|
78
|
+
if output_dir:
|
|
79
|
+
output_dir = Path(output_dir).resolve()
|
|
80
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
81
|
+
else:
|
|
82
|
+
output_dir = Path.cwd()
|
|
83
|
+
|
|
84
|
+
skill_filename = output_dir / f"{skill_name}.skill"
|
|
85
|
+
|
|
86
|
+
# Create zip
|
|
87
|
+
try:
|
|
88
|
+
with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
|
89
|
+
for file_path in skill_path.rglob('*'):
|
|
90
|
+
if file_path.is_file():
|
|
91
|
+
# Skip common exclusions
|
|
92
|
+
if file_path.name.startswith('.') and file_path.name != '.gitkeep':
|
|
93
|
+
continue
|
|
94
|
+
if '__pycache__' in str(file_path):
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
arcname = file_path.relative_to(skill_path.parent)
|
|
98
|
+
zipf.write(file_path, arcname)
|
|
99
|
+
print(f" Added: {arcname}")
|
|
100
|
+
|
|
101
|
+
print(f"\nPackaged skill to: {skill_filename}")
|
|
102
|
+
return skill_filename
|
|
103
|
+
|
|
104
|
+
except Exception as e:
|
|
105
|
+
print(f"Error creating .skill file: {e}")
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def main():
|
|
110
|
+
if len(sys.argv) < 2:
|
|
111
|
+
print("Usage: python package_skill.py <path/to/skill-folder> [output-directory]")
|
|
112
|
+
sys.exit(1)
|
|
113
|
+
|
|
114
|
+
skill_path = Path(sys.argv[1]).resolve()
|
|
115
|
+
output_dir = Path(sys.argv[2]).resolve() if len(sys.argv) > 2 else None
|
|
116
|
+
|
|
117
|
+
print(f"Packaging skill: {skill_path}")
|
|
118
|
+
result = package_skill(skill_path, output_dir)
|
|
119
|
+
sys.exit(0 if result else 1)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
if __name__ == "__main__":
|
|
123
|
+
main()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Stitch Design System Documentation Skill
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx add-skill google-labs-code/stitch-skills --skill design-md --global
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Example Prompt
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
Analyze my Furniture Collection project's Home screen and generate a comprehensive DESIGN.md file documenting the design system.
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Skill Structure
|
|
16
|
+
|
|
17
|
+
This repository follows the **Agent Skills** open standard. Each skill is self-contained with its own logic, workflow, and reference materials.
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
design-md/
|
|
21
|
+
├── SKILL.md — Core instructions & workflow
|
|
22
|
+
├── examples/ — Sample DESIGN.md outputs
|
|
23
|
+
└── README.md — This file
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## How it Works
|
|
27
|
+
|
|
28
|
+
When activated, the agent follows a structured design analysis pipeline:
|
|
29
|
+
|
|
30
|
+
1. **Retrieval**: Uses the Stitch MCP Server to fetch project screens, HTML code, and design metadata.
|
|
31
|
+
2. **Extraction**: Identifies design tokens including colors, typography, spacing, and component patterns.
|
|
32
|
+
3. **Translation**: Converts technical CSS/Tailwind values into descriptive, natural design language.
|
|
33
|
+
4. **Synthesis**: Generates a comprehensive DESIGN.md following the semantic design system format.
|
|
34
|
+
5. **Alignment**: Ensures output follows Stitch Effective Prompting Guide principles for optimal screen generation.
|