@anov/gis-skills-cli 0.3.0 → 0.3.4
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/CHANGELOG.md +24 -0
- package/INSTALL.md +59 -22
- package/README.md +10 -9
- package/RELEASING.md +6 -4
- package/bin/anov-gis-skills.mjs +217 -84
- package/lib/agents.mjs +236 -0
- package/lib/mcp-config.mjs +28 -5
- package/package.json +2 -1
- package/skills/using-anovgis/DEMO-SKILL-MAP.md +1 -1
- package/skills/using-anovgis/DOMAINS.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,30 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.3.4] - 2026-11-02
|
|
8
|
+
|
|
9
|
+
- feat: setup 按检测到的智能体安装 skill 与 MCP,修 Codex 装错目录 (`1379891`)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## [0.3.3] - 2026-11-02
|
|
13
|
+
|
|
14
|
+
- fix: README 文档链接改绝对 URL,修 npm 包页面点不开的问题 (`a118366`)
|
|
15
|
+
- feat: npm run release 自动打 tag 并推送 (`018027d`)
|
|
16
|
+
- feat: npm run release 自动提交并推送发版文件 (`e6c5bb1`)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## [0.3.2] - 2026-10-30
|
|
20
|
+
|
|
21
|
+
- chore: 新增 npm run release 一键发版脚本 (`e147f1d`)
|
|
22
|
+
- fix: setup 只装已检测智能体,MCP 默认写 Claude Code + Codex (`ee704ee`)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## [0.3.1] - 2026-10-30
|
|
26
|
+
|
|
27
|
+
- chore: 新增 npm run release 一键发版脚本 (`e147f1d`)
|
|
28
|
+
- fix: setup 只装已检测智能体,MCP 默认写 Claude Code + Codex (`ee704ee`)
|
|
29
|
+
|
|
30
|
+
|
|
7
31
|
## [0.3.0] - 2026-10-30
|
|
8
32
|
|
|
9
33
|
分发体系改造:npm 包内置 Cesium skill(vendor 15 个,Apache-2.0)、CLI 命令族重写为 setup/mcp/doctor/uninstall、MCP 配置自动写入各智能体
|
package/INSTALL.md
CHANGED
|
@@ -44,10 +44,10 @@ anov-gis-skills setup
|
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
46
|
# 装到哪(默认用户级,任何项目都能用)
|
|
47
|
-
npx @anov/gis-skills-cli setup # →
|
|
47
|
+
npx @anov/gis-skills-cli setup # → 探测到的智能体各自的 skill 目录
|
|
48
48
|
npx @anov/gis-skills-cli setup --project # → ./.claude/skills/,可提交进项目仓库
|
|
49
49
|
|
|
50
|
-
#
|
|
50
|
+
# 装给谁(默认:探测到的所有智能体)
|
|
51
51
|
npx @anov/gis-skills-cli setup --agent claude-code
|
|
52
52
|
npx @anov/gis-skills-cli setup --agent claude-code --agent codex
|
|
53
53
|
|
|
@@ -60,13 +60,35 @@ npx @anov/gis-skills-cli setup --print
|
|
|
60
60
|
|
|
61
61
|
### A.3 各智能体的落点
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
63
|
+
`setup` 探测本机装了哪些智能体 —— **判定标准是「配置目录存在且非空」**(空目录不算),只装给探测到的那些:
|
|
64
|
+
|
|
65
|
+
| 智能体 | 探测目录 | skill 装到 | MCP 配置写到 |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| Claude Code | `~/.claude` | `~/.claude/skills/` | `~/.claude.json` 的 `mcpServers`(项目级 → `./.mcp.json`) |
|
|
68
|
+
| Codex | `~/.codex` | `~/.codex/skills/` | `~/.codex/config.toml` 的 `[mcp_servers.anov-gis]` |
|
|
69
|
+
| Cursor | `~/.cursor` | `~/.cursor/skills/` | `~/.cursor/mcp.json`(项目级 → `./.cursor/mcp.json`) |
|
|
70
|
+
| OpenClaw | `~/.openclaw` | `~/.openclaw/skills/` | 不支持 |
|
|
71
|
+
| Hermes Agent | `~/.hermes` | `~/.hermes/skills/` | 不支持 |
|
|
72
|
+
| Trae | `~/.trae` | `~/.trae/skills/` | 不支持 |
|
|
73
|
+
| Trae CN | `~/.trae-cn` | `~/.trae-cn/skills/` | 不支持 |
|
|
74
|
+
| Gemini CLI | `~/.gemini` | `~/.gemini/skills/` | 不支持 |
|
|
75
|
+
| Antigravity | `~/.gemini/config` | `~/.gemini/config/skills/` | 不支持 |
|
|
76
|
+
| GitHub Copilot | `~/.copilot` | `~/.copilot/skills/` | 不支持 |
|
|
77
|
+
| VS Code | `./.vscode` | 不支持 | `./.vscode/mcp.json` 的 `servers`(仅项目级) |
|
|
78
|
+
| Claude 桌面端 | `%APPDATA%/Claude` | 不支持(只能在 UI 里上传) | `claude_desktop_config.json` 的 `mcpServers` |
|
|
79
|
+
| 共享目录 | `~/.kimi-code` / `~/.cline` / `~/.dexto` / `~/.loaf` / `~/.warp` 等任一 | `~/.agents/skills/` | 不支持 |
|
|
80
|
+
|
|
81
|
+
> **落点为什么不全信上游。** 底层 `skills` CLI 把所有「项目级 skill 目录是 `.agents/skills`」的智能体归成一族,
|
|
82
|
+
> 用户级一律装到 `~/.agents/skills`。这对 Codex / Cursor / Gemini CLI / Antigravity / Copilot 都是错的 ——
|
|
83
|
+
> 它们各有自己的用户级目录(如 Codex 只读 `~/.codex/skills`)。这几个由本 CLI 直接复制到正确位置,
|
|
84
|
+
> 装完还会核对一遍落点,上游算错就兜底。
|
|
85
|
+
|
|
86
|
+
> **几个容易搞混的读法。**
|
|
87
|
+
> - Cursor 同时读 `~/.agents/skills/` 和 `~/.cursor/skills/`,但**只有 `~/.cursor/skills/` 会同步到 Cloud Agents**。
|
|
88
|
+
> - Codex 只读 `~/.codex/skills`(`~/.agents/skills` 是项目级路径)。
|
|
89
|
+
> - Antigravity 的 App / CLI / IDE 现在共用 `~/.gemini/config/skills/`,**App 不读 `~/.gemini/skills/`**。
|
|
90
|
+
> - Claude Code 桌面版(Code 标签页)与 CLI 共享 `~/.claude/skills`,装一次两边都有。
|
|
91
|
+
> - 「Claude 桌面端」指 claude.ai 桌面聊天端,它的 skill 只能在 UI 里上传,本 CLI 只能帮它写 MCP。
|
|
70
92
|
|
|
71
93
|
底层 `skills` CLI 版本**锁定在 `skills@1.5.18`**(不是 latest):1.6.0+ 的 `engines` 要求 `node >= 22.20.0`,而团队环境实测是 node 22.19.0,锁低版本才能在 node ≥ 18 全覆盖。
|
|
72
94
|
|
|
@@ -87,12 +109,12 @@ npx @anov/gis-skills-cli setup --print
|
|
|
87
109
|
|
|
88
110
|
### A.5 MCP 接入
|
|
89
111
|
|
|
90
|
-
`setup`
|
|
112
|
+
`setup` 默认给**探测到的**每个智能体各写一条 MCP 配置(stdio 直连 `anov-gis-mcp`)—— 没装的智能体不会留配置,避免「MCP 配好了但一个 skill 都没有」的半装状态。单独管理:
|
|
91
113
|
|
|
92
114
|
```bash
|
|
93
115
|
npx @anov/gis-skills-cli mcp show # 看当前状态
|
|
94
|
-
npx @anov/gis-skills-cli mcp add #
|
|
95
|
-
npx @anov/gis-skills-cli mcp add --mcp-agent
|
|
116
|
+
npx @anov/gis-skills-cli mcp add # 补上(默认写给检测到的智能体 + 用户级)
|
|
117
|
+
npx @anov/gis-skills-cli mcp add --mcp-agent cursor
|
|
96
118
|
npx @anov/gis-skills-cli mcp remove # 拿掉
|
|
97
119
|
```
|
|
98
120
|
|
|
@@ -100,7 +122,7 @@ npx @anov/gis-skills-cli mcp remove # 拿掉
|
|
|
100
122
|
|
|
101
123
|
| 参数 | 说明 |
|
|
102
124
|
|---|---|
|
|
103
|
-
| `--mcp-agent
|
|
125
|
+
| `--mcp-agent <名字...>` | `claude-code` / `codex` / `cursor` / `vscode` / `claude-desktop`,可指定多个;不指定就只写检测到的 |
|
|
104
126
|
| `--mcp-mode stdio\|http` | 默认 `stdio`(本地起进程);`http` 连服务器 |
|
|
105
127
|
| `--mcp-url <地址>` | HTTP 模式必填,例如 `http://192.168.11.164:3000/mcp` |
|
|
106
128
|
| `--mcp-command` / `--mcp-arg` | 自定义 stdio 启动命令(默认 `npx -y anov-gis-mcp --stdio`) |
|
|
@@ -121,17 +143,28 @@ npx @anov/gis-skills-cli mcp remove # 拿掉
|
|
|
121
143
|
npx @anov/gis-skills-cli doctor
|
|
122
144
|
```
|
|
123
145
|
|
|
124
|
-
|
|
146
|
+
逐个落点报:
|
|
125
147
|
|
|
126
148
|
```
|
|
127
149
|
包内 skill 数:27
|
|
128
150
|
|
|
129
|
-
──
|
|
130
|
-
✓
|
|
151
|
+
── skill 落点 ──
|
|
152
|
+
✓ Claude Code C:\Users\你\.claude\skills —— 27/27 齐全
|
|
153
|
+
✓ frontmatter 全部可被严格 YAML 解析
|
|
154
|
+
✓ Codex C:\Users\你\.codex\skills —— 27/27 齐全
|
|
131
155
|
✓ frontmatter 全部可被严格 YAML 解析
|
|
156
|
+
· Cursor C:\Users\你\.cursor\skills —— 未安装该智能体
|
|
157
|
+
|
|
158
|
+
── MCP ──
|
|
132
159
|
|
|
133
|
-
|
|
160
|
+
Claude Code(用户级) —— C:\Users\你\.claude.json
|
|
134
161
|
✓ 已配置(stdio)
|
|
162
|
+
|
|
163
|
+
Codex(用户级) —— C:\Users\你\.codex\config.toml
|
|
164
|
+
✓ 已配置(stdio)
|
|
165
|
+
|
|
166
|
+
── 一致性 ──
|
|
167
|
+
✓ 没有「MCP 配了但 skill 缺失」的半装状态
|
|
135
168
|
```
|
|
136
169
|
|
|
137
170
|
| 检查项 | 不通过意味着 |
|
|
@@ -139,6 +172,7 @@ npx @anov/gis-skills-cli doctor
|
|
|
139
172
|
| skill 齐全 | 装漏了,或只装了一部分(单独装部分 skill 时跨 skill 链接会失效) |
|
|
140
173
|
| frontmatter 可被严格 YAML 解析 | 某些 agent 的 skill 加载器会**整个跳过**这个 skill(v0.2.17 踩过:只发现 10/12) |
|
|
141
174
|
| MCP 已配置 | 少了条目 —— 跑 `mcp add` |
|
|
175
|
+
| 一致性 | 该智能体 MCP 配了但一个 skill 都没有 —— 跑 `setup` 补上 |
|
|
142
176
|
|
|
143
177
|
有问题会逐条列出并以退出码 1 结束。
|
|
144
178
|
|
|
@@ -241,7 +275,7 @@ Claude Code 走 marketplace,多两个好处:**发版后自动升级**、**
|
|
|
241
275
|
|
|
242
276
|
> ⚠️ **版本约束只对 `enabledPlugins` 生效**。`/plugin install` 与 `claude plugin install` 的参数只接受 `插件名` 或 `插件名@市场名`(第三段会被丢弃),所以**命令行装的时候锁不住版本** —— 要锁版本就靠 settings 里的 `enabledPlugins`。
|
|
243
277
|
|
|
244
|
-
**完全锁死(不推荐)**:把约束写成精确版本 `anov-gis-skills@anov-gis-skills@0.3.
|
|
278
|
+
**完全锁死(不推荐)**:把约束写成精确版本 `anov-gis-skills@anov-gis-skills@0.3.4`。精确锁定后**不会自动升级**,每次发版都要人工改这一行 —— 这正是 v0.2.15 之前"发完版还要挨个催"的原因。
|
|
245
279
|
|
|
246
280
|
### B.4 插件缓存位置
|
|
247
281
|
|
|
@@ -294,7 +328,8 @@ npx skills add <repo-url> -l
|
|
|
294
328
|
npx skills update
|
|
295
329
|
```
|
|
296
330
|
|
|
297
|
-
- 装到 `~/.claude/skills/`(Claude Code)、`~/.
|
|
331
|
+
- 装到 `~/.claude/skills/`(Claude Code)、`~/.agents/skills/`(Codex / Cursor / Cline 等共用一个目录)等位置
|
|
332
|
+
—— 上游把「项目级目录是 `.agents/skills`」的一族都归到共享目录,Codex 的 `~/.codex/skills`、Cursor 的 `~/.cursor/skills` 不会被填;要装对请用 §方式 A
|
|
298
333
|
- 默认**拷贝**(`--copy` 是显式开关,默认行为随版本变化);加 `--copy` 强制拷贝
|
|
299
334
|
- **不带 cesiumjs-skills** —— 这条路没有 marketplace 的 `dependencies` 机制,Cesium 原生 skill 要单独装(见 §方式 B.5)
|
|
300
335
|
|
|
@@ -448,9 +483,9 @@ git clone https://github.com/CesiumGS/cesiumjs-skills.git ~/.codex/skills/cesium
|
|
|
448
483
|
| 场景 | 说明 |
|
|
449
484
|
|---|---|
|
|
450
485
|
| 首次开启 `autoUpdate` | 2026-10 之前装的,`known_marketplaces.json` 里 `autoUpdate` 默认是 `false`(第三方 marketplace 的默认值)。改一次 §方式 B.2 的配置或跑一次 `/plugin marketplace update` 即可 |
|
|
451
|
-
| 用了精确锁版本 | `anov-gis-skills@anov-gis-skills@0.3.
|
|
486
|
+
| 用了精确锁版本 | `anov-gis-skills@anov-gis-skills@0.3.4` 这种精确锁定**不会自动升级**,必须改这一行 |
|
|
452
487
|
| 提示 restart required | 重开 Claude Code 会话 |
|
|
453
|
-
| 想立刻跳到指定版本 | `/plugin install anov-gis-skills@anov-gis-skills@0.3.
|
|
488
|
+
| 想立刻跳到指定版本 | `/plugin install anov-gis-skills@anov-gis-skills@0.3.4`(降级同理) |
|
|
454
489
|
|
|
455
490
|
### 查看当前版本
|
|
456
491
|
|
|
@@ -461,7 +496,7 @@ git clone https://github.com/CesiumGS/cesiumjs-skills.git ~/.codex/skills/cesium
|
|
|
461
496
|
|
|
462
497
|
### 破坏性变更
|
|
463
498
|
|
|
464
|
-
**从 v0.1.1 升级到 v0.3.
|
|
499
|
+
**从 v0.1.1 升级到 v0.3.4 的破坏性变更**:无。所有 v0.1.1 skill 在 v0.3.4 仍然可用;v0.2.0 新增 3 个 skill + DOMAINS 强化;v0.2.1–v0.3.4 为修复性版本(skill 名称与目录结构未变)。
|
|
465
500
|
|
|
466
501
|
---
|
|
467
502
|
|
|
@@ -474,5 +509,7 @@ git clone https://github.com/CesiumGS/cesiumjs-skills.git ~/.codex/skills/cesium
|
|
|
474
509
|
| 插件装了但 skill 一个都没出现 | frontmatter 没被严格 YAML 解析 | 跑 `npx @anov/gis-skills-cli doctor` 看哪几条断了 |
|
|
475
510
|
| skill 只有一部分能用 | 单独装了部分 skill,指向兄弟 skill 的相对链接失效 | 全量装(12 个同级),别只装一个 |
|
|
476
511
|
| `doctor` 报 skill 不齐 | 只装了一部分 | 重跑 `setup`;仓库侧跑 `node scripts/build-npm.mjs` 复查 |
|
|
512
|
+
| `doctor` 报「MCP 配了但 skill 缺失」 | MCP 写了但 skill 没装上(0.3.3 的 bug:只装 Claude Code,MCP 却写了 Codex) | 重跑 `setup`(当前版本起按检测结果装齐) |
|
|
513
|
+
| Codex 里看不到 skill | skill 被装到了 `~/.agents/skills`,而 Codex 只读 `~/.codex/skills` | 重跑 `setup`(当前版本起直装到 `~/.codex/skills`) |
|
|
477
514
|
| 已装过官方 `cesiumjs-skills` 导致触发混乱 | 官方版与内网镜像版注册了同名 skill | 见 §方式 B.5 的卸载步骤二选一 |
|
|
478
515
|
| Chrome DevTools MCP 起不来 | 内网访问不了 npm registry | 不影响 skill 本身,可忽略 |
|
package/README.md
CHANGED
|
@@ -23,8 +23,8 @@ npx @anov/gis-skills-cli setup # 27 个 skill + MCP 接入
|
|
|
23
23
|
|
|
24
24
|
`setup` 做两件事:
|
|
25
25
|
|
|
26
|
-
1.
|
|
27
|
-
2.
|
|
26
|
+
1. 探测本机装了哪些智能体(配置目录存在且非空),把 **27 个 skill** 装到它们各自读 skill 的目录
|
|
27
|
+
2. 写 **MCP 配置**(只写探测到的智能体,stdio 直连 `anov-gis-mcp`)—— 不想要就加 `--no-mcp`
|
|
28
28
|
|
|
29
29
|
不需要预先 `npm i -g`,也不需要 clone 本仓库。
|
|
30
30
|
|
|
@@ -32,13 +32,14 @@ npx @anov/gis-skills-cli setup # 27 个 skill + MCP 接入
|
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
npx @anov/gis-skills-cli setup --project # 装到当前项目(默认用户级)
|
|
35
|
-
npx @anov/gis-skills-cli setup --agent cursor #
|
|
35
|
+
npx @anov/gis-skills-cli setup --agent cursor # 只装给某个智能体(跳过探测)
|
|
36
|
+
npx @anov/gis-skills-cli setup --agent codex --agent cursor # 装给多个智能体
|
|
36
37
|
npx @anov/gis-skills-cli setup --no-mcp # 只装 skill,不碰 MCP
|
|
37
|
-
npx @anov/gis-skills-cli mcp add --mcp-agent
|
|
38
|
+
npx @anov/gis-skills-cli mcp add --mcp-agent cursor # MCP 接到 Cursor(默认写给检测到的智能体)
|
|
38
39
|
npx @anov/gis-skills-cli uninstall # 清理(只删自己的)
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
完整参数见 [INSTALL.md](INSTALL.md)。
|
|
42
|
+
完整参数见 [INSTALL.md](https://cdn.jsdelivr.net/npm/@anov/gis-skills-cli@0.3.4/INSTALL.md)。
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
### 验证
|
|
@@ -47,11 +48,11 @@ npx @anov/gis-skills-cli uninstall # 清理(只删自己的)
|
|
|
47
48
|
npx @anov/gis-skills-cli doctor
|
|
48
49
|
```
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
逐个落点报:27 个 skill 是否齐全、frontmatter 能否被严格 YAML 解析、MCP 条目写没写对,以及有没有「MCP 配了但 skill 缺失」的半装状态。
|
|
51
52
|
|
|
52
53
|
新开一个会话提问"flowPolyline 颜色怎么改",应自动激活 `anovgis-materials` 并给出溯源 snippet。
|
|
53
54
|
|
|
54
|
-
安装排错见 [INSTALL.md](INSTALL.md
|
|
55
|
+
安装排错见 [INSTALL.md](https://cdn.jsdelivr.net/npm/@anov/gis-skills-cli@0.3.4/INSTALL.md) 的「排错」一节;地图黑屏 / Workers 404 / 材质不生效等问题看下面的「报错排查」。
|
|
55
56
|
|
|
56
57
|
---
|
|
57
58
|
|
|
@@ -77,7 +78,7 @@ npx @anov/gis-skills-cli doctor
|
|
|
77
78
|
|
|
78
79
|
### 改 SDK 自带 demo
|
|
79
80
|
|
|
80
|
-
团队最常见的场景是「复制 SDK 自带 demo → 改成自己的业务」。137 个 demo 的路由表在 [`skills/using-anovgis/DEMO-SKILL-MAP.md`](skills/using-anovgis/DEMO-SKILL-MAP.md)。
|
|
81
|
+
团队最常见的场景是「复制 SDK 自带 demo → 改成自己的业务」。137 个 demo 的路由表在 [`skills/using-anovgis/DEMO-SKILL-MAP.md`](https://cdn.jsdelivr.net/npm/@anov/gis-skills-cli@0.3.4/skills/using-anovgis/DEMO-SKILL-MAP.md)。
|
|
81
82
|
|
|
82
83
|
直接跟 AI 说文件名 + 想改什么,它会自动路由:
|
|
83
84
|
|
|
@@ -143,7 +144,7 @@ npx @anov/gis-skills-cli mcp remove # 拿掉
|
|
|
143
144
|
| 11 | `anovgis-effects` | 天气 / 漫游 / 动画 / 后期处理(Bloom / 夜视 / 景深 / 黑白)+ 天空盒 | weather、roaming、AroundPoint、FlyManager、bloom、skybox |
|
|
144
145
|
| 12 | `anovgis-pitfalls` | Cesium 1.143 + v1.8.6 典型陷阱(P0–P12)+ 自定义图元报错 | 黑屏、白屏、不生效、报错、Workers 404、AMD、CustomPrimitive |
|
|
145
146
|
|
|
146
|
-
完整路由(用户意图 → skill)见 `skills/using-anovgis/SKILL.md`;完整 demo 路由(demo 文件名 → skill)见 [`skills/using-anovgis/DEMO-SKILL-MAP.md`](skills/using-anovgis/DEMO-SKILL-MAP.md)。
|
|
147
|
+
完整路由(用户意图 → skill)见 `skills/using-anovgis/SKILL.md`;完整 demo 路由(demo 文件名 → skill)见 [`skills/using-anovgis/DEMO-SKILL-MAP.md`](https://cdn.jsdelivr.net/npm/@anov/gis-skills-cli@0.3.4/skills/using-anovgis/DEMO-SKILL-MAP.md)。
|
|
147
148
|
|
|
148
149
|
另外 15 个 Cesium skill 由官方 `cesiumjs-skills` 提供(`cesiumjs-3d-tiles` / `cesiumjs-camera` / `cesiumjs-primitives` …),
|
|
149
150
|
`using-cesiumjs-skills` 是它们的入口 —— 由 `using-anovgis` 自动转过去,你一般不用直接调用。
|
package/RELEASING.md
CHANGED
|
@@ -79,18 +79,20 @@ node scripts/bump.mjs --check # 校验所有版本位一致(发版前自检
|
|
|
79
79
|
10. **结构自检**:`node scripts/check-structure.mjs` —— 相对链接 / 锚点 / frontmatter / 章节完整性,不一致就 exit 1
|
|
80
80
|
11. **npm 包自检**:`node scripts/build-npm.mjs` —— 校验两棵 skill 树的相对链接、无本机绝对路径、vendor 齐全(15 个 skill + LICENSE + NOTICE),不一致就 exit 1
|
|
81
81
|
11b. **vendor 一致性**(改动过 Cesium skill 时):`node scripts/sync-cesium.mjs --check` —— vendor 与内网镜像不一致就 exit 1;需要更新时去掉 `--check` 重新同步,并核对 `vendor/cesiumjs-skills/NOTICE` 里的版本号
|
|
82
|
-
12. `git commit -
|
|
83
|
-
13.
|
|
82
|
+
12. **提交推送**:用 `npm run release` 时自动完成 —— 只 `git add` bump 改写的发版文件后 commit + push(`--no-commit` 可只改文件不提交)。手工流程则 `git add` 发版文件 + `git commit -m "chore: release v<X.Y.Z>"` + `git push`
|
|
83
|
+
13. **打 tag**:用 `npm run release` 时自动打 `anov-gis-skills--v<版本>` 注解 tag 并推送;不走 release 时按 §四 手工打
|
|
84
84
|
14. **发 npm 包**(方式 A 的分发源):`npm publish` —— 发到哪由仓库根 `.npmrc` 决定(内网 / 公网),见 §五
|
|
85
85
|
15. **验证已发布的包**:`node scripts/verify-published.mjs` —— 确认可安装、内容与源码一致、CLI 能发现全部 skill、链接全解析,不一致就 exit 1
|
|
86
86
|
|
|
87
87
|
> v0.2.15 起,第 8 步之前的手工改版本号(各 manifest + DOMAINS.md + DEMO-SKILL-MAP.md)全部由 `scripts/bump.mjs` 代劳,避免版本漂移。
|
|
88
|
+
>
|
|
89
|
+
> 用 `npm run release` 时,第 8–13 步(bump · 版本校验 · 结构校验 · npm 包校验 · 提交推送 · 打 tag)会一并自动执行;两道结构校验在写文件之前跑,失败则什么都不会改。
|
|
88
90
|
|
|
89
91
|
---
|
|
90
92
|
|
|
91
|
-
##
|
|
93
|
+
## 四、tag
|
|
92
94
|
|
|
93
|
-
本仓库**不跑 CI**(内网 GitLab 上没有 runner
|
|
95
|
+
本仓库**不跑 CI**(内网 GitLab 上没有 runner),没有流水线帮你打 tag —— `npm run release` 会自动打并推送,手工发版时用下面的命令。
|
|
94
96
|
|
|
95
97
|
**打 tag** —— 带版本约束的安装串(`"anov-gis-skills@anov-gis-skills@^0.3.0"`)靠这个 tag 解析版本,没有匹配 tag 会报 `no-matching-tag`:
|
|
96
98
|
|
package/bin/anov-gis-skills.mjs
CHANGED
|
@@ -5,12 +5,18 @@
|
|
|
5
5
|
// anov-gis-skills setup 装全部 skill(+ 写 MCP 配置)
|
|
6
6
|
// anov-gis-skills mcp add 只写 MCP 配置
|
|
7
7
|
// anov-gis-skills mcp remove 删掉 MCP 配置
|
|
8
|
-
// anov-gis-skills mcp show
|
|
9
|
-
// anov-gis-skills doctor
|
|
10
|
-
// anov-gis-skills uninstall
|
|
8
|
+
// anov-gis-skills mcp show 看当前配置状态
|
|
9
|
+
// anov-gis-skills doctor 自检
|
|
10
|
+
// anov-gis-skills uninstall 清理
|
|
11
11
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
12
|
+
// 装到哪、写到哪,都由 lib/agents.mjs 的一张表决定:探测本机装了哪些智能体
|
|
13
|
+
// (配置目录存在且非空),只装给它们,MCP 也只写给它们。
|
|
14
|
+
//
|
|
15
|
+
// 底层用 vercel-labs 的 skills CLI(npm 包 `skills`)搬 skill —— 但只用于它能
|
|
16
|
+
// 算对落点的那些 agent。它把所有 skillsDir === ".agents/skills" 的 agent 归进
|
|
17
|
+
// universal 一族、一律装到 ~/.agents/skills,会把 codex / cursor / gemini-cli
|
|
18
|
+
// 这些另有独立目录的 agent 装错地方,那些由我们自己 copy(见 lib/agents.mjs)。
|
|
19
|
+
// 锁 1.5.18 而不是 latest:1.6.0+ 的 engines 要求 node >= 22.20.0,
|
|
14
20
|
// 而团队环境实测是 node 22.19.0,锁低版本才能在 node >= 18 全覆盖。
|
|
15
21
|
//
|
|
16
22
|
// MCP 配置由我们自己写(lib/mcp-config.mjs),不引第三方库 —— 只覆盖我们真正常用的
|
|
@@ -20,7 +26,6 @@ import { spawnSync } from "node:child_process";
|
|
|
20
26
|
import { readdirSync, existsSync, readFileSync } from "node:fs";
|
|
21
27
|
import { fileURLToPath } from "node:url";
|
|
22
28
|
import { dirname, join, resolve } from "node:path";
|
|
23
|
-
import { homedir } from "node:os";
|
|
24
29
|
|
|
25
30
|
import {
|
|
26
31
|
MCP_SERVER_NAME,
|
|
@@ -33,17 +38,30 @@ import {
|
|
|
33
38
|
writeServer,
|
|
34
39
|
} from "../lib/mcp-config.mjs";
|
|
35
40
|
|
|
41
|
+
import {
|
|
42
|
+
SKILL_TARGETS,
|
|
43
|
+
detectMcpAgents,
|
|
44
|
+
detectSkillTargets,
|
|
45
|
+
resolveSkillDir,
|
|
46
|
+
installSelf,
|
|
47
|
+
uninstallSelf,
|
|
48
|
+
} from "../lib/agents.mjs";
|
|
49
|
+
|
|
36
50
|
const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
37
51
|
const SKILLS_DIR = join(PKG_ROOT, "skills");
|
|
38
52
|
const CESIUM_DIR = join(PKG_ROOT, "vendor", "cesiumjs-skills", "skills");
|
|
39
53
|
const SKILLS_CLI = "skills@1.5.18";
|
|
40
54
|
|
|
41
|
-
|
|
55
|
+
// 用 npx 跑时脚本在 npm 缓存的 _npx 目录里,此时 `anov-gis-skills` 不在 PATH 上,
|
|
56
|
+
// 提示语必须给回 npx 形式,否则用户会撞上「不是内部或外部命令」。
|
|
57
|
+
const CLI_CMD = /[\\/]_npx[\\/]/.test(process.argv[1] ?? "")
|
|
58
|
+
? "npx @anov/gis-skills-cli"
|
|
59
|
+
: "anov-gis-skills";
|
|
42
60
|
|
|
43
61
|
// ---------------------------------------------------------------- 参数解析
|
|
44
62
|
|
|
45
63
|
function parseArgs(argv) {
|
|
46
|
-
const out = { _: [], agents: [], mcpArgs: [], unknown: [] };
|
|
64
|
+
const out = { _: [], agents: [], mcpAgents: [], mcpArgs: [], unknown: [] };
|
|
47
65
|
for (let i = 0; i < argv.length; i++) {
|
|
48
66
|
const a = argv[i];
|
|
49
67
|
if (a === "-g" || a === "--global") out.scope = "global";
|
|
@@ -54,13 +72,18 @@ function parseArgs(argv) {
|
|
|
54
72
|
else if (a === "--no-mcp") out.noMcp = true;
|
|
55
73
|
else if (a === "--mcp") out.mcp = true;
|
|
56
74
|
else if (a === "-a" || a === "--agent") {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
75
|
+
// 只在真的吃到值时才推进 i —— 否则下一个 "-" 开头的 flag 会被连同位置
|
|
76
|
+
// 一起跳过(`--agent codex --no-mcp` 会把 --no-mcp 吞掉)
|
|
77
|
+
while (i + 1 < argv.length && !argv[i + 1].startsWith("-")) out.agents.push(argv[++i]);
|
|
78
|
+
} else if (a === "--mcp-agent") {
|
|
79
|
+
while (i + 1 < argv.length && !argv[i + 1].startsWith("-")) {
|
|
80
|
+
for (const v of argv[++i].split(",")) if (v.trim()) out.mcpAgents.push(v.trim());
|
|
81
|
+
}
|
|
82
|
+
} else if (a === "--mcp-mode") out.mcpMode = argv[++i];
|
|
60
83
|
else if (a === "--mcp-url") out.mcpUrl = argv[++i];
|
|
61
84
|
else if (a === "--mcp-command") out.mcpCommand = argv[++i];
|
|
62
85
|
else if (a === "--mcp-arg") {
|
|
63
|
-
while (
|
|
86
|
+
while (i + 1 < argv.length && !argv[i + 1].startsWith("-")) out.mcpArgs.push(argv[++i]);
|
|
64
87
|
} else if (a === "-h" || a === "--help") out.help = true;
|
|
65
88
|
else if (a.startsWith("-")) out.unknown.push(a);
|
|
66
89
|
else out._.push(a);
|
|
@@ -68,26 +91,26 @@ function parseArgs(argv) {
|
|
|
68
91
|
return out;
|
|
69
92
|
}
|
|
70
93
|
|
|
71
|
-
const HELP =
|
|
94
|
+
const HELP = `${CLI_CMD} —— 装 skill + 接 MCP
|
|
72
95
|
|
|
73
96
|
用法
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
${CLI_CMD} setup 装全部 skill(默认顺带写 MCP 配置)
|
|
98
|
+
${CLI_CMD} mcp add 只写 MCP 配置
|
|
99
|
+
${CLI_CMD} mcp remove 删掉 MCP 配置
|
|
100
|
+
${CLI_CMD} mcp show 看 MCP 配置状态
|
|
101
|
+
${CLI_CMD} doctor 自检(skill 完整性 + MCP 配置)
|
|
102
|
+
${CLI_CMD} uninstall 清理(只删本包与本 MCP 的东西)
|
|
80
103
|
|
|
81
104
|
通用选项
|
|
82
105
|
--scope global|project 装到哪(默认 global = 用户级,任何项目都能用)
|
|
83
106
|
-g, --global 等价于 --scope global
|
|
84
107
|
--project 等价于 --scope project
|
|
85
|
-
-a, --agent <名字...>
|
|
108
|
+
-a, --agent <名字...> 只装给指定智能体(默认:本机检测到的智能体)
|
|
86
109
|
-y, --yes 跳过所有交互
|
|
87
110
|
--print 只打印要写的内容,不落盘
|
|
88
111
|
|
|
89
112
|
MCP 选项
|
|
90
|
-
--mcp-agent
|
|
113
|
+
--mcp-agent <名字...> 写到哪个智能体(${SUPPORTED_AGENTS.join(" / ")};默认:检测到的)
|
|
91
114
|
--mcp-mode stdio|http 连接方式(默认 stdio)
|
|
92
115
|
--mcp-url <地址> HTTP 模式的服务地址(stdio 模式不需要)
|
|
93
116
|
--mcp-command <命令> stdio 模式的启动命令(默认 npx)
|
|
@@ -97,17 +120,18 @@ MCP 选项
|
|
|
97
120
|
|
|
98
121
|
// ---------------------------------------------------------------- 基础工具
|
|
99
122
|
|
|
100
|
-
|
|
123
|
+
/** 一个 skill 的来源:名字 + 它在包里的目录。 */
|
|
124
|
+
function skillSources(dir) {
|
|
101
125
|
if (!existsSync(dir)) return [];
|
|
102
126
|
return readdirSync(dir, { withFileTypes: true })
|
|
103
127
|
.filter((d) => d.isDirectory() && existsSync(join(dir, d.name, "SKILL.md")))
|
|
104
|
-
.map((d) => d.name)
|
|
105
|
-
.sort();
|
|
128
|
+
.map((d) => ({ name: d.name, srcDir: dir }))
|
|
129
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
106
130
|
}
|
|
107
131
|
|
|
108
132
|
/** 本包提供的全部 skill:anov-gis 12 个 + Cesium 15 个。 */
|
|
109
133
|
function allSkillNames() {
|
|
110
|
-
return [...
|
|
134
|
+
return [...skillSources(SKILLS_DIR), ...skillSources(CESIUM_DIR)].map((s) => s.name);
|
|
111
135
|
}
|
|
112
136
|
|
|
113
137
|
function runSkillsCLI(extra, { quiet = false } = {}) {
|
|
@@ -129,16 +153,32 @@ function scopeFlags(scope) {
|
|
|
129
153
|
return scope === "global" ? ["--global"] : [];
|
|
130
154
|
}
|
|
131
155
|
|
|
132
|
-
|
|
133
|
-
|
|
156
|
+
/** 目标落点。scope=project 时相对当前目录,global 时按表里的用户级落点。 */
|
|
157
|
+
function targetDir(target, scope = "global") {
|
|
158
|
+
return resolveSkillDir(target, scope);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** --agent 的名字 → 安装目标。同时接受我们的 id 和上游的 agent 名。 */
|
|
162
|
+
function targetsByName(names) {
|
|
163
|
+
const out = [];
|
|
164
|
+
for (const name of names) {
|
|
165
|
+
const t = SKILL_TARGETS.find((x) => x.id === name || x.upstream === name);
|
|
166
|
+
if (!t) {
|
|
167
|
+
console.error(`✗ 不支持的智能体:${name}`);
|
|
168
|
+
console.error(` 可用:${SKILL_TARGETS.map((x) => x.id).join(" / ")}`);
|
|
169
|
+
process.exit(2);
|
|
170
|
+
}
|
|
171
|
+
if (!out.includes(t)) out.push(t);
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
134
174
|
}
|
|
135
175
|
|
|
136
176
|
// ---------------------------------------------------------------- setup
|
|
137
177
|
|
|
138
178
|
function cmdSetup(opts) {
|
|
139
179
|
const scope = opts.scope ?? "global";
|
|
140
|
-
const anov =
|
|
141
|
-
const cesium =
|
|
180
|
+
const anov = skillSources(SKILLS_DIR);
|
|
181
|
+
const cesium = skillSources(CESIUM_DIR);
|
|
142
182
|
|
|
143
183
|
if (!anov.length) {
|
|
144
184
|
console.error("✗ 包内找不到 skill(skills/ 目录缺失或为空)");
|
|
@@ -149,23 +189,58 @@ function cmdSetup(opts) {
|
|
|
149
189
|
process.exit(1);
|
|
150
190
|
}
|
|
151
191
|
|
|
192
|
+
const detected = detectSkillTargets();
|
|
193
|
+
const targets = opts.agents.length ? targetsByName(opts.agents) : detected;
|
|
194
|
+
|
|
152
195
|
console.log(`\n安装 ${anov.length + cesium.length} 个 skill`);
|
|
153
196
|
console.log(` anov-gis ${anov.length} 个`);
|
|
154
197
|
console.log(` cesiumjs ${cesium.length} 个`);
|
|
155
198
|
console.log(` 范围 ${scope === "global" ? "用户级(任何项目可用)" : "项目级(当前目录)"}`);
|
|
199
|
+
if (targets.length) {
|
|
200
|
+
console.log(` 智能体 ${opts.agents.length ? "(指定)" : "(检测到)"}`);
|
|
201
|
+
for (const t of targets) console.log(` · ${t.label.padEnd(16)} ${targetDir(t, scope)}`);
|
|
202
|
+
} else {
|
|
203
|
+
console.log(" 智能体 未检测到任何智能体 —— 用 --agent 指定");
|
|
204
|
+
}
|
|
156
205
|
|
|
157
|
-
|
|
158
|
-
console.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
206
|
+
if (!targets.length) {
|
|
207
|
+
console.error("\n✗ 没有目标智能体可装");
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 走上游的:它能算对这些 agent 的落点
|
|
212
|
+
const upstreamTargets = targets.filter((t) => t.upstream);
|
|
213
|
+
if (upstreamTargets.length) {
|
|
214
|
+
const agentNames = upstreamTargets.map((t) => t.upstream);
|
|
215
|
+
for (const [label, dir] of [["anov-gis", SKILLS_DIR], ["cesiumjs", CESIUM_DIR]]) {
|
|
216
|
+
console.log(`\n── ${label} ──`);
|
|
217
|
+
const code = runSkillsCLI(["add", dir, "--agent", ...agentNames, ...scopeFlags(scope), "-y"]);
|
|
218
|
+
if (code !== 0) {
|
|
219
|
+
console.error(`✗ ${label} 安装失败(退出码 ${code})`);
|
|
220
|
+
process.exit(code);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// 自己 copy 的:上游会把它们装错目录
|
|
226
|
+
const skills = [...anov, ...cesium];
|
|
227
|
+
const fallback = targets.filter((t) => !t.upstream);
|
|
228
|
+
for (const t of upstreamTargets) {
|
|
229
|
+
// 上游装完核对落点 —— 它要是算错了目录,这里兜住
|
|
230
|
+
const dir = targetDir(t, scope);
|
|
231
|
+
if (!skills.every((s) => existsSync(join(dir, s.name, "SKILL.md")))) fallback.push(t);
|
|
232
|
+
}
|
|
233
|
+
if (fallback.length) {
|
|
234
|
+
console.log(`\n── 直装(上游落点有误,改为直接复制)──`);
|
|
235
|
+
for (const t of fallback) {
|
|
236
|
+
const dir = targetDir(t, scope);
|
|
237
|
+
installSelf({ skillDir: dir }, skills);
|
|
238
|
+
console.log(` ✓ ${t.label}:${skills.length} 个 → ${dir}`);
|
|
163
239
|
}
|
|
164
240
|
}
|
|
165
241
|
|
|
166
242
|
if (!opts.noMcp) {
|
|
167
243
|
const mode = opts.mcpMode ?? "stdio";
|
|
168
|
-
const agent = opts.mcpAgent ?? "claude-code";
|
|
169
244
|
const config = buildServerConfig({
|
|
170
245
|
mode,
|
|
171
246
|
url: opts.mcpUrl,
|
|
@@ -173,32 +248,79 @@ function cmdSetup(opts) {
|
|
|
173
248
|
args: opts.mcpArgs.length ? opts.mcpArgs : undefined,
|
|
174
249
|
env: collectEnv(),
|
|
175
250
|
});
|
|
176
|
-
writeMcp(
|
|
251
|
+
writeMcp(mcpAgents(opts, scope), scope, config, {
|
|
252
|
+
printOnly: opts.print,
|
|
253
|
+
strict: opts.mcpAgents.length > 0,
|
|
254
|
+
});
|
|
177
255
|
}
|
|
178
256
|
|
|
179
257
|
console.log("\n✓ 完成");
|
|
180
258
|
if (!opts.noMcp) {
|
|
181
|
-
console.log(
|
|
259
|
+
console.log(` 验证:${CLI_CMD} doctor`);
|
|
182
260
|
}
|
|
183
261
|
}
|
|
184
262
|
|
|
185
263
|
// ---------------------------------------------------------------- MCP
|
|
186
264
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
265
|
+
/** 默认只写探测到的智能体;--mcp-agent 显式点名时用点名的那些。 */
|
|
266
|
+
function mcpAgents(opts, scope = "global") {
|
|
267
|
+
if (opts.mcpAgents.length) return opts.mcpAgents;
|
|
268
|
+
const detected = new Set(detectMcpAgents(scope).map((a) => a.id));
|
|
269
|
+
return SUPPORTED_AGENTS.filter((a) => detected.has(a) && agentTargets(a, scope).length);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* strict = 用户显式点名了智能体:不支持当前 scope 就直接报错。
|
|
274
|
+
* 默认集合则静默跳过(如 Codex 没有项目级配置),不算失败。
|
|
275
|
+
*/
|
|
276
|
+
function mcpTargets(agents, scope, strict) {
|
|
277
|
+
const out = [];
|
|
278
|
+
for (const agent of agents) {
|
|
279
|
+
if (!SUPPORTED_AGENTS.includes(agent)) {
|
|
280
|
+
console.error(`✗ 不支持的智能体:${agent}(可用:${SUPPORTED_AGENTS.join(" / ")})`);
|
|
281
|
+
process.exit(2);
|
|
282
|
+
}
|
|
283
|
+
const targets = agentTargets(agent, scope);
|
|
284
|
+
if (!targets.length) {
|
|
285
|
+
if (strict) {
|
|
286
|
+
console.error(`✗ ${agent} 不支持 ${scope === "global" ? "用户级" : "项目级"}配置`);
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
out.push(...targets);
|
|
292
|
+
}
|
|
293
|
+
return out;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** --print 的片段按目标格式输出:Codex 是 TOML,其余是 JSON。 */
|
|
297
|
+
function printTarget(target, config) {
|
|
298
|
+
console.log(`\n# ${target.label} → ${target.file}`);
|
|
299
|
+
if (target.key !== null) {
|
|
300
|
+
console.log(JSON.stringify({ [target.key]: { [MCP_SERVER_NAME]: config } }, null, 2));
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const toml = (v) =>
|
|
304
|
+
typeof v === "string"
|
|
305
|
+
? `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`
|
|
306
|
+
: Array.isArray(v)
|
|
307
|
+
? `[${v.map(toml).join(", ")}]`
|
|
308
|
+
: String(v);
|
|
309
|
+
const lines = [`[mcp_servers.${MCP_SERVER_NAME}]`];
|
|
310
|
+
for (const [k, v] of Object.entries(config)) {
|
|
311
|
+
if (k !== "env") lines.push(`${k} = ${toml(v)}`);
|
|
193
312
|
}
|
|
194
|
-
|
|
313
|
+
if (config.env) {
|
|
314
|
+
lines.push("", `[mcp_servers.${MCP_SERVER_NAME}.env]`);
|
|
315
|
+
for (const [k, v] of Object.entries(config.env)) lines.push(`${k} = ${toml(v)}`);
|
|
316
|
+
}
|
|
317
|
+
console.log(lines.join("\n"));
|
|
195
318
|
}
|
|
196
319
|
|
|
197
|
-
function writeMcp(
|
|
198
|
-
for (const target of mcpTargets(
|
|
320
|
+
function writeMcp(agents, scope, config, { printOnly = false, strict = false } = {}) {
|
|
321
|
+
for (const target of mcpTargets(agents, scope, strict)) {
|
|
199
322
|
if (printOnly) {
|
|
200
|
-
|
|
201
|
-
console.log(JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: config } }, null, 2));
|
|
323
|
+
printTarget(target, config);
|
|
202
324
|
continue;
|
|
203
325
|
}
|
|
204
326
|
writeServer(target, MCP_SERVER_NAME, config);
|
|
@@ -209,10 +331,11 @@ function writeMcp(agent, scope, config, printOnly) {
|
|
|
209
331
|
function cmdMcp(opts) {
|
|
210
332
|
const action = opts._[0] ?? "show";
|
|
211
333
|
const scope = opts.scope ?? "global";
|
|
212
|
-
const
|
|
334
|
+
const agents = mcpAgents(opts, scope);
|
|
335
|
+
const strict = opts.mcpAgents.length > 0;
|
|
213
336
|
|
|
214
337
|
if (action === "show") {
|
|
215
|
-
for (const target of mcpTargets(
|
|
338
|
+
for (const target of mcpTargets(agents, scope, strict)) {
|
|
216
339
|
const existing = readServer(target, MCP_SERVER_NAME);
|
|
217
340
|
console.log(`\n${target.label} —— ${target.file}`);
|
|
218
341
|
if (!existing) {
|
|
@@ -225,7 +348,7 @@ function cmdMcp(opts) {
|
|
|
225
348
|
}
|
|
226
349
|
|
|
227
350
|
if (action === "remove") {
|
|
228
|
-
for (const target of mcpTargets(
|
|
351
|
+
for (const target of mcpTargets(agents, scope, strict)) {
|
|
229
352
|
const r = removeServer(target, MCP_SERVER_NAME);
|
|
230
353
|
console.log(r.removed ? ` ✓ 已删除:${target.file}` : ` · 本来就没有:${target.file}`);
|
|
231
354
|
}
|
|
@@ -246,7 +369,7 @@ function cmdMcp(opts) {
|
|
|
246
369
|
env: collectEnv(),
|
|
247
370
|
});
|
|
248
371
|
console.log(`\n接入 MCP(${mode})`);
|
|
249
|
-
writeMcp(
|
|
372
|
+
writeMcp(agents, scope, config, { printOnly: opts.print, strict });
|
|
250
373
|
if (!opts.print) console.log("\n✓ 完成。重启智能体生效。");
|
|
251
374
|
}
|
|
252
375
|
|
|
@@ -267,43 +390,32 @@ function frontmatterOk(text) {
|
|
|
267
390
|
return { ok: true, name: name[1] };
|
|
268
391
|
}
|
|
269
392
|
|
|
270
|
-
/** 智能体的 skills 目录(用户级 / 项目级),与 skills CLI 的落点一致。 */
|
|
271
|
-
function installedSkillDirs(scope) {
|
|
272
|
-
const home = homedir();
|
|
273
|
-
const bases =
|
|
274
|
-
scope === "global"
|
|
275
|
-
? [
|
|
276
|
-
["Claude Code", join(home, ".claude", "skills")],
|
|
277
|
-
["Codex", join(home, ".codex", "skills")],
|
|
278
|
-
["通用 / Cursor", join(home, ".agents", "skills")],
|
|
279
|
-
]
|
|
280
|
-
: [
|
|
281
|
-
["Claude Code", join(process.cwd(), ".claude", "skills")],
|
|
282
|
-
["Codex / 通用", join(process.cwd(), ".agents", "skills")],
|
|
283
|
-
];
|
|
284
|
-
return bases.filter(([, dir]) => existsSync(dir));
|
|
285
|
-
}
|
|
286
|
-
|
|
287
393
|
function cmdDoctor(opts) {
|
|
288
394
|
const scope = opts.scope ?? "global";
|
|
289
395
|
const expected = allSkillNames();
|
|
396
|
+
const detected = detectSkillTargets();
|
|
290
397
|
let problems = 0;
|
|
291
398
|
|
|
292
399
|
console.log(`\n检查 @anov/gis-skills-cli\n`);
|
|
293
400
|
console.log(`包内 skill 数:${expected.length}`);
|
|
294
401
|
|
|
295
|
-
|
|
402
|
+
console.log(`\n── skill 落点 ──`);
|
|
403
|
+
const skillStatus = new Map();
|
|
404
|
+
for (const target of SKILL_TARGETS) {
|
|
405
|
+
const dir = targetDir(target, scope);
|
|
406
|
+
const installed = detected.some((d) => d.id === target.id);
|
|
296
407
|
const present = expected.filter((n) => existsSync(join(dir, n, "SKILL.md")));
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
408
|
+
skillStatus.set(target.id, { dir, installed, present: present.length });
|
|
409
|
+
|
|
410
|
+
if (!installed) {
|
|
411
|
+
console.log(` · ${target.label.padEnd(16)} ${dir} —— 未安装该智能体`);
|
|
300
412
|
continue;
|
|
301
413
|
}
|
|
302
414
|
if (present.length === expected.length) {
|
|
303
|
-
console.log(` ✓ ${present.length}
|
|
415
|
+
console.log(` ✓ ${target.label.padEnd(16)} ${dir} —— ${present.length}/${expected.length} 齐全`);
|
|
304
416
|
} else {
|
|
305
417
|
const missing = expected.filter((n) => !present.includes(n));
|
|
306
|
-
console.log(` ! 只装了 ${present.length}/${expected.length}
|
|
418
|
+
console.log(` ! ${target.label.padEnd(16)} ${dir} —— 只装了 ${present.length}/${expected.length},缺:${missing.join(", ")}`);
|
|
307
419
|
problems++;
|
|
308
420
|
}
|
|
309
421
|
|
|
@@ -319,21 +431,36 @@ function cmdDoctor(opts) {
|
|
|
319
431
|
if (bad) problems++;
|
|
320
432
|
}
|
|
321
433
|
|
|
434
|
+
console.log(`\n── MCP ──`);
|
|
435
|
+
const mcpConfigured = new Set();
|
|
322
436
|
for (const agent of SUPPORTED_AGENTS) {
|
|
323
437
|
for (const target of agentTargets(agent, scope)) {
|
|
324
438
|
const existing = readServer(target, MCP_SERVER_NAME);
|
|
325
|
-
console.log(`\n
|
|
439
|
+
console.log(`\n ${target.label} —— ${target.file}`);
|
|
326
440
|
if (existing) {
|
|
441
|
+
mcpConfigured.add(agent);
|
|
327
442
|
console.log(` ✓ 已配置(${existing.type ?? "unknown"})`);
|
|
328
443
|
} else {
|
|
329
|
-
console.log(
|
|
444
|
+
console.log(` · 未配置 —— ${CLI_CMD} mcp add`);
|
|
330
445
|
}
|
|
331
446
|
}
|
|
332
447
|
}
|
|
333
448
|
|
|
449
|
+
// 半装检查:MCP 配了但对应智能体一个 skill 都没有
|
|
450
|
+
console.log(`\n── 一致性 ──`);
|
|
451
|
+
let half = 0;
|
|
452
|
+
for (const agent of mcpConfigured) {
|
|
453
|
+
const st = skillStatus.get(agent);
|
|
454
|
+
if (!st || !st.installed || st.present > 0) continue;
|
|
455
|
+
console.log(` ! ${agent}:MCP 已配置但 ${st.dir} 下没有本包的 skill —— 跑 ${CLI_CMD} setup 补上`);
|
|
456
|
+
half++;
|
|
457
|
+
}
|
|
458
|
+
if (!half) console.log(" ✓ 没有「MCP 配了但 skill 缺失」的半装状态");
|
|
459
|
+
problems += half;
|
|
460
|
+
|
|
334
461
|
console.log("");
|
|
335
462
|
if (problems) {
|
|
336
|
-
console.error(`✗ 发现 ${problems} 处问题 ——
|
|
463
|
+
console.error(`✗ 发现 ${problems} 处问题 —— 重装:${CLI_CMD} setup\n`);
|
|
337
464
|
process.exit(1);
|
|
338
465
|
}
|
|
339
466
|
console.log("✓ 检查通过\n");
|
|
@@ -350,15 +477,21 @@ function cmdUninstall(opts) {
|
|
|
350
477
|
}
|
|
351
478
|
|
|
352
479
|
console.log(`\n移除 ${names.length} 个 skill(${scope === "global" ? "用户级" : "项目级"})`);
|
|
480
|
+
// 不传 --agent:上游的语义是从所有智能体删,正好清掉历史上 --all 铺出去的残留。
|
|
353
481
|
// 只按名字删本包提供的 skill —— skills remove --skill '*' 会连别的来源的一起删掉
|
|
354
|
-
const code = runSkillsCLI(["remove", ...names, ...
|
|
482
|
+
const code = runSkillsCLI(["remove", ...names, ...scopeFlags(scope), "-y"]);
|
|
355
483
|
if (code !== 0) {
|
|
356
484
|
console.error(`✗ 移除 skill 失败(退出码 ${code})`);
|
|
357
485
|
process.exit(code);
|
|
358
486
|
}
|
|
359
487
|
|
|
360
|
-
|
|
361
|
-
for (const target of
|
|
488
|
+
// 上游不认识 Antigravity 的新落点,这几个自己删
|
|
489
|
+
for (const target of SKILL_TARGETS.filter((t) => !t.upstream)) {
|
|
490
|
+
uninstallSelf({ skillDir: targetDir(target, scope) }, names);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const agents = mcpAgents(opts, scope);
|
|
494
|
+
for (const target of mcpTargets(agents, scope, opts.mcpAgents.length > 0)) {
|
|
362
495
|
const r = removeServer(target, MCP_SERVER_NAME);
|
|
363
496
|
console.log(r.removed ? ` ✓ 已删除 MCP 条目:${target.file}` : ` · 没有 MCP 条目:${target.file}`);
|
|
364
497
|
}
|
|
@@ -378,8 +511,8 @@ function main() {
|
|
|
378
511
|
return;
|
|
379
512
|
}
|
|
380
513
|
if (opts.unknown.length) {
|
|
381
|
-
console.error(`✗ 未知选项:${opts.unknown.join("
|
|
382
|
-
console.error(
|
|
514
|
+
console.error(`✗ 未知选项:${opts.unknown.join(" ")}`);
|
|
515
|
+
console.error(` 用 anov-gis-skills --help 看用法`);
|
|
383
516
|
process.exit(2);
|
|
384
517
|
}
|
|
385
518
|
|
package/lib/agents.mjs
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// 各智能体的 skill 落点、检测规则、以及「MCP 配置写到哪」。
|
|
2
|
+
//
|
|
3
|
+
// 落点一律按各家官方文档定,不抄上游 skills CLI 的 --agent 映射 ——
|
|
4
|
+
// 上游把所有 skillsDir === ".agents/skills" 的 agent 归进 universal 一族,
|
|
5
|
+
// 装的时候一律落到 ~/.agents/skills,会把 codex / cursor / gemini-cli
|
|
6
|
+
// 这些另有独立目录的 agent 装错地方:
|
|
7
|
+
//
|
|
8
|
+
// codex 上游装到 ~/.agents/skills,但 Codex 用户级只读 ~/.codex/skills
|
|
9
|
+
// cursor 上游装到 ~/.agents/skills,但 Cursor 只有 ~/.cursor/skills 才同步云端
|
|
10
|
+
// gemini-cli 上游装到 ~/.agents/skills,但 Gemini CLI 读 ~/.gemini/skills
|
|
11
|
+
//
|
|
12
|
+
// 所以「自己装」= 绕开上游、直接把 skill 目录 copy 到正确位置。
|
|
13
|
+
//
|
|
14
|
+
// 判定「已安装」= 探测目录存在且非空。上游用的是纯 existsSync,家目录里
|
|
15
|
+
// 躺个同名空壳文件夹就会被认成已装 —— 实测能误判 50+ 个。
|
|
16
|
+
|
|
17
|
+
import { existsSync, readdirSync, cpSync, mkdirSync, rmSync } from "node:fs";
|
|
18
|
+
import { homedir } from "node:os";
|
|
19
|
+
import { join, dirname, basename } from "node:path";
|
|
20
|
+
|
|
21
|
+
/** 把 ~ / %APPDATA% 展开成绝对路径。 */
|
|
22
|
+
export function expand(p) {
|
|
23
|
+
if (p === "~") return homedir();
|
|
24
|
+
if (p.startsWith("~/")) return join(homedir(), p.slice(2));
|
|
25
|
+
if (p.startsWith("%APPDATA%/")) {
|
|
26
|
+
const base = process.env.APPDATA || join(homedir(), "AppData", "Roaming");
|
|
27
|
+
return join(base, p.slice("%APPDATA%/".length));
|
|
28
|
+
}
|
|
29
|
+
return p;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 目录存在且非空才算「装了这个智能体」。
|
|
34
|
+
* ignore 里的子项不计入 —— Gemini CLI 和 Antigravity 共用 ~/.gemini,
|
|
35
|
+
* 只装了 Antigravity 时 ~/.gemini 也非空,但那不代表装了 Gemini CLI。
|
|
36
|
+
*/
|
|
37
|
+
export function dirHasContent(p, ignore = []) {
|
|
38
|
+
try {
|
|
39
|
+
return readdirSync(p).some((name) => !ignore.includes(name));
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* skill 的安装目标。一个目标 = 一个落点。
|
|
47
|
+
*
|
|
48
|
+
* probes 判定「已安装」用的目录,任一非空即命中
|
|
49
|
+
* skillDir 用户级落点(字符串模板,或由命中目录推导的函数)
|
|
50
|
+
* projectDir 项目级落点(相对当前目录)
|
|
51
|
+
* upstream 交给上游 skills CLI 装的 agent 名;null = 我们自己 copy
|
|
52
|
+
*/
|
|
53
|
+
export const SKILL_TARGETS = [
|
|
54
|
+
{
|
|
55
|
+
id: "claude-code",
|
|
56
|
+
label: "Claude Code",
|
|
57
|
+
probes: ["~/.claude"],
|
|
58
|
+
skillDir: "~/.claude/skills",
|
|
59
|
+
projectDir: ".claude/skills",
|
|
60
|
+
upstream: "claude-code",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: "codex",
|
|
64
|
+
label: "Codex",
|
|
65
|
+
probes: ["~/.codex"],
|
|
66
|
+
skillDir: "~/.codex/skills",
|
|
67
|
+
projectDir: ".codex/skills",
|
|
68
|
+
upstream: null,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "cursor",
|
|
72
|
+
label: "Cursor",
|
|
73
|
+
probes: ["~/.cursor"],
|
|
74
|
+
skillDir: "~/.cursor/skills",
|
|
75
|
+
projectDir: ".cursor/skills",
|
|
76
|
+
upstream: null,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "openclaw",
|
|
80
|
+
label: "OpenClaw",
|
|
81
|
+
probes: ["~/.openclaw", "~/.clawdbot", "~/.moltbot"],
|
|
82
|
+
skillDir: (probe) => join(probe, "skills"),
|
|
83
|
+
projectDir: "skills",
|
|
84
|
+
upstream: "openclaw",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: "hermes-agent",
|
|
88
|
+
label: "Hermes Agent",
|
|
89
|
+
probes: ["~/.hermes"],
|
|
90
|
+
skillDir: "~/.hermes/skills",
|
|
91
|
+
projectDir: ".hermes/skills",
|
|
92
|
+
upstream: "hermes-agent",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: "trae",
|
|
96
|
+
label: "Trae",
|
|
97
|
+
probes: ["~/.trae"],
|
|
98
|
+
skillDir: "~/.trae/skills",
|
|
99
|
+
projectDir: ".trae/skills",
|
|
100
|
+
upstream: "trae",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: "trae-cn",
|
|
104
|
+
label: "Trae CN",
|
|
105
|
+
probes: ["~/.trae-cn"],
|
|
106
|
+
skillDir: "~/.trae-cn/skills",
|
|
107
|
+
projectDir: ".trae/skills",
|
|
108
|
+
upstream: "trae-cn",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "gemini-cli",
|
|
112
|
+
label: "Gemini CLI",
|
|
113
|
+
probes: ["~/.gemini"],
|
|
114
|
+
ignore: ["antigravity", "antigravity-cli", "config"],
|
|
115
|
+
skillDir: "~/.gemini/skills",
|
|
116
|
+
projectDir: ".gemini/skills",
|
|
117
|
+
upstream: null,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "antigravity",
|
|
121
|
+
label: "Antigravity",
|
|
122
|
+
// App / CLI / IDE 现在共用 ~/.gemini/config/skills;IDE 另兼容旧的
|
|
123
|
+
// ~/.gemini/antigravity/skills,但 App 明确不读 ~/.gemini/skills。
|
|
124
|
+
probes: ["~/.gemini/config", "~/.gemini/antigravity", "~/.gemini/antigravity-cli"],
|
|
125
|
+
skillDir: "~/.gemini/config/skills",
|
|
126
|
+
projectDir: ".agents/skills",
|
|
127
|
+
upstream: null,
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "github-copilot",
|
|
131
|
+
label: "GitHub Copilot",
|
|
132
|
+
probes: ["~/.copilot"],
|
|
133
|
+
skillDir: "~/.copilot/skills",
|
|
134
|
+
projectDir: ".copilot/skills",
|
|
135
|
+
upstream: null,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: "agents-shared",
|
|
139
|
+
label: "共享目录",
|
|
140
|
+
// 这几个 agent 共用 ~/.agents/skills,装一次覆盖全部
|
|
141
|
+
probes: [
|
|
142
|
+
"~/.kimi-code",
|
|
143
|
+
"~/.kimi",
|
|
144
|
+
"~/.cline",
|
|
145
|
+
"~/.dexto",
|
|
146
|
+
"~/.loaf",
|
|
147
|
+
"~/.warp",
|
|
148
|
+
"~/.config/zed",
|
|
149
|
+
"%APPDATA%/Zed",
|
|
150
|
+
],
|
|
151
|
+
skillDir: "~/.agents/skills",
|
|
152
|
+
projectDir: ".agents/skills",
|
|
153
|
+
upstream: "cline",
|
|
154
|
+
},
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 目标落点。项目级直接相对当前目录;用户级看 skillDir —— 字符串模板直接展开,
|
|
159
|
+
* 函数则用第一个存在的探测目录推导。
|
|
160
|
+
*/
|
|
161
|
+
export function resolveSkillDir(target, scope = "global", cwd = process.cwd()) {
|
|
162
|
+
if (scope === "project") return join(cwd, target.projectDir);
|
|
163
|
+
if (typeof target.skillDir !== "function") return expand(target.skillDir);
|
|
164
|
+
for (const probe of target.probes) {
|
|
165
|
+
const abs = expand(probe);
|
|
166
|
+
if (existsSync(abs)) return target.skillDir(abs);
|
|
167
|
+
}
|
|
168
|
+
return target.skillDir(expand(target.probes[0]));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** 探测本机装了哪些智能体,返回命中的目标(含实际落点)。 */
|
|
172
|
+
export function detectSkillTargets() {
|
|
173
|
+
const out = [];
|
|
174
|
+
for (const target of SKILL_TARGETS) {
|
|
175
|
+
for (const probe of target.probes) {
|
|
176
|
+
const abs = expand(probe);
|
|
177
|
+
const dir =
|
|
178
|
+
typeof target.skillDir === "function" ? target.skillDir(abs) : expand(target.skillDir);
|
|
179
|
+
// skill 落点就在探测目录底下时,别把我们自己装的那份算成「已安装」的证据
|
|
180
|
+
const ignore = [...(target.ignore ?? [])];
|
|
181
|
+
if (dirname(dir) === abs) ignore.push(basename(dir));
|
|
182
|
+
if (!dirHasContent(abs, ignore)) continue;
|
|
183
|
+
out.push({ ...target, probe: abs, skillDir: dir, ignore });
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** 把 skill 目录直接 copy 到目标落点(上游装错位置的走这条路)。 */
|
|
191
|
+
export function installSelf(target, skills) {
|
|
192
|
+
mkdirSync(target.skillDir, { recursive: true });
|
|
193
|
+
for (const s of skills) {
|
|
194
|
+
cpSync(join(s.srcDir, s.name), join(target.skillDir, s.name), { recursive: true, force: true });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** 删掉自己 copy 出去的 skill。 */
|
|
199
|
+
export function uninstallSelf(target, names) {
|
|
200
|
+
for (const name of names) {
|
|
201
|
+
rmSync(join(target.skillDir, name), { recursive: true, force: true });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ---------------------------------------------------------------- MCP
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* 支持写 MCP 配置的智能体。落点由 lib/mcp-config.mjs 负责(各家格式不同)。
|
|
209
|
+
* probes 是「这个智能体装了没」的判据 —— 默认集合只写探测到的那些。
|
|
210
|
+
*/
|
|
211
|
+
export const MCP_AGENTS = [
|
|
212
|
+
{ id: "claude-code", label: "Claude Code", probes: ["~/.claude"], skillTarget: "claude-code" },
|
|
213
|
+
{ id: "codex", label: "Codex", probes: ["~/.codex"], skillTarget: "codex" },
|
|
214
|
+
{ id: "cursor", label: "Cursor", probes: ["~/.cursor"], skillTarget: "cursor" },
|
|
215
|
+
{
|
|
216
|
+
id: "claude-desktop",
|
|
217
|
+
label: "Claude 桌面端",
|
|
218
|
+
probes: ["%APPDATA%/Claude", "~/Library/Application Support/Claude", "~/.config/Claude"],
|
|
219
|
+
skillTarget: null,
|
|
220
|
+
},
|
|
221
|
+
{ id: "vscode", label: "VS Code", probes: ["<cwd>/.vscode"], skillTarget: null },
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
/** 探测装了哪些支持 MCP 的智能体。scope=project 时只看项目级目录。 */
|
|
225
|
+
export function detectMcpAgents(scope = "global", cwd = process.cwd()) {
|
|
226
|
+
const out = [];
|
|
227
|
+
for (const agent of MCP_AGENTS) {
|
|
228
|
+
for (const probe of agent.probes) {
|
|
229
|
+
const abs = probe === "<cwd>/.vscode" ? join(cwd, ".vscode") : expand(probe);
|
|
230
|
+
if (!dirHasContent(abs)) continue;
|
|
231
|
+
out.push({ ...agent, probe: abs });
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return out;
|
|
236
|
+
}
|
package/lib/mcp-config.mjs
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
// 格式适配,收益却只落在少数人身上。
|
|
5
5
|
//
|
|
6
6
|
// 支持的 agent 与配置位置:
|
|
7
|
-
// claude-code
|
|
8
|
-
// codex
|
|
9
|
-
// cursor
|
|
10
|
-
// vscode
|
|
7
|
+
// claude-code 用户级 ~/.claude.json 的 mcpServers / 项目级 <cwd>/.mcp.json 的 mcpServers
|
|
8
|
+
// codex 用户级 ~/.codex/config.toml 的 [mcp_servers.<name>]
|
|
9
|
+
// cursor 项目级 <cwd>/.cursor/mcp.json / 用户级 ~/.cursor/mcp.json 的 mcpServers
|
|
10
|
+
// vscode 项目级 <cwd>/.vscode/mcp.json 的 servers(VS Code 用 servers,不是 mcpServers)
|
|
11
|
+
// claude-desktop 用户级 claude_desktop_config.json 的 mcpServers(Claude 桌面聊天端)
|
|
11
12
|
//
|
|
12
13
|
// 写入原则:读现有文件 → 只动自己那一个条目 → 原子写回。别人的条目一律不碰。
|
|
13
14
|
|
|
@@ -55,12 +56,34 @@ export function agentTargets(agent, scope, cwd = process.cwd()) {
|
|
|
55
56
|
return scope === "global"
|
|
56
57
|
? []
|
|
57
58
|
: [{ file: resolve(cwd, ".vscode", "mcp.json"), key: "servers", label: "VS Code(项目级)" }];
|
|
59
|
+
case "claude-desktop": {
|
|
60
|
+
if (scope !== "global") return [];
|
|
61
|
+
return [
|
|
62
|
+
{
|
|
63
|
+
file: claudeDesktopConfig(),
|
|
64
|
+
key: "mcpServers",
|
|
65
|
+
label: "Claude 桌面端(用户级)",
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
}
|
|
58
69
|
default:
|
|
59
70
|
return [];
|
|
60
71
|
}
|
|
61
72
|
}
|
|
62
73
|
|
|
63
|
-
|
|
74
|
+
/** Claude 桌面聊天端的 MCP 配置文件(各平台路径不同)。 */
|
|
75
|
+
function claudeDesktopConfig() {
|
|
76
|
+
if (process.platform === "darwin") {
|
|
77
|
+
return join(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
78
|
+
}
|
|
79
|
+
if (process.platform === "win32") {
|
|
80
|
+
const base = process.env.APPDATA || join(homedir(), "AppData", "Roaming");
|
|
81
|
+
return join(base, "Claude", "claude_desktop_config.json");
|
|
82
|
+
}
|
|
83
|
+
return join(homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const SUPPORTED_AGENTS = ["claude-code", "codex", "cursor", "vscode", "claude-desktop"];
|
|
64
87
|
|
|
65
88
|
/** 从当前进程环境里挑出要透传给 MCP 的变量。 */
|
|
66
89
|
export function collectEnv(env = process.env) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anov/gis-skills-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "12 个 @anov/gis (Cesium 1.143) 领域 skill + 15 个 Cesium 原生 skill,外加 anov-gis-mcp 的接入配置。一条命令装到 Claude Code / Codex / Cursor 等智能体。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "ISC AND Apache-2.0",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"cursor"
|
|
39
39
|
],
|
|
40
40
|
"scripts": {
|
|
41
|
+
"release": "node scripts/release.cjs",
|
|
41
42
|
"prepublishOnly": "node scripts/bump.mjs --check && node scripts/check-structure.mjs",
|
|
42
43
|
"pack:check": "node scripts/build-npm.mjs"
|
|
43
44
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# DEMO-SKILL-MAP.md — 137 个 demo → Skill 路由矩阵
|
|
2
2
|
|
|
3
3
|
> **SDK 版本基准:** @anov/gis v1.8.6(基于 Cesium 1.143.0)
|
|
4
|
-
> **Plugin 版本:** anov-gis-skills v0.3.
|
|
4
|
+
> **Plugin 版本:** anov-gis-skills v0.3.4
|
|
5
5
|
> **Demo 来源:** ANOV-GIS 仓库 `examples/public/examples/html/`(仓库内相对路径)共 137 个 .html 文件,按 13 类目分组
|
|
6
6
|
|
|
7
7
|
本文档是 demo **文件名** → skill 的**完整版**路由矩阵(`using-anovgis/DEMO-MAP.md` 是场景级的简版)。当用户提到具体 demo 文件名或场景时,按本表路由到对应 skill。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# DOMAINS.md — anov-gis-skills 权威归属
|
|
2
2
|
|
|
3
3
|
> **SDK 版本基准:** @anov/gis **v1.8.6**(基于 Cesium **1.143.0**)
|
|
4
|
-
> **Plugin 版本:** anov-gis-skills **v0.3.
|
|
4
|
+
> **Plugin 版本:** anov-gis-skills **v0.3.4**
|
|
5
5
|
> **Skill 数:** **12**(含 `using-anovgis` 入口 + 3 个 v0.2.0 新增 skill)
|
|
6
6
|
> **入口 skill 额外职责**:引导式初始化(AskUserQuestion 向导:底图 / 控件 / 部署;**技术栈固定 Vue 3 + Vite**)
|
|
7
7
|
|