@phuc1403/musketeer 0.7.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 (84) 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/inject-design-docs.cjs +13 -13
  7. package/template/.claude/hooks/inject-ubiquitous-language.cjs +52 -0
  8. package/template/.claude/hooks/lib/colors.cjs +180 -122
  9. package/template/.claude/hooks/lib/transcript-parser.cjs +300 -277
  10. package/template/.claude/skills/code-review/SKILL.md +201 -54
  11. package/template/.claude/skills/code-review/references/checklist-workflow.md +96 -0
  12. package/template/.claude/skills/code-review/references/checklists/api.md +52 -52
  13. package/template/.claude/skills/code-review/references/checklists/base.md +100 -100
  14. package/template/.claude/skills/code-review/references/checklists/web-app.md +54 -54
  15. package/template/.claude/skills/code-review/references/code-review-reception.md +113 -0
  16. package/template/.claude/skills/code-review/references/codebase-scan-workflow.md +30 -0
  17. package/template/.claude/skills/code-review/references/edge-case-scouting.md +119 -0
  18. package/template/.claude/skills/code-review/references/input-mode-resolution.md +135 -0
  19. package/template/.claude/skills/code-review/references/parallel-review-workflow.md +76 -0
  20. package/template/.claude/skills/code-review/references/requesting-code-review.md +116 -0
  21. package/template/.claude/skills/code-review/references/spec-compliance-review.md +43 -0
  22. package/template/.claude/skills/code-review/references/task-management-reviews.md +140 -0
  23. package/template/.claude/skills/code-review/references/verification-before-completion.md +139 -0
  24. package/template/.claude/skills/context-map/SKILL.md +1 -1
  25. package/template/.claude/skills/git/SKILL.md +131 -115
  26. package/template/.claude/skills/git/references/branch-management.md +88 -88
  27. package/template/.claude/skills/git/references/commit-standards.md +46 -46
  28. package/template/.claude/skills/git/references/context-efficiency.md +54 -0
  29. package/template/.claude/skills/git/references/gh-cli-guide.md +109 -109
  30. package/template/.claude/skills/git/references/safety-protocols.md +69 -69
  31. package/template/.claude/skills/git/references/workflow-commit.md +58 -58
  32. package/template/.claude/skills/git/references/workflow-merge-pr.md +136 -0
  33. package/template/.claude/skills/git/references/workflow-merge.md +48 -48
  34. package/template/.claude/skills/git/references/workflow-pr.md +58 -58
  35. package/template/.claude/skills/git/references/workflow-push.md +52 -52
  36. package/template/.claude/skills/knowledge-crunching/SKILL.md +56 -92
  37. package/template/.claude/skills/knowledge-crunching/assets/ubiquitous-language.template.md +3 -0
  38. package/template/.claude/skills/skill-creator/LICENSE.txt +201 -201
  39. package/template/.claude/skills/skill-creator/SKILL.md +154 -149
  40. package/template/.claude/skills/skill-creator/agents/analyzer.md +274 -274
  41. package/template/.claude/skills/skill-creator/agents/comparator.md +202 -202
  42. package/template/.claude/skills/skill-creator/agents/grader.md +223 -223
  43. package/template/.claude/skills/skill-creator/assets/eval_review.html +146 -146
  44. package/template/.claude/skills/skill-creator/eval-viewer/generate_review.py +471 -471
  45. package/template/.claude/skills/skill-creator/eval-viewer/viewer.html +1325 -1325
  46. package/template/.claude/skills/skill-creator/references/benchmark-optimization-guide.md +86 -86
  47. package/template/.claude/skills/skill-creator/references/distribution-guide.md +79 -79
  48. package/template/.claude/skills/skill-creator/references/eval-infrastructure-guide.md +129 -129
  49. package/template/.claude/skills/skill-creator/references/eval-schemas.md +121 -121
  50. package/template/.claude/skills/skill-creator/references/mcp-skills-integration.md +71 -71
  51. package/template/.claude/skills/skill-creator/references/metadata-quality-criteria.md +94 -94
  52. package/template/.claude/skills/skill-creator/references/plugin-marketplace-hosting.md +104 -104
  53. package/template/.claude/skills/skill-creator/references/plugin-marketplace-overview.md +89 -89
  54. package/template/.claude/skills/skill-creator/references/plugin-marketplace-schema.md +93 -93
  55. package/template/.claude/skills/skill-creator/references/plugin-marketplace-sources.md +103 -103
  56. package/template/.claude/skills/skill-creator/references/plugin-marketplace-troubleshooting.md +76 -76
  57. package/template/.claude/skills/skill-creator/references/script-quality-criteria.md +106 -106
  58. package/template/.claude/skills/skill-creator/references/skill-anatomy-and-requirements.md +77 -77
  59. package/template/.claude/skills/skill-creator/references/skill-creation-workflow.md +152 -151
  60. package/template/.claude/skills/skill-creator/references/skill-design-patterns.md +75 -75
  61. package/template/.claude/skills/skill-creator/references/skillmark-benchmark-criteria.md +102 -102
  62. package/template/.claude/skills/skill-creator/references/structure-organization-criteria.md +114 -114
  63. package/template/.claude/skills/skill-creator/references/testing-and-iteration.md +78 -78
  64. package/template/.claude/skills/skill-creator/references/token-efficiency-criteria.md +74 -74
  65. package/template/.claude/skills/skill-creator/references/troubleshooting-guide.md +81 -81
  66. package/template/.claude/skills/skill-creator/references/validation-checklist.md +83 -83
  67. package/template/.claude/skills/skill-creator/references/writing-effective-instructions.md +88 -88
  68. package/template/.claude/skills/skill-creator/references/yaml-frontmatter-reference.md +92 -92
  69. package/template/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +401 -401
  70. package/template/.claude/skills/skill-creator/scripts/encoding_utils.py +36 -36
  71. package/template/.claude/skills/skill-creator/scripts/generate_report.py +326 -326
  72. package/template/.claude/skills/skill-creator/scripts/improve_description.py +248 -248
  73. package/template/.claude/skills/skill-creator/scripts/init_skill.py +360 -360
  74. package/template/.claude/skills/skill-creator/scripts/package_skill.py +143 -143
  75. package/template/.claude/skills/skill-creator/scripts/quick_validate.py +110 -110
  76. package/template/.claude/skills/skill-creator/scripts/run_eval.py +310 -310
  77. package/template/.claude/skills/skill-creator/scripts/run_loop.py +332 -332
  78. package/template/.claude/skills/skill-creator/scripts/utils.py +47 -47
  79. package/template/.claude/statusline.cjs +0 -0
  80. package/template/.claude/hooks/inject-context.cjs +0 -52
  81. package/template/.claude/skills/code-review/references/adversarial-review.md +0 -223
  82. package/template/.claude/skills/knowledge-crunching/assets/context.template.md +0 -59
  83. package/template/.claude/skills/knowledge-crunching/references/crunching-dialogue.md +0 -113
  84. /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)