@stacksjs/skills 0.70.88 → 0.70.90

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.
@@ -0,0 +1,2 @@
1
+ export type { Skill, SkillMetadata, SkillManifest } from './types';
2
+ export { listSkills, getSkill, validateSkill, loadSkillMetadata } from './skills';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { listSkills, getSkill, validateSkill, loadSkillMetadata } from "./skills";
@@ -0,0 +1,5 @@
1
+ import type { Skill, SkillMetadata } from './types';
2
+ export declare function listSkills(): string[];
3
+ export declare function getSkill(name: string): Skill | null;
4
+ export declare function loadSkillMetadata(name: string): SkillMetadata | null;
5
+ export declare function validateSkill(name: string): { valid: boolean, errors: string[] };
package/dist/skills.js ADDED
@@ -0,0 +1,74 @@
1
+ import { join, resolve } from "@stacksjs/path";
2
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
+ const SKILLS_DIR = resolve(join(import.meta.dir, "..", "..", "..", "..", "..", ".claude", "skills"));
4
+ function parseFrontmatter(content) {
5
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
6
+ if (!match)
7
+ return {
8
+ metadata: { name: "", description: "" },
9
+ body: content
10
+ };
11
+ const [, frontmatterStr, body] = match, metadata = {};
12
+ for (const line of (frontmatterStr ?? "").split(`
13
+ `)) {
14
+ const colonIndex = line.indexOf(":");
15
+ if (colonIndex === -1)
16
+ continue;
17
+ const key = line.slice(0, colonIndex).trim(), value = line.slice(colonIndex + 1).trim();
18
+ metadata[key] = value;
19
+ }
20
+ return { metadata, body: body ?? "" };
21
+ }
22
+ export function listSkills() {
23
+ if (!existsSync(SKILLS_DIR))
24
+ return [];
25
+ return readdirSync(SKILLS_DIR).filter((entry) => {
26
+ const entryPath = join(SKILLS_DIR, entry);
27
+ return statSync(entryPath).isDirectory() && existsSync(join(entryPath, "SKILL.md"));
28
+ });
29
+ }
30
+ export function getSkill(name) {
31
+ const skillPath = join(SKILLS_DIR, name, "SKILL.md");
32
+ if (!existsSync(skillPath))
33
+ return null;
34
+ const content = readFileSync(skillPath, "utf-8"), { metadata, body } = parseFrontmatter(content), skillDir = join(SKILLS_DIR, name), scripts = existsSync(join(skillDir, "scripts")) ? readdirSync(join(skillDir, "scripts")) : [], references = existsSync(join(skillDir, "references")) ? readdirSync(join(skillDir, "references")) : [], assets = existsSync(join(skillDir, "assets")) ? readdirSync(join(skillDir, "assets")) : [];
35
+ return {
36
+ metadata,
37
+ instructions: body,
38
+ path: skillPath,
39
+ scripts,
40
+ references,
41
+ assets
42
+ };
43
+ }
44
+ export function loadSkillMetadata(name) {
45
+ return getSkill(name)?.metadata ?? null;
46
+ }
47
+ export function validateSkill(name) {
48
+ const errors = [], skillDir = join(SKILLS_DIR, name);
49
+ if (!existsSync(skillDir)) {
50
+ errors.push(`Skill directory not found: ${skillDir}`);
51
+ return { valid: !1, errors };
52
+ }
53
+ const skillPath = join(skillDir, "SKILL.md");
54
+ if (!existsSync(skillPath)) {
55
+ errors.push(`SKILL.md not found in ${skillDir}`);
56
+ return { valid: !1, errors };
57
+ }
58
+ const content = readFileSync(skillPath, "utf-8"), { metadata } = parseFrontmatter(content);
59
+ if (!metadata.name)
60
+ errors.push("Missing required field: name");
61
+ else {
62
+ if (metadata.name.length > 64)
63
+ errors.push("Name must be 1-64 characters");
64
+ if (!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(metadata.name))
65
+ errors.push("Name must be lowercase letters, numbers, and hyphens only");
66
+ if (metadata.name !== name)
67
+ errors.push(`Name "${metadata.name}" must match directory name "${name}"`);
68
+ }
69
+ if (!metadata.description)
70
+ errors.push("Missing required field: description");
71
+ else if (metadata.description.length > 1024)
72
+ errors.push("Description must be 1-1024 characters");
73
+ return { valid: errors.length === 0, errors };
74
+ }
@@ -0,0 +1,28 @@
1
+ export declare interface SkillMetadata {
2
+ name: string
3
+ description: string
4
+ license?: string
5
+ compatibility?: string
6
+ metadata?: Record<string, unknown>
7
+ 'allowed-tools'?: string
8
+ 'disable-model-invocation'?: boolean
9
+ 'user-invocable'?: boolean
10
+ context?: 'fork'
11
+ agent?: 'Explore' | 'Plan' | 'general-purpose'
12
+ 'argument-hint'?: string
13
+ model?: string
14
+ effort?: 'low' | 'medium' | 'high' | 'max'
15
+ }
16
+ export declare interface Skill {
17
+ metadata: SkillMetadata
18
+ instructions: string
19
+ path: string
20
+ scripts?: string[]
21
+ references?: string[]
22
+ assets?: string[]
23
+ }
24
+ export declare interface SkillManifest {
25
+ skills: Skill[]
26
+ version: string
27
+ framework: string
28
+ }
package/dist/types.js ADDED
File without changes
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/skills",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.88",
5
+ "version": "0.70.90",
6
6
  "description": "Agent skills for the Stacks framework, following the agentskills.io standard.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -54,11 +54,11 @@
54
54
  "prepublishOnly": "bun run build"
55
55
  },
56
56
  "dependencies": {
57
- "@stacksjs/path": "0.70.88",
58
- "@stacksjs/storage": "0.70.88"
57
+ "@stacksjs/path": "0.70.90",
58
+ "@stacksjs/storage": "0.70.90"
59
59
  },
60
60
  "devDependencies": {
61
61
  "better-dx": "^0.2.16",
62
- "@stacksjs/types": "0.70.88"
62
+ "@stacksjs/types": "0.70.90"
63
63
  }
64
64
  }