@stacksjs/skills 0.70.163 → 0.70.165
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 +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.js +9 -1
- package/dist/skills.d.ts +23 -0
- package/dist/skills.js +46 -24
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -353,7 +353,7 @@ For help, discussion about best practices, or any other conversation that would
|
|
|
353
353
|
|
|
354
354
|
For casual chit-chat with others using this package:
|
|
355
355
|
|
|
356
|
-
[Join the Stacks Discord Server](https://
|
|
356
|
+
[Join the Stacks Discord Server](https://stacksjs.com/discord)
|
|
357
357
|
|
|
358
358
|
## Postcardware
|
|
359
359
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,10 @@
|
|
|
1
|
-
export type { Skill,
|
|
2
|
-
export {
|
|
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
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 {
|
|
2
|
-
import {
|
|
3
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
32
|
-
if (!
|
|
49
|
+
const skillDir = resolveSkillDir(name);
|
|
50
|
+
if (!skillDir)
|
|
33
51
|
return null;
|
|
34
|
-
const content = readFileSync(skillPath, "utf-8"), { metadata, body } = parseFrontmatter(content),
|
|
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 =
|
|
49
|
-
if (!
|
|
50
|
-
errors.push(`Skill
|
|
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
|
|
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.
|
|
6
|
-
"description": "
|
|
5
|
+
"version": "0.70.165",
|
|
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.
|
|
58
|
-
"@stacksjs/storage": "0.70.
|
|
56
|
+
"@stacksjs/path": "0.70.165",
|
|
57
|
+
"@stacksjs/storage": "0.70.165"
|
|
59
58
|
},
|
|
60
59
|
"devDependencies": {
|
|
61
60
|
"better-dx": "^0.2.17",
|
|
62
|
-
"@stacksjs/types": "0.70.
|
|
61
|
+
"@stacksjs/types": "0.70.165"
|
|
63
62
|
}
|
|
64
63
|
}
|