@anov/gis-skills-cli 0.0.0-stage → 0.3.3

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +637 -0
  2. package/INSTALL.md +481 -0
  3. package/LICENSE +15 -0
  4. package/README.md +148 -2
  5. package/RELEASING.md +162 -0
  6. package/bin/anov-gis-skills.mjs +470 -0
  7. package/lib/mcp-config.mjs +273 -0
  8. package/package.json +43 -4
  9. package/skills/anovgis-analysis/SKILL.md +585 -0
  10. package/skills/anovgis-effects/SKILL.md +260 -0
  11. package/skills/anovgis-imagery-terrain/SKILL.md +505 -0
  12. package/skills/anovgis-layers/SKILL.md +627 -0
  13. package/skills/anovgis-materials/SKILL.md +635 -0
  14. package/skills/anovgis-models-3dtiles/SKILL.md +448 -0
  15. package/skills/anovgis-pitfalls/SKILL.md +561 -0
  16. package/skills/anovgis-popup-widget/SKILL.md +474 -0
  17. package/skills/anovgis-primitives/SKILL.md +482 -0
  18. package/skills/anovgis-vector-graphics/SKILL.md +602 -0
  19. package/skills/anovgis-viewer/SKILL.md +618 -0
  20. package/skills/using-anovgis/DEMO-MAP.md +64 -0
  21. package/skills/using-anovgis/DEMO-SKILL-MAP.md +248 -0
  22. package/skills/using-anovgis/DOMAINS.md +183 -0
  23. package/skills/using-anovgis/REFERENCE.md +114 -0
  24. package/skills/using-anovgis/SKILL.md +392 -0
  25. package/skills/using-anovgis/templates/README.md +154 -0
  26. package/skills/using-anovgis/templates/combo1-vue3-vite.md +295 -0
  27. package/skills/using-anovgis/templates/combo2-vue2-cli.md +119 -0
  28. package/skills/using-anovgis/templates/combo3-html-cdn.md +107 -0
  29. package/skills/using-anovgis/templates/combo4-vanilla-webpack.md +91 -0
  30. package/skills/using-anovgis/templates/wizard-profiles.md +105 -0
  31. package/vendor/cesiumjs-skills/LICENSE +201 -0
  32. package/vendor/cesiumjs-skills/NOTICE +18 -0
  33. package/vendor/cesiumjs-skills/skills/cesiumjs-3d-tiles/SKILL.md +465 -0
  34. package/vendor/cesiumjs-skills/skills/cesiumjs-camera/SKILL.md +500 -0
  35. package/vendor/cesiumjs-skills/skills/cesiumjs-core-utilities/SKILL.md +403 -0
  36. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/REFERENCE.md +397 -0
  37. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/SKILL.md +351 -0
  38. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/01-diffuse-tint.js +38 -0
  39. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/02-texture-swap.js +42 -0
  40. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/03-feature-id-tileset.js +29 -0
  41. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/04-translucent-override.js +37 -0
  42. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/05-vertex-displacement.js +49 -0
  43. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/06-metadata-ramp.js +34 -0
  44. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/07-voxel-shader.js +27 -0
  45. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/README.md +19 -0
  46. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/_sandcastle-template.html +9 -0
  47. package/vendor/cesiumjs-skills/skills/cesiumjs-entities/SKILL.md +389 -0
  48. package/vendor/cesiumjs-skills/skills/cesiumjs-imagery/SKILL.md +471 -0
  49. package/vendor/cesiumjs-skills/skills/cesiumjs-interaction/SKILL.md +423 -0
  50. package/vendor/cesiumjs-skills/skills/cesiumjs-materials-shaders/SKILL.md +292 -0
  51. package/vendor/cesiumjs-skills/skills/cesiumjs-models-particles/SKILL.md +423 -0
  52. package/vendor/cesiumjs-skills/skills/cesiumjs-primitives/SKILL.md +537 -0
  53. package/vendor/cesiumjs-skills/skills/cesiumjs-spatial-math/SKILL.md +358 -0
  54. package/vendor/cesiumjs-skills/skills/cesiumjs-terrain-environment/SKILL.md +401 -0
  55. package/vendor/cesiumjs-skills/skills/cesiumjs-time-properties/SKILL.md +353 -0
  56. package/vendor/cesiumjs-skills/skills/cesiumjs-viewer-setup/SKILL.md +434 -0
  57. package/vendor/cesiumjs-skills/skills/using-cesiumjs-skills/SKILL.md +35 -0
@@ -0,0 +1,273 @@
1
+ // 各智能体的 MCP 配置读写。
2
+ //
3
+ // 只覆盖我们真正常用的几个,不做通用框架 —— 每多支持一个 agent 就多一份要维护的
4
+ // 格式适配,收益却只落在少数人身上。
5
+ //
6
+ // 支持的 agent 与配置位置:
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
+ //
12
+ // 写入原则:读现有文件 → 只动自己那一个条目 → 原子写回。别人的条目一律不碰。
13
+
14
+ import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync } from "node:fs";
15
+ import { homedir } from "node:os";
16
+ import { dirname, join, resolve } from "node:path";
17
+
18
+ export const MCP_SERVER_NAME = "anov-gis";
19
+
20
+ /** 我们往客户端注入的 env 变量白名单(只有这几个跟 MCP 运行有关)。 */
21
+ const ENV_WHITELIST = [
22
+ "ANOV_GIS_MINIO_ENDPOINT",
23
+ "ANOV_GIS_MINIO_BUCKET",
24
+ "ANOV_GIS_MINIO_ACCESS_KEY",
25
+ "ANOV_GIS_MINIO_SECRET_KEY",
26
+ "ANOV_GIS_MINIO_REGION",
27
+ "ANOV_GIS_PUBLIC_STATIC_BASE",
28
+ "ANOV_GIS_PUBLIC_API_BASE",
29
+ "ANOV_GIS_ANOVCITY_BASE",
30
+ "ANOV_GIS_IP_ALLOWLIST",
31
+ ];
32
+
33
+ /**
34
+ * 各 agent 的 MCP 配置位置。
35
+ *
36
+ * scope: project = 项目目录里的文件(可提交、团队共享);global = 用户家目录(每人一份)。
37
+ * key: 该文件里承载 server 条目的顶层键。
38
+ */
39
+ export function agentTargets(agent, scope, cwd = process.cwd()) {
40
+ const home = homedir();
41
+ switch (agent) {
42
+ case "claude-code":
43
+ return scope === "global"
44
+ ? [{ file: join(home, ".claude.json"), key: "mcpServers", label: "Claude Code(用户级)" }]
45
+ : [{ file: resolve(cwd, ".mcp.json"), key: "mcpServers", label: "Claude Code(项目级)" }];
46
+ case "codex":
47
+ return scope === "global"
48
+ ? [{ file: join(home, ".codex", "config.toml"), key: null, label: "Codex(用户级)" }]
49
+ : [];
50
+ case "cursor":
51
+ return scope === "global"
52
+ ? [{ file: join(home, ".cursor", "mcp.json"), key: "mcpServers", label: "Cursor(用户级)" }]
53
+ : [{ file: resolve(cwd, ".cursor", "mcp.json"), key: "mcpServers", label: "Cursor(项目级)" }];
54
+ case "vscode":
55
+ return scope === "global"
56
+ ? []
57
+ : [{ file: resolve(cwd, ".vscode", "mcp.json"), key: "servers", label: "VS Code(项目级)" }];
58
+ default:
59
+ return [];
60
+ }
61
+ }
62
+
63
+ export const SUPPORTED_AGENTS = ["claude-code", "codex", "cursor", "vscode"];
64
+
65
+ /** 从当前进程环境里挑出要透传给 MCP 的变量。 */
66
+ export function collectEnv(env = process.env) {
67
+ const out = {};
68
+ for (const key of ENV_WHITELIST) {
69
+ if (env[key]) out[key] = env[key];
70
+ }
71
+ return out;
72
+ }
73
+
74
+ /** 组装 MCP server 条目。 */
75
+ export function buildServerConfig({ mode = "stdio", url, command, args, env }) {
76
+ if (mode === "http") {
77
+ if (!url) throw new Error("HTTP 模式需要 MCP 服务地址(--mcp-url)");
78
+ return { type: "http", url };
79
+ }
80
+ return {
81
+ type: "stdio",
82
+ command: command ?? "npx",
83
+ args: args ?? ["-y", "anov-gis-mcp", "--stdio"],
84
+ ...(env && Object.keys(env).length ? { env } : {}),
85
+ };
86
+ }
87
+
88
+ // ---------------------------------------------------------------- JSON 目标
89
+
90
+ function readJson(file) {
91
+ if (!existsSync(file)) return {};
92
+ try {
93
+ return JSON.parse(readFileSync(file, "utf8"));
94
+ } catch (err) {
95
+ throw new Error(`${file} 不是合法 JSON:${err.message}`);
96
+ }
97
+ }
98
+
99
+ /** 原子写:先写临时文件再 rename,避免写到一半把用户的配置弄坏。 */
100
+ function writeAtomic(file, content) {
101
+ mkdirSync(dirname(file), { recursive: true });
102
+ const tmp = `${file}.anov-tmp`;
103
+ writeFileSync(tmp, content, "utf8");
104
+ renameSync(tmp, file);
105
+ }
106
+
107
+ export function readJsonServer(file, key, name) {
108
+ const json = readJson(file);
109
+ return json?.[key]?.[name];
110
+ }
111
+
112
+ export function writeJsonServer(file, key, name, config) {
113
+ const json = readJson(file);
114
+ const bucket = json[key] && typeof json[key] === "object" ? json[key] : {};
115
+ bucket[name] = config;
116
+ json[key] = bucket;
117
+ writeAtomic(file, `${JSON.stringify(json, null, 2)}\n`);
118
+ return file;
119
+ }
120
+
121
+ export function removeJsonServer(file, key, name) {
122
+ if (!existsSync(file)) return { file, removed: false };
123
+ const json = readJson(file);
124
+ if (!json?.[key]?.[name]) return { file, removed: false };
125
+ delete json[key][name];
126
+ writeAtomic(file, `${JSON.stringify(json, null, 2)}\n`);
127
+ return { file, removed: true };
128
+ }
129
+
130
+ // ---------------------------------------------------------------- TOML 目标(Codex)
131
+
132
+ function tomlEscape(value) {
133
+ return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
134
+ }
135
+
136
+ function tomlValue(value) {
137
+ if (typeof value === "boolean") return value ? "true" : "false";
138
+ if (typeof value === "number") return String(value);
139
+ if (Array.isArray(value)) return `[${value.map(tomlValue).join(", ")}]`;
140
+ return `"${tomlEscape(value)}"`;
141
+ }
142
+
143
+ /**
144
+ * Codex 的 config.toml 没有现成的解析器可用,这里只做「按表块定位与替换」:
145
+ * 找到 [mcp_servers.<name>] 到下一个 [ 之间的行,整块替换或删除。
146
+ *
147
+ * TOML 里追加到文件末尾是安全的 —— 新表从该行开始生效,不影响前面的表。
148
+ */
149
+ export function readTomlServer(file, name) {
150
+ if (!existsSync(file)) return undefined;
151
+ const text = readFileSync(file, "utf8");
152
+ const main = findTomlBlock(text, name);
153
+ if (!main) return undefined;
154
+
155
+ const out = {};
156
+ for (const line of main.lines) {
157
+ const m = /^([A-Za-z0-9_-]+)\s*=\s*(.+)$/.exec(line.trim());
158
+ if (!m) continue;
159
+ out[m[1]] = parseTomlValue(m[2].trim());
160
+ }
161
+
162
+ // env 在紧跟主表的子表里 —— 表头本身不属于主表行,所以这里单独解析
163
+ const env = findTomlBlock(text, `${name}.env`);
164
+ if (env) {
165
+ const envObj = {};
166
+ for (const line of env.lines) {
167
+ const m = /^([A-Za-z0-9_-]+)\s*=\s*(.+)$/.exec(line.trim());
168
+ if (!m) continue;
169
+ envObj[m[1]] = parseTomlValue(m[2].trim());
170
+ }
171
+ if (Object.keys(envObj).length) out.env = envObj;
172
+ }
173
+ return out;
174
+ }
175
+
176
+ /** TOML 值的反向解析:够用即可(字符串 / 布尔 / 数字 / 字符串数组)。 */
177
+ function parseTomlValue(raw) {
178
+ if (raw.startsWith("[")) {
179
+ try {
180
+ return JSON.parse(raw);
181
+ } catch {
182
+ return raw;
183
+ }
184
+ }
185
+ if (raw.startsWith('"') && raw.endsWith('"')) return raw.slice(1, -1);
186
+ if (raw === "true" || raw === "false") return raw === "true";
187
+ if (/^-?\d+(\.\d+)?$/.test(raw)) return Number(raw);
188
+ return raw;
189
+ }
190
+
191
+ /**
192
+ * 定位 `[mcp_servers.<name>]` 表块(`<name>` 可带后缀,找 env 子表时传 `${name}.env`)。
193
+ */
194
+ function findTomlBlock(text, name) {
195
+ const lines = text.split(/\r?\n/);
196
+ const header = `[mcp_servers.${name}]`;
197
+ const start = lines.findIndex((l) => l.trim() === header);
198
+ if (start === -1) return null;
199
+ let end = lines.length;
200
+ for (let i = start + 1; i < lines.length; i++) {
201
+ if (/^\s*\[/.test(lines[i])) {
202
+ end = i;
203
+ break;
204
+ }
205
+ }
206
+ return { start, end, lines: lines.slice(start + 1, end) };
207
+ }
208
+
209
+ /**
210
+ * 主表 + 紧跟其后的 `.env` 子表算同一块 —— 否则替换主表时旧的 env 表会残留在文件里。
211
+ */
212
+ function findServerBlock(text, name) {
213
+ const main = findTomlBlock(text, name);
214
+ if (!main) return null;
215
+ const env = findTomlBlock(text, `${name}.env`);
216
+ const end = env && env.start === main.end ? env.end : main.end;
217
+ const lines = text.split(/\r?\n/);
218
+ return { start: main.start, end, lines: lines.slice(main.start + 1, end) };
219
+ }
220
+
221
+ export function writeTomlServer(file, name, config) {
222
+ let text = existsSync(file) ? readFileSync(file, "utf8") : "";
223
+ const block = findServerBlock(text, name);
224
+
225
+ const body = [
226
+ `[mcp_servers.${name}]`,
227
+ ...Object.entries(config)
228
+ .filter(([k]) => k !== "env")
229
+ .map(([k, v]) => `${k} = ${tomlValue(v)}`),
230
+ ];
231
+ if (config.env && Object.keys(config.env).length) {
232
+ body.push("", `[mcp_servers.${name}.env]`);
233
+ for (const [k, v] of Object.entries(config.env)) body.push(`${k} = ${tomlValue(v)}`);
234
+ }
235
+
236
+ if (block) {
237
+ const lines = text.split(/\r?\n/);
238
+ lines.splice(block.start, block.end - block.start, ...body);
239
+ text = lines.join("\n");
240
+ } else {
241
+ text = `${text.replace(/\s*$/, "")}\n\n${body.join("\n")}\n`;
242
+ }
243
+ writeAtomic(file, text);
244
+ return file;
245
+ }
246
+
247
+ export function removeTomlServer(file, name) {
248
+ if (!existsSync(file)) return { file, removed: false };
249
+ const text = readFileSync(file, "utf8");
250
+ const block = findServerBlock(text, name);
251
+ if (!block) return { file, removed: false };
252
+ const lines = text.split(/\r?\n/);
253
+ lines.splice(block.start, block.end - block.start);
254
+ writeAtomic(file, lines.join("\n"));
255
+ return { file, removed: true };
256
+ }
257
+
258
+ // ---------------------------------------------------------------- 统一入口
259
+
260
+ export function readServer(target, name) {
261
+ if (!target.key) return readTomlServer(target.file, name);
262
+ return readJsonServer(target.file, target.key, name);
263
+ }
264
+
265
+ export function writeServer(target, name, config) {
266
+ if (!target.key) return writeTomlServer(target.file, name, config);
267
+ return writeJsonServer(target.file, target.key, name, config);
268
+ }
269
+
270
+ export function removeServer(target, name) {
271
+ if (!target.key) return removeTomlServer(target.file, name);
272
+ return removeJsonServer(target.file, target.key, name);
273
+ }
package/package.json CHANGED
@@ -1,6 +1,45 @@
1
1
  {
2
2
  "name": "@anov/gis-skills-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.3.3",
4
+ "description": "12 个 @anov/gis (Cesium 1.143) 领域 skill + 15 个 Cesium 原生 skill,外加 anov-gis-mcp 的接入配置。一条命令装到 Claude Code / Codex / Cursor 等智能体。",
5
+ "type": "module",
6
+ "license": "ISC AND Apache-2.0",
7
+ "author": "",
8
+ "homepage": "",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": ""
12
+ },
13
+ "files": [
14
+ "skills",
15
+ "vendor",
16
+ "lib",
17
+ "README.md",
18
+ "INSTALL.md",
19
+ "RELEASING.md",
20
+ "LICENSE",
21
+ "CHANGELOG.md"
22
+ ],
23
+ "bin": {
24
+ "anov-gis-skills": "bin/anov-gis-skills.mjs",
25
+ "anov-gis-skills-cli": "bin/anov-gis-skills.mjs"
26
+ },
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "keywords": [
31
+ "anov-gis",
32
+ "cesium",
33
+ "gis",
34
+ "3dtiles",
35
+ "agent-skills",
36
+ "claude-code",
37
+ "codex",
38
+ "cursor"
39
+ ],
40
+ "scripts": {
41
+ "release": "node scripts/release.cjs",
42
+ "prepublishOnly": "node scripts/bump.mjs --check && node scripts/check-structure.mjs",
43
+ "pack:check": "node scripts/build-npm.mjs"
44
+ }
45
+ }