@yottameta/yotta-skills-plugin 0.6.1 → 0.6.2

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.
@@ -12,7 +12,7 @@
12
12
  "authentication": "ON_INSTALL"
13
13
  },
14
14
  "category": "Developer Tools",
15
- "version": "0.6.1",
15
+ "version": "0.6.2",
16
16
  "description": "YuanGe (元阁) - orchestration routing, inventory, and one-command installer for the YottaMeta skill family (zero dependencies, Node.js only).",
17
17
  "interface": {
18
18
  "displayName": "元阁 yotta-skills",
@@ -12,7 +12,7 @@
12
12
  "authentication": "ON_INSTALL"
13
13
  },
14
14
  "category": "Developer Tools",
15
- "version": "0.6.1",
15
+ "version": "0.6.2",
16
16
  "description": "YuanGe (元阁) - orchestration routing, inventory, and one-command installer for the YottaMeta skill family (zero dependencies, Node.js only).",
17
17
  "interface": {
18
18
  "displayName": "元阁 yotta-skills",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yottameta/yotta-skills-plugin",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "YuanGe (元阁) — orchestration and routing for the YottaMeta skill family, packaged as a YottaMeta Agent Plugin.",
5
5
  "license": "MIT",
6
6
  "keywords": [
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "yotta-skills",
4
- "version": "0.6.1",
4
+ "version": "0.6.2",
5
5
  "description": "YuanGe (元阁) - orchestration routing, inventory, and one-command installer for the YottaMeta skill family (zero dependencies, Node.js only).",
6
6
  "author": {
7
7
  "name": "YottaMeta",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: yotta-skills
3
- version: 0.6.1
4
- description: 元阁 -- 元阁全家技能的总编排策划 + 编排路由 + 一键安装器 + 技能盘点。路由层:--route / route_request 按需求摘要给出候选组合、调用顺序、角色、置信度、依据、已装/缺失状态与安装命令,只建议不自动安装;非元阁家族已装技能按 frontmatter description 机械匹配作并列候选(标注来源与未扫描状态,只读不自动调用);策划层:按场景给出「该组合哪几个元技能、组合强在哪、怎么自动装+自动用」;安装层:一条命令把 YottaMeta 已发布的全部 yotta-* 技能装进指定智能体或目录;盘点层:--inventory / --reindex 扫描本机已装技能生成/更新注册表,新装技能自动被发现(install/update 后自动 re-index,会话开工可先跑 --reindex;自包含零依赖,不依赖任何元技能);MCP 按需加载(可选:list_installed_skills/describe_skill/reindex/route_request,不常驻,未加载降级 CLI)。支持 --list 清单 / --route 路由 / install / update / --inventory / --reindex / --dry-run 预览 / --pin 锁版本。触发:需要批量安装或更新元阁全家技能、按场景组合多个元技能、路由或判断该用哪些技能、盘点或查看本机已装技能、重扫技能注册表、给某个智能体或目录一次性铺齐 yotta-* 技能、预览安装清单、锁版本安装、或用户说 元阁/装全家/一次装齐/yotta-skills/install-all/更新全家/该用哪个技能/路由技能/盘点技能/查看已装技能 等。边界(Do NOT trigger):只做「组合策划 + 静态路由建议 + 清单 + 下载 + 落位 + 汇总 + 盘点 + re-index」,不含技能本体、不做技能内容开发、不 -g 污染全局、不自动安装缺失技能;装前摘要仅供参考,安装决策由用户确认。
3
+ version: 0.6.2
4
+ description: 元阁 -- 元阁全家技能的总编排策划 + 编排路由 + 一键安装器 + 技能盘点。路由层:--route / route_request 按需求摘要给出候选组合、调用顺序、角色、置信度、依据、已装/缺失状态与安装命令,只建议不自动安装;非元阁家族已装技能按 frontmatter description 机械匹配作并列候选(标注来源与未扫描状态,只读不自动调用);策划层:按场景给出「该组合哪几个元技能、组合强在哪、怎么自动装+自动用」;安装层:一条命令把 YottaMeta 已发布的全部 yotta-* 技能装进指定智能体或目录;盘点层:--inventory / --reindex 扫描本机已装技能生成/更新注册表,新装技能自动被发现(install/update 后自动 re-index,会话开工可先跑 --reindex 与 update --check(联网只读检查更新);自包含零依赖,不依赖任何元技能);MCP 按需加载(可选:list_installed_skills/describe_skill/reindex/route_request,不常驻,未加载降级 CLI)。支持 --list 清单 / --route 路由 / install / update / update --check(只读检查)/ update --auto(家族自动更新)/ --inventory / --reindex / --dry-run 预览 / --pin 锁版本。触发:需要批量安装或更新元阁全家技能、按场景组合多个元技能、路由或判断该用哪些技能、盘点或查看本机已装技能、重扫技能注册表、给某个智能体或目录一次性铺齐 yotta-* 技能、预览安装清单、锁版本安装、或用户说 元阁/装全家/一次装齐/yotta-skills/install-all/更新全家/检查更新/自动更新/该用哪个技能/路由技能/盘点技能/查看已装技能 等。边界(Do NOT trigger):只做「组合策划 + 静态路由建议 + 清单 + 下载 + 落位 + 汇总 + 盘点 + re-index」,不含技能本体、不做技能内容开发、不 -g 污染全局、不自动安装缺失技能;装前摘要仅供参考,安装决策由用户确认。
5
5
  license: MIT
6
6
  metadata:
7
7
  zh_name: 元阁
@@ -16,7 +16,8 @@ metadata:
16
16
  **写入内容(逐字)**:
17
17
 
18
18
  > **元阁编排**:单技能是零件,组合才是系统。会话开工先跑一次 `yotta-skills --reindex`
19
- > (重扫本机技能注册表,新装技能自动被看见)。接到需求,先查「元阁编排策划」命中哪个组合
19
+ > (重扫本机技能注册表,新装技能自动被看见);会话开工再跑一次 `yotta-skills update --check`
20
+ > (联网只读检查本地已装技能是否有更新;有更新列清单,确认后 `update`,或 `update --auto` 仅自动更新自家 yotta-* 家族)。接到需求,先查「元阁编排策划」命中哪个组合
20
21
  > (输出呈现标准 / 长生命周期 / 交付质量门 / 装前安全门 / 造技能发版 / 安全事件响应 / 入口安装),
21
22
  > 再按需自动安装并应用。完整决策表见技能 `yotta-skills/references/orchestration.md`。
22
23
 
@@ -31,7 +32,7 @@ metadata:
31
32
 
32
33
  - **路由层(该用哪几个)**:`--route "<需求摘要>"` / MCP `route_request` 查本地注册表与静态编排 playbook,输出候选组合、调用顺序、每个技能角色、置信度、依据、已装/缺失状态与安装命令;非元阁家族已装技能按 frontmatter description 机械匹配作并列候选(标注来源与未扫描状态,只读不自动调用);只建议安装,不自动安装。
33
34
  - **策划层(怎么用)**:接到需求,先按「编排策划」定位命中哪个组合——哪些元技能搭配起来最强、适合什么场景、AI 该怎么自动装并自动用起来。
34
- - **安装层(怎么装)**:一条 `npx -y @yottameta/yotta-skills` 把组合/全家装进指定智能体或目录——`--list` 看清单、`install` 装、`update` 增量更新、`--dry-run` 预览、`--pin` 锁版本。
35
+ - **安装层(怎么装)**:一条 `npx -y @yottameta/yotta-skills` 把组合/全家装进指定智能体或目录——`--list` 看清单、`install` 装、`update` 增量更新、`update --check` 只读检查更新、`update --auto` 家族自动更新、`--dry-run` 预览、`--pin` 锁版本。
35
36
  - **盘点层(已装了什么)**:`--inventory` / `--reindex` 扫描本机各智能体技能目录,生成/更新本地注册表;装技能后自动 re-index,新装技能自动被发现——自包含扫描,不依赖任何元技能。
36
37
 
37
38
  每个技能仍走各自独立的 npm 包(版本源唯一);本包只做「清单 + 下载 + 落位 + 汇总」,**不内置任何技能本体**。
@@ -97,6 +98,12 @@ npx -y @yottameta/yotta-skills install yotta-memory yotta-verify --dir ~/my-skil
97
98
  # 增量更新已装技能(补齐缺失 / 版本不一致)
98
99
  npx -y @yottameta/yotta-skills update --agent codex
99
100
 
101
+ # 只读检查有没有更新(联网对 npm 最新,不改动;0=全部最新 / 3=有更新 / 1=查失败)
102
+ npx -y @yottameta/yotta-skills update --check --agent codex
103
+
104
+ # 检查到家族更新后自动更新(仅 yotta-* 自家家族,含装前安全扫描)
105
+ npx -y @yottameta/yotta-skills update --auto --agent codex
106
+
100
107
  # 预览将安装清单(不联网、不改动)
101
108
  npx -y @yottameta/yotta-skills --dry-run
102
109
 
@@ -116,6 +123,8 @@ npx -y @yottameta/yotta-skills --reindex
116
123
  | `install --dir <path>` | 装全家到指定目录,每个技能落在 `<path>/<slug>` |
117
124
  | `install <skill>... [--agent <name> \| --dir <path>]` | 只装指定的一个或多个技能 |
118
125
  | `update [--agent <name> \| --dir <path>]` | 增量更新:补齐缺失技能、升级版本不一致的技能 |
126
+ | `update --check [--agent <name> \| --dir <path>]` | 只读检查更新:联网对 npm 最新,不改动;退出码 0=全部最新 / 3=有更新 / 1=查失败 |
127
+ | `update --auto [--agent <name> \| --dir <path>]` | 检查到家族更新后自动更新(仅 yotta-* 自家家族,含装前安全扫描) |
119
128
  | `--inventory` | 盘点本机已装技能:扫描技能目录生成/更新注册表(自包含,不依赖元技能);`--json` 输出 JSON、`--project` 附扫项目级目录 |
120
129
  | `--reindex` | 重扫注册表:扫描技能目录并增量合并变化(会话开工 / 装技能后自动调用);`--json` 输出 JSON、`--project` 附扫项目级目录;`--rescan` 同义 |
121
130
  | `--route <需求摘要>` | 静态编排路由:输出组合、调用顺序、技能角色、置信度、依据、已装/缺失状态与安装建议;`--json` 输出 JSON、`--project` 附扫项目级目录 |
@@ -158,6 +167,22 @@ npx -y @yottameta/yotta-skills --inventory --dir ~/my-skills --project
158
167
  让新装 / 更新的技能自动进入注册表。
159
168
  - **手动**:`yotta-skills --reindex`(`--rescan` 同义);`--json` 机器可读、`--project` 附扫项目级目录。
160
169
 
170
+ ### update 增量更新与检查(--check / --auto)
171
+
172
+ 增量更新遍历清单,补齐缺失、升级版本不一致,默认跳过已最新。`--check` 只读联网
173
+ (对 npm `dist-tags.latest`),按本地 `SKILL.md` 版本对比——无论技能源自哪个安装渠道
174
+ (npm / git clone / 本地拷贝等)都兼容;`--auto` 检测到家族(`yotta-*` / 清单内)可更新时,走安装管线
175
+ (含元信装前安全扫描)自动更新。**非元阁家族(非 yotta-*)技能绝不自动更新**(默认保守:`--check` 列清单,
176
+ 用户确认后再 `update`)。
177
+
178
+ ```bash
179
+ # 只读检查(0=全部最新 / 3=有更新 / 1=查失败)
180
+ npx -y @yottameta/yotta-skills update --check --agent codex
181
+
182
+ # 检查到家族更新后自动更新(仅自家家族)
183
+ npx -y @yottameta/yotta-skills update --auto --agent codex
184
+ ```
185
+
161
186
  ## 编排路由(--route)
162
187
 
163
188
  把需求摘要交给静态编排 playbook 和本地注册表,得到一组可执行建议:
@@ -8,6 +8,8 @@
8
8
  * npx -y @yottameta/yotta-skills install --dir <path> # 装全家到指定目录
9
9
  * npx -y @yottameta/yotta-skills install <skill> --dir <path> # 装单个技能
10
10
  * npx -y @yottameta/yotta-skills update --agent <name> # 增量更新已装技能(补齐缺失/版本不一致)
11
+ * npx -y @yottameta/yotta-skills update --check # 只读检查更新(联网对 npm 最新,不改动;退出码 0/3/1)
12
+ * npx -y @yottameta/yotta-skills update --auto # 检查到家族更新后自动更新(仅 yotta-* 家族,含装前扫描)
11
13
  * npx -y @yottameta/yotta-skills --dry-run # 预览将安装清单(不联网、不改动)
12
14
  *
13
15
  * 版本策略:清单锁定 `major.x`(不锁死 patch,维护性更新随最新);--pin 锁死精确版本。
@@ -20,6 +22,8 @@ const fs = require('fs');
20
22
  const path = require('path');
21
23
  const os = require('os');
22
24
  const { spawnSync } = require('child_process');
25
+ const http = require('http');
26
+ const https = require('https');
23
27
 
24
28
  const PKG_ROOT = path.join(__dirname, '..');
25
29
  let VERSION = '0.2.1';
@@ -132,6 +136,7 @@ function parseArgs(argv) {
132
136
  help: false, version: false, agent: null, dir: null, npm: null,
133
137
  python: null, verify: null, command: null, skill: null, rest: [],
134
138
  inventory: false, reindex: false, noReindex: false, json: false, project: false, route: null,
139
+ check: false, auto: false, registry: null,
135
140
  };
136
141
  const positionals = [];
137
142
  for (let i = 0; i < argv.length; i++) {
@@ -160,6 +165,9 @@ function parseArgs(argv) {
160
165
  else if (a === '--npm') opts.npm = take('--npm');
161
166
  else if (a === '--python') opts.python = take('--python');
162
167
  else if (a === '--verify') opts.verify = take('--verify');
168
+ else if (a === '--check') opts.check = true;
169
+ else if (a === '--auto') opts.auto = true;
170
+ else if (a === '--registry') opts.registry = take('--registry');
163
171
  else if (a.startsWith('-')) die('未知参数: ' + a);
164
172
  else positionals.push(a);
165
173
  }
@@ -208,6 +216,147 @@ function readInstalledVersion(dir) {
208
216
  } catch (_) { return null; }
209
217
  }
210
218
 
219
+
220
+ // ── 更新检查(只读)与自动更新 ─────────────────────────────────────────────
221
+ function registryUrl(pkg, registry) {
222
+ var base = (registry || process.env.YOTTA_SKILLS_REGISTRY || 'https://registry.npmjs.org/').replace(/\/$/, '');
223
+ return base + '/' + pkg.replace(/\//g, '%2f');
224
+ }
225
+
226
+ function fetchRegistryLatest(pkg, opts) {
227
+ return new Promise(function (resolve) {
228
+ var url = registryUrl(pkg, opts.registry);
229
+ var client = url.startsWith('https:') ? https : http;
230
+ var req = client.get(url, { timeout: 15000, headers: { 'accept': 'application/json', 'user-agent': 'yotta-skills-check' } }, function (res) {
231
+ var data = '';
232
+ res.setEncoding('utf8');
233
+ res.on('data', function (c) { data += c; });
234
+ res.on('end', function () {
235
+ try {
236
+ var j = JSON.parse(data);
237
+ var latest = j && j['dist-tags'] && j['dist-tags'].latest;
238
+ if (!latest) { resolve({ ok: false, error: '响应缺少 dist-tags.latest(' + pkg + ')' }); return; }
239
+ resolve({ ok: true, version: latest });
240
+ } catch (e) {
241
+ resolve({ ok: false, error: '解析 registry 响应失败: ' + e.message });
242
+ }
243
+ });
244
+ });
245
+ req.on('error', function (e) { resolve({ ok: false, error: '网络错误: ' + (e && e.message ? e.message : e) }); });
246
+ req.on('timeout', function () { req.destroy(); resolve({ ok: false, error: '网络超时(15s)' }); });
247
+ });
248
+ }
249
+
250
+ function readInstalledMeta(dir) {
251
+ var f = path.join(dir, 'SKILL.md');
252
+ try {
253
+ var text = fs.readFileSync(f, 'utf8');
254
+ var name = (text.match(/^name:\s*(.+)$/m) || [])[1];
255
+ var version = (text.match(/^version:\s*([0-9]+\.[0-9]+\.[0-9]+)/m) || [])[1];
256
+ return { name: name ? name.trim() : null, version: version || null };
257
+ } catch (e) { return { name: null, version: null }; }
258
+ }
259
+
260
+ function familySkillFor(slug) {
261
+ var m = findSkill(slug);
262
+ if (m) return m;
263
+ if (/^yotta-/.test(slug)) {
264
+ return { slug: slug, name: slug.replace(/^yotta-/, ''), pkg: '@yottameta/' + slug, version: null, desc: '推断的家族技能(不在 skills.json 清单)' };
265
+ }
266
+ return null;
267
+ }
268
+
269
+ function scanInstalledSlugs(dest) {
270
+ var list = [];
271
+ var entries;
272
+ try { entries = fs.readdirSync(dest, { withFileTypes: true }); } catch (e) { return list; }
273
+ for (var i = 0; i < entries.length; i++) {
274
+ var e = entries[i];
275
+ if (!e.isDirectory()) continue;
276
+ var meta = readInstalledMeta(path.join(dest, e.name));
277
+ if (meta.name) list.push({ slug: e.name, name: meta.name, version: meta.version });
278
+ }
279
+ return list;
280
+ }
281
+
282
+ async function runUpdateCheck(opts, dest) {
283
+ var lines = [];
284
+ var quiet = !!opts.json;
285
+ function say(s) { if (!quiet) lines.push(s); }
286
+ say('yotta-skills(元阁)v' + VERSION + ' —— 检查更新(只读,不改动) -> ' + dest);
287
+ say('版本源: ' + (opts.registry || process.env.YOTTA_SKILLS_REGISTRY || 'https://registry.npmjs.org/'));
288
+ say('');
289
+ var installed = scanInstalledSlugs(dest);
290
+ if (installed.length === 0) {
291
+ say('(' + dest + ' 下未发现已装技能目录)');
292
+ return { code: 0, rows: [], updates: 0, latest: 0, failed: 0, nonFamily: 0 };
293
+ }
294
+ var rows = [];
295
+ var updates = 0, latest = 0, failed = 0, nonFamily = 0;
296
+ for (var i = 0; i < installed.length; i++) {
297
+ var it = installed[i];
298
+ var fam = familySkillFor(it.slug);
299
+ if (!fam) {
300
+ nonFamily++;
301
+ say(' - ' + it.slug.padEnd(22) + '非元阁家族,跳过');
302
+ continue;
303
+ }
304
+ var res = await fetchRegistryLatest(fam.pkg, opts);
305
+ if (!res.ok) {
306
+ failed++;
307
+ say(' ✘ ' + it.slug.padEnd(22) + '检查失败: ' + res.error);
308
+ continue;
309
+ }
310
+ var current = res.version;
311
+ var cur = it.version || null;
312
+ var isUp = (cur === current);
313
+ if (isUp) {
314
+ latest++;
315
+ say(' ✔ ' + it.slug.padEnd(22) + '已最新(本地 v' + cur + ')');
316
+ } else {
317
+ updates++;
318
+ say(' ➤ ' + it.slug.padEnd(22) + '有更新:本地 v' + (cur || '未知') + ' -> 最新 v' + current);
319
+ if (fam.version && fam.version !== current) {
320
+ say(' ⚠ 清单 skills.json 记为 v' + fam.version + ',与 npm 最新 v' + current + ' 不一致(需同步清单)');
321
+ }
322
+ }
323
+ rows.push({ slug: it.slug, installed: cur, latest: current, pkg: fam.pkg, hasUpdate: !isUp, family: fam });
324
+ }
325
+ say('');
326
+ say('汇总: 有更新 ' + updates + ' / 已最新 ' + latest + ' / 检查失败 ' + failed + ' / 非家族跳过 ' + nonFamily);
327
+ for (var j = 0; j < lines.length; j++) out(lines[j]);
328
+ var code = (failed > 0) ? 1 : (updates > 0 ? 3 : 0);
329
+ return { code: code, rows: rows, updates: updates, latest: latest, failed: failed, nonFamily: nonFamily };
330
+ }
331
+
332
+ async function runUpdateAuto(opts, dest) {
333
+ out('yotta-skills(元阁)v' + VERSION + ' —— 检查并自动更新(仅 yotta-* 家族) -> ' + dest);
334
+ var r = await runUpdateCheck(Object.assign({}, opts, { json: false }), dest);
335
+ if (r.failed > 0) {
336
+ out('检查未完成(' + r.failed + ' 个失败),未自动更新;可先排查网络后重试。');
337
+ return { code: 1 };
338
+ }
339
+ if (r.updates === 0) {
340
+ out('全部已最新,无需更新。');
341
+ return { code: 0 };
342
+ }
343
+ out('');
344
+ out('检测到 ' + r.updates + ' 个家族技能可更新,开始自动更新(安装管线,含装前安全扫描):');
345
+ var ok = 0, failed2 = 0;
346
+ for (var i = 0; i < r.rows.length; i++) {
347
+ var row = r.rows[i];
348
+ if (!row.hasUpdate) continue;
349
+ var res = installOne(Object.assign({}, row.family, { version: row.latest }), dest, Object.assign({}, opts, { force: true, pin: true }));
350
+ if (res.status === 'ok') ok++;
351
+ else if (res.status === 'skip') ok++;
352
+ else failed2++;
353
+ }
354
+ out('');
355
+ out('自动更新汇总: 成功 ' + ok + ' / 失败 ' + failed2);
356
+ maybeAutoReindex(opts, dest);
357
+ return { code: failed2 > 0 ? 1 : 0 };
358
+ }
359
+
211
360
  function shouldSkip(name, isFile) {
212
361
  if (name === '__pycache__' || name === '.pytest_cache' || name === '.mypy_cache') return true;
213
362
  if (isFile && (name.endsWith('.pyc') || name.endsWith('.pyo'))) return true;
@@ -458,6 +607,9 @@ function printHelp() {
458
607
  out(' --verify <path> 指定 yotta_verify.py 路径(默认找目标目录已装的元信)');
459
608
  out(' --json inventory / reindex / route 时输出 JSON');
460
609
  out(' --route <需求> 静态编排路由(输出组合 / 顺序 / 依据 / 缺失技能建议)');
610
+ out(' --check update 时仅只读检查更新(联网对 npm 最新版本,不改动;退出码 0/3/1)');
611
+ out(' --auto update 时检查到家族更新后自动更新(仅 yotta-* 家族,含装前扫描)');
612
+ out(' --registry <url> npm registry 地址(默认 https://registry.npmjs.org/;YOTTA_SKILLS_REGISTRY 覆盖)');
461
613
  out(' --project inventory / reindex 时附加扫描当前项目 .agents/skills / .codex/skills');
462
614
  out(' --no-reindex 安装 / 更新后不自动重扫注册表');
463
615
  out(' -h, --help 帮助');
@@ -614,9 +766,23 @@ function main() {
614
766
  return;
615
767
  }
616
768
 
617
- if (command === 'update') runUpdate(opts, dest);
618
- else runInstall(opts, dest);
619
- maybeAutoReindex(opts, dest);
769
+ if (command === 'update') {
770
+ if (opts.check || opts.auto) {
771
+ var runFn = opts.auto ? runUpdateAuto : runUpdateCheck;
772
+ runFn(opts, dest).then(function (r) {
773
+ if (opts.json && !opts.auto) {
774
+ out(JSON.stringify({ dest: dest, updatable: r.rows.filter(function (x) { return x.hasUpdate; }), updates: r.updates, latest: r.latest, failed: r.failed, nonFamily: r.nonFamily }, null, 2));
775
+ }
776
+ process.exitCode = r.code;
777
+ });
778
+ } else {
779
+ runUpdate(opts, dest);
780
+ maybeAutoReindex(opts, dest);
781
+ }
782
+ } else {
783
+ runInstall(opts, dest);
784
+ maybeAutoReindex(opts, dest);
785
+ }
620
786
  }
621
787
 
622
788
  main();
@@ -24,7 +24,7 @@ import subprocess
24
24
  import sys
25
25
  from pathlib import Path
26
26
 
27
- VERSION = "0.6.1"
27
+ VERSION = "0.6.2"
28
28
  TOOL_NAME = "yotta-skills"
29
29
  CN_NAME = "元阁"
30
30
  MCP_PROTOCOL_MODERN = "2026-07-28"