claude-skills-cli 0.0.5 → 0.0.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/README.md +34 -9
- package/dist/commands/init.js +5 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.js +1 -1
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/stats.js +1 -1
- package/dist/commands/stats.js.map +1 -1
- package/dist/commands/validate.js +24 -3
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/watch.js +82 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/core/validator.js +169 -321
- package/dist/core/validator.js.map +1 -1
- package/dist/index.js +23 -12
- package/dist/index.js.map +1 -1
- package/dist/skills/skill-creator/SKILL.md +26 -108
- package/dist/skills/skill-creator/references/cli-reference.md +35 -35
- package/dist/skills/skill-creator/references/development-process.md +208 -0
- package/dist/skills/skill-creator/references/skill-examples.md +1 -1
- package/dist/validators/alignment-validator.js +54 -0
- package/dist/validators/alignment-validator.js.map +1 -0
- package/dist/validators/content-validator.js +144 -0
- package/dist/validators/content-validator.js.map +1 -0
- package/dist/validators/description-validator.js +136 -0
- package/dist/validators/description-validator.js.map +1 -0
- package/dist/validators/file-structure-validator.js +125 -0
- package/dist/validators/file-structure-validator.js.map +1 -0
- package/dist/validators/frontmatter-validator.js +114 -0
- package/dist/validators/frontmatter-validator.js.map +1 -0
- package/dist/validators/references-validator.js +125 -0
- package/dist/validators/references-validator.js.map +1 -0
- package/dist/validators/text-analysis.js +71 -0
- package/dist/validators/text-analysis.js.map +1 -0
- package/docs/CLI-IMPROVEMENTS.md +960 -0
- package/docs/SKILL-CREATOR-UPDATES.md +1071 -0
- package/docs/SKILL-DEVELOPMENT.md +10 -10
- package/docs/SKILLS-ARCHITECTURE.md +1 -1
- package/docs/SKILLS-ECOSYSTEM-ANALYSIS.md +509 -0
- package/docs/SKILLS-OPPORTUNITIES.md +652 -0
- package/package.json +4 -4
- package/dist/skills/skill-creator/skill-creator/SKILL.md +0 -143
- package/dist/skills/skill-creator/skill-creator/references/anthropic-resources.md +0 -504
- package/dist/skills/skill-creator/skill-creator/references/cli-reference.md +0 -507
- package/dist/skills/skill-creator/skill-creator/references/skill-examples.md +0 -413
- package/dist/skills/skill-creator/skill-creator/references/writing-guide.md +0 -619
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content validation (Level 2 progressive disclosure)
|
|
3
|
+
*/
|
|
4
|
+
import { count_words, estimate_tokens, strip_html_comments, } from './text-analysis.js';
|
|
5
|
+
// Progressive disclosure limits (enforced as hard limits)
|
|
6
|
+
const MAX_WORDS = 1000; // Hard limit (was recommended)
|
|
7
|
+
const RECOMMENDED_WORDS = 500; // Warning threshold
|
|
8
|
+
/**
|
|
9
|
+
* Analyze content structure and patterns
|
|
10
|
+
*/
|
|
11
|
+
export function analyze_content_structure(body) {
|
|
12
|
+
// Count code blocks
|
|
13
|
+
const code_block_matches = body.match(/```[\s\S]*?```/g);
|
|
14
|
+
const code_blocks = code_block_matches
|
|
15
|
+
? code_block_matches.length
|
|
16
|
+
: 0;
|
|
17
|
+
// Count markdown sections (headings)
|
|
18
|
+
const heading_matches = body.match(/^#{1,6}\s/gm);
|
|
19
|
+
const sections = heading_matches ? heading_matches.length : 0;
|
|
20
|
+
// Count long paragraphs (>100 words)
|
|
21
|
+
const paragraphs = body.split(/\n\n+/);
|
|
22
|
+
const long_paragraphs = paragraphs.filter((p) => {
|
|
23
|
+
const words = count_words(p);
|
|
24
|
+
return words > 100;
|
|
25
|
+
}).length;
|
|
26
|
+
return { code_blocks, sections, long_paragraphs };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validate progressive disclosure (word count, token budget, and line count)
|
|
30
|
+
*/
|
|
31
|
+
export function validate_content(body) {
|
|
32
|
+
const word_count = count_words(body);
|
|
33
|
+
const estimated_tokens = estimate_tokens(word_count);
|
|
34
|
+
// Strip HTML comments before counting lines (progressive disclosure guidance shouldn't inflate count)
|
|
35
|
+
const body_without_comments = strip_html_comments(body);
|
|
36
|
+
const line_count = body_without_comments.trim().split('\n').length;
|
|
37
|
+
// Analyze content structure
|
|
38
|
+
const structure = analyze_content_structure(body);
|
|
39
|
+
const validation = {
|
|
40
|
+
stats: {
|
|
41
|
+
word_count,
|
|
42
|
+
estimated_tokens,
|
|
43
|
+
line_count,
|
|
44
|
+
...structure,
|
|
45
|
+
},
|
|
46
|
+
warnings: [],
|
|
47
|
+
errors: [],
|
|
48
|
+
};
|
|
49
|
+
// Hard limit check (error) - enforced at 1000 words
|
|
50
|
+
if (word_count > MAX_WORDS) {
|
|
51
|
+
validation.errors.push({
|
|
52
|
+
type: 'word_count',
|
|
53
|
+
message: `SKILL.md body has ${word_count} words (MAX: ${MAX_WORDS})\n` +
|
|
54
|
+
` → Move detailed content to references/ directory for Level 3 loading\n` +
|
|
55
|
+
` → This is a hard limit - skills must be concise`,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Warning threshold at 500 words
|
|
59
|
+
else if (word_count > RECOMMENDED_WORDS) {
|
|
60
|
+
validation.warnings.push({
|
|
61
|
+
type: 'word_count',
|
|
62
|
+
message: `SKILL.md body has ${word_count} words (recommended: <${RECOMMENDED_WORDS}, max: ${MAX_WORDS})\n` +
|
|
63
|
+
` → Consider moving examples/docs to references/ for better token efficiency`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// Line count validation (Level 2 progressive disclosure)
|
|
67
|
+
// Hard limit: 50 lines (enforced)
|
|
68
|
+
if (line_count > 50) {
|
|
69
|
+
validation.errors.push({
|
|
70
|
+
type: 'line_count',
|
|
71
|
+
message: `SKILL.md body is ${line_count} lines (MAX: 50 for Level 2 progressive disclosure)\n` +
|
|
72
|
+
` → Move detailed content to references/ directory\n` +
|
|
73
|
+
` → This is a hard limit - skills must be concise`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else if (line_count > 40) {
|
|
77
|
+
validation.warnings.push({
|
|
78
|
+
type: 'line_count',
|
|
79
|
+
message: `SKILL.md body is ${line_count} lines (recommended: ~40, max: 50)\n` +
|
|
80
|
+
` → Consider moving examples to references/ for Level 3 loading`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// Content analysis warnings
|
|
84
|
+
// Code blocks: Recommend 1-2, warn at >3
|
|
85
|
+
if (structure.code_blocks > 3) {
|
|
86
|
+
validation.warnings.push({
|
|
87
|
+
type: 'code_blocks',
|
|
88
|
+
message: `SKILL.md contains ${structure.code_blocks} code examples (recommended: 1-2)\n` +
|
|
89
|
+
` → Move additional examples to references/examples.md for Level 3 loading`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// Long paragraphs
|
|
93
|
+
if (structure.long_paragraphs > 3) {
|
|
94
|
+
validation.warnings.push({
|
|
95
|
+
type: 'long_paragraphs',
|
|
96
|
+
message: `SKILL.md contains ${structure.long_paragraphs} lengthy paragraphs (>100 words)\n` +
|
|
97
|
+
` → Consider moving detailed explanations to references/`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// Sections: Recommend 3-5, warn at >8
|
|
101
|
+
if (structure.sections > 8) {
|
|
102
|
+
validation.warnings.push({
|
|
103
|
+
type: 'sections',
|
|
104
|
+
message: `SKILL.md contains ${structure.sections} sections (recommended: 3-5)\n` +
|
|
105
|
+
` → Consider splitting into focused reference files`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Check for "Quick Start" section
|
|
109
|
+
if (!body.includes('## Quick Start') &&
|
|
110
|
+
!body.includes('## Quick start')) {
|
|
111
|
+
validation.warnings.push({
|
|
112
|
+
type: 'missing_quick_start',
|
|
113
|
+
message: `Missing "## Quick Start" section\n` +
|
|
114
|
+
` → Add one minimal working example to help Claude get started quickly`,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// Check for references/ links when body is long
|
|
118
|
+
const has_references = body.includes('references/');
|
|
119
|
+
if (!has_references && line_count > 60) {
|
|
120
|
+
validation.warnings.push({
|
|
121
|
+
type: 'no_references',
|
|
122
|
+
message: `No references/ links found but SKILL.md is ${line_count} lines\n` +
|
|
123
|
+
` → Consider splitting detailed content into reference files`,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Check body content
|
|
127
|
+
if (body.trim().length < 100) {
|
|
128
|
+
validation.warnings.push({
|
|
129
|
+
type: 'short_body',
|
|
130
|
+
message: 'SKILL.md body is very short',
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
// Check for TODO placeholders
|
|
134
|
+
if (body.includes('TODO') ||
|
|
135
|
+
body.includes('[Add your') ||
|
|
136
|
+
body.includes('[Provide')) {
|
|
137
|
+
validation.warnings.push({
|
|
138
|
+
type: 'todo_placeholders',
|
|
139
|
+
message: 'SKILL.md contains TODO placeholders',
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return validation;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=content-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-validator.js","sourceRoot":"","sources":["../../src/validators/content-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Description validation (Level 1 progressive disclosure)
|
|
3
|
+
*/
|
|
4
|
+
import { estimate_string_tokens, } from './text-analysis.js';
|
|
5
|
+
/**
|
|
6
|
+
* Validate description length and quality
|
|
7
|
+
*/
|
|
8
|
+
export function validate_description_content(description) {
|
|
9
|
+
const desc_length = description.length;
|
|
10
|
+
const desc_tokens = estimate_string_tokens(description);
|
|
11
|
+
const validation = {
|
|
12
|
+
stats: {
|
|
13
|
+
description_length: desc_length,
|
|
14
|
+
description_tokens: desc_tokens,
|
|
15
|
+
},
|
|
16
|
+
warnings: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
};
|
|
19
|
+
// Enforced limit: 300 chars (prevents Claude from bloating descriptions)
|
|
20
|
+
// Anthropic allows 1024, but that leads to verbose, inefficient descriptions
|
|
21
|
+
if (desc_length > 300) {
|
|
22
|
+
validation.errors.push({
|
|
23
|
+
type: 'length',
|
|
24
|
+
message: `Description is ${desc_length} characters (MAX: 300 for efficiency)\n` +
|
|
25
|
+
` → Keep descriptions concise - quality over quantity`,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else if (desc_length > 200) {
|
|
29
|
+
validation.warnings.push({
|
|
30
|
+
type: 'length',
|
|
31
|
+
message: `Description is ${desc_length} characters (recommended: <200)\n` +
|
|
32
|
+
` → Estimated ~${desc_tokens} tokens - consider shortening`,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// Check for trigger keywords
|
|
36
|
+
const lower_desc = description.toLowerCase();
|
|
37
|
+
const has_trigger = lower_desc.includes('use when') ||
|
|
38
|
+
lower_desc.includes('use for') ||
|
|
39
|
+
lower_desc.includes('use to');
|
|
40
|
+
if (!has_trigger) {
|
|
41
|
+
validation.warnings.push({
|
|
42
|
+
type: 'trigger',
|
|
43
|
+
message: `Description missing trigger keywords ('Use when...', 'Use for...', 'Use to...')\n` +
|
|
44
|
+
` → Help Claude know when to activate this skill`,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// Check for list bloat (multiple commas indicating detailed lists)
|
|
48
|
+
// Only warn if BOTH long description AND many commas (allows concise technical lists)
|
|
49
|
+
const comma_count = (description.match(/,/g) || []).length;
|
|
50
|
+
if (desc_length > 150 && comma_count >= 5) {
|
|
51
|
+
validation.warnings.push({
|
|
52
|
+
type: 'list_bloat',
|
|
53
|
+
message: `Description contains long lists (${comma_count} commas, ${desc_length} chars)\n` +
|
|
54
|
+
` → Move detailed lists to Level 2 (SKILL.md body) or Level 3 (references/)`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// Short description check
|
|
58
|
+
if (desc_length < 20) {
|
|
59
|
+
validation.warnings.push({
|
|
60
|
+
type: 'short',
|
|
61
|
+
message: 'Description is very short (consider adding more detail)',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return validation;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Analyze trigger phrase in description
|
|
68
|
+
*/
|
|
69
|
+
export function analyze_trigger_phrase(description) {
|
|
70
|
+
const lower = description.toLowerCase();
|
|
71
|
+
const has_trigger = lower.includes('use when') ||
|
|
72
|
+
lower.includes('use for') ||
|
|
73
|
+
lower.includes('use to');
|
|
74
|
+
let trigger_phrase = null;
|
|
75
|
+
let trigger_type = 'missing';
|
|
76
|
+
if (has_trigger) {
|
|
77
|
+
const match = description.match(/(use when|use for|use to)[^.!?]*/i);
|
|
78
|
+
if (match) {
|
|
79
|
+
trigger_phrase = match[0].trim();
|
|
80
|
+
trigger_type =
|
|
81
|
+
trigger_phrase.length > 50 ? 'specific' : 'generic';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
has_explicit_trigger: has_trigger,
|
|
86
|
+
trigger_phrase,
|
|
87
|
+
trigger_type,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Analyze user phrasing style
|
|
92
|
+
*/
|
|
93
|
+
export function analyze_user_phrasing(description) {
|
|
94
|
+
const issues = [];
|
|
95
|
+
const warnings = [];
|
|
96
|
+
// Check for first person
|
|
97
|
+
const is_third_person = !/\b(I can|I will|I help|my|me)\b/i.test(description);
|
|
98
|
+
const first_person_patterns = /\b(I can|I will|I help|my|me)\b/i;
|
|
99
|
+
if (first_person_patterns.test(description)) {
|
|
100
|
+
const match = description.match(first_person_patterns);
|
|
101
|
+
if (match) {
|
|
102
|
+
warnings.push({
|
|
103
|
+
type: 'first_person',
|
|
104
|
+
message: `Description uses first person: "${match[0]}"\n` +
|
|
105
|
+
` → Prefer third person for clarity (not required but recommended)`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Check for vague terms
|
|
110
|
+
const vague_patterns = /\b(helper|utility|tool|various|several|some)\b/i;
|
|
111
|
+
if (vague_patterns.test(description)) {
|
|
112
|
+
const match = description.match(vague_patterns);
|
|
113
|
+
if (match) {
|
|
114
|
+
warnings.push({
|
|
115
|
+
type: 'vague',
|
|
116
|
+
message: `Description contains vague term: "${match[0]}"\n` +
|
|
117
|
+
` → Be specific about what the skill does`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Check for gerund form (verbs ending in -ing)
|
|
122
|
+
const uses_gerund = /\b\w+ing\b/i.test(description);
|
|
123
|
+
// Check for action-oriented (starts with action verbs)
|
|
124
|
+
const action_verbs = /^(create|build|design|analyze|test|validate|generate|process|manage|execute|handle|provide)/i;
|
|
125
|
+
const is_action_oriented = action_verbs.test(description.trim());
|
|
126
|
+
const analysis = {
|
|
127
|
+
style_checks: {
|
|
128
|
+
is_third_person,
|
|
129
|
+
uses_gerund_form: uses_gerund,
|
|
130
|
+
is_action_oriented,
|
|
131
|
+
},
|
|
132
|
+
issues,
|
|
133
|
+
};
|
|
134
|
+
return { analysis, warnings };
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=description-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"description-validator.js","sourceRoot":"","sources":["../../src/validators/description-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File structure validation - paths, scripts, assets
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readdirSync, readFileSync, statSync, } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
/**
|
|
7
|
+
* Validate that skill directory exists and is valid
|
|
8
|
+
*/
|
|
9
|
+
export function validate_directory(skill_path) {
|
|
10
|
+
const errors = [];
|
|
11
|
+
if (!existsSync(skill_path)) {
|
|
12
|
+
errors.push({
|
|
13
|
+
type: 'not_found',
|
|
14
|
+
message: `Skill directory does not exist: ${skill_path}`,
|
|
15
|
+
});
|
|
16
|
+
return { valid: false, errors };
|
|
17
|
+
}
|
|
18
|
+
const stats = statSync(skill_path);
|
|
19
|
+
if (!stats.isDirectory()) {
|
|
20
|
+
errors.push({
|
|
21
|
+
type: 'not_directory',
|
|
22
|
+
message: `Path is not a directory: ${skill_path}`,
|
|
23
|
+
});
|
|
24
|
+
return { valid: false, errors };
|
|
25
|
+
}
|
|
26
|
+
return { valid: true, errors: [] };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validate path formats (no Windows backslashes)
|
|
30
|
+
*/
|
|
31
|
+
export function validate_path_formats(content, file_name = 'SKILL.md') {
|
|
32
|
+
const invalid_paths = [];
|
|
33
|
+
const errors = [];
|
|
34
|
+
const lines = content.split('\n');
|
|
35
|
+
lines.forEach((line, index) => {
|
|
36
|
+
// Skip code blocks (they might legitimately show Windows paths as examples)
|
|
37
|
+
if (line.trim().startsWith('```'))
|
|
38
|
+
return;
|
|
39
|
+
// Detect backslashes in file paths
|
|
40
|
+
// Match patterns like: scripts\file.py, references\doc.md, etc.
|
|
41
|
+
const backslash_pattern = /(?:scripts|references|assets|examples)\\[\w\\.-]+/g;
|
|
42
|
+
const matches = line.match(backslash_pattern);
|
|
43
|
+
if (matches) {
|
|
44
|
+
matches.forEach((match) => {
|
|
45
|
+
const fixed = match.replace(/\\/g, '/');
|
|
46
|
+
// Store in validation
|
|
47
|
+
invalid_paths.push({
|
|
48
|
+
line_number: index + 1,
|
|
49
|
+
path: match,
|
|
50
|
+
error: 'Windows-style backslash detected',
|
|
51
|
+
suggested_fix: fixed,
|
|
52
|
+
});
|
|
53
|
+
errors.push({
|
|
54
|
+
type: 'windows_path',
|
|
55
|
+
message: `Windows-style path in ${file_name}:${index + 1}\n` +
|
|
56
|
+
` → Found: ${match}\n` +
|
|
57
|
+
` → Use: ${fixed}`,
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
validation: { invalid_paths },
|
|
64
|
+
errors,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validate scripts directory
|
|
69
|
+
*/
|
|
70
|
+
export function validate_scripts(skill_path) {
|
|
71
|
+
const scripts_dir = join(skill_path, 'scripts');
|
|
72
|
+
const warnings = [];
|
|
73
|
+
if (existsSync(scripts_dir)) {
|
|
74
|
+
const files = readdirSync(scripts_dir);
|
|
75
|
+
const script_files = files.filter((f) => f.endsWith('.js') ||
|
|
76
|
+
f.endsWith('.ts') ||
|
|
77
|
+
f.endsWith('.mjs') ||
|
|
78
|
+
f.endsWith('.sh'));
|
|
79
|
+
if (script_files.length === 0) {
|
|
80
|
+
warnings.push({
|
|
81
|
+
type: 'empty_directory',
|
|
82
|
+
message: 'scripts/ directory exists but is empty',
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
for (const script_file of script_files) {
|
|
86
|
+
const script_path = join(scripts_dir, script_file);
|
|
87
|
+
const stats = statSync(script_path);
|
|
88
|
+
// Check if executable (0o111 = --x--x--x)
|
|
89
|
+
if ((stats.mode & 0o111) === 0) {
|
|
90
|
+
warnings.push({
|
|
91
|
+
type: 'not_executable',
|
|
92
|
+
message: `Script is not executable: ${script_file}`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Check for shebang
|
|
96
|
+
const content = readFileSync(script_path, 'utf-8');
|
|
97
|
+
const first_line = content.split('\n')[0];
|
|
98
|
+
if (!first_line.startsWith('#!')) {
|
|
99
|
+
warnings.push({
|
|
100
|
+
type: 'missing_shebang',
|
|
101
|
+
message: `Script missing shebang: ${script_file}`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { warnings };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Validate assets directory
|
|
110
|
+
*/
|
|
111
|
+
export function validate_assets(skill_path) {
|
|
112
|
+
const assets_dir = join(skill_path, 'assets');
|
|
113
|
+
const warnings = [];
|
|
114
|
+
if (existsSync(assets_dir)) {
|
|
115
|
+
const files = readdirSync(assets_dir);
|
|
116
|
+
if (files.length === 0) {
|
|
117
|
+
warnings.push({
|
|
118
|
+
type: 'empty_directory',
|
|
119
|
+
message: 'assets/ directory exists but is empty',
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return { warnings };
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=file-structure-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-structure-validator.js","sourceRoot":"","sources":["../../src/validators/file-structure-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML frontmatter validation for SKILL.md
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check if content has valid YAML frontmatter
|
|
6
|
+
*/
|
|
7
|
+
export function has_yaml_frontmatter(content) {
|
|
8
|
+
return content.startsWith('---\n') || content.startsWith('---\r\n');
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Extract frontmatter and body from SKILL.md content
|
|
12
|
+
*/
|
|
13
|
+
export function extract_frontmatter(content) {
|
|
14
|
+
if (!has_yaml_frontmatter(content)) {
|
|
15
|
+
return { name: null, description: null, body: content };
|
|
16
|
+
}
|
|
17
|
+
const parts = content.split('---\n');
|
|
18
|
+
if (parts.length < 3) {
|
|
19
|
+
return { name: null, description: null, body: content };
|
|
20
|
+
}
|
|
21
|
+
const frontmatter = parts[1];
|
|
22
|
+
const body = parts.slice(2).join('---\n');
|
|
23
|
+
// Extract name
|
|
24
|
+
const name_match = frontmatter.match(/name:\s*(.+)/);
|
|
25
|
+
const name = name_match ? name_match[1].trim() : null;
|
|
26
|
+
// Extract description
|
|
27
|
+
const desc_match = frontmatter.match(/description:\s*(.+?)(?=\n[a-z]+:|$)/s);
|
|
28
|
+
const description = desc_match ? desc_match[1].trim() : null;
|
|
29
|
+
return { name, description, body };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Validate YAML frontmatter structure
|
|
33
|
+
*/
|
|
34
|
+
export function validate_frontmatter_structure(content) {
|
|
35
|
+
const validation = {
|
|
36
|
+
valid: true,
|
|
37
|
+
has_frontmatter: false,
|
|
38
|
+
parse_error: null,
|
|
39
|
+
missing_fields: [],
|
|
40
|
+
};
|
|
41
|
+
if (!has_yaml_frontmatter(content)) {
|
|
42
|
+
validation.valid = false;
|
|
43
|
+
validation.parse_error = 'Missing YAML frontmatter';
|
|
44
|
+
return validation;
|
|
45
|
+
}
|
|
46
|
+
validation.has_frontmatter = true;
|
|
47
|
+
const parts = content.split('---\n');
|
|
48
|
+
if (parts.length < 3) {
|
|
49
|
+
validation.valid = false;
|
|
50
|
+
validation.parse_error = 'Malformed YAML frontmatter';
|
|
51
|
+
return validation;
|
|
52
|
+
}
|
|
53
|
+
const frontmatter = parts[1];
|
|
54
|
+
// Check required fields
|
|
55
|
+
if (!frontmatter.includes('name:')) {
|
|
56
|
+
validation.missing_fields.push('name');
|
|
57
|
+
validation.valid = false;
|
|
58
|
+
}
|
|
59
|
+
if (!frontmatter.includes('description:')) {
|
|
60
|
+
validation.missing_fields.push('description');
|
|
61
|
+
validation.valid = false;
|
|
62
|
+
}
|
|
63
|
+
return validation;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Validate skill name format
|
|
67
|
+
*/
|
|
68
|
+
export function validate_name_format(name, directory_name) {
|
|
69
|
+
const validation = {
|
|
70
|
+
name,
|
|
71
|
+
format_valid: true,
|
|
72
|
+
directory_name,
|
|
73
|
+
matches_directory: true,
|
|
74
|
+
errors: [],
|
|
75
|
+
};
|
|
76
|
+
// Validate kebab-case format
|
|
77
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
78
|
+
validation.format_valid = false;
|
|
79
|
+
validation.errors.push(`Skill name must be lowercase kebab-case: '${name}'`);
|
|
80
|
+
}
|
|
81
|
+
// Check name matches directory
|
|
82
|
+
if (name !== directory_name) {
|
|
83
|
+
validation.matches_directory = false;
|
|
84
|
+
validation.errors.push(`Skill name '${name}' must match directory name '${directory_name}'`);
|
|
85
|
+
}
|
|
86
|
+
return validation;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validate hard limits for name and description
|
|
90
|
+
*/
|
|
91
|
+
export function validate_hard_limits(name, description) {
|
|
92
|
+
const limits = {
|
|
93
|
+
name: { length: 0, limit: 64, valid: true, error: null },
|
|
94
|
+
description: { length: 0, limit: 1024, valid: true, error: null },
|
|
95
|
+
};
|
|
96
|
+
// Validate name length
|
|
97
|
+
if (name) {
|
|
98
|
+
limits.name.length = name.length;
|
|
99
|
+
if (name.length > 64) {
|
|
100
|
+
limits.name.valid = false;
|
|
101
|
+
limits.name.error = `Skill name too long (max 64 chars): ${name.length}`;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Validate description length (Anthropic hard limit)
|
|
105
|
+
if (description) {
|
|
106
|
+
limits.description.length = description.length;
|
|
107
|
+
if (description.length > 1024) {
|
|
108
|
+
limits.description.valid = false;
|
|
109
|
+
limits.description.error = `Description too long (max 1024 chars per Anthropic): ${description.length}`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return limits;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=frontmatter-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter-validator.js","sourceRoot":"","sources":["../../src/validators/frontmatter-validator.ts"],"names":[],"mappings":"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"}
|