@stacksjs/skills 0.70.162 → 0.70.164

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 CHANGED
@@ -310,6 +310,7 @@ _Focus on coding, not publishing._
310
310
 
311
311
  Convention over configuration, while staying wholly configurable. _No more boilerplate._
312
312
 
313
+ - 🧠 **LLM-Friendly Authoring** _models generate compact application intent instead of repeating framework glue or reading `node_modules`_
313
314
  - 💎 **Automated Upgrades** _no need to worry about upgrading to the latest versions, Stacks upgrades you_
314
315
  - 🦋 **Pretty Dev URLs** _your-project.localhost instead of localhost:3000_
315
316
  - 💡 **IDE Integration** _auto-completions, inline docs & a powerful IDE setup_
@@ -352,7 +353,7 @@ For help, discussion about best practices, or any other conversation that would
352
353
 
353
354
  For casual chit-chat with others using this package:
354
355
 
355
- [Join the Stacks Discord Server](https://discord.gg/stacksjs)
356
+ [Join the Stacks Discord Server](https://stacksjs.com/discord)
356
357
 
357
358
  ## Postcardware
358
359
 
package/dist/index.d.ts CHANGED
@@ -1,2 +1,10 @@
1
- export type { Skill, SkillMetadata, SkillManifest } from './types';
2
- export { listSkills, getSkill, validateSkill, loadSkillMetadata } from './skills';
1
+ export type { Skill, SkillManifest, SkillMetadata } from './types';
2
+ export {
3
+ bundledSkillsPath,
4
+ getSkill,
5
+ listSkills,
6
+ loadSkillMetadata,
7
+ projectSkillsPath,
8
+ resolveSkillPath,
9
+ validateSkill,
10
+ } from './skills';
package/dist/index.js CHANGED
@@ -1 +1,9 @@
1
- export { listSkills, getSkill, validateSkill, loadSkillMetadata } from "./skills";
1
+ export {
2
+ bundledSkillsPath,
3
+ getSkill,
4
+ listSkills,
5
+ loadSkillMetadata,
6
+ projectSkillsPath,
7
+ resolveSkillPath,
8
+ validateSkill
9
+ } from "./skills";
package/dist/skills.d.ts CHANGED
@@ -1,5 +1,28 @@
1
1
  import type { Skill, SkillMetadata } from './types';
2
+ /**
3
+ * Every available skill name, sorted, with project skills shadowing bundled
4
+ * ones of the same name rather than appearing twice.
5
+ */
2
6
  export declare function listSkills(): string[];
3
7
  export declare function getSkill(name: string): Skill | null;
4
8
  export declare function loadSkillMetadata(name: string): SkillMetadata | null;
9
+ /**
10
+ * Checks a skill against the agentskills.io frontmatter rules.
11
+ */
5
12
  export declare function validateSkill(name: string): { valid: boolean, errors: string[] };
13
+ /**
14
+ * The directory the framework's own skills ship from. `buddy setup:ai` reads it;
15
+ * nothing should write into it.
16
+ */
17
+ export declare function bundledSkillsPath(): string;
18
+ /**
19
+ * The directory a project puts its own skills in. Searched before
20
+ * {@link bundledSkillsPath}, so a skill here shadows a bundled one of the same
21
+ * name.
22
+ */
23
+ export declare function projectSkillsPath(): string;
24
+ /**
25
+ * Resolves a skill to its directory on disk, or `null` if no source has it.
26
+ * Exposed so `buddy setup:ai` can link/copy the winning directory per skill.
27
+ */
28
+ export declare function resolveSkillPath(name: string): string | null;
package/dist/skills.js CHANGED
@@ -1,6 +1,19 @@
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"));
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { appPath, frameworkPath, join } from "@stacksjs/path";
3
+ function skillSources() {
4
+ return [
5
+ appPath("Skills"),
6
+ frameworkPath("defaults/ai/skills")
7
+ ];
8
+ }
9
+ function resolveSkillDir(name) {
10
+ for (const source of skillSources()) {
11
+ const dir = join(source, name);
12
+ if (existsSync(join(dir, "SKILL.md")))
13
+ return dir;
14
+ }
15
+ return null;
16
+ }
4
17
  function parseFrontmatter(content) {
5
18
  const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
6
19
  if (!match)
@@ -20,42 +33,42 @@ function parseFrontmatter(content) {
20
33
  return { metadata, body: body ?? "" };
21
34
  }
22
35
  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
- });
36
+ const names = new Set;
37
+ for (const source of skillSources()) {
38
+ if (!existsSync(source))
39
+ continue;
40
+ for (const entry of readdirSync(source)) {
41
+ const entryPath = join(source, entry);
42
+ if (statSync(entryPath).isDirectory() && existsSync(join(entryPath, "SKILL.md")))
43
+ names.add(entry);
44
+ }
45
+ }
46
+ return [...names].sort();
29
47
  }
30
48
  export function getSkill(name) {
31
- const skillPath = join(SKILLS_DIR, name, "SKILL.md");
32
- if (!existsSync(skillPath))
49
+ const skillDir = resolveSkillDir(name);
50
+ if (!skillDir)
33
51
  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")) : [];
52
+ const skillPath = join(skillDir, "SKILL.md"), content = readFileSync(skillPath, "utf-8"), { metadata, body } = parseFrontmatter(content), listDir = (dir) => existsSync(join(skillDir, dir)) ? readdirSync(join(skillDir, dir)) : [];
35
53
  return {
36
54
  metadata,
37
55
  instructions: body,
38
56
  path: skillPath,
39
- scripts,
40
- references,
41
- assets
57
+ scripts: listDir("scripts"),
58
+ references: listDir("references"),
59
+ assets: listDir("assets")
42
60
  };
43
61
  }
44
62
  export function loadSkillMetadata(name) {
45
63
  return getSkill(name)?.metadata ?? null;
46
64
  }
47
65
  export function validateSkill(name) {
48
- const errors = [], skillDir = join(SKILLS_DIR, name);
49
- if (!existsSync(skillDir)) {
50
- errors.push(`Skill directory not found: ${skillDir}`);
66
+ const errors = [], skillDir = resolveSkillDir(name);
67
+ if (!skillDir) {
68
+ errors.push(`Skill not found in any source: ${skillSources().map((source) => join(source, name)).join(", ")}`);
51
69
  return { valid: !1, errors };
52
70
  }
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);
71
+ const content = readFileSync(join(skillDir, "SKILL.md"), "utf-8"), { metadata } = parseFrontmatter(content);
59
72
  if (!metadata.name)
60
73
  errors.push("Missing required field: name");
61
74
  else {
@@ -72,3 +85,12 @@ export function validateSkill(name) {
72
85
  errors.push("Description must be 1-1024 characters");
73
86
  return { valid: errors.length === 0, errors };
74
87
  }
88
+ export function bundledSkillsPath() {
89
+ return frameworkPath("defaults/ai/skills");
90
+ }
91
+ export function projectSkillsPath() {
92
+ return appPath("Skills");
93
+ }
94
+ export function resolveSkillPath(name) {
95
+ return resolveSkillDir(name);
96
+ }
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "name": "@stacksjs/skills",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.162",
6
- "description": "Agent skills for the Stacks framework, following the agentskills.io standard.",
5
+ "version": "0.70.164",
6
+ "description": "Reads the Stacks framework's agent skills, following the agentskills.io standard. The skills themselves ship in storage/framework/defaults/ai/skills.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
9
9
  "Chris Breuer <chris@stacksjs.com>"
@@ -45,8 +45,7 @@
45
45
  "types": "dist/index.d.ts",
46
46
  "files": [
47
47
  "README.md",
48
- "dist",
49
- "skills"
48
+ "dist"
50
49
  ],
51
50
  "scripts": {
52
51
  "build": "bun build.ts",
@@ -54,11 +53,11 @@
54
53
  "prepublishOnly": "bun run build"
55
54
  },
56
55
  "dependencies": {
57
- "@stacksjs/path": "0.70.162",
58
- "@stacksjs/storage": "0.70.162"
56
+ "@stacksjs/path": "0.70.164",
57
+ "@stacksjs/storage": "0.70.164"
59
58
  },
60
59
  "devDependencies": {
61
60
  "better-dx": "^0.2.17",
62
- "@stacksjs/types": "0.70.162"
61
+ "@stacksjs/types": "0.70.164"
63
62
  }
64
63
  }