@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 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;
@@ -1 +1 @@
1
- {"version":3,"file":"builtin.d.ts","sourceRoot":"","sources":["../src/builtin.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C"}
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() {
@@ -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;;;;;;;;;;;;;;;;;GAiBG;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"}
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
@@ -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,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,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"}
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,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devxiyang/agent-skill",
3
- "version": "0.0.8",
3
+ "version": "0.1.0",
4
4
  "description": "SDK for skill discovery and registration — integrates into any agent",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=copy.test.d.ts.map
@@ -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
@@ -1 +0,0 @@
1
- {"version":3,"file":"copy.test.js","sourceRoot":"","sources":["../src/copy.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=discovery.test.d.ts.map
@@ -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,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=frontmatter.test.d.ts.map
@@ -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"}
@@ -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
- ```
@@ -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&current_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
- ```