aiblueprint-cli 1.4.22 → 1.4.24

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 (90) hide show
  1. package/claude-code-config/skills/git-commit/SKILL.md +42 -0
  2. package/claude-code-config/{commands/git/create-pr.md → skills/git-create-pr/SKILL.md} +12 -18
  3. package/claude-code-config/skills/git-fix-pr-comments/SKILL.md +51 -0
  4. package/claude-code-config/skills/git-merge/SKILL.md +68 -0
  5. package/claude-code-config/skills/{claude-memory → meta-claude-memory}/SKILL.md +7 -2
  6. package/claude-code-config/skills/meta-claude-memory/references/rules-directory-guide.md +298 -0
  7. package/claude-code-config/skills/meta-prompt-creator/SKILL.md +285 -0
  8. package/claude-code-config/skills/meta-prompt-creator/references/anthropic-best-practices.md +126 -0
  9. package/claude-code-config/skills/meta-prompt-creator/references/anti-patterns.md +57 -0
  10. package/claude-code-config/skills/meta-prompt-creator/references/clarity-principles.md +54 -0
  11. package/claude-code-config/skills/meta-prompt-creator/references/context-management.md +389 -0
  12. package/claude-code-config/skills/meta-prompt-creator/references/few-shot-patterns.md +47 -0
  13. package/claude-code-config/skills/meta-prompt-creator/references/openai-best-practices.md +50 -0
  14. package/claude-code-config/skills/meta-prompt-creator/references/prompt-templates.md +110 -0
  15. package/claude-code-config/skills/meta-prompt-creator/references/reasoning-techniques.md +52 -0
  16. package/claude-code-config/skills/meta-prompt-creator/references/system-prompt-patterns.md +48 -0
  17. package/claude-code-config/skills/meta-prompt-creator/references/xml-structure.md +36 -0
  18. package/claude-code-config/skills/meta-skill-creator/LICENSE.txt +202 -0
  19. package/claude-code-config/skills/meta-skill-creator/SKILL.md +421 -0
  20. package/claude-code-config/skills/meta-skill-creator/package.json +5 -0
  21. package/claude-code-config/skills/meta-skill-creator/references/output-patterns.md +82 -0
  22. package/claude-code-config/skills/meta-skill-creator/references/progressive-disclosure-patterns.md +374 -0
  23. package/claude-code-config/skills/meta-skill-creator/references/prompting-integration.md +363 -0
  24. package/claude-code-config/skills/meta-skill-creator/references/real-world-examples.md +513 -0
  25. package/claude-code-config/skills/meta-skill-creator/references/script-patterns.md +385 -0
  26. package/claude-code-config/skills/meta-skill-creator/references/workflows.md +28 -0
  27. package/claude-code-config/skills/meta-skill-creator/references/xml-tag-guide.md +606 -0
  28. package/claude-code-config/skills/meta-skill-creator/scripts/init-skill.ts +214 -0
  29. package/claude-code-config/skills/meta-skill-creator/scripts/package-skill.ts +146 -0
  30. package/claude-code-config/skills/meta-skill-creator/scripts/validate.ts +138 -0
  31. package/claude-code-config/skills/{create-subagents → meta-subagent-creator}/SKILL.md +41 -15
  32. package/claude-code-config/skills/{setup-ralph → ralph-loop}/steps/step-00-init.md +2 -3
  33. package/claude-code-config/skills/utils-fix-errors/SKILL.md +61 -0
  34. package/claude-code-config/skills/utils-fix-grammar/SKILL.md +59 -0
  35. package/claude-code-config/skills/utils-oneshot/SKILL.md +56 -0
  36. package/claude-code-config/skills/workflow-apex/SKILL.md +303 -0
  37. package/claude-code-config/skills/workflow-apex/scripts/setup-templates.sh +134 -0
  38. package/claude-code-config/skills/workflow-apex/scripts/update-progress.sh +80 -0
  39. package/claude-code-config/skills/workflow-apex/steps/step-00-init.md +288 -0
  40. package/claude-code-config/skills/workflow-apex/steps/step-00b-branch.md +126 -0
  41. package/claude-code-config/skills/workflow-apex/steps/step-00b-economy.md +244 -0
  42. package/claude-code-config/skills/workflow-apex/steps/step-00b-interactive.md +153 -0
  43. package/claude-code-config/skills/workflow-apex/steps/step-01-analyze.md +361 -0
  44. package/claude-code-config/skills/workflow-apex/steps/step-02-plan.md +264 -0
  45. package/claude-code-config/skills/workflow-apex/steps/step-03-execute.md +239 -0
  46. package/claude-code-config/skills/workflow-apex/steps/step-04-validate.md +264 -0
  47. package/claude-code-config/skills/workflow-apex/steps/step-05-examine.md +294 -0
  48. package/claude-code-config/skills/workflow-apex/steps/step-06-resolve.md +237 -0
  49. package/claude-code-config/skills/workflow-apex/steps/step-07-tests.md +250 -0
  50. package/claude-code-config/skills/workflow-apex/steps/step-08-run-tests.md +308 -0
  51. package/claude-code-config/skills/workflow-apex/steps/step-09-finish.md +193 -0
  52. package/claude-code-config/skills/workflow-apex/templates/00-context.md +51 -0
  53. package/claude-code-config/skills/workflow-apex/templates/01-analyze.md +10 -0
  54. package/claude-code-config/skills/workflow-apex/templates/02-plan.md +10 -0
  55. package/claude-code-config/skills/workflow-apex/templates/03-execute.md +10 -0
  56. package/claude-code-config/skills/workflow-apex/templates/04-validate.md +10 -0
  57. package/claude-code-config/skills/workflow-apex/templates/05-examine.md +10 -0
  58. package/claude-code-config/skills/workflow-apex/templates/06-resolve.md +10 -0
  59. package/claude-code-config/skills/workflow-apex/templates/07-tests.md +10 -0
  60. package/claude-code-config/skills/workflow-apex/templates/08-run-tests.md +10 -0
  61. package/claude-code-config/skills/workflow-apex/templates/09-finish.md +10 -0
  62. package/claude-code-config/skills/workflow-apex/templates/README.md +195 -0
  63. package/claude-code-config/skills/workflow-apex/templates/step-complete.md +7 -0
  64. package/dist/cli.js +46 -3
  65. package/package.json +1 -1
  66. package/claude-code-config/commands/explore.md +0 -90
  67. package/claude-code-config/commands/git/commit.md +0 -60
  68. package/claude-code-config/commands/git/fix-pr-comments.md +0 -59
  69. package/claude-code-config/commands/oneshot.md +0 -57
  70. package/claude-code-config/skills/create-slash-commands/SKILL.md +0 -1110
  71. package/claude-code-config/skills/create-slash-commands/references/arguments.md +0 -273
  72. package/claude-code-config/skills/create-slash-commands/references/patterns.md +0 -947
  73. package/claude-code-config/skills/create-slash-commands/references/prompt-examples.md +0 -656
  74. package/claude-code-config/skills/create-slash-commands/references/tool-restrictions.md +0 -389
  75. /package/claude-code-config/skills/{claude-memory → meta-claude-memory}/references/comprehensive-example.md +0 -0
  76. /package/claude-code-config/skills/{claude-memory → meta-claude-memory}/references/project-patterns.md +0 -0
  77. /package/claude-code-config/skills/{claude-memory → meta-claude-memory}/references/prompting-techniques.md +0 -0
  78. /package/claude-code-config/skills/{claude-memory → meta-claude-memory}/references/section-templates.md +0 -0
  79. /package/claude-code-config/skills/{create-subagents → meta-subagent-creator}/references/context-management.md +0 -0
  80. /package/claude-code-config/skills/{create-subagents → meta-subagent-creator}/references/debugging-agents.md +0 -0
  81. /package/claude-code-config/skills/{create-subagents → meta-subagent-creator}/references/error-handling-and-recovery.md +0 -0
  82. /package/claude-code-config/skills/{create-subagents → meta-subagent-creator}/references/evaluation-and-testing.md +0 -0
  83. /package/claude-code-config/skills/{create-subagents → meta-subagent-creator}/references/orchestration-patterns.md +0 -0
  84. /package/claude-code-config/skills/{create-subagents → meta-subagent-creator}/references/subagents.md +0 -0
  85. /package/claude-code-config/skills/{create-subagents → meta-subagent-creator}/references/writing-subagent-prompts.md +0 -0
  86. /package/claude-code-config/skills/{setup-ralph → ralph-loop}/SKILL.md +0 -0
  87. /package/claude-code-config/skills/{setup-ralph → ralph-loop}/scripts/setup.sh +0 -0
  88. /package/claude-code-config/skills/{setup-ralph → ralph-loop}/steps/step-01-interactive-prd.md +0 -0
  89. /package/claude-code-config/skills/{setup-ralph → ralph-loop}/steps/step-02-create-stories.md +0 -0
  90. /package/claude-code-config/skills/{setup-ralph → ralph-loop}/steps/step-03-finish.md +0 -0
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Skill Initializer - Creates a new skill from template
4
+ *
5
+ * Usage:
6
+ * bun scripts/init-skill.ts <skill-name> --path <path>
7
+ *
8
+ * Examples:
9
+ * bun scripts/init-skill.ts my-new-skill --path ~/.claude/skills
10
+ * bun scripts/init-skill.ts my-api-helper --path .claude/skills
11
+ */
12
+
13
+ import { existsSync, mkdirSync, writeFileSync, chmodSync } from "fs";
14
+ import { join, resolve } from "path";
15
+
16
+ const SKILL_TEMPLATE = `---
17
+ name: {skill_name}
18
+ description: [TODO: What the skill does and when to use it. Include trigger phrases like "use when..." or specific scenarios.]
19
+ ---
20
+
21
+ # {skill_title}
22
+
23
+ ## Overview
24
+
25
+ [TODO: 1-2 sentences explaining what this skill enables]
26
+
27
+ ## Quick Start
28
+
29
+ [TODO: Immediate, actionable guidance - minimal working example]
30
+
31
+ ## Workflow
32
+
33
+ [TODO: Step-by-step procedures if applicable]
34
+
35
+ ## Resources
36
+
37
+ This skill includes example resource directories:
38
+
39
+ ### scripts/
40
+ Executable code (TypeScript/Python/Bash) for automation tasks.
41
+
42
+ ### references/
43
+ Documentation loaded into context as needed. Keep SKILL.md lean (<500 lines) and move detailed content here.
44
+
45
+ ### assets/
46
+ Files used in output (templates, images, fonts) - not loaded into context.
47
+
48
+ ---
49
+
50
+ **Delete unused directories.** Not every skill needs all three resource types.
51
+ `;
52
+
53
+ const EXAMPLE_SCRIPT = `#!/usr/bin/env bun
54
+ /**
55
+ * Example helper script for {skill_name}
56
+ *
57
+ * Replace with actual implementation or delete if not needed.
58
+ */
59
+
60
+ function main() {
61
+ console.log("This is an example script for {skill_name}");
62
+ // TODO: Add actual script logic here
63
+ }
64
+
65
+ main();
66
+ `;
67
+
68
+ const EXAMPLE_REFERENCE = `# Reference Documentation for {skill_title}
69
+
70
+ This is a placeholder for detailed reference documentation.
71
+ Replace with actual content or delete if not needed.
72
+
73
+ ## When Reference Docs Are Useful
74
+
75
+ - Comprehensive API documentation
76
+ - Detailed workflow guides
77
+ - Complex multi-step processes
78
+ - Information too lengthy for main SKILL.md
79
+ - Content only needed for specific use cases
80
+
81
+ ## Structure Suggestions
82
+
83
+ ### API Reference Example
84
+ - Overview
85
+ - Authentication
86
+ - Endpoints with examples
87
+ - Error codes
88
+
89
+ ### Workflow Guide Example
90
+ - Prerequisites
91
+ - Step-by-step instructions
92
+ - Common patterns
93
+ - Troubleshooting
94
+ `;
95
+
96
+ const EXAMPLE_ASSET = `# Example Asset File
97
+
98
+ This placeholder represents where asset files would be stored.
99
+ Replace with actual assets (templates, images, fonts) or delete if not needed.
100
+
101
+ Asset files are NOT loaded into context - they're used in Claude's output.
102
+
103
+ ## Common Asset Types
104
+
105
+ - Templates: .pptx, .docx, boilerplate directories
106
+ - Images: .png, .jpg, .svg
107
+ - Fonts: .ttf, .woff2
108
+ - Boilerplate: Project directories, starter files
109
+ - Data: .csv, .json sample files
110
+ `;
111
+
112
+ function titleCase(skillName: string): string {
113
+ return skillName
114
+ .split("-")
115
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
116
+ .join(" ");
117
+ }
118
+
119
+ function initSkill(skillName: string, basePath: string): string | null {
120
+ const skillDir = resolve(basePath, skillName);
121
+
122
+ if (existsSync(skillDir)) {
123
+ console.log(`❌ Error: Skill directory already exists: ${skillDir}`);
124
+ return null;
125
+ }
126
+
127
+ try {
128
+ mkdirSync(skillDir, { recursive: true });
129
+ console.log(`✅ Created skill directory: ${skillDir}`);
130
+ } catch (e) {
131
+ console.log(`❌ Error creating directory: ${e}`);
132
+ return null;
133
+ }
134
+
135
+ const skillTitle = titleCase(skillName);
136
+
137
+ // Create SKILL.md
138
+ const skillContent = SKILL_TEMPLATE.replace(/{skill_name}/g, skillName).replace(
139
+ /{skill_title}/g,
140
+ skillTitle
141
+ );
142
+ const skillMdPath = join(skillDir, "SKILL.md");
143
+ try {
144
+ writeFileSync(skillMdPath, skillContent);
145
+ console.log("✅ Created SKILL.md");
146
+ } catch (e) {
147
+ console.log(`❌ Error creating SKILL.md: ${e}`);
148
+ return null;
149
+ }
150
+
151
+ try {
152
+ // Create scripts/
153
+ const scriptsDir = join(skillDir, "scripts");
154
+ mkdirSync(scriptsDir);
155
+ const exampleScript = join(scriptsDir, "example.ts");
156
+ writeFileSync(
157
+ exampleScript,
158
+ EXAMPLE_SCRIPT.replace(/{skill_name}/g, skillName)
159
+ );
160
+ chmodSync(exampleScript, 0o755);
161
+ console.log("✅ Created scripts/example.ts");
162
+
163
+ // Create references/
164
+ const referencesDir = join(skillDir, "references");
165
+ mkdirSync(referencesDir);
166
+ writeFileSync(
167
+ join(referencesDir, "api-reference.md"),
168
+ EXAMPLE_REFERENCE.replace(/{skill_title}/g, skillTitle)
169
+ );
170
+ console.log("✅ Created references/api-reference.md");
171
+
172
+ // Create assets/
173
+ const assetsDir = join(skillDir, "assets");
174
+ mkdirSync(assetsDir);
175
+ writeFileSync(join(assetsDir, "example-asset.txt"), EXAMPLE_ASSET);
176
+ console.log("✅ Created assets/example-asset.txt");
177
+ } catch (e) {
178
+ console.log(`❌ Error creating resource directories: ${e}`);
179
+ return null;
180
+ }
181
+
182
+ console.log(`\n✅ Skill '${skillName}' initialized at ${skillDir}`);
183
+ console.log("\nNext steps:");
184
+ console.log("1. Edit SKILL.md to complete the TODO items");
185
+ console.log("2. Customize or delete example files in scripts/, references/, assets/");
186
+ console.log("3. Run validator: bun scripts/validate.ts " + skillDir);
187
+
188
+ return skillDir;
189
+ }
190
+
191
+ if (import.meta.main) {
192
+ const args = process.argv.slice(2);
193
+
194
+ if (args.length < 3 || args[1] !== "--path") {
195
+ console.log("Usage: bun scripts/init-skill.ts <skill-name> --path <path>");
196
+ console.log("\nSkill name requirements:");
197
+ console.log(" - Hyphen-case (e.g., 'data-analyzer')");
198
+ console.log(" - Lowercase letters, digits, and hyphens only");
199
+ console.log(" - Max 64 characters");
200
+ console.log("\nExamples:");
201
+ console.log(" bun scripts/init-skill.ts my-skill --path ~/.claude/skills");
202
+ console.log(" bun scripts/init-skill.ts api-helper --path .claude/skills");
203
+ process.exit(1);
204
+ }
205
+
206
+ const skillName = args[0];
207
+ const basePath = args[2];
208
+
209
+ console.log(`🚀 Initializing skill: ${skillName}`);
210
+ console.log(` Location: ${basePath}\n`);
211
+
212
+ const result = initSkill(skillName, basePath);
213
+ process.exit(result ? 0 : 1);
214
+ }
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Skill Packager - Creates a distributable .skill file
4
+ *
5
+ * Usage:
6
+ * bun scripts/package-skill.ts <path/to/skill-folder> [output-directory]
7
+ *
8
+ * Examples:
9
+ * bun scripts/package-skill.ts ~/.claude/skills/my-skill
10
+ * bun scripts/package-skill.ts ~/.claude/skills/my-skill ./dist
11
+ */
12
+
13
+ import { existsSync, mkdirSync, readdirSync, statSync, readFileSync } from "fs";
14
+ import { join, resolve, relative, basename } from "path";
15
+ import { validateSkill } from "./validate";
16
+
17
+ async function getAllFiles(dir: string): Promise<string[]> {
18
+ const files: string[] = [];
19
+
20
+ function walk(currentDir: string) {
21
+ const entries = readdirSync(currentDir);
22
+ for (const entry of entries) {
23
+ const fullPath = join(currentDir, entry);
24
+ const stat = statSync(fullPath);
25
+ if (stat.isDirectory()) {
26
+ walk(fullPath);
27
+ } else {
28
+ files.push(fullPath);
29
+ }
30
+ }
31
+ }
32
+
33
+ walk(dir);
34
+ return files;
35
+ }
36
+
37
+ async function packageSkill(
38
+ skillPath: string,
39
+ outputDir?: string
40
+ ): Promise<string | null> {
41
+ const resolvedPath = resolve(skillPath);
42
+
43
+ if (!existsSync(resolvedPath)) {
44
+ console.log(`❌ Error: Skill folder not found: ${resolvedPath}`);
45
+ return null;
46
+ }
47
+
48
+ const stat = statSync(resolvedPath);
49
+ if (!stat.isDirectory()) {
50
+ console.log(`❌ Error: Path is not a directory: ${resolvedPath}`);
51
+ return null;
52
+ }
53
+
54
+ const skillMdPath = join(resolvedPath, "SKILL.md");
55
+ if (!existsSync(skillMdPath)) {
56
+ console.log(`❌ Error: SKILL.md not found in ${resolvedPath}`);
57
+ return null;
58
+ }
59
+
60
+ // Validate skill
61
+ console.log("🔍 Validating skill...");
62
+ const { valid, message } = validateSkill(resolvedPath);
63
+ if (!valid) {
64
+ console.log(`❌ Validation failed: ${message}`);
65
+ console.log(" Please fix the validation errors before packaging.");
66
+ return null;
67
+ }
68
+ console.log(`✅ ${message}\n`);
69
+
70
+ // Determine output location
71
+ const skillName = basename(resolvedPath);
72
+ const outputPath = outputDir ? resolve(outputDir) : process.cwd();
73
+
74
+ if (outputDir && !existsSync(outputPath)) {
75
+ mkdirSync(outputPath, { recursive: true });
76
+ }
77
+
78
+ const skillFilename = join(outputPath, `${skillName}.skill`);
79
+
80
+ // Create zip file using Bun's built-in zip
81
+ try {
82
+ const files = await getAllFiles(resolvedPath);
83
+ const zipEntries: { path: string; data: Uint8Array }[] = [];
84
+
85
+ for (const filePath of files) {
86
+ const relativePath = join(skillName, relative(resolvedPath, filePath));
87
+ const data = readFileSync(filePath);
88
+ zipEntries.push({ path: relativePath, data });
89
+ console.log(` Added: ${relativePath}`);
90
+ }
91
+
92
+ // Use Bun's native zip writer
93
+ const zipFile = Bun.file(skillFilename);
94
+ const writer = zipFile.writer();
95
+
96
+ // Create a simple zip manually or use a library
97
+ // For now, use the 'archiver' pattern with Bun.spawn
98
+ const { spawn } = await import("child_process");
99
+
100
+ // Create zip using system zip command (cross-platform approach)
101
+ const parentDir = resolve(resolvedPath, "..");
102
+ const result = Bun.spawnSync(["zip", "-r", skillFilename, skillName], {
103
+ cwd: parentDir,
104
+ stdout: "pipe",
105
+ stderr: "pipe",
106
+ });
107
+
108
+ if (result.exitCode !== 0) {
109
+ throw new Error(
110
+ `zip command failed: ${Buffer.from(result.stderr).toString()}`
111
+ );
112
+ }
113
+
114
+ console.log(`\n✅ Successfully packaged skill to: ${skillFilename}`);
115
+ return skillFilename;
116
+ } catch (e) {
117
+ console.log(`❌ Error creating .skill file: ${e}`);
118
+ return null;
119
+ }
120
+ }
121
+
122
+ if (import.meta.main) {
123
+ const args = process.argv.slice(2);
124
+
125
+ if (args.length < 1) {
126
+ console.log(
127
+ "Usage: bun scripts/package-skill.ts <path/to/skill-folder> [output-directory]"
128
+ );
129
+ console.log("\nExamples:");
130
+ console.log(" bun scripts/package-skill.ts ~/.claude/skills/my-skill");
131
+ console.log(" bun scripts/package-skill.ts ~/.claude/skills/my-skill ./dist");
132
+ process.exit(1);
133
+ }
134
+
135
+ const skillPath = args[0];
136
+ const outputDir = args[1];
137
+
138
+ console.log(`📦 Packaging skill: ${skillPath}`);
139
+ if (outputDir) {
140
+ console.log(` Output directory: ${outputDir}`);
141
+ }
142
+ console.log();
143
+
144
+ const result = await packageSkill(skillPath, outputDir);
145
+ process.exit(result ? 0 : 1);
146
+ }
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Skill Validator - Validates skill structure and frontmatter
4
+ *
5
+ * Usage:
6
+ * bun scripts/validate.ts <skill-directory>
7
+ */
8
+
9
+ import { existsSync, readFileSync } from "fs";
10
+ import { join } from "path";
11
+ import { parse as parseYaml } from "yaml";
12
+
13
+ const ALLOWED_PROPERTIES = new Set([
14
+ "name",
15
+ "description",
16
+ "license",
17
+ "metadata",
18
+ "allowed-tools",
19
+ "disable-model-invocation",
20
+ "user-invocable",
21
+ "argument-hint",
22
+ "model",
23
+ "context",
24
+ "agent",
25
+ "hooks",
26
+ ]);
27
+
28
+ interface ValidationResult {
29
+ valid: boolean;
30
+ message: string;
31
+ }
32
+
33
+ export function validateSkill(skillPath: string): ValidationResult {
34
+ const skillMdPath = join(skillPath, "SKILL.md");
35
+
36
+ if (!existsSync(skillMdPath)) {
37
+ return { valid: false, message: "SKILL.md not found" };
38
+ }
39
+
40
+ const content = readFileSync(skillMdPath, "utf-8");
41
+
42
+ if (!content.startsWith("---")) {
43
+ return { valid: false, message: "No YAML frontmatter found" };
44
+ }
45
+
46
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
47
+ if (!frontmatterMatch) {
48
+ return { valid: false, message: "Invalid frontmatter format" };
49
+ }
50
+
51
+ let frontmatter: Record<string, unknown>;
52
+ try {
53
+ frontmatter = parseYaml(frontmatterMatch[1]);
54
+ if (typeof frontmatter !== "object" || frontmatter === null) {
55
+ return { valid: false, message: "Frontmatter must be a YAML dictionary" };
56
+ }
57
+ } catch (e) {
58
+ return { valid: false, message: `Invalid YAML in frontmatter: ${e}` };
59
+ }
60
+
61
+ const unexpectedKeys = Object.keys(frontmatter).filter(
62
+ (key) => !ALLOWED_PROPERTIES.has(key)
63
+ );
64
+ if (unexpectedKeys.length > 0) {
65
+ return {
66
+ valid: false,
67
+ message: `Unexpected key(s) in frontmatter: ${unexpectedKeys.join(", ")}. Allowed: ${[...ALLOWED_PROPERTIES].sort().join(", ")}`,
68
+ };
69
+ }
70
+
71
+ const name = frontmatter.name;
72
+ if (name !== undefined) {
73
+ if (typeof name !== "string") {
74
+ return { valid: false, message: `Name must be a string` };
75
+ }
76
+ const trimmedName = name.trim();
77
+ if (trimmedName) {
78
+ if (!/^[a-z0-9-]+$/.test(trimmedName)) {
79
+ return {
80
+ valid: false,
81
+ message: `Name '${trimmedName}' should be hyphen-case (lowercase letters, digits, and hyphens only)`,
82
+ };
83
+ }
84
+ if (
85
+ trimmedName.startsWith("-") ||
86
+ trimmedName.endsWith("-") ||
87
+ trimmedName.includes("--")
88
+ ) {
89
+ return {
90
+ valid: false,
91
+ message: `Name '${trimmedName}' cannot start/end with hyphen or contain consecutive hyphens`,
92
+ };
93
+ }
94
+ if (trimmedName.length > 64) {
95
+ return {
96
+ valid: false,
97
+ message: `Name is too long (${trimmedName.length} characters). Maximum is 64 characters.`,
98
+ };
99
+ }
100
+ }
101
+ }
102
+
103
+ const description = frontmatter.description;
104
+ if (description !== undefined) {
105
+ if (typeof description !== "string") {
106
+ return { valid: false, message: `Description must be a string` };
107
+ }
108
+ const trimmedDesc = description.trim();
109
+ if (trimmedDesc) {
110
+ if (trimmedDesc.includes("<") || trimmedDesc.includes(">")) {
111
+ return {
112
+ valid: false,
113
+ message: "Description cannot contain angle brackets (< or >)",
114
+ };
115
+ }
116
+ if (trimmedDesc.length > 1024) {
117
+ return {
118
+ valid: false,
119
+ message: `Description is too long (${trimmedDesc.length} characters). Maximum is 1024 characters.`,
120
+ };
121
+ }
122
+ }
123
+ }
124
+
125
+ return { valid: true, message: "Skill is valid!" };
126
+ }
127
+
128
+ if (import.meta.main) {
129
+ const args = process.argv.slice(2);
130
+ if (args.length !== 1) {
131
+ console.log("Usage: bun scripts/validate.ts <skill_directory>");
132
+ process.exit(1);
133
+ }
134
+
135
+ const { valid, message } = validateSkill(args[0]);
136
+ console.log(message);
137
+ process.exit(valid ? 0 : 1);
138
+ }