@devxiyang/agent-skill 0.0.7 → 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/README.md +5 -0
- 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/skills/python/SKILL.md +151 -0
- package/skills/python/references/install.md +52 -0
- package/skills/shell/SKILL.md +218 -0
- 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/weather/SKILL.md +0 -50
- package/skills/weather/references/install.md +0 -51
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# agent.skill
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@devxiyang/agent-skill)
|
|
4
|
+
[](https://www.npmjs.com/package/@devxiyang/agent-skill)
|
|
5
|
+
[](https://www.npmjs.com/package/@devxiyang/agent-skill)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
3
8
|
SDK for skill discovery and registration — integrates into any agent.
|
|
4
9
|
|
|
5
10
|
A **skill** is a folder containing a `SKILL.md` file (with YAML frontmatter + instructions) and optional resources (scripts, references, assets). This SDK provides the tooling to discover, validate, and load skills into an agent's context.
|
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
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: python
|
|
3
|
+
description: Run Python scripts, manage environments, and use common stdlib patterns. Use for scripting, data processing, automation, and general Python development.
|
|
4
|
+
requires: bin:python3
|
|
5
|
+
tags: python,scripting
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Python Skill
|
|
9
|
+
|
|
10
|
+
## Preflight
|
|
11
|
+
|
|
12
|
+
Verify Python is available before proceeding:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
python3 --version
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If missing, load `references/install.md` for installation instructions.
|
|
19
|
+
|
|
20
|
+
## Running scripts
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python3 script.py
|
|
24
|
+
python3 script.py arg1 arg2
|
|
25
|
+
python3 -c "print('hello')"
|
|
26
|
+
|
|
27
|
+
# Run a module
|
|
28
|
+
python3 -m http.server 8000
|
|
29
|
+
python3 -m json.tool data.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Virtual environments
|
|
33
|
+
|
|
34
|
+
### venv (built-in)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Create
|
|
38
|
+
python3 -m venv .venv
|
|
39
|
+
|
|
40
|
+
# Activate
|
|
41
|
+
source .venv/bin/activate # macOS/Linux
|
|
42
|
+
.venv\Scripts\activate # Windows
|
|
43
|
+
|
|
44
|
+
# Deactivate
|
|
45
|
+
deactivate
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### uv (fast, recommended)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Install uv
|
|
52
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh # macOS/Linux
|
|
53
|
+
powershell -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows
|
|
54
|
+
|
|
55
|
+
# Create and activate venv
|
|
56
|
+
uv venv
|
|
57
|
+
source .venv/bin/activate
|
|
58
|
+
|
|
59
|
+
# Run without activating
|
|
60
|
+
uv run script.py
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Package management
|
|
64
|
+
|
|
65
|
+
### pip
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install requests
|
|
69
|
+
pip install -r requirements.txt
|
|
70
|
+
pip freeze > requirements.txt
|
|
71
|
+
pip list --outdated
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### uv (faster alternative)
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uv pip install requests
|
|
78
|
+
uv pip install -r requirements.txt
|
|
79
|
+
uv pip freeze > requirements.txt
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Common stdlib patterns
|
|
83
|
+
|
|
84
|
+
### File I/O (pathlib)
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from pathlib import Path
|
|
88
|
+
|
|
89
|
+
p = Path("data/file.txt")
|
|
90
|
+
text = p.read_text()
|
|
91
|
+
p.write_text("content")
|
|
92
|
+
|
|
93
|
+
# Iterate files
|
|
94
|
+
for f in Path("src").rglob("*.py"):
|
|
95
|
+
print(f)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### JSON
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import json
|
|
102
|
+
|
|
103
|
+
# Parse
|
|
104
|
+
data = json.loads('{"key": "value"}')
|
|
105
|
+
data = json.load(open("data.json"))
|
|
106
|
+
|
|
107
|
+
# Serialize
|
|
108
|
+
json.dumps(data, indent=2)
|
|
109
|
+
json.dump(data, open("out.json", "w"), indent=2)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### HTTP requests
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# Built-in (no deps)
|
|
116
|
+
from urllib.request import urlopen
|
|
117
|
+
import json
|
|
118
|
+
|
|
119
|
+
with urlopen("https://api.example.com/data") as r:
|
|
120
|
+
data = json.loads(r.read())
|
|
121
|
+
|
|
122
|
+
# With requests (install first)
|
|
123
|
+
import requests
|
|
124
|
+
r = requests.get("https://api.example.com/data")
|
|
125
|
+
data = r.json()
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Subprocess
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import subprocess
|
|
132
|
+
|
|
133
|
+
# Run and capture output
|
|
134
|
+
result = subprocess.run(["git", "status"], capture_output=True, text=True)
|
|
135
|
+
print(result.stdout)
|
|
136
|
+
|
|
137
|
+
# Check for errors
|
|
138
|
+
result = subprocess.run(["npm", "test"], check=True)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Argument parsing
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import argparse
|
|
145
|
+
|
|
146
|
+
parser = argparse.ArgumentParser(description="My script")
|
|
147
|
+
parser.add_argument("input", help="Input file")
|
|
148
|
+
parser.add_argument("--output", "-o", default="out.txt")
|
|
149
|
+
parser.add_argument("--verbose", "-v", action="store_true")
|
|
150
|
+
args = parser.parse_args()
|
|
151
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Installing Python
|
|
2
|
+
|
|
3
|
+
## macOS
|
|
4
|
+
|
|
5
|
+
macOS ships with Python 3 from Xcode Command Line Tools:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
xcode-select --install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
To get a newer version, download from https://www.python.org/downloads/mac-osx/ and run the `.pkg` installer — no Homebrew needed.
|
|
12
|
+
|
|
13
|
+
If you have Homebrew:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
brew install python3
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Windows
|
|
20
|
+
|
|
21
|
+
Download the installer from https://www.python.org/downloads/windows/ — pick the latest stable release and run the `.exe` installer. Check "Add Python to PATH" during installation.
|
|
22
|
+
|
|
23
|
+
If winget is available:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
winget install Python.Python.3
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Linux
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Debian/Ubuntu
|
|
33
|
+
sudo apt update && sudo apt install python3 python3-pip python3-venv
|
|
34
|
+
|
|
35
|
+
# Fedora
|
|
36
|
+
sudo dnf install python3 python3-pip
|
|
37
|
+
|
|
38
|
+
# Arch
|
|
39
|
+
sudo pacman -S python
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## uv (optional, fast package manager)
|
|
43
|
+
|
|
44
|
+
uv is a fast Python package and environment manager. Install it separately:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# macOS/Linux
|
|
48
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
49
|
+
|
|
50
|
+
# Windows
|
|
51
|
+
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
52
|
+
```
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: shell
|
|
3
|
+
description: Write and run shell scripts. Use for automation, file operations, pipelines, and system tasks. Covers bash/zsh (macOS/Linux) and PowerShell (Windows).
|
|
4
|
+
tags: shell,cli
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Shell Skill
|
|
8
|
+
|
|
9
|
+
## Unix (bash/zsh)
|
|
10
|
+
|
|
11
|
+
### Variables & strings
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
name="alice"
|
|
15
|
+
echo "Hello, $name"
|
|
16
|
+
echo "Home is ${HOME}"
|
|
17
|
+
|
|
18
|
+
# Command substitution
|
|
19
|
+
files=$(ls -1 | wc -l)
|
|
20
|
+
today=$(date +%Y-%m-%d)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Conditionals
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
if [ -f "file.txt" ]; then
|
|
27
|
+
echo "exists"
|
|
28
|
+
elif [ -d "dir" ]; then
|
|
29
|
+
echo "is a directory"
|
|
30
|
+
else
|
|
31
|
+
echo "not found"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# One-liner
|
|
35
|
+
[ -f "file.txt" ] && echo "exists" || echo "missing"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Loops
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Over a list
|
|
42
|
+
for name in alice bob carol; do
|
|
43
|
+
echo "Hello, $name"
|
|
44
|
+
done
|
|
45
|
+
|
|
46
|
+
# Over files
|
|
47
|
+
for f in *.log; do
|
|
48
|
+
echo "Processing $f"
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
# While loop
|
|
52
|
+
while IFS= read -r line; do
|
|
53
|
+
echo "$line"
|
|
54
|
+
done < input.txt
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Functions
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
greet() {
|
|
61
|
+
local name="$1"
|
|
62
|
+
echo "Hello, $name"
|
|
63
|
+
}
|
|
64
|
+
greet "alice"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Pipes & redirection
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Pipe output
|
|
71
|
+
cat file.txt | grep "error" | sort | uniq -c
|
|
72
|
+
|
|
73
|
+
# Redirect stdout
|
|
74
|
+
echo "log" >> output.log
|
|
75
|
+
|
|
76
|
+
# Redirect stderr
|
|
77
|
+
command 2>> errors.log
|
|
78
|
+
|
|
79
|
+
# Redirect both
|
|
80
|
+
command > output.log 2>&1
|
|
81
|
+
|
|
82
|
+
# Discard output
|
|
83
|
+
command > /dev/null 2>&1
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Error handling
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Exit on first error
|
|
90
|
+
set -e
|
|
91
|
+
|
|
92
|
+
# Exit on unset variable
|
|
93
|
+
set -u
|
|
94
|
+
|
|
95
|
+
# Catch pipe failures
|
|
96
|
+
set -o pipefail
|
|
97
|
+
|
|
98
|
+
# Combine (recommended for scripts)
|
|
99
|
+
set -euo pipefail
|
|
100
|
+
|
|
101
|
+
# Check exit code
|
|
102
|
+
if ! command; then
|
|
103
|
+
echo "command failed"
|
|
104
|
+
fi
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Useful patterns
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Find files by name
|
|
111
|
+
find . -name "*.log" -type f
|
|
112
|
+
|
|
113
|
+
# Find and delete
|
|
114
|
+
find . -name "*.tmp" -type f -delete
|
|
115
|
+
|
|
116
|
+
# Find and execute
|
|
117
|
+
find . -name "*.js" -exec wc -l {} +
|
|
118
|
+
|
|
119
|
+
# Filter with grep
|
|
120
|
+
grep -r "TODO" src/ --include="*.ts"
|
|
121
|
+
|
|
122
|
+
# Transform with awk
|
|
123
|
+
awk '{print $1, $3}' data.txt
|
|
124
|
+
|
|
125
|
+
# Process with xargs
|
|
126
|
+
find . -name "*.log" | xargs rm -f
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Windows (PowerShell)
|
|
132
|
+
|
|
133
|
+
### Variables & strings
|
|
134
|
+
|
|
135
|
+
```powershell
|
|
136
|
+
$name = "alice"
|
|
137
|
+
Write-Output "Hello, $name"
|
|
138
|
+
|
|
139
|
+
# Command substitution
|
|
140
|
+
$files = (Get-ChildItem).Count
|
|
141
|
+
$today = Get-Date -Format "yyyy-MM-dd"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Conditionals
|
|
145
|
+
|
|
146
|
+
```powershell
|
|
147
|
+
if (Test-Path "file.txt") {
|
|
148
|
+
Write-Output "exists"
|
|
149
|
+
} elseif (Test-Path "dir" -PathType Container) {
|
|
150
|
+
Write-Output "is a directory"
|
|
151
|
+
} else {
|
|
152
|
+
Write-Output "not found"
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Loops
|
|
157
|
+
|
|
158
|
+
```powershell
|
|
159
|
+
# Over a list
|
|
160
|
+
foreach ($name in "alice", "bob", "carol") {
|
|
161
|
+
Write-Output "Hello, $name"
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
# Over files
|
|
165
|
+
Get-ChildItem *.log | ForEach-Object {
|
|
166
|
+
Write-Output "Processing $($_.Name)"
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Functions
|
|
171
|
+
|
|
172
|
+
```powershell
|
|
173
|
+
function Greet {
|
|
174
|
+
param($Name)
|
|
175
|
+
Write-Output "Hello, $Name"
|
|
176
|
+
}
|
|
177
|
+
Greet "alice"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Pipes & redirection
|
|
181
|
+
|
|
182
|
+
```powershell
|
|
183
|
+
# Pipe objects
|
|
184
|
+
Get-Content file.txt | Select-String "error" | Sort-Object | Get-Unique
|
|
185
|
+
|
|
186
|
+
# Redirect to file
|
|
187
|
+
"log" | Out-File -Append output.log
|
|
188
|
+
|
|
189
|
+
# Discard output
|
|
190
|
+
command | Out-Null
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Error handling
|
|
194
|
+
|
|
195
|
+
```powershell
|
|
196
|
+
# Stop on error
|
|
197
|
+
$ErrorActionPreference = "Stop"
|
|
198
|
+
|
|
199
|
+
# Try/catch
|
|
200
|
+
try {
|
|
201
|
+
SomeCommand
|
|
202
|
+
} catch {
|
|
203
|
+
Write-Error "Failed: $_"
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Useful patterns
|
|
208
|
+
|
|
209
|
+
```powershell
|
|
210
|
+
# Find files
|
|
211
|
+
Get-ChildItem -Recurse -Filter "*.log"
|
|
212
|
+
|
|
213
|
+
# Find and delete
|
|
214
|
+
Get-ChildItem -Recurse -Filter "*.tmp" | Remove-Item
|
|
215
|
+
|
|
216
|
+
# Search in files
|
|
217
|
+
Select-String -Path "src\*.ts" -Pattern "TODO"
|
|
218
|
+
```
|
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/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
|
-
```
|