@ckelsoe/prompt-architect 3.0.2 → 3.1.1

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/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +264 -264
  4. package/LICENSE +21 -21
  5. package/README.md +1064 -1184
  6. package/adapters/README.md +75 -267
  7. package/adapters/for-windsurf.md +136 -136
  8. package/adapters/system-prompt.md +243 -243
  9. package/package.json +139 -138
  10. package/scripts/build-skill.js +64 -0
  11. package/scripts/install.js +4 -54
  12. package/scripts/test.js +205 -213
  13. package/scripts/validate-skill.js +350 -350
  14. package/skills/prompt-architect/SKILL.md +331 -331
  15. package/skills/prompt-architect/assets/templates/ape_template.txt +5 -5
  16. package/skills/prompt-architect/assets/templates/bab_template.txt +15 -15
  17. package/skills/prompt-architect/assets/templates/broke_template.txt +15 -15
  18. package/skills/prompt-architect/assets/templates/cai-critique-revise_template.txt +18 -18
  19. package/skills/prompt-architect/assets/templates/care_template.txt +16 -16
  20. package/skills/prompt-architect/assets/templates/chain-of-density_template.txt +46 -46
  21. package/skills/prompt-architect/assets/templates/chain-of-thought_template.txt +49 -49
  22. package/skills/prompt-architect/assets/templates/co-star_template.txt +17 -17
  23. package/skills/prompt-architect/assets/templates/crispe_template.txt +14 -14
  24. package/skills/prompt-architect/assets/templates/ctf_template.txt +15 -15
  25. package/skills/prompt-architect/assets/templates/devils-advocate_template.txt +25 -25
  26. package/skills/prompt-architect/assets/templates/hybrid_template.txt +101 -101
  27. package/skills/prompt-architect/assets/templates/least-to-most_template.txt +16 -16
  28. package/skills/prompt-architect/assets/templates/plan-and-solve_template.txt +7 -7
  29. package/skills/prompt-architect/assets/templates/pre-mortem_template.txt +27 -27
  30. package/skills/prompt-architect/assets/templates/race_template.txt +19 -19
  31. package/skills/prompt-architect/assets/templates/rcot_template.txt +31 -31
  32. package/skills/prompt-architect/assets/templates/react_template.txt +27 -27
  33. package/skills/prompt-architect/assets/templates/reverse-role_template.txt +11 -11
  34. package/skills/prompt-architect/assets/templates/rise-ie_template.txt +23 -23
  35. package/skills/prompt-architect/assets/templates/rise-ix_template.txt +28 -28
  36. package/skills/prompt-architect/assets/templates/risen_template.txt +21 -21
  37. package/skills/prompt-architect/assets/templates/rpef_template.txt +26 -26
  38. package/skills/prompt-architect/assets/templates/rtf_template.txt +13 -13
  39. package/skills/prompt-architect/assets/templates/self-refine_template.txt +16 -16
  40. package/skills/prompt-architect/assets/templates/skeleton-of-thought_template.txt +15 -15
  41. package/skills/prompt-architect/assets/templates/step-back_template.txt +10 -10
  42. package/skills/prompt-architect/assets/templates/tidd-ec_template.txt +45 -45
  43. package/skills/prompt-architect/assets/templates/tree-of-thought_template.txt +30 -30
  44. package/skills/prompt-architect/references/frameworks/ape.md +200 -200
  45. package/skills/prompt-architect/references/frameworks/bab.md +242 -242
  46. package/skills/prompt-architect/references/frameworks/broke.md +242 -242
  47. package/skills/prompt-architect/references/frameworks/cai-critique-revise.md +230 -230
  48. package/skills/prompt-architect/references/frameworks/care.md +235 -235
  49. package/skills/prompt-architect/references/frameworks/chain-of-density.md +479 -479
  50. package/skills/prompt-architect/references/frameworks/chain-of-thought.md +424 -424
  51. package/skills/prompt-architect/references/frameworks/co-star.md +256 -256
  52. package/skills/prompt-architect/references/frameworks/crispe.md +253 -253
  53. package/skills/prompt-architect/references/frameworks/ctf.md +207 -207
  54. package/skills/prompt-architect/references/frameworks/devils-advocate.md +206 -206
  55. package/skills/prompt-architect/references/frameworks/least-to-most.md +226 -226
  56. package/skills/prompt-architect/references/frameworks/plan-and-solve.md +210 -210
  57. package/skills/prompt-architect/references/frameworks/pre-mortem.md +197 -197
  58. package/skills/prompt-architect/references/frameworks/race.md +243 -243
  59. package/skills/prompt-architect/references/frameworks/rcot.md +203 -203
  60. package/skills/prompt-architect/references/frameworks/react.md +304 -304
  61. package/skills/prompt-architect/references/frameworks/reverse-role.md +189 -189
  62. package/skills/prompt-architect/references/frameworks/rise.md +555 -555
  63. package/skills/prompt-architect/references/frameworks/risen.md +297 -297
  64. package/skills/prompt-architect/references/frameworks/rpef.md +195 -195
  65. package/skills/prompt-architect/references/frameworks/rtf.md +358 -358
  66. package/skills/prompt-architect/references/frameworks/self-refine.md +205 -205
  67. package/skills/prompt-architect/references/frameworks/skeleton-of-thought.md +186 -186
  68. package/skills/prompt-architect/references/frameworks/step-back.md +206 -206
  69. package/skills/prompt-architect/references/frameworks/tidd-ec.md +470 -470
  70. package/skills/prompt-architect/references/frameworks/tree-of-thought.md +260 -260
  71. package/skills/prompt-architect/scripts/framework_analyzer.py +807 -807
  72. package/skills/prompt-architect/scripts/prompt_evaluator.py +336 -336
  73. package/adapters/for-cursor.mdc +0 -138
  74. package/adapters/for-gemini-cli.md +0 -70
  75. package/adapters/for-github-copilot.md +0 -141
  76. package/adapters/for-openai-codex-cli.md +0 -158
@@ -1,350 +1,350 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Skill Structure Validator
5
- *
6
- * Validates the Claude Code skill structure before publishing to npm.
7
- * Checks:
8
- * - SKILL.md exists and has valid frontmatter
9
- * - Required directories are present
10
- * - Framework files exist
11
- * - Templates exist
12
- * - File sizes are reasonable
13
- */
14
-
15
- const fs = require('fs');
16
- const path = require('path');
17
-
18
- // Colors for console output
19
- const colors = {
20
- reset: '\x1b[0m',
21
- red: '\x1b[31m',
22
- green: '\x1b[32m',
23
- yellow: '\x1b[33m',
24
- blue: '\x1b[34m',
25
- };
26
-
27
- function log(message, color = 'reset') {
28
- console.log(`${colors[color]}${message}${colors.reset}`);
29
- }
30
-
31
- function error(message) {
32
- log(`❌ ${message}`, 'red');
33
- }
34
-
35
- function success(message) {
36
- log(`✅ ${message}`, 'green');
37
- }
38
-
39
- function warning(message) {
40
- log(`⚠️ ${message}`, 'yellow');
41
- }
42
-
43
- function info(message) {
44
- log(`ℹ️ ${message}`, 'blue');
45
- }
46
-
47
- // Configuration
48
- const SKILL_DIR = path.join(__dirname, '..', 'skills', 'prompt-architect');
49
- const SKILL_FILE = path.join(SKILL_DIR, 'SKILL.md');
50
-
51
- const REQUIRED_DIRS = [
52
- 'scripts',
53
- 'references/frameworks',
54
- 'assets/templates',
55
- ];
56
-
57
- const REQUIRED_FRAMEWORKS = [
58
- 'co-star.md',
59
- 'risen.md',
60
- 'rise.md',
61
- 'tidd-ec.md',
62
- 'rtf.md',
63
- 'chain-of-thought.md',
64
- 'chain-of-density.md',
65
- ];
66
-
67
- const REQUIRED_TEMPLATES = [
68
- 'co-star_template.txt',
69
- 'risen_template.txt',
70
- 'rise-ie_template.txt',
71
- 'rise-ix_template.txt',
72
- 'tidd-ec_template.txt',
73
- 'rtf_template.txt',
74
- 'hybrid_template.txt',
75
- ];
76
-
77
- const REQUIRED_SCRIPTS = [
78
- 'framework_analyzer.py',
79
- 'prompt_evaluator.py',
80
- ];
81
-
82
- let errorCount = 0;
83
- let warningCount = 0;
84
-
85
- // Main validation
86
- function validateSkill() {
87
- log('\n🔍 Validating Prompt Architect Skill Structure...\n', 'blue');
88
-
89
- // Check skill directory exists
90
- if (!fs.existsSync(SKILL_DIR)) {
91
- error(`Skill directory not found: ${SKILL_DIR}`);
92
- process.exit(1);
93
- }
94
- success('Skill directory found');
95
-
96
- // Check SKILL.md exists
97
- if (!fs.existsSync(SKILL_FILE)) {
98
- error('SKILL.md not found');
99
- errorCount++;
100
- } else {
101
- success('SKILL.md found');
102
- validateSkillFile();
103
- }
104
-
105
- // Check required directories
106
- REQUIRED_DIRS.forEach(dir => {
107
- const fullPath = path.join(SKILL_DIR, dir);
108
- if (!fs.existsSync(fullPath)) {
109
- error(`Required directory missing: ${dir}`);
110
- errorCount++;
111
- } else {
112
- success(`Directory found: ${dir}`);
113
- }
114
- });
115
-
116
- // Check framework files
117
- info('\nValidating framework files...');
118
- REQUIRED_FRAMEWORKS.forEach(framework => {
119
- const frameworkPath = path.join(SKILL_DIR, 'references', 'frameworks', framework);
120
- if (!fs.existsSync(frameworkPath)) {
121
- error(`Framework file missing: ${framework}`);
122
- errorCount++;
123
- } else {
124
- const stats = fs.statSync(frameworkPath);
125
- const sizeKB = (stats.size / 1024).toFixed(2);
126
- success(`Framework found: ${framework} (${sizeKB} KB)`);
127
-
128
- // Warn if framework file is too small
129
- if (stats.size < 5000) {
130
- warning(`Framework ${framework} seems small (< 5 KB)`);
131
- warningCount++;
132
- }
133
- }
134
- });
135
-
136
- // Check template files
137
- info('\nValidating template files...');
138
- REQUIRED_TEMPLATES.forEach(template => {
139
- const templatePath = path.join(SKILL_DIR, 'assets', 'templates', template);
140
- if (!fs.existsSync(templatePath)) {
141
- error(`Template file missing: ${template}`);
142
- errorCount++;
143
- } else {
144
- success(`Template found: ${template}`);
145
- }
146
- });
147
-
148
- // Check script files
149
- info('\nValidating script files...');
150
- REQUIRED_SCRIPTS.forEach(script => {
151
- const scriptPath = path.join(SKILL_DIR, 'scripts', script);
152
- if (!fs.existsSync(scriptPath)) {
153
- error(`Script file missing: ${script}`);
154
- errorCount++;
155
- } else {
156
- success(`Script found: ${script}`);
157
- }
158
- });
159
-
160
- // Check package structure
161
- info('\nValidating package structure...');
162
- const packageJson = path.join(__dirname, '..', 'package.json');
163
- if (!fs.existsSync(packageJson)) {
164
- error('package.json not found');
165
- errorCount++;
166
- } else {
167
- success('package.json found');
168
- validatePackageJson();
169
- }
170
-
171
- }
172
-
173
- function validateSkillFile() {
174
- const content = fs.readFileSync(SKILL_FILE, 'utf8');
175
-
176
- // Check for YAML frontmatter (handle both LF and CRLF line endings)
177
- const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
178
- if (!frontmatterMatch) {
179
- error('SKILL.md missing YAML frontmatter (---\\n...\\n---)');
180
- errorCount++;
181
- return;
182
- }
183
- success('YAML frontmatter found');
184
-
185
- const frontmatter = frontmatterMatch[1];
186
-
187
- // Check required fields
188
- const requiredFields = ['name', 'description'];
189
- requiredFields.forEach(field => {
190
- if (!frontmatter.includes(`${field}:`)) {
191
- error(`SKILL.md missing required field: ${field}`);
192
- errorCount++;
193
- } else {
194
- success(`Required field found: ${field}`);
195
- }
196
- });
197
-
198
- // Validate name format
199
- const nameMatch = frontmatter.match(/name:\s*([^\n]+)/);
200
- if (nameMatch) {
201
- const name = nameMatch[1].trim();
202
- if (!/^[a-z0-9-]+$/.test(name)) {
203
- error(`Invalid skill name format: "${name}" (use lowercase, numbers, hyphens only)`);
204
- errorCount++;
205
- } else if (name.length > 64) {
206
- error(`Skill name too long: ${name.length} characters (max 64)`);
207
- errorCount++;
208
- } else {
209
- success(`Valid skill name: ${name}`);
210
- }
211
- }
212
-
213
- // Validate description length
214
- const descMatch = frontmatter.match(/description:\s*([^\n]+)/);
215
- if (descMatch && descMatch[1].length > 1024) {
216
- error(`Description too long: ${descMatch[1].length} characters (max 1024)`);
217
- errorCount++;
218
- } else if (descMatch) {
219
- success(`Valid description length: ${descMatch[1].length} characters`);
220
- }
221
-
222
- // Check content size
223
- const sizeKB = (Buffer.byteLength(content, 'utf8') / 1024).toFixed(2);
224
- info(`SKILL.md size: ${sizeKB} KB`);
225
- if (sizeKB > 100) {
226
- warning('SKILL.md is quite large (> 100 KB). Consider splitting content.');
227
- warningCount++;
228
- }
229
- }
230
-
231
- function validatePackageJson() {
232
- const packageJsonPath = path.join(__dirname, '..', 'package.json');
233
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
234
-
235
- // Check required fields
236
- const requiredFields = ['name', 'version', 'description', 'main', 'keywords', 'license'];
237
- requiredFields.forEach(field => {
238
- if (!packageJson[field]) {
239
- error(`package.json missing required field: ${field}`);
240
- errorCount++;
241
- } else {
242
- success(`package.json has ${field}`);
243
- }
244
- });
245
-
246
- // Check keywords include claude-code
247
- if (packageJson.keywords && !packageJson.keywords.includes('claude-code')) {
248
- warning('package.json keywords should include "claude-code"');
249
- warningCount++;
250
- }
251
-
252
- // Check files array
253
- if (!packageJson.files || packageJson.files.length === 0) {
254
- warning('package.json should specify "files" array for npm publish');
255
- warningCount++;
256
- } else {
257
- success(`package.json specifies ${packageJson.files.length} file patterns`);
258
- }
259
-
260
- // Validate version format
261
- const versionRegex = /^\d+\.\d+\.\d+(-[a-z0-9.]+)?$/;
262
- if (!versionRegex.test(packageJson.version)) {
263
- error(`Invalid version format: ${packageJson.version} (use semver: X.Y.Z)`);
264
- errorCount++;
265
- } else {
266
- success(`Valid version: ${packageJson.version}`);
267
- }
268
- }
269
-
270
- function validatePluginManifest() {
271
- info('\nValidating Claude plugin manifest...');
272
- const pluginJsonPath = path.join(__dirname, '..', '.claude-plugin', 'plugin.json');
273
- const marketplacePath = path.join(__dirname, '..', '.claude-plugin', 'marketplace.json');
274
-
275
- if (!fs.existsSync(pluginJsonPath)) {
276
- error('.claude-plugin/plugin.json not found');
277
- errorCount++;
278
- return;
279
- }
280
- success('.claude-plugin/plugin.json found');
281
-
282
- try {
283
- const plugin = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
284
- const requiredFields = ['name', 'description', 'version'];
285
- requiredFields.forEach(field => {
286
- if (!plugin[field]) {
287
- error(`plugin.json missing required field: ${field}`);
288
- errorCount++;
289
- } else {
290
- success(`plugin.json has ${field}`);
291
- }
292
- });
293
-
294
- // Cross-check version with package.json
295
- const packageJsonPath = path.join(__dirname, '..', 'package.json');
296
- if (fs.existsSync(packageJsonPath)) {
297
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
298
- if (plugin.version !== pkg.version) {
299
- error(`Version mismatch: plugin.json=${plugin.version}, package.json=${pkg.version}`);
300
- errorCount++;
301
- } else {
302
- success('plugin.json version matches package.json');
303
- }
304
- }
305
- } catch (err) {
306
- error(`plugin.json parse error: ${err.message}`);
307
- errorCount++;
308
- }
309
-
310
- if (!fs.existsSync(marketplacePath)) {
311
- warning('.claude-plugin/marketplace.json not found (optional for plugins)');
312
- warningCount++;
313
- } else {
314
- try {
315
- const mkt = JSON.parse(fs.readFileSync(marketplacePath, 'utf8'));
316
- if (!mkt.name || !mkt.owner || !mkt.plugins) {
317
- error('marketplace.json missing required fields (name, owner, plugins)');
318
- errorCount++;
319
- } else {
320
- success(`marketplace.json valid: ${mkt.plugins.length} plugin(s) defined`);
321
- }
322
- } catch (err) {
323
- error(`marketplace.json parse error: ${err.message}`);
324
- errorCount++;
325
- }
326
- }
327
- }
328
-
329
- // Run validation
330
- try {
331
- validateSkill();
332
- validatePluginManifest();
333
-
334
- // Final summary
335
- log('\n' + '='.repeat(50), 'blue');
336
- if (errorCount === 0 && warningCount === 0) {
337
- success('\n✨ All validation checks passed! Ready to publish. ✨\n');
338
- process.exit(0);
339
- } else if (errorCount === 0) {
340
- warning(`\n⚠️ Validation passed with ${warningCount} warning(s)\n`);
341
- process.exit(0);
342
- } else {
343
- error(`\n❌ Validation failed with ${errorCount} error(s) and ${warningCount} warning(s)\n`);
344
- process.exit(1);
345
- }
346
- } catch (err) {
347
- error(`Validation error: ${err.message}`);
348
- console.error(err);
349
- process.exit(1);
350
- }
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Skill Structure Validator
5
+ *
6
+ * Validates the Claude Code skill structure before publishing to npm.
7
+ * Checks:
8
+ * - SKILL.md exists and has valid frontmatter
9
+ * - Required directories are present
10
+ * - Framework files exist
11
+ * - Templates exist
12
+ * - File sizes are reasonable
13
+ */
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+
18
+ // Colors for console output
19
+ const colors = {
20
+ reset: '\x1b[0m',
21
+ red: '\x1b[31m',
22
+ green: '\x1b[32m',
23
+ yellow: '\x1b[33m',
24
+ blue: '\x1b[34m',
25
+ };
26
+
27
+ function log(message, color = 'reset') {
28
+ console.log(`${colors[color]}${message}${colors.reset}`);
29
+ }
30
+
31
+ function error(message) {
32
+ log(`❌ ${message}`, 'red');
33
+ }
34
+
35
+ function success(message) {
36
+ log(`✅ ${message}`, 'green');
37
+ }
38
+
39
+ function warning(message) {
40
+ log(`⚠️ ${message}`, 'yellow');
41
+ }
42
+
43
+ function info(message) {
44
+ log(`ℹ️ ${message}`, 'blue');
45
+ }
46
+
47
+ // Configuration
48
+ const SKILL_DIR = path.join(__dirname, '..', 'skills', 'prompt-architect');
49
+ const SKILL_FILE = path.join(SKILL_DIR, 'SKILL.md');
50
+
51
+ const REQUIRED_DIRS = [
52
+ 'scripts',
53
+ 'references/frameworks',
54
+ 'assets/templates',
55
+ ];
56
+
57
+ const REQUIRED_FRAMEWORKS = [
58
+ 'co-star.md',
59
+ 'risen.md',
60
+ 'rise.md',
61
+ 'tidd-ec.md',
62
+ 'rtf.md',
63
+ 'chain-of-thought.md',
64
+ 'chain-of-density.md',
65
+ ];
66
+
67
+ const REQUIRED_TEMPLATES = [
68
+ 'co-star_template.txt',
69
+ 'risen_template.txt',
70
+ 'rise-ie_template.txt',
71
+ 'rise-ix_template.txt',
72
+ 'tidd-ec_template.txt',
73
+ 'rtf_template.txt',
74
+ 'hybrid_template.txt',
75
+ ];
76
+
77
+ const REQUIRED_SCRIPTS = [
78
+ 'framework_analyzer.py',
79
+ 'prompt_evaluator.py',
80
+ ];
81
+
82
+ let errorCount = 0;
83
+ let warningCount = 0;
84
+
85
+ // Main validation
86
+ function validateSkill() {
87
+ log('\n🔍 Validating Prompt Architect Skill Structure...\n', 'blue');
88
+
89
+ // Check skill directory exists
90
+ if (!fs.existsSync(SKILL_DIR)) {
91
+ error(`Skill directory not found: ${SKILL_DIR}`);
92
+ process.exit(1);
93
+ }
94
+ success('Skill directory found');
95
+
96
+ // Check SKILL.md exists
97
+ if (!fs.existsSync(SKILL_FILE)) {
98
+ error('SKILL.md not found');
99
+ errorCount++;
100
+ } else {
101
+ success('SKILL.md found');
102
+ validateSkillFile();
103
+ }
104
+
105
+ // Check required directories
106
+ REQUIRED_DIRS.forEach(dir => {
107
+ const fullPath = path.join(SKILL_DIR, dir);
108
+ if (!fs.existsSync(fullPath)) {
109
+ error(`Required directory missing: ${dir}`);
110
+ errorCount++;
111
+ } else {
112
+ success(`Directory found: ${dir}`);
113
+ }
114
+ });
115
+
116
+ // Check framework files
117
+ info('\nValidating framework files...');
118
+ REQUIRED_FRAMEWORKS.forEach(framework => {
119
+ const frameworkPath = path.join(SKILL_DIR, 'references', 'frameworks', framework);
120
+ if (!fs.existsSync(frameworkPath)) {
121
+ error(`Framework file missing: ${framework}`);
122
+ errorCount++;
123
+ } else {
124
+ const stats = fs.statSync(frameworkPath);
125
+ const sizeKB = (stats.size / 1024).toFixed(2);
126
+ success(`Framework found: ${framework} (${sizeKB} KB)`);
127
+
128
+ // Warn if framework file is too small
129
+ if (stats.size < 5000) {
130
+ warning(`Framework ${framework} seems small (< 5 KB)`);
131
+ warningCount++;
132
+ }
133
+ }
134
+ });
135
+
136
+ // Check template files
137
+ info('\nValidating template files...');
138
+ REQUIRED_TEMPLATES.forEach(template => {
139
+ const templatePath = path.join(SKILL_DIR, 'assets', 'templates', template);
140
+ if (!fs.existsSync(templatePath)) {
141
+ error(`Template file missing: ${template}`);
142
+ errorCount++;
143
+ } else {
144
+ success(`Template found: ${template}`);
145
+ }
146
+ });
147
+
148
+ // Check script files
149
+ info('\nValidating script files...');
150
+ REQUIRED_SCRIPTS.forEach(script => {
151
+ const scriptPath = path.join(SKILL_DIR, 'scripts', script);
152
+ if (!fs.existsSync(scriptPath)) {
153
+ error(`Script file missing: ${script}`);
154
+ errorCount++;
155
+ } else {
156
+ success(`Script found: ${script}`);
157
+ }
158
+ });
159
+
160
+ // Check package structure
161
+ info('\nValidating package structure...');
162
+ const packageJson = path.join(__dirname, '..', 'package.json');
163
+ if (!fs.existsSync(packageJson)) {
164
+ error('package.json not found');
165
+ errorCount++;
166
+ } else {
167
+ success('package.json found');
168
+ validatePackageJson();
169
+ }
170
+
171
+ }
172
+
173
+ function validateSkillFile() {
174
+ const content = fs.readFileSync(SKILL_FILE, 'utf8');
175
+
176
+ // Check for YAML frontmatter (handle both LF and CRLF line endings)
177
+ const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
178
+ if (!frontmatterMatch) {
179
+ error('SKILL.md missing YAML frontmatter (---\\n...\\n---)');
180
+ errorCount++;
181
+ return;
182
+ }
183
+ success('YAML frontmatter found');
184
+
185
+ const frontmatter = frontmatterMatch[1];
186
+
187
+ // Check required fields
188
+ const requiredFields = ['name', 'description'];
189
+ requiredFields.forEach(field => {
190
+ if (!frontmatter.includes(`${field}:`)) {
191
+ error(`SKILL.md missing required field: ${field}`);
192
+ errorCount++;
193
+ } else {
194
+ success(`Required field found: ${field}`);
195
+ }
196
+ });
197
+
198
+ // Validate name format
199
+ const nameMatch = frontmatter.match(/name:\s*([^\n]+)/);
200
+ if (nameMatch) {
201
+ const name = nameMatch[1].trim();
202
+ if (!/^[a-z0-9-]+$/.test(name)) {
203
+ error(`Invalid skill name format: "${name}" (use lowercase, numbers, hyphens only)`);
204
+ errorCount++;
205
+ } else if (name.length > 64) {
206
+ error(`Skill name too long: ${name.length} characters (max 64)`);
207
+ errorCount++;
208
+ } else {
209
+ success(`Valid skill name: ${name}`);
210
+ }
211
+ }
212
+
213
+ // Validate description length
214
+ const descMatch = frontmatter.match(/description:\s*([^\n]+)/);
215
+ if (descMatch && descMatch[1].length > 1024) {
216
+ error(`Description too long: ${descMatch[1].length} characters (max 1024)`);
217
+ errorCount++;
218
+ } else if (descMatch) {
219
+ success(`Valid description length: ${descMatch[1].length} characters`);
220
+ }
221
+
222
+ // Check content size
223
+ const sizeKB = (Buffer.byteLength(content, 'utf8') / 1024).toFixed(2);
224
+ info(`SKILL.md size: ${sizeKB} KB`);
225
+ if (sizeKB > 100) {
226
+ warning('SKILL.md is quite large (> 100 KB). Consider splitting content.');
227
+ warningCount++;
228
+ }
229
+ }
230
+
231
+ function validatePackageJson() {
232
+ const packageJsonPath = path.join(__dirname, '..', 'package.json');
233
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
234
+
235
+ // Check required fields
236
+ const requiredFields = ['name', 'version', 'description', 'main', 'keywords', 'license'];
237
+ requiredFields.forEach(field => {
238
+ if (!packageJson[field]) {
239
+ error(`package.json missing required field: ${field}`);
240
+ errorCount++;
241
+ } else {
242
+ success(`package.json has ${field}`);
243
+ }
244
+ });
245
+
246
+ // Check keywords include claude-code
247
+ if (packageJson.keywords && !packageJson.keywords.includes('claude-code')) {
248
+ warning('package.json keywords should include "claude-code"');
249
+ warningCount++;
250
+ }
251
+
252
+ // Check files array
253
+ if (!packageJson.files || packageJson.files.length === 0) {
254
+ warning('package.json should specify "files" array for npm publish');
255
+ warningCount++;
256
+ } else {
257
+ success(`package.json specifies ${packageJson.files.length} file patterns`);
258
+ }
259
+
260
+ // Validate version format
261
+ const versionRegex = /^\d+\.\d+\.\d+(-[a-z0-9.]+)?$/;
262
+ if (!versionRegex.test(packageJson.version)) {
263
+ error(`Invalid version format: ${packageJson.version} (use semver: X.Y.Z)`);
264
+ errorCount++;
265
+ } else {
266
+ success(`Valid version: ${packageJson.version}`);
267
+ }
268
+ }
269
+
270
+ function validatePluginManifest() {
271
+ info('\nValidating Claude plugin manifest...');
272
+ const pluginJsonPath = path.join(__dirname, '..', '.claude-plugin', 'plugin.json');
273
+ const marketplacePath = path.join(__dirname, '..', '.claude-plugin', 'marketplace.json');
274
+
275
+ if (!fs.existsSync(pluginJsonPath)) {
276
+ error('.claude-plugin/plugin.json not found');
277
+ errorCount++;
278
+ return;
279
+ }
280
+ success('.claude-plugin/plugin.json found');
281
+
282
+ try {
283
+ const plugin = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
284
+ const requiredFields = ['name', 'description', 'version'];
285
+ requiredFields.forEach(field => {
286
+ if (!plugin[field]) {
287
+ error(`plugin.json missing required field: ${field}`);
288
+ errorCount++;
289
+ } else {
290
+ success(`plugin.json has ${field}`);
291
+ }
292
+ });
293
+
294
+ // Cross-check version with package.json
295
+ const packageJsonPath = path.join(__dirname, '..', 'package.json');
296
+ if (fs.existsSync(packageJsonPath)) {
297
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
298
+ if (plugin.version !== pkg.version) {
299
+ error(`Version mismatch: plugin.json=${plugin.version}, package.json=${pkg.version}`);
300
+ errorCount++;
301
+ } else {
302
+ success('plugin.json version matches package.json');
303
+ }
304
+ }
305
+ } catch (err) {
306
+ error(`plugin.json parse error: ${err.message}`);
307
+ errorCount++;
308
+ }
309
+
310
+ if (!fs.existsSync(marketplacePath)) {
311
+ warning('.claude-plugin/marketplace.json not found (optional for plugins)');
312
+ warningCount++;
313
+ } else {
314
+ try {
315
+ const mkt = JSON.parse(fs.readFileSync(marketplacePath, 'utf8'));
316
+ if (!mkt.name || !mkt.owner || !mkt.plugins) {
317
+ error('marketplace.json missing required fields (name, owner, plugins)');
318
+ errorCount++;
319
+ } else {
320
+ success(`marketplace.json valid: ${mkt.plugins.length} plugin(s) defined`);
321
+ }
322
+ } catch (err) {
323
+ error(`marketplace.json parse error: ${err.message}`);
324
+ errorCount++;
325
+ }
326
+ }
327
+ }
328
+
329
+ // Run validation
330
+ try {
331
+ validateSkill();
332
+ validatePluginManifest();
333
+
334
+ // Final summary
335
+ log('\n' + '='.repeat(50), 'blue');
336
+ if (errorCount === 0 && warningCount === 0) {
337
+ success('\n✨ All validation checks passed! Ready to publish. ✨\n');
338
+ process.exit(0);
339
+ } else if (errorCount === 0) {
340
+ warning(`\n⚠️ Validation passed with ${warningCount} warning(s)\n`);
341
+ process.exit(0);
342
+ } else {
343
+ error(`\n❌ Validation failed with ${errorCount} error(s) and ${warningCount} warning(s)\n`);
344
+ process.exit(1);
345
+ }
346
+ } catch (err) {
347
+ error(`Validation error: ${err.message}`);
348
+ console.error(err);
349
+ process.exit(1);
350
+ }