@phuc1403/musketeer 0.8.0 → 0.9.0

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.
Files changed (76) hide show
  1. package/README.md +49 -49
  2. package/manifest.json +333 -301
  3. package/package.json +1 -1
  4. package/template/.claude/agents/code-reviewer.md +182 -166
  5. package/template/.claude/hooks/git-skill-reminder.cjs +53 -0
  6. package/template/.claude/hooks/lib/colors.cjs +180 -122
  7. package/template/.claude/hooks/lib/transcript-parser.cjs +300 -277
  8. package/template/.claude/skills/code-review/SKILL.md +201 -54
  9. package/template/.claude/skills/code-review/references/checklist-workflow.md +96 -0
  10. package/template/.claude/skills/code-review/references/checklists/api.md +52 -52
  11. package/template/.claude/skills/code-review/references/checklists/base.md +100 -100
  12. package/template/.claude/skills/code-review/references/checklists/web-app.md +54 -54
  13. package/template/.claude/skills/code-review/references/code-review-reception.md +113 -0
  14. package/template/.claude/skills/code-review/references/codebase-scan-workflow.md +30 -0
  15. package/template/.claude/skills/code-review/references/edge-case-scouting.md +119 -0
  16. package/template/.claude/skills/code-review/references/input-mode-resolution.md +135 -0
  17. package/template/.claude/skills/code-review/references/parallel-review-workflow.md +76 -0
  18. package/template/.claude/skills/code-review/references/requesting-code-review.md +116 -0
  19. package/template/.claude/skills/code-review/references/spec-compliance-review.md +43 -0
  20. package/template/.claude/skills/code-review/references/task-management-reviews.md +140 -0
  21. package/template/.claude/skills/code-review/references/verification-before-completion.md +139 -0
  22. package/template/.claude/skills/git/SKILL.md +131 -115
  23. package/template/.claude/skills/git/references/branch-management.md +88 -88
  24. package/template/.claude/skills/git/references/commit-standards.md +46 -46
  25. package/template/.claude/skills/git/references/context-efficiency.md +54 -0
  26. package/template/.claude/skills/git/references/gh-cli-guide.md +109 -109
  27. package/template/.claude/skills/git/references/safety-protocols.md +69 -69
  28. package/template/.claude/skills/git/references/workflow-commit.md +58 -58
  29. package/template/.claude/skills/git/references/workflow-merge-pr.md +136 -0
  30. package/template/.claude/skills/git/references/workflow-merge.md +48 -48
  31. package/template/.claude/skills/git/references/workflow-pr.md +58 -58
  32. package/template/.claude/skills/git/references/workflow-push.md +52 -52
  33. package/template/.claude/skills/skill-creator/LICENSE.txt +201 -201
  34. package/template/.claude/skills/skill-creator/SKILL.md +154 -149
  35. package/template/.claude/skills/skill-creator/agents/analyzer.md +274 -274
  36. package/template/.claude/skills/skill-creator/agents/comparator.md +202 -202
  37. package/template/.claude/skills/skill-creator/agents/grader.md +223 -223
  38. package/template/.claude/skills/skill-creator/assets/eval_review.html +146 -146
  39. package/template/.claude/skills/skill-creator/eval-viewer/generate_review.py +471 -471
  40. package/template/.claude/skills/skill-creator/eval-viewer/viewer.html +1325 -1325
  41. package/template/.claude/skills/skill-creator/references/benchmark-optimization-guide.md +86 -86
  42. package/template/.claude/skills/skill-creator/references/distribution-guide.md +79 -79
  43. package/template/.claude/skills/skill-creator/references/eval-infrastructure-guide.md +129 -129
  44. package/template/.claude/skills/skill-creator/references/eval-schemas.md +121 -121
  45. package/template/.claude/skills/skill-creator/references/mcp-skills-integration.md +71 -71
  46. package/template/.claude/skills/skill-creator/references/metadata-quality-criteria.md +94 -94
  47. package/template/.claude/skills/skill-creator/references/plugin-marketplace-hosting.md +104 -104
  48. package/template/.claude/skills/skill-creator/references/plugin-marketplace-overview.md +89 -89
  49. package/template/.claude/skills/skill-creator/references/plugin-marketplace-schema.md +93 -93
  50. package/template/.claude/skills/skill-creator/references/plugin-marketplace-sources.md +103 -103
  51. package/template/.claude/skills/skill-creator/references/plugin-marketplace-troubleshooting.md +76 -76
  52. package/template/.claude/skills/skill-creator/references/script-quality-criteria.md +106 -106
  53. package/template/.claude/skills/skill-creator/references/skill-anatomy-and-requirements.md +77 -77
  54. package/template/.claude/skills/skill-creator/references/skill-creation-workflow.md +152 -151
  55. package/template/.claude/skills/skill-creator/references/skill-design-patterns.md +75 -75
  56. package/template/.claude/skills/skill-creator/references/skillmark-benchmark-criteria.md +102 -102
  57. package/template/.claude/skills/skill-creator/references/structure-organization-criteria.md +114 -114
  58. package/template/.claude/skills/skill-creator/references/testing-and-iteration.md +78 -78
  59. package/template/.claude/skills/skill-creator/references/token-efficiency-criteria.md +74 -74
  60. package/template/.claude/skills/skill-creator/references/troubleshooting-guide.md +81 -81
  61. package/template/.claude/skills/skill-creator/references/validation-checklist.md +83 -83
  62. package/template/.claude/skills/skill-creator/references/writing-effective-instructions.md +88 -88
  63. package/template/.claude/skills/skill-creator/references/yaml-frontmatter-reference.md +92 -92
  64. package/template/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +401 -401
  65. package/template/.claude/skills/skill-creator/scripts/encoding_utils.py +36 -36
  66. package/template/.claude/skills/skill-creator/scripts/generate_report.py +326 -326
  67. package/template/.claude/skills/skill-creator/scripts/improve_description.py +248 -248
  68. package/template/.claude/skills/skill-creator/scripts/init_skill.py +360 -360
  69. package/template/.claude/skills/skill-creator/scripts/package_skill.py +143 -143
  70. package/template/.claude/skills/skill-creator/scripts/quick_validate.py +110 -110
  71. package/template/.claude/skills/skill-creator/scripts/run_eval.py +310 -310
  72. package/template/.claude/skills/skill-creator/scripts/run_loop.py +332 -332
  73. package/template/.claude/skills/skill-creator/scripts/utils.py +47 -47
  74. package/template/.claude/statusline.cjs +0 -0
  75. package/template/.claude/skills/code-review/references/adversarial-review.md +0 -223
  76. /package/template/.claude/hooks/{usage-context-awareness.cjs → usage-quota-cache-refresh.cjs} +0 -0
@@ -1,143 +1,143 @@
1
- #!/usr/bin/env python3
2
- """
3
- Skill Packager - Creates a distributable zip file of a skill folder
4
-
5
- Usage:
6
- python utils/package_skill.py <path/to/skill-folder> [output-directory]
7
-
8
- Example:
9
- python utils/package_skill.py skills/public/my-skill
10
- python utils/package_skill.py skills/public/my-skill ./dist
11
- """
12
-
13
- import fnmatch
14
- import sys
15
- import zipfile
16
- from pathlib import Path
17
-
18
- from encoding_utils import configure_utf8_console
19
- from quick_validate import validate_skill
20
-
21
- # Fix Windows console encoding for Unicode output (emojis, arrows)
22
- configure_utf8_console()
23
-
24
- # Exclusion patterns (from official Anthropic skill-creator)
25
- EXCLUDE_DIRS = {'__pycache__', 'node_modules', '.git', '.DS_Store'}
26
- EXCLUDE_GLOBS = {'*.pyc', '*.pyo', '.DS_Store', '*.egg-info'}
27
- ROOT_EXCLUDE_DIRS = {'evals'} # Only excluded at skill root level
28
-
29
-
30
- def package_skill(skill_path, output_dir=None):
31
- """
32
- Package a skill folder into a zip file.
33
-
34
- Args:
35
- skill_path: Path to the skill folder
36
- output_dir: Optional output directory for the zip file (defaults to current directory)
37
-
38
- Returns:
39
- Path to the created zip file, or None if error
40
- """
41
- skill_path = Path(skill_path).resolve()
42
-
43
- # Validate skill folder exists
44
- if not skill_path.exists():
45
- print(f"❌ Error: Skill folder not found: {skill_path}")
46
- return None
47
-
48
- if not skill_path.is_dir():
49
- print(f"❌ Error: Path is not a directory: {skill_path}")
50
- return None
51
-
52
- # Validate SKILL.md exists
53
- skill_md = skill_path / "SKILL.md"
54
- if not skill_md.exists():
55
- print(f"❌ Error: SKILL.md not found in {skill_path}")
56
- return None
57
-
58
- # Run validation before packaging
59
- print("🔍 Validating skill...")
60
- valid, message = validate_skill(skill_path)
61
- if not valid:
62
- print(f"❌ Validation failed: {message}")
63
- print(" Please fix the validation errors before packaging.")
64
- return None
65
- print(f"✅ {message}\n")
66
-
67
- # Determine output location
68
- skill_name = skill_path.name
69
- if output_dir:
70
- output_path = Path(output_dir).resolve()
71
- output_path.mkdir(parents=True, exist_ok=True)
72
- else:
73
- output_path = Path.cwd()
74
-
75
- zip_filename = output_path / f"{skill_name}.zip"
76
-
77
- # Create the zip file
78
- try:
79
- with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
80
- # Walk through the skill directory, excluding unwanted files
81
- skipped = []
82
- for file_path in skill_path.rglob('*'):
83
- if file_path.is_file():
84
- rel = file_path.relative_to(skill_path)
85
- parts = rel.parts
86
-
87
- # Skip excluded directories
88
- if any(p in EXCLUDE_DIRS for p in parts):
89
- skipped.append(str(rel))
90
- continue
91
-
92
- # Skip root-only excluded dirs (e.g., evals/)
93
- if parts[0] in ROOT_EXCLUDE_DIRS:
94
- skipped.append(str(rel))
95
- continue
96
-
97
- # Skip excluded file patterns
98
- if any(fnmatch.fnmatch(file_path.name, g) for g in EXCLUDE_GLOBS):
99
- skipped.append(str(rel))
100
- continue
101
-
102
- arcname = file_path.relative_to(skill_path.parent)
103
- zipf.write(file_path, arcname)
104
- print(f" Added: {arcname}")
105
-
106
- if skipped:
107
- print(f"\n Skipped {len(skipped)} file(s): {', '.join(skipped[:5])}"
108
- + ("..." if len(skipped) > 5 else ""))
109
-
110
- print(f"\n✅ Successfully packaged skill to: {zip_filename}")
111
- return zip_filename
112
-
113
- except Exception as e:
114
- print(f"❌ Error creating zip file: {e}")
115
- return None
116
-
117
-
118
- def main():
119
- if len(sys.argv) < 2:
120
- print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
121
- print("\nExample:")
122
- print(" python utils/package_skill.py skills/public/my-skill")
123
- print(" python utils/package_skill.py skills/public/my-skill ./dist")
124
- sys.exit(1)
125
-
126
- skill_path = sys.argv[1]
127
- output_dir = sys.argv[2] if len(sys.argv) > 2 else None
128
-
129
- print(f"📦 Packaging skill: {skill_path}")
130
- if output_dir:
131
- print(f" Output directory: {output_dir}")
132
- print()
133
-
134
- result = package_skill(skill_path, output_dir)
135
-
136
- if result:
137
- sys.exit(0)
138
- else:
139
- sys.exit(1)
140
-
141
-
142
- if __name__ == "__main__":
143
- main()
1
+ #!/usr/bin/env python3
2
+ """
3
+ Skill Packager - Creates a distributable zip file of a skill folder
4
+
5
+ Usage:
6
+ python utils/package_skill.py <path/to/skill-folder> [output-directory]
7
+
8
+ Example:
9
+ python utils/package_skill.py skills/public/my-skill
10
+ python utils/package_skill.py skills/public/my-skill ./dist
11
+ """
12
+
13
+ import fnmatch
14
+ import sys
15
+ import zipfile
16
+ from pathlib import Path
17
+
18
+ from encoding_utils import configure_utf8_console
19
+ from quick_validate import validate_skill
20
+
21
+ # Fix Windows console encoding for Unicode output (emojis, arrows)
22
+ configure_utf8_console()
23
+
24
+ # Exclusion patterns (from official Anthropic skill-creator)
25
+ EXCLUDE_DIRS = {'__pycache__', 'node_modules', '.git', '.DS_Store'}
26
+ EXCLUDE_GLOBS = {'*.pyc', '*.pyo', '.DS_Store', '*.egg-info'}
27
+ ROOT_EXCLUDE_DIRS = {'evals'} # Only excluded at skill root level
28
+
29
+
30
+ def package_skill(skill_path, output_dir=None):
31
+ """
32
+ Package a skill folder into a zip file.
33
+
34
+ Args:
35
+ skill_path: Path to the skill folder
36
+ output_dir: Optional output directory for the zip file (defaults to current directory)
37
+
38
+ Returns:
39
+ Path to the created zip file, or None if error
40
+ """
41
+ skill_path = Path(skill_path).resolve()
42
+
43
+ # Validate skill folder exists
44
+ if not skill_path.exists():
45
+ print(f"❌ Error: Skill folder not found: {skill_path}")
46
+ return None
47
+
48
+ if not skill_path.is_dir():
49
+ print(f"❌ Error: Path is not a directory: {skill_path}")
50
+ return None
51
+
52
+ # Validate SKILL.md exists
53
+ skill_md = skill_path / "SKILL.md"
54
+ if not skill_md.exists():
55
+ print(f"❌ Error: SKILL.md not found in {skill_path}")
56
+ return None
57
+
58
+ # Run validation before packaging
59
+ print("🔍 Validating skill...")
60
+ valid, message = validate_skill(skill_path)
61
+ if not valid:
62
+ print(f"❌ Validation failed: {message}")
63
+ print(" Please fix the validation errors before packaging.")
64
+ return None
65
+ print(f"✅ {message}\n")
66
+
67
+ # Determine output location
68
+ skill_name = skill_path.name
69
+ if output_dir:
70
+ output_path = Path(output_dir).resolve()
71
+ output_path.mkdir(parents=True, exist_ok=True)
72
+ else:
73
+ output_path = Path.cwd()
74
+
75
+ zip_filename = output_path / f"{skill_name}.zip"
76
+
77
+ # Create the zip file
78
+ try:
79
+ with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
80
+ # Walk through the skill directory, excluding unwanted files
81
+ skipped = []
82
+ for file_path in skill_path.rglob('*'):
83
+ if file_path.is_file():
84
+ rel = file_path.relative_to(skill_path)
85
+ parts = rel.parts
86
+
87
+ # Skip excluded directories
88
+ if any(p in EXCLUDE_DIRS for p in parts):
89
+ skipped.append(str(rel))
90
+ continue
91
+
92
+ # Skip root-only excluded dirs (e.g., evals/)
93
+ if parts[0] in ROOT_EXCLUDE_DIRS:
94
+ skipped.append(str(rel))
95
+ continue
96
+
97
+ # Skip excluded file patterns
98
+ if any(fnmatch.fnmatch(file_path.name, g) for g in EXCLUDE_GLOBS):
99
+ skipped.append(str(rel))
100
+ continue
101
+
102
+ arcname = file_path.relative_to(skill_path.parent)
103
+ zipf.write(file_path, arcname)
104
+ print(f" Added: {arcname}")
105
+
106
+ if skipped:
107
+ print(f"\n Skipped {len(skipped)} file(s): {', '.join(skipped[:5])}"
108
+ + ("..." if len(skipped) > 5 else ""))
109
+
110
+ print(f"\n✅ Successfully packaged skill to: {zip_filename}")
111
+ return zip_filename
112
+
113
+ except Exception as e:
114
+ print(f"❌ Error creating zip file: {e}")
115
+ return None
116
+
117
+
118
+ def main():
119
+ if len(sys.argv) < 2:
120
+ print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
121
+ print("\nExample:")
122
+ print(" python utils/package_skill.py skills/public/my-skill")
123
+ print(" python utils/package_skill.py skills/public/my-skill ./dist")
124
+ sys.exit(1)
125
+
126
+ skill_path = sys.argv[1]
127
+ output_dir = sys.argv[2] if len(sys.argv) > 2 else None
128
+
129
+ print(f"📦 Packaging skill: {skill_path}")
130
+ if output_dir:
131
+ print(f" Output directory: {output_dir}")
132
+ print()
133
+
134
+ result = package_skill(skill_path, output_dir)
135
+
136
+ if result:
137
+ sys.exit(0)
138
+ else:
139
+ sys.exit(1)
140
+
141
+
142
+ if __name__ == "__main__":
143
+ main()
@@ -1,110 +1,110 @@
1
- #!/usr/bin/env python3
2
- """
3
- Quick validation script for skills - minimal version
4
- """
5
-
6
- import sys
7
- import re
8
- from pathlib import Path
9
-
10
- from encoding_utils import configure_utf8_console, read_text_utf8
11
-
12
- # Fix Windows console encoding for Unicode output
13
- configure_utf8_console()
14
-
15
- def validate_skill(skill_path):
16
- """Basic validation of a skill"""
17
- skill_path = Path(skill_path)
18
-
19
- # Check SKILL.md exists
20
- skill_md = skill_path / 'SKILL.md'
21
- if not skill_md.exists():
22
- return False, "SKILL.md not found"
23
-
24
- # Read and validate frontmatter
25
- content = read_text_utf8(skill_md)
26
- if not content.startswith('---'):
27
- return False, "No YAML frontmatter found"
28
-
29
- # Extract frontmatter
30
- match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
31
- if not match:
32
- return False, "Invalid frontmatter format"
33
-
34
- frontmatter = match.group(1)
35
-
36
- # Check required fields
37
- if 'name:' not in frontmatter:
38
- return False, "Missing 'name' in frontmatter"
39
- if 'description:' not in frontmatter:
40
- return False, "Missing 'description' in frontmatter"
41
-
42
- # Extract name for validation
43
- name_match = re.search(r'name:\s*(.+)', frontmatter)
44
- if name_match:
45
- name = name_match.group(1).strip().strip('"').strip("'")
46
-
47
- # Support namespaced identifiers: ck:skill-name (single namespace segment)
48
- if name.count(':') > 1:
49
- return False, (
50
- f"Name '{name}' is invalid. Use either 'skill-name' or "
51
- "'namespace:skill-name' with a single colon."
52
- )
53
-
54
- namespace = None
55
- skill_id = name
56
- if ':' in name:
57
- namespace, skill_id = name.split(':', 1)
58
-
59
- id_pattern = r'^[a-z0-9-]+$'
60
- if namespace and not re.match(id_pattern, namespace):
61
- return False, (
62
- f"Namespace '{namespace}' must be lowercase letters, digits, and hyphens only"
63
- )
64
-
65
- if not re.match(id_pattern, skill_id):
66
- return False, (
67
- f"Skill id '{skill_id}' must be lowercase letters, digits, and hyphens only"
68
- )
69
-
70
- for segment_name, segment in [("namespace", namespace), ("skill id", skill_id)]:
71
- if segment and (segment.startswith('-') or segment.endswith('-') or '--' in segment):
72
- return False, (
73
- f"{segment_name.capitalize()} '{segment}' cannot start/end with hyphen "
74
- "or contain consecutive hyphens"
75
- )
76
-
77
- # Validate name length (official max: 64 chars)
78
- if name_match:
79
- if len(skill_id) > 64:
80
- return False, f"Skill id '{skill_id}' exceeds 64 characters ({len(skill_id)})"
81
- if namespace and len(namespace) > 64:
82
- return False, f"Namespace '{namespace}' exceeds 64 characters ({len(namespace)})"
83
-
84
- # Extract and validate description
85
- desc_match = re.search(r'description:\s*(.+)', frontmatter)
86
- if desc_match:
87
- description = desc_match.group(1).strip().strip('"').strip("'")
88
-
89
- # YAML block scalar indicators are valid (e.g. description: >-)
90
- if description in {'>', '>-', '|', '|-'}:
91
- description = ''
92
-
93
- # Check for angle brackets
94
- if '<' in description or '>' in description:
95
- return False, "Description cannot contain angle brackets (< or >)"
96
-
97
- # Check description length (official max: 1024 chars)
98
- if len(description) > 1024:
99
- return False, f"Description exceeds 1024 characters ({len(description)})"
100
-
101
- return True, "Skill is valid!"
102
-
103
- if __name__ == "__main__":
104
- if len(sys.argv) != 2:
105
- print("Usage: python quick_validate.py <skill_directory>")
106
- sys.exit(1)
107
-
108
- valid, message = validate_skill(sys.argv[1])
109
- print(message)
110
- sys.exit(0 if valid else 1)
1
+ #!/usr/bin/env python3
2
+ """
3
+ Quick validation script for skills - minimal version
4
+ """
5
+
6
+ import sys
7
+ import re
8
+ from pathlib import Path
9
+
10
+ from encoding_utils import configure_utf8_console, read_text_utf8
11
+
12
+ # Fix Windows console encoding for Unicode output
13
+ configure_utf8_console()
14
+
15
+ def validate_skill(skill_path):
16
+ """Basic validation of a skill"""
17
+ skill_path = Path(skill_path)
18
+
19
+ # Check SKILL.md exists
20
+ skill_md = skill_path / 'SKILL.md'
21
+ if not skill_md.exists():
22
+ return False, "SKILL.md not found"
23
+
24
+ # Read and validate frontmatter
25
+ content = read_text_utf8(skill_md)
26
+ if not content.startswith('---'):
27
+ return False, "No YAML frontmatter found"
28
+
29
+ # Extract frontmatter
30
+ match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
31
+ if not match:
32
+ return False, "Invalid frontmatter format"
33
+
34
+ frontmatter = match.group(1)
35
+
36
+ # Check required fields
37
+ if 'name:' not in frontmatter:
38
+ return False, "Missing 'name' in frontmatter"
39
+ if 'description:' not in frontmatter:
40
+ return False, "Missing 'description' in frontmatter"
41
+
42
+ # Extract name for validation
43
+ name_match = re.search(r'name:\s*(.+)', frontmatter)
44
+ if name_match:
45
+ name = name_match.group(1).strip().strip('"').strip("'")
46
+
47
+ # Support namespaced identifiers: ck:skill-name (single namespace segment)
48
+ if name.count(':') > 1:
49
+ return False, (
50
+ f"Name '{name}' is invalid. Use either 'skill-name' or "
51
+ "'namespace:skill-name' with a single colon."
52
+ )
53
+
54
+ namespace = None
55
+ skill_id = name
56
+ if ':' in name:
57
+ namespace, skill_id = name.split(':', 1)
58
+
59
+ id_pattern = r'^[a-z0-9-]+$'
60
+ if namespace and not re.match(id_pattern, namespace):
61
+ return False, (
62
+ f"Namespace '{namespace}' must be lowercase letters, digits, and hyphens only"
63
+ )
64
+
65
+ if not re.match(id_pattern, skill_id):
66
+ return False, (
67
+ f"Skill id '{skill_id}' must be lowercase letters, digits, and hyphens only"
68
+ )
69
+
70
+ for segment_name, segment in [("namespace", namespace), ("skill id", skill_id)]:
71
+ if segment and (segment.startswith('-') or segment.endswith('-') or '--' in segment):
72
+ return False, (
73
+ f"{segment_name.capitalize()} '{segment}' cannot start/end with hyphen "
74
+ "or contain consecutive hyphens"
75
+ )
76
+
77
+ # Validate name length (official max: 64 chars)
78
+ if name_match:
79
+ if len(skill_id) > 64:
80
+ return False, f"Skill id '{skill_id}' exceeds 64 characters ({len(skill_id)})"
81
+ if namespace and len(namespace) > 64:
82
+ return False, f"Namespace '{namespace}' exceeds 64 characters ({len(namespace)})"
83
+
84
+ # Extract and validate description
85
+ desc_match = re.search(r'description:\s*(.+)', frontmatter)
86
+ if desc_match:
87
+ description = desc_match.group(1).strip().strip('"').strip("'")
88
+
89
+ # YAML block scalar indicators are valid (e.g. description: >-)
90
+ if description in {'>', '>-', '|', '|-'}:
91
+ description = ''
92
+
93
+ # Check for angle brackets
94
+ if '<' in description or '>' in description:
95
+ return False, "Description cannot contain angle brackets (< or >)"
96
+
97
+ # Check description length (official max: 1024 chars)
98
+ if len(description) > 1024:
99
+ return False, f"Description exceeds 1024 characters ({len(description)})"
100
+
101
+ return True, "Skill is valid!"
102
+
103
+ if __name__ == "__main__":
104
+ if len(sys.argv) != 2:
105
+ print("Usage: python quick_validate.py <skill_directory>")
106
+ sys.exit(1)
107
+
108
+ valid, message = validate_skill(sys.argv[1])
109
+ print(message)
110
+ sys.exit(0 if valid else 1)