@devxiyang/agent-skill 0.0.6 → 0.0.7
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/dist/copy.test.d.ts +2 -0
- package/dist/copy.test.d.ts.map +1 -0
- package/dist/copy.test.js +66 -0
- package/dist/copy.test.js.map +1 -0
- package/dist/discovery/discovery.test.d.ts +2 -0
- package/dist/discovery/discovery.test.d.ts.map +1 -0
- package/dist/discovery/discovery.test.js +128 -0
- package/dist/discovery/discovery.test.js.map +1 -0
- package/dist/discovery/frontmatter.test.d.ts +2 -0
- package/dist/discovery/frontmatter.test.d.ts.map +1 -0
- package/dist/discovery/frontmatter.test.js +39 -0
- package/dist/discovery/frontmatter.test.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy.test.d.ts","sourceRoot":"","sources":["../src/copy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import { copySkills } from './copy.js';
|
|
6
|
+
let tmpDir;
|
|
7
|
+
let srcRoot;
|
|
8
|
+
beforeAll(async () => {
|
|
9
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'agent-skill-copy-test-'));
|
|
10
|
+
srcRoot = path.join(tmpDir, 'src');
|
|
11
|
+
// Create fixture skills
|
|
12
|
+
for (const name of ['git', 'github', 'web']) {
|
|
13
|
+
const dir = path.join(srcRoot, name);
|
|
14
|
+
await fs.mkdir(dir, { recursive: true });
|
|
15
|
+
await fs.writeFile(path.join(dir, 'SKILL.md'), `---\nname: ${name}\n---\n`);
|
|
16
|
+
}
|
|
17
|
+
// A dir without SKILL.md (should be ignored)
|
|
18
|
+
await fs.mkdir(path.join(srcRoot, 'not-a-skill'), { recursive: true });
|
|
19
|
+
});
|
|
20
|
+
afterAll(async () => {
|
|
21
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
22
|
+
});
|
|
23
|
+
describe('copySkills', () => {
|
|
24
|
+
it('copies all skills to target', async () => {
|
|
25
|
+
const to = path.join(tmpDir, 'dest-all');
|
|
26
|
+
const result = await copySkills({ from: srcRoot, to });
|
|
27
|
+
expect(result.copied.sort()).toEqual(['git', 'github', 'web']);
|
|
28
|
+
expect(result.skipped).toEqual([]);
|
|
29
|
+
for (const name of result.copied) {
|
|
30
|
+
const skillMd = path.join(to, name, 'SKILL.md');
|
|
31
|
+
await expect(fs.access(skillMd)).resolves.toBeUndefined();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
it('filters by skill names', async () => {
|
|
35
|
+
const to = path.join(tmpDir, 'dest-filter');
|
|
36
|
+
const result = await copySkills({ from: srcRoot, to, skills: ['git', 'web'] });
|
|
37
|
+
expect(result.copied.sort()).toEqual(['git', 'web']);
|
|
38
|
+
expect(result.skipped).toEqual([]);
|
|
39
|
+
await expect(fs.access(path.join(to, 'github'))).rejects.toThrow();
|
|
40
|
+
});
|
|
41
|
+
it('skips existing skills by default', async () => {
|
|
42
|
+
const to = path.join(tmpDir, 'dest-skip');
|
|
43
|
+
await copySkills({ from: srcRoot, to });
|
|
44
|
+
const result = await copySkills({ from: srcRoot, to });
|
|
45
|
+
expect(result.copied).toEqual([]);
|
|
46
|
+
expect(result.skipped.sort()).toEqual(['git', 'github', 'web']);
|
|
47
|
+
});
|
|
48
|
+
it('overwrites existing skills when overwrite: true', async () => {
|
|
49
|
+
const to = path.join(tmpDir, 'dest-overwrite');
|
|
50
|
+
await copySkills({ from: srcRoot, to });
|
|
51
|
+
const result = await copySkills({ from: srcRoot, to, overwrite: true });
|
|
52
|
+
expect(result.copied.sort()).toEqual(['git', 'github', 'web']);
|
|
53
|
+
expect(result.skipped).toEqual([]);
|
|
54
|
+
});
|
|
55
|
+
it('ignores directories without SKILL.md', async () => {
|
|
56
|
+
const to = path.join(tmpDir, 'dest-no-skill-md');
|
|
57
|
+
const result = await copySkills({ from: srcRoot, to });
|
|
58
|
+
expect(result.copied).not.toContain('not-a-skill');
|
|
59
|
+
});
|
|
60
|
+
it('creates target directory if it does not exist', async () => {
|
|
61
|
+
const to = path.join(tmpDir, 'new', 'nested', 'dest');
|
|
62
|
+
await copySkills({ from: srcRoot, to });
|
|
63
|
+
await expect(fs.access(to)).resolves.toBeUndefined();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=copy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy.test.js","sourceRoot":"","sources":["../src/copy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.test.d.ts","sourceRoot":"","sources":["../../src/discovery/discovery.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import { SkillDiscovery } from './discovery.js';
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Fixture helpers
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
async function makeSkillDir(root, name, frontmatter, body = '') {
|
|
10
|
+
const dir = path.join(root, name);
|
|
11
|
+
await fs.mkdir(dir, { recursive: true });
|
|
12
|
+
await fs.writeFile(path.join(dir, 'SKILL.md'), `---\n${frontmatter}\n---\n${body}`);
|
|
13
|
+
return dir;
|
|
14
|
+
}
|
|
15
|
+
let tmpDir;
|
|
16
|
+
beforeAll(async () => {
|
|
17
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'agent-skill-test-'));
|
|
18
|
+
});
|
|
19
|
+
afterAll(async () => {
|
|
20
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
21
|
+
});
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
describe('SkillDiscovery.list()', () => {
|
|
24
|
+
it('returns empty list when root does not exist', async () => {
|
|
25
|
+
const d = new SkillDiscovery([{ path: '/nonexistent/path', scope: 'system' }]);
|
|
26
|
+
expect(await d.list()).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
it('discovers a valid skill', async () => {
|
|
29
|
+
const root = path.join(tmpDir, 'basic');
|
|
30
|
+
await makeSkillDir(root, 'git', 'name: git\ndescription: Git skill');
|
|
31
|
+
const d = new SkillDiscovery([{ path: root, scope: 'system' }]);
|
|
32
|
+
const entries = await d.list();
|
|
33
|
+
expect(entries).toHaveLength(1);
|
|
34
|
+
expect(entries[0].name).toBe('git');
|
|
35
|
+
expect(entries[0].description).toBe('Git skill');
|
|
36
|
+
expect(entries[0].scope).toBe('system');
|
|
37
|
+
});
|
|
38
|
+
it('skips directories without SKILL.md', async () => {
|
|
39
|
+
const root = path.join(tmpDir, 'skip');
|
|
40
|
+
await fs.mkdir(path.join(root, 'empty-dir'), { recursive: true });
|
|
41
|
+
await makeSkillDir(root, 'real', 'name: real');
|
|
42
|
+
const d = new SkillDiscovery([{ path: root, scope: 'system' }]);
|
|
43
|
+
const entries = await d.list();
|
|
44
|
+
expect(entries).toHaveLength(1);
|
|
45
|
+
expect(entries[0].name).toBe('real');
|
|
46
|
+
});
|
|
47
|
+
it('user scope takes priority over system scope for same name', async () => {
|
|
48
|
+
const userRoot = path.join(tmpDir, 'priority-user');
|
|
49
|
+
const sysRoot = path.join(tmpDir, 'priority-sys');
|
|
50
|
+
await makeSkillDir(userRoot, 'shared', 'name: shared\ndescription: user version');
|
|
51
|
+
await makeSkillDir(sysRoot, 'shared', 'name: shared\ndescription: system version');
|
|
52
|
+
const d = new SkillDiscovery([
|
|
53
|
+
{ path: userRoot, scope: 'user' },
|
|
54
|
+
{ path: sysRoot, scope: 'system' },
|
|
55
|
+
]);
|
|
56
|
+
const entries = await d.list();
|
|
57
|
+
expect(entries).toHaveLength(1);
|
|
58
|
+
expect(entries[0].description).toBe('user version');
|
|
59
|
+
expect(entries[0].scope).toBe('user');
|
|
60
|
+
});
|
|
61
|
+
it('returns entries sorted by name', async () => {
|
|
62
|
+
const root = path.join(tmpDir, 'sorted');
|
|
63
|
+
for (const name of ['zebra', 'alpha', 'mango']) {
|
|
64
|
+
await makeSkillDir(root, name, `name: ${name}`);
|
|
65
|
+
}
|
|
66
|
+
const d = new SkillDiscovery([{ path: root, scope: 'system' }]);
|
|
67
|
+
const names = (await d.list()).map((e) => e.name);
|
|
68
|
+
expect(names).toEqual([...names].sort());
|
|
69
|
+
});
|
|
70
|
+
it('marks skill ineligible when validator reports missing bin', async () => {
|
|
71
|
+
const root = path.join(tmpDir, 'ineligible-bin');
|
|
72
|
+
await makeSkillDir(root, 'gh', 'name: gh\nrequires: bin:definitely-not-a-real-bin-xyz');
|
|
73
|
+
const validator = {
|
|
74
|
+
checkBin: async () => false,
|
|
75
|
+
checkEnv: () => true,
|
|
76
|
+
checkOs: () => true,
|
|
77
|
+
};
|
|
78
|
+
const d = new SkillDiscovery([{ path: root, scope: 'system' }], validator);
|
|
79
|
+
const [entry] = await d.list();
|
|
80
|
+
expect(entry.eligible).toBe(false);
|
|
81
|
+
expect(entry.missing[0].kind).toBe('bin');
|
|
82
|
+
});
|
|
83
|
+
it('marks skill ineligible when validator reports missing env', async () => {
|
|
84
|
+
const root = path.join(tmpDir, 'ineligible-env');
|
|
85
|
+
await makeSkillDir(root, 'api', 'name: api\nrequires: env:MISSING_API_KEY');
|
|
86
|
+
const validator = {
|
|
87
|
+
checkBin: async () => true,
|
|
88
|
+
checkEnv: () => false,
|
|
89
|
+
checkOs: () => true,
|
|
90
|
+
};
|
|
91
|
+
const d = new SkillDiscovery([{ path: root, scope: 'system' }], validator);
|
|
92
|
+
const [entry] = await d.list();
|
|
93
|
+
expect(entry.eligible).toBe(false);
|
|
94
|
+
expect(entry.missing[0].kind).toBe('env');
|
|
95
|
+
});
|
|
96
|
+
it('marks skill ineligible when OS does not match', async () => {
|
|
97
|
+
const root = path.join(tmpDir, 'ineligible-os');
|
|
98
|
+
await makeSkillDir(root, 'platform', `name: platform\nos: unsupported-os-xyz`);
|
|
99
|
+
const validator = {
|
|
100
|
+
checkBin: async () => true,
|
|
101
|
+
checkEnv: () => true,
|
|
102
|
+
checkOs: () => false,
|
|
103
|
+
};
|
|
104
|
+
const d = new SkillDiscovery([{ path: root, scope: 'system' }], validator);
|
|
105
|
+
const [entry] = await d.list();
|
|
106
|
+
expect(entry.eligible).toBe(false);
|
|
107
|
+
expect(entry.missing[0].kind).toBe('os');
|
|
108
|
+
});
|
|
109
|
+
it('exposes always flag', async () => {
|
|
110
|
+
const root = path.join(tmpDir, 'always');
|
|
111
|
+
await makeSkillDir(root, 'memory', 'name: memory\nalways: true');
|
|
112
|
+
const d = new SkillDiscovery([{ path: root, scope: 'system' }]);
|
|
113
|
+
const [entry] = await d.list();
|
|
114
|
+
expect(entry.always).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe('SkillDiscovery.load()', () => {
|
|
118
|
+
it('returns full SKILL.md content including frontmatter', async () => {
|
|
119
|
+
const root = path.join(tmpDir, 'load');
|
|
120
|
+
const dir = await makeSkillDir(root, 'mskill', 'name: mskill', 'This is the body.');
|
|
121
|
+
const filePath = path.join(dir, 'SKILL.md');
|
|
122
|
+
const d = new SkillDiscovery([{ path: root, scope: 'system' }]);
|
|
123
|
+
const content = await d.load(filePath);
|
|
124
|
+
expect(content).toContain('name: mskill');
|
|
125
|
+
expect(content).toContain('This is the body.');
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
//# sourceMappingURL=discovery.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.test.js","sourceRoot":"","sources":["../../src/discovery/discovery.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.test.d.ts","sourceRoot":"","sources":["../../src/discovery/frontmatter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { parseFrontmatter } from './frontmatter.js';
|
|
3
|
+
const wrap = (body, content = '') => `---\n${body}\n---\n${content}`;
|
|
4
|
+
describe('parseFrontmatter', () => {
|
|
5
|
+
it('returns defaults when no frontmatter', () => {
|
|
6
|
+
const fm = parseFrontmatter('just markdown');
|
|
7
|
+
expect(fm.name).toBeNull();
|
|
8
|
+
expect(fm.description).toBeNull();
|
|
9
|
+
expect(fm.always).toBe(false);
|
|
10
|
+
expect(fm.requiresBins).toEqual([]);
|
|
11
|
+
expect(fm.requiresEnvs).toEqual([]);
|
|
12
|
+
expect(fm.requiresOs).toEqual([]);
|
|
13
|
+
});
|
|
14
|
+
it('parses basic fields', () => {
|
|
15
|
+
const fm = parseFrontmatter(wrap('name: github\ndescription: GitHub CLI skill\nalways: true'));
|
|
16
|
+
expect(fm.name).toBe('github');
|
|
17
|
+
expect(fm.description).toBe('GitHub CLI skill');
|
|
18
|
+
expect(fm.always).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it('parses requires string', () => {
|
|
21
|
+
const fm = parseFrontmatter(wrap('name: git\nrequires: bin:git,env:GITHUB_TOKEN'));
|
|
22
|
+
expect(fm.requiresBins).toContain('git');
|
|
23
|
+
expect(fm.requiresEnvs).toContain('GITHUB_TOKEN');
|
|
24
|
+
});
|
|
25
|
+
it('handles quoted description', () => {
|
|
26
|
+
const fm = parseFrontmatter(wrap('name: x\ndescription: "hello world"'));
|
|
27
|
+
expect(fm.description).toBe('hello world');
|
|
28
|
+
});
|
|
29
|
+
it('ignores unknown boolean values and uses fallback', () => {
|
|
30
|
+
const fm = parseFrontmatter(wrap('name: x\nalways: maybe'));
|
|
31
|
+
expect(fm.always).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
it('parses top-level os field', () => {
|
|
34
|
+
const fm = parseFrontmatter(wrap('name: tmux\nos: darwin,linux'));
|
|
35
|
+
expect(fm.requiresOs).toContain('darwin');
|
|
36
|
+
expect(fm.requiresOs).toContain('linux');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=frontmatter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.test.js","sourceRoot":"","sources":["../../src/discovery/frontmatter.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,OAAO,GAAG,EAAE,EAAE,EAAE,CAC1C,QAAQ,IAAI,UAAU,OAAO,EAAE,CAAC;AAElC,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,EAAE,GAAG,gBAAgB,CAAC,eAAe,CAAC,CAAC;QAC7C,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC,CAAC;QAC/F,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAChD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC,CAAC;QACnF,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC,CAAC;QACzE,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;QAC5D,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devxiyang/agent-skill",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "SDK for skill discovery and registration — integrates into any agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"build": "tsc -p tsconfig.json",
|
|
37
37
|
"clean": "rm -rf dist",
|
|
38
38
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
39
|
-
"test": "vitest run",
|
|
40
|
-
"test:watch": "vitest"
|
|
39
|
+
"test": "vitest run tests",
|
|
40
|
+
"test:watch": "vitest tests"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@types/node": ">=18"
|