neo-skill 0.1.17 → 0.1.19
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 +43 -18
- package/package.json +1 -1
- package/src/omni_skill/README.md +53 -0
- package/src/omni_skill/cli.py +144 -4
package/README.md
CHANGED
|
@@ -22,14 +22,17 @@ pip install neo-skill
|
|
|
22
22
|
### 命令行工具(安装后)
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
#
|
|
26
|
-
omni-skill init --ai
|
|
25
|
+
# 初始化技能(从 npm 包安装所有 skills)
|
|
26
|
+
omni-skill init --ai windsurf
|
|
27
27
|
|
|
28
|
-
#
|
|
29
|
-
skill
|
|
28
|
+
# 手动安装本地创建的 skill
|
|
29
|
+
omni-skill install ./skills/my-new-skill
|
|
30
30
|
|
|
31
|
-
#
|
|
32
|
-
skill
|
|
31
|
+
# 更新 npm 包并重新初始化
|
|
32
|
+
omni-skill update
|
|
33
|
+
|
|
34
|
+
# 查看帮助
|
|
35
|
+
omni-skill --help
|
|
33
36
|
```
|
|
34
37
|
|
|
35
38
|
### 直接运行 Python 模块(开发模式)
|
|
@@ -72,29 +75,51 @@ python -m skill_creator.cli validate skills/skill-name/skillspec.json
|
|
|
72
75
|
|
|
73
76
|
### 使用场景
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
**1. 初始化技能(首次使用)**
|
|
76
79
|
```bash
|
|
77
80
|
# 初始化指定 AI 助手的技能文件
|
|
78
|
-
omni-skill init --ai claude
|
|
79
81
|
omni-skill init --ai windsurf
|
|
82
|
+
omni-skill init --ai claude
|
|
80
83
|
omni-skill init --ai all # 初始化所有支持的 AI 助手
|
|
81
|
-
|
|
82
|
-
# 更新(基于上次 init 的配置)
|
|
83
|
-
omni-skill update
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
这会:
|
|
87
|
+
- 从 npm 包同步 skills/ 和 .shared/ 到当前目录
|
|
88
|
+
- 为所有 skills 生成**指定 AI 助手**的输出文件
|
|
89
|
+
- `--ai windsurf` → 只生成 `.windsurf/workflows/`
|
|
90
|
+
- `--ai claude` → 只生成 `.claude/skills/`
|
|
91
|
+
- `--ai all` → 生成所有目标
|
|
92
|
+
- 保存初始化状态到 .neo-skill.json
|
|
93
|
+
|
|
94
|
+
**2. 使用 skill-creator 创建新 skill**
|
|
95
|
+
|
|
96
|
+
在 IDE 中输入 `/skill-creator`(Windsurf)或使用其他 AI 助手的触发方式,按照对话式流程创建新 skill。
|
|
97
|
+
|
|
98
|
+
**3. 安装刚创建的 skill**
|
|
87
99
|
```bash
|
|
88
|
-
#
|
|
89
|
-
skill
|
|
100
|
+
# 安装单个 skill
|
|
101
|
+
omni-skill install ./skills/my-new-skill
|
|
90
102
|
|
|
91
|
-
#
|
|
92
|
-
skill
|
|
103
|
+
# 或安装整个 skills 目录
|
|
104
|
+
omni-skill install ./skills
|
|
105
|
+
```
|
|
93
106
|
|
|
94
|
-
|
|
95
|
-
|
|
107
|
+
这会:
|
|
108
|
+
- 复制 skill 到当前目录的 skills/ 文件夹
|
|
109
|
+
- 为该 skill 生成**所有 AI 助手**的输出文件(.windsurf, .claude, .cursor, .github)
|
|
110
|
+
|
|
111
|
+
**注意**:与 `init` 不同,`install` 命令总是生成所有 AI 目标的输出,以确保最大兼容性。
|
|
112
|
+
|
|
113
|
+
**4. 更新 npm 包**
|
|
114
|
+
```bash
|
|
115
|
+
# 更新到最新版本并重新初始化
|
|
116
|
+
omni-skill update
|
|
96
117
|
```
|
|
97
118
|
|
|
119
|
+
这会:
|
|
120
|
+
- 运行 `npm install neo-skill@latest`
|
|
121
|
+
- 重新执行 `omni-skill init`(使用保存的 AI 目标)
|
|
122
|
+
|
|
98
123
|
**在其他项目中使用**
|
|
99
124
|
将 neo-skill 仓库克隆到你的项目中(例如 `vendor/neo-skill/`),然后:
|
|
100
125
|
1. 设置 PYTHONPATH:`export PYTHONPATH=$PWD/vendor/neo-skill/src:$PYTHONPATH`
|
package/package.json
CHANGED
package/src/omni_skill/README.md
CHANGED
|
@@ -10,3 +10,56 @@
|
|
|
10
10
|
## 约定
|
|
11
11
|
|
|
12
12
|
- 同步规则与生成行为应保持确定性(同输入得到同输出)。
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
### `omni-skill init --ai <target>`
|
|
17
|
+
Initialize skills for target AI assistants.
|
|
18
|
+
|
|
19
|
+
**Usage:**
|
|
20
|
+
```bash
|
|
21
|
+
omni-skill init --ai windsurf
|
|
22
|
+
omni-skill init --ai claude
|
|
23
|
+
omni-skill init --ai all
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**What it does:**
|
|
27
|
+
1. Syncs skills/ and .shared/ from npm package to current directory
|
|
28
|
+
2. Installs all skills (generates outputs for **specified AI targets only**)
|
|
29
|
+
3. Writes VERSION files for each AI target
|
|
30
|
+
4. Saves init state to .neo-skill.json
|
|
31
|
+
|
|
32
|
+
**Example:**
|
|
33
|
+
- `omni-skill init --ai windsurf` → Only generates `.windsurf/workflows/`
|
|
34
|
+
- `omni-skill init --ai claude` → Only generates `.claude/skills/`
|
|
35
|
+
- `omni-skill init --ai all` → Generates all targets (.windsurf, .claude, .cursor, .github)
|
|
36
|
+
|
|
37
|
+
### `omni-skill install <path>`
|
|
38
|
+
Install skill(s) from a local directory.
|
|
39
|
+
|
|
40
|
+
**Usage:**
|
|
41
|
+
```bash
|
|
42
|
+
# Install a single skill
|
|
43
|
+
omni-skill install ./skills/my-new-skill
|
|
44
|
+
|
|
45
|
+
# Install all skills from a directory
|
|
46
|
+
omni-skill install ./skills
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**What it does:**
|
|
50
|
+
1. Copies skill(s) to current directory's skills/ folder
|
|
51
|
+
2. Generates outputs for **all AI targets** (.windsurf, .claude, .cursor, .github)
|
|
52
|
+
|
|
53
|
+
**Note:** Unlike `init`, the `install` command always generates outputs for all AI targets to ensure maximum compatibility.
|
|
54
|
+
|
|
55
|
+
### `omni-skill update`
|
|
56
|
+
Update npm package and re-initialize skills.
|
|
57
|
+
|
|
58
|
+
**Usage:**
|
|
59
|
+
```bash
|
|
60
|
+
omni-skill update
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**What it does:**
|
|
64
|
+
1. Runs `npm install neo-skill@latest`
|
|
65
|
+
2. Re-runs `omni-skill init` with saved AI targets
|
package/src/omni_skill/cli.py
CHANGED
|
@@ -4,7 +4,7 @@ import argparse
|
|
|
4
4
|
import json
|
|
5
5
|
import shutil
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Dict, List, Set
|
|
7
|
+
from typing import Dict, List, Optional, Set
|
|
8
8
|
|
|
9
9
|
from skill_creator.cli import cmd_generate
|
|
10
10
|
|
|
@@ -185,13 +185,96 @@ def _generate_outputs_best_effort(pkg_root: Path, cwd: Path) -> None:
|
|
|
185
185
|
print("\nGenerating skill outputs from skillspec.json ...")
|
|
186
186
|
for spec_path in specs:
|
|
187
187
|
try:
|
|
188
|
-
ns = argparse.Namespace(repo_root=str(cwd), spec=str(spec_path))
|
|
188
|
+
ns = argparse.Namespace(repo_root=str(cwd), spec=str(spec_path), all=True)
|
|
189
189
|
cmd_generate(ns)
|
|
190
190
|
except SystemExit as e:
|
|
191
191
|
rel = spec_path.relative_to(cwd) if spec_path.is_relative_to(cwd) else spec_path
|
|
192
192
|
print(f" Skipping generator for {rel} (exit {e.code})")
|
|
193
193
|
|
|
194
194
|
|
|
195
|
+
def _install_skills_from_dir(skills_dir: Path, cwd: Path, selected_ais: Optional[List[str]] = None) -> int:
|
|
196
|
+
"""
|
|
197
|
+
Install skills from a directory (either from npm package or local path).
|
|
198
|
+
Generates outputs for specified AI targets.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
skills_dir: Directory containing skills
|
|
202
|
+
cwd: Current working directory
|
|
203
|
+
selected_ais: List of AI targets to generate for. If None, generates for all targets.
|
|
204
|
+
"""
|
|
205
|
+
if not skills_dir.exists():
|
|
206
|
+
print(f"Skills directory not found: {skills_dir}")
|
|
207
|
+
return 1
|
|
208
|
+
|
|
209
|
+
specs = sorted(skills_dir.glob("*/skillspec.json"))
|
|
210
|
+
if not specs:
|
|
211
|
+
print(f"No skillspec.json found in: {skills_dir}")
|
|
212
|
+
return 1
|
|
213
|
+
|
|
214
|
+
# Determine target mapping: AI assistant -> skill-creator target
|
|
215
|
+
ai_to_target = {
|
|
216
|
+
"windsurf": "windsurf",
|
|
217
|
+
"claude": "claude",
|
|
218
|
+
"cursor": "cursor",
|
|
219
|
+
"antigravity": "github",
|
|
220
|
+
"copilot": "github",
|
|
221
|
+
"kiro": "github",
|
|
222
|
+
"codex": "github",
|
|
223
|
+
"qoder": "github",
|
|
224
|
+
"roocode": "github",
|
|
225
|
+
"gemini": "github",
|
|
226
|
+
"trae": "github",
|
|
227
|
+
"opencode": "github",
|
|
228
|
+
"continue": "github",
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
# Determine which targets to generate
|
|
232
|
+
if selected_ais is None:
|
|
233
|
+
# Generate all targets
|
|
234
|
+
generate_all_targets = True
|
|
235
|
+
targets_list = None
|
|
236
|
+
else:
|
|
237
|
+
# Map AI assistants to skill-creator targets
|
|
238
|
+
targets_set = set()
|
|
239
|
+
for ai in selected_ais:
|
|
240
|
+
target = ai_to_target.get(ai, "windsurf")
|
|
241
|
+
targets_set.add(target)
|
|
242
|
+
targets_list = sorted(targets_set)
|
|
243
|
+
generate_all_targets = False
|
|
244
|
+
|
|
245
|
+
print(f"\nInstalling {len(specs)} skill(s) from {skills_dir} ...")
|
|
246
|
+
for spec_path in specs:
|
|
247
|
+
skill_name = spec_path.parent.name
|
|
248
|
+
print(f" Installing skill: {skill_name}")
|
|
249
|
+
|
|
250
|
+
# Copy skill to cwd/skills if not already there
|
|
251
|
+
dest_skill_dir = cwd / "skills" / skill_name
|
|
252
|
+
if spec_path.parent.resolve() != dest_skill_dir.resolve():
|
|
253
|
+
dest_skill_dir.parent.mkdir(parents=True, exist_ok=True)
|
|
254
|
+
if dest_skill_dir.exists():
|
|
255
|
+
import shutil
|
|
256
|
+
shutil.rmtree(dest_skill_dir)
|
|
257
|
+
shutil.copytree(spec_path.parent, dest_skill_dir)
|
|
258
|
+
print(f" Copied to: {dest_skill_dir}")
|
|
259
|
+
|
|
260
|
+
# Generate outputs for specified targets
|
|
261
|
+
try:
|
|
262
|
+
if generate_all_targets:
|
|
263
|
+
ns = argparse.Namespace(repo_root=str(cwd), spec=str(cwd / "skills" / skill_name / "skillspec.json"), all=True)
|
|
264
|
+
cmd_generate(ns)
|
|
265
|
+
print(f" Generated outputs for all targets")
|
|
266
|
+
else:
|
|
267
|
+
# Generate for each target separately
|
|
268
|
+
for target in targets_list:
|
|
269
|
+
ns = argparse.Namespace(repo_root=str(cwd), spec=str(cwd / "skills" / skill_name / "skillspec.json"), all=False, target=target)
|
|
270
|
+
cmd_generate(ns)
|
|
271
|
+
print(f" Generated outputs for: {', '.join(targets_list)}")
|
|
272
|
+
except SystemExit as e:
|
|
273
|
+
print(f" Warning: Generator failed (exit {e.code})")
|
|
274
|
+
|
|
275
|
+
return 0
|
|
276
|
+
|
|
277
|
+
|
|
195
278
|
def _handle_init(selected_ais: List[str], mode: str) -> int:
|
|
196
279
|
pkg_root = _get_pkg_root()
|
|
197
280
|
cwd = Path.cwd().resolve()
|
|
@@ -201,7 +284,12 @@ def _handle_init(selected_ais: List[str], mode: str) -> int:
|
|
|
201
284
|
sync_pairs = _build_sync_pairs(effective_ais)
|
|
202
285
|
print("Initializing skills in:", cwd)
|
|
203
286
|
_perform_sync(pkg_root, cwd, sync_pairs)
|
|
204
|
-
|
|
287
|
+
|
|
288
|
+
# Install all skills from npm package with specified AI targets
|
|
289
|
+
pkg_skills_dir = pkg_root / "skills"
|
|
290
|
+
if pkg_skills_dir.exists():
|
|
291
|
+
_install_skills_from_dir(pkg_skills_dir, cwd, selected_ais=selected_ais)
|
|
292
|
+
|
|
205
293
|
_write_version_files(cwd, effective_ais, version)
|
|
206
294
|
print("\nDone! neo-skill initialized.")
|
|
207
295
|
|
|
@@ -222,11 +310,59 @@ def _cmd_init(args: argparse.Namespace) -> int:
|
|
|
222
310
|
return _handle_init(resolved["selected"], "init")
|
|
223
311
|
|
|
224
312
|
|
|
313
|
+
def _cmd_install(args: argparse.Namespace) -> int:
|
|
314
|
+
"""
|
|
315
|
+
Install skill(s) from a local directory.
|
|
316
|
+
Usage: omni-skill install <path-to-skill-or-skills-dir>
|
|
317
|
+
|
|
318
|
+
Note: install command always generates outputs for all AI targets.
|
|
319
|
+
"""
|
|
320
|
+
cwd = Path.cwd().resolve()
|
|
321
|
+
skill_path = Path(args.path).resolve()
|
|
322
|
+
|
|
323
|
+
if not skill_path.exists():
|
|
324
|
+
raise SystemExit(f"Path not found: {skill_path}")
|
|
325
|
+
|
|
326
|
+
# Check if it's a single skill directory (contains skillspec.json)
|
|
327
|
+
if (skill_path / "skillspec.json").exists():
|
|
328
|
+
# Single skill - generate for all targets
|
|
329
|
+
temp_skills_dir = skill_path.parent
|
|
330
|
+
return _install_skills_from_dir(temp_skills_dir, cwd, selected_ais=None)
|
|
331
|
+
|
|
332
|
+
# Check if it's a skills directory (contains subdirs with skillspec.json)
|
|
333
|
+
elif skill_path.is_dir():
|
|
334
|
+
return _install_skills_from_dir(skill_path, cwd, selected_ais=None)
|
|
335
|
+
|
|
336
|
+
else:
|
|
337
|
+
raise SystemExit(f"Invalid path: {skill_path}. Must be a skill directory or skills directory.")
|
|
338
|
+
|
|
339
|
+
|
|
225
340
|
def _cmd_update(args: argparse.Namespace) -> int:
|
|
341
|
+
"""
|
|
342
|
+
Update npm package and re-initialize skills.
|
|
343
|
+
"""
|
|
344
|
+
import subprocess
|
|
345
|
+
|
|
226
346
|
cwd = Path.cwd().resolve()
|
|
227
347
|
state = _read_init_state(cwd)
|
|
228
348
|
if not state["ok"]:
|
|
229
349
|
raise SystemExit(state["error"])
|
|
350
|
+
|
|
351
|
+
print("Updating neo-skill npm package...")
|
|
352
|
+
result = subprocess.run(
|
|
353
|
+
["npm", "install", "neo-skill@latest"],
|
|
354
|
+
cwd=cwd,
|
|
355
|
+
capture_output=True,
|
|
356
|
+
text=True
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
if result.returncode != 0:
|
|
360
|
+
print(f"Warning: npm install failed: {result.stderr}")
|
|
361
|
+
print("Continuing with re-initialization...")
|
|
362
|
+
else:
|
|
363
|
+
print("Package updated successfully.")
|
|
364
|
+
|
|
365
|
+
print("\nRe-initializing skills...")
|
|
230
366
|
return _handle_init(state["selected"], "update")
|
|
231
367
|
|
|
232
368
|
|
|
@@ -253,7 +389,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
253
389
|
p_init.add_argument("--ai", action="append", help="Target AI (can be repeated)")
|
|
254
390
|
p_init.set_defaults(func=_cmd_init)
|
|
255
391
|
|
|
256
|
-
|
|
392
|
+
p_install = sub.add_parser("install", help="Install skill(s) from a local directory")
|
|
393
|
+
p_install.add_argument("path", help="Path to skill directory or skills directory")
|
|
394
|
+
p_install.set_defaults(func=_cmd_install)
|
|
395
|
+
|
|
396
|
+
p_update = sub.add_parser("update", help="Update npm package and re-initialize skills")
|
|
257
397
|
p_update.set_defaults(func=_cmd_update)
|
|
258
398
|
|
|
259
399
|
return p
|