@devxiyang/agent-skill 0.0.8 → 0.1.0
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/builtin.d.ts +3 -1
- package/dist/builtin.d.ts.map +1 -1
- package/dist/builtin.js +3 -1
- package/dist/builtin.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/copy.test.d.ts +0 -2
- package/dist/copy.test.d.ts.map +0 -1
- package/dist/copy.test.js +0 -66
- package/dist/copy.test.js.map +0 -1
- package/dist/discovery/discovery.test.d.ts +0 -2
- package/dist/discovery/discovery.test.d.ts.map +0 -1
- package/dist/discovery/discovery.test.js +0 -128
- package/dist/discovery/discovery.test.js.map +0 -1
- package/dist/discovery/frontmatter.test.d.ts +0 -2
- package/dist/discovery/frontmatter.test.d.ts.map +0 -1
- package/dist/discovery/frontmatter.test.js +0 -39
- package/dist/discovery/frontmatter.test.js.map +0 -1
- package/skills/jq/SKILL.md +0 -109
- package/skills/jq/references/install.md +0 -38
- package/skills/weather/SKILL.md +0 -50
- package/skills/weather/references/install.md +0 -51
package/dist/builtin.d.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* as a system-scoped root:
|
|
7
7
|
*
|
|
8
8
|
* ```ts
|
|
9
|
+
* import { SkillDiscovery, builtinSkillsRoot } from '@devxiyang/agent-skill-core';
|
|
10
|
+
*
|
|
9
11
|
* new SkillDiscovery([
|
|
10
12
|
* { path: userSkillsDir, scope: 'user' },
|
|
11
13
|
* { path: builtinSkillsRoot(), scope: 'system' },
|
|
@@ -13,7 +15,7 @@
|
|
|
13
15
|
* ```
|
|
14
16
|
*
|
|
15
17
|
* Note for Electron apps: if the app is packaged with asar, add
|
|
16
|
-
* `node_modules/@devxiyang/agent-skill/skills` to `asarUnpack` in
|
|
18
|
+
* `node_modules/@devxiyang/agent-skill-core/skills` to `asarUnpack` in
|
|
17
19
|
* electron-builder config so the directory is accessible via the filesystem.
|
|
18
20
|
*/
|
|
19
21
|
export declare function builtinSkillsRoot(): string;
|
package/dist/builtin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin.d.ts","sourceRoot":"","sources":["../src/builtin.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"builtin.d.ts","sourceRoot":"","sources":["../src/builtin.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C"}
|
package/dist/builtin.js
CHANGED
|
@@ -8,6 +8,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
8
8
|
* as a system-scoped root:
|
|
9
9
|
*
|
|
10
10
|
* ```ts
|
|
11
|
+
* import { SkillDiscovery, builtinSkillsRoot } from '@devxiyang/agent-skill-core';
|
|
12
|
+
*
|
|
11
13
|
* new SkillDiscovery([
|
|
12
14
|
* { path: userSkillsDir, scope: 'user' },
|
|
13
15
|
* { path: builtinSkillsRoot(), scope: 'system' },
|
|
@@ -15,7 +17,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
15
17
|
* ```
|
|
16
18
|
*
|
|
17
19
|
* Note for Electron apps: if the app is packaged with asar, add
|
|
18
|
-
* `node_modules/@devxiyang/agent-skill/skills` to `asarUnpack` in
|
|
20
|
+
* `node_modules/@devxiyang/agent-skill-core/skills` to `asarUnpack` in
|
|
19
21
|
* electron-builder config so the directory is accessible via the filesystem.
|
|
20
22
|
*/
|
|
21
23
|
export function builtinSkillsRoot() {
|
package/dist/builtin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin.js","sourceRoot":"","sources":["../src/builtin.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC
|
|
1
|
+
{"version":3,"file":"builtin.js","sourceRoot":"","sources":["../src/builtin.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC3C,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ export type { SkillEntry, SkillRoot, SkillScope, SkillMissingReason, SkillMissin
|
|
|
2
2
|
export type { SkillValidator } from './validator.js';
|
|
3
3
|
export { SkillDiscovery, parseFrontmatter } from './discovery/index.js';
|
|
4
4
|
export type { SkillFrontmatter } from './discovery/index.js';
|
|
5
|
-
export { builtinSkillsRoot } from './builtin.js';
|
|
6
5
|
export { defaultValidator } from './validators/index.js';
|
|
7
6
|
export { copySkills } from './copy.js';
|
|
8
7
|
export type { CopySkillsOptions, CopySkillsResult } from './copy.js';
|
|
8
|
+
export { builtinSkillsRoot } from './builtin.js';
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAChH,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAChH,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { SkillDiscovery, parseFrontmatter } from './discovery/index.js';
|
|
2
|
-
export { builtinSkillsRoot } from './builtin.js';
|
|
3
2
|
export { defaultValidator } from './validators/index.js';
|
|
4
3
|
export { copySkills } from './copy.js';
|
|
4
|
+
export { builtinSkillsRoot } from './builtin.js';
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
|
package/package.json
CHANGED
package/dist/copy.test.d.ts
DELETED
package/dist/copy.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"copy.test.d.ts","sourceRoot":"","sources":["../src/copy.test.ts"],"names":[],"mappings":""}
|
package/dist/copy.test.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
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
|
package/dist/copy.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"copy.test.js","sourceRoot":"","sources":["../src/copy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.test.d.ts","sourceRoot":"","sources":["../../src/discovery/discovery.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,128 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.test.js","sourceRoot":"","sources":["../../src/discovery/discovery.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter.test.d.ts","sourceRoot":"","sources":["../../src/discovery/frontmatter.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,39 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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/skills/jq/SKILL.md
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: jq
|
|
3
|
-
description: Process and transform JSON data using jq. Use when filtering API responses, extracting fields, reshaping JSON, or querying structured data.
|
|
4
|
-
requires: bin:jq
|
|
5
|
-
tags: json,jq
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# jq Skill
|
|
9
|
-
|
|
10
|
-
## Preflight
|
|
11
|
-
|
|
12
|
-
Verify jq is available before proceeding:
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
jq --version
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
If missing, load `references/install.md` for installation instructions.
|
|
19
|
-
|
|
20
|
-
## Basic filtering
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
# Pretty-print JSON
|
|
24
|
-
cat data.json | jq .
|
|
25
|
-
|
|
26
|
-
# Extract a field
|
|
27
|
-
echo '{"name":"alice","age":30}' | jq '.name'
|
|
28
|
-
|
|
29
|
-
# Nested field
|
|
30
|
-
echo '{"user":{"email":"a@b.com"}}' | jq '.user.email'
|
|
31
|
-
|
|
32
|
-
# Array index
|
|
33
|
-
echo '[1,2,3]' | jq '.[0]'
|
|
34
|
-
|
|
35
|
-
# Array slice
|
|
36
|
-
echo '[1,2,3,4,5]' | jq '.[2:4]'
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Iterating arrays
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
# Iterate all elements
|
|
43
|
-
curl -s "https://api.example.com/users" | jq '.[]'
|
|
44
|
-
|
|
45
|
-
# Extract field from each element
|
|
46
|
-
curl -s "https://api.example.com/users" | jq '.[].name'
|
|
47
|
-
|
|
48
|
-
# Same with pipe
|
|
49
|
-
curl -s "https://api.example.com/users" | jq '.[] | .name'
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Selecting & filtering
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
# Filter array by condition
|
|
56
|
-
jq '[.[] | select(.age > 25)]' data.json
|
|
57
|
-
|
|
58
|
-
# Filter by string match
|
|
59
|
-
jq '[.[] | select(.status == "active")]' data.json
|
|
60
|
-
|
|
61
|
-
# Filter by field existence
|
|
62
|
-
jq '[.[] | select(.email != null)]' data.json
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Transforming
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
# Build a new object
|
|
69
|
-
jq '{id: .id, label: .name}' data.json
|
|
70
|
-
|
|
71
|
-
# Map over array
|
|
72
|
-
jq '[.[] | {id: .id, label: .name}]' data.json
|
|
73
|
-
|
|
74
|
-
# Append a field
|
|
75
|
-
jq '. + {processed: true}' data.json
|
|
76
|
-
|
|
77
|
-
# keys, values, length
|
|
78
|
-
jq 'keys' data.json
|
|
79
|
-
jq '.items | length' data.json
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## String interpolation
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
jq '.[] | "User \(.name) is \(.age) years old"' data.json
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Combining with curl
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
# Extract specific field from API response
|
|
92
|
-
curl -s "https://api.example.com/item/1" | jq '.data.title'
|
|
93
|
-
|
|
94
|
-
# Filter and format a list
|
|
95
|
-
curl -s "https://api.example.com/items" | jq '[.[] | select(.active) | {id, name}]'
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Raw output & compact
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
# Raw string output (no quotes)
|
|
102
|
-
jq -r '.name' data.json
|
|
103
|
-
|
|
104
|
-
# Compact output (no whitespace)
|
|
105
|
-
jq -c '.' data.json
|
|
106
|
-
|
|
107
|
-
# Read from file
|
|
108
|
-
jq '.items' data.json
|
|
109
|
-
```
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# Installing jq
|
|
2
|
-
|
|
3
|
-
## macOS
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
brew install jq
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
If Homebrew is not installed, download the binary from https://jqlang.github.io/jq/download/ and place it in `/usr/local/bin`.
|
|
10
|
-
|
|
11
|
-
## Windows
|
|
12
|
-
|
|
13
|
-
If winget is available:
|
|
14
|
-
|
|
15
|
-
```powershell
|
|
16
|
-
winget install jqlang.jq
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Download the binary directly from https://jqlang.github.io/jq/download/ — pick `jq-windows-amd64.exe`, rename to `jq.exe`, and add its location to PATH.
|
|
20
|
-
|
|
21
|
-
If Chocolatey is available:
|
|
22
|
-
|
|
23
|
-
```powershell
|
|
24
|
-
choco install jq
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Linux
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
# Debian/Ubuntu
|
|
31
|
-
sudo apt install jq
|
|
32
|
-
|
|
33
|
-
# Fedora
|
|
34
|
-
sudo dnf install jq
|
|
35
|
-
|
|
36
|
-
# Arch
|
|
37
|
-
sudo pacman -S jq
|
|
38
|
-
```
|
package/skills/weather/SKILL.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: weather
|
|
3
|
-
description: Get current weather and forecasts for any location. No API key required.
|
|
4
|
-
requires: bin:curl
|
|
5
|
-
tags: weather,web
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Weather Skill
|
|
9
|
-
|
|
10
|
-
## Preflight
|
|
11
|
-
|
|
12
|
-
Verify curl is available before proceeding:
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
curl --version
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
If missing, load `references/install.md` for installation instructions.
|
|
19
|
-
|
|
20
|
-
Two free services, no API keys needed.
|
|
21
|
-
|
|
22
|
-
## wttr.in (primary)
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
# One-liner
|
|
26
|
-
curl -s "wttr.in/London?format=3"
|
|
27
|
-
# London: ⛅️ +8°C
|
|
28
|
-
|
|
29
|
-
# Compact format
|
|
30
|
-
curl -s "wttr.in/London?format=%l:+%c+%t+%h+%w"
|
|
31
|
-
|
|
32
|
-
# Full 3-day forecast
|
|
33
|
-
curl -s "wttr.in/London?T"
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Format codes: `%c` condition · `%t` temp · `%h` humidity · `%w` wind · `%l` location
|
|
37
|
-
|
|
38
|
-
Tips:
|
|
39
|
-
- URL-encode spaces: `wttr.in/New+York`
|
|
40
|
-
- Airport codes work: `wttr.in/JFK`
|
|
41
|
-
- Units: `?m` metric · `?u` imperial
|
|
42
|
-
- Today only: `?1` · Current only: `?0`
|
|
43
|
-
|
|
44
|
-
## Open-Meteo (fallback, JSON, no key)
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
curl -s "https://api.open-meteo.com/v1/forecast?latitude=51.5&longitude=-0.12¤t_weather=true"
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Get coordinates first, then query. Returns JSON with temperature, windspeed, and weather code.
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Installing curl
|
|
2
|
-
|
|
3
|
-
curl is pre-installed on macOS and Windows 10 (version 1803+). Check first:
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
curl --version
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Install only if the command is not found.
|
|
10
|
-
|
|
11
|
-
## macOS
|
|
12
|
-
|
|
13
|
-
curl ships with every macOS installation. If the command is somehow missing, it likely indicates a system issue rather than a missing package. Try reinstalling Xcode Command Line Tools:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
xcode-select --install
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
If you need a newer version and have Homebrew:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
brew install curl
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Windows
|
|
26
|
-
|
|
27
|
-
curl is bundled with Windows 10 version 1803+ as `curl.exe`. If missing:
|
|
28
|
-
|
|
29
|
-
Download from https://curl.se/windows/ and add the binary to your PATH.
|
|
30
|
-
|
|
31
|
-
If winget is available:
|
|
32
|
-
|
|
33
|
-
```powershell
|
|
34
|
-
winget install cURL.cURL
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Linux
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
# Debian/Ubuntu
|
|
41
|
-
sudo apt update && sudo apt install curl
|
|
42
|
-
|
|
43
|
-
# Fedora
|
|
44
|
-
sudo dnf install curl
|
|
45
|
-
|
|
46
|
-
# Arch
|
|
47
|
-
sudo pacman -S curl
|
|
48
|
-
|
|
49
|
-
# openSUSE
|
|
50
|
-
sudo zypper install curl
|
|
51
|
-
```
|