@yottameta/yotta-skills 0.20.1 → 0.20.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.
- package/CHANGELOG.md +6 -0
- package/SKILL.md +5 -3
- package/bin/yotta-skills.js +8 -24
- package/lib/install-pipeline.js +1 -0
- package/lib/npm-pack.js +104 -0
- package/package.json +1 -1
- package/references/install-flow.md +2 -1
- package/references/tutorial.md +2 -2
- package/scripts/yotta-skills-mcp.py +1 -1
- package/skill-manifest.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## v0.20.2 (2026-09-29)
|
|
2
|
+
- 家族安装的 npm 拉包新增镜像回退:默认源返回 404(国内镜像未同步该版本 tarball)时自动改用官方源 `https://registry.npmjs.org/` 重试一次;安装输出显示回退行,安装证据新增 `npm_registry_fallback` 字段。
|
|
3
|
+
- 两次都失败时给出可直接复制的修复提示(`npm_config_registry` / `YOTTA_SKILLS_NPM_FLAGS`);已显式指定 registry 或设置 `YOTTA_SKILLS_NO_FALLBACK=1` 时不回退。
|
|
4
|
+
- 非 404 错误(网络超时等)不触发回退,保持原失败信息。
|
|
5
|
+
- 静态 playbook / 路由 / hook / scanPolicy 契约零变更。
|
|
6
|
+
|
|
1
7
|
## v0.20.1 (2026-09-29)
|
|
2
8
|
- 家族安装接入 scanPolicy 例外复核:元信判 `DO NOT INSTALL` 时,按包内 `scan-policy.json` 的已审查例外(逐条绑定技能 + 版本 + treeHash + 规则 + 路径)复核,豁免检测规则表 / 攻防样例 / 文档说明类命中;复核后无阻断级发现则继续安装。
|
|
3
9
|
- 修复元忆 / 元察 / 元鉴从元阁安装时被元信自指误报阻断的问题(检测类技能自带规则表字面量);例外表与 handoff / OpenCode 的 scanPolicy 同源,由 `tools/build_scan_policy.py` 生成。
|
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yotta-skills
|
|
3
|
-
version: 0.20.
|
|
3
|
+
version: 0.20.2
|
|
4
4
|
description: 元阁 -- 元阁全家技能的总编排策划 + 编排路由 + 一键安装器 + 技能盘点 + 运行时 hook 适配。路由层:--route / route_request 按需求摘要给出候选组合、调用顺序、角色、置信度、依据、已装/缺失状态与安装命令,只建议不自动安装;非元阁家族已装技能按 frontmatter description 机械匹配作并列候选(标注来源与未扫描状态,只读不自动调用);策划层:按场景给出「该组合哪几个元技能、组合强在哪、怎么组合使用(安装与调用均由用户确认后执行)」;安装层:一条命令把 YottaMeta 已发布的全部 yotta-* 技能装进指定智能体或目录(默认 --pin 锁死清单精确版本);盘点层:--inventory / --reindex 扫描本机已装技能生成/更新注册表,新装技能自动被发现(install/update 后自动 re-index,会话开工只建议跑本地 --reindex;更新检查走手动 --check 或后台 --check --scheduled);运行时适配层:hook capabilities / evaluate / bind / unbind 按宿主能力矩阵执行六个统一事件并留证降级,元信 before_install 已接入安装管线;自包含零依赖,不依赖任何元技能;MCP 按需加载且需用户确认后写入配置(可选:list_installed_skills/describe_skill/reindex/route_request,不常驻,未加载降级 CLI)。支持 --list 清单 / --route 路由 / install / update / update --check(只读检查)/ update --check --scheduled(后台周检)/ update --auto(家族自动更新)/ hook 适配 / --inventory / --reindex / --dry-run 预览 / --pin(默认)/ --range。触发:需要批量安装或更新元阁全家技能、按场景组合多个元技能、路由或判断该用哪些技能、盘点或查看本机已装技能、重扫技能注册表、给某个智能体或目录一次性铺齐 yotta-* 技能、评估宿主 hook 能力、预览安装清单、锁版本安装、或用户说 元阁/装全家/一次装齐/yotta-skills/install-all/更新全家/检查更新/自动更新/hook 适配/该用哪个技能/路由技能/盘点技能/查看已装技能 等。边界(Do NOT trigger):只做「组合策划 + 静态路由建议 + 清单 + 下载 + 落位 + 汇总 + 盘点 + re-index + hook 适配」,不含技能本体、不做技能内容开发、不 -g 污染全局、不自动安装缺失技能、不静默写宿主配置或全局记忆;家族安装先自举或调用元信装前门禁,DO NOT INSTALL 阻断,非元阁家族包不自动安装。
|
|
5
5
|
license: MIT
|
|
6
6
|
metadata:
|
|
@@ -375,14 +375,16 @@ npx -y @yottameta/yotta-skills --route "检查代码质量,别糊弄" --json
|
|
|
375
375
|
|---|---|
|
|
376
376
|
| `YOTTA_SKILLS_NPM` | 指定 npm 可执行文件(同 `--npm`) |
|
|
377
377
|
| `YOTTA_SKILLS_NPM_FLAGS` | 追加传给 `npm pack` 的参数(按空白拆分,如 `--registry=...`) |
|
|
378
|
+
| `YOTTA_SKILLS_NO_FALLBACK` | 设为 `1` 时禁用「默认源 404 → 官方源重试」的自动回退 |
|
|
378
379
|
| `YOTTA_SKILLS_PYTHON` | 指定 python 可执行文件(元信 scan 用,同 `--python`) |
|
|
379
380
|
| `YOTTA_SKILLS_VERIFY` | 指定 yotta_verify.py 路径(同 `--verify`) |
|
|
380
381
|
| `YOTTA_SKILLS_MANIFEST` | 指定技能清单 JSON 路径(默认随包 skills.json) |
|
|
381
382
|
|
|
382
383
|
## 常见问题
|
|
383
384
|
|
|
384
|
-
- **npmmirror 全新包 404
|
|
385
|
-
|
|
385
|
+
- **npmmirror 全新包 404**:默认源返回 404 时安装器会**自动**改用官方源
|
|
386
|
+
`https://registry.npmjs.org/` 重试一次(输出显示回退行,安装证据记 `npm_registry_fallback`);
|
|
387
|
+
若已显式指定 registry 或设置 `YOTTA_SKILLS_NO_FALLBACK=1`,则保持在指定源上,失败时给出可复制的修复提示。
|
|
386
388
|
- **未收录智能体**:`--agent <name>` 报未收录时,改用 `--dir` 指到它的技能目录。
|
|
387
389
|
- **Windows 下 npm 报错**:CLI 已内置 npm-cli.js 解析,无需额外处理;如需覆盖用 `--npm`。
|
|
388
390
|
- **某技能安装失败**:汇总报告会列出失败原因,可单装该技能排查。
|
package/bin/yotta-skills.js
CHANGED
|
@@ -36,10 +36,11 @@ const snapshotLib = require('../lib/install-snapshot');
|
|
|
36
36
|
const updateCheckLib = require('../lib/update-check');
|
|
37
37
|
const hookAdapterLib = require('../lib/hook-adapter');
|
|
38
38
|
const scanPolicyLib = require('../lib/scan-policy');
|
|
39
|
+
const npmPackLib = require('../lib/npm-pack');
|
|
39
40
|
const { createInstaller, isSafeTarEntry } = require('../lib/install-pipeline');
|
|
40
41
|
|
|
41
42
|
const PKG_ROOT = path.join(__dirname, '..');
|
|
42
|
-
let VERSION = '0.20.
|
|
43
|
+
let VERSION = '0.20.2';
|
|
43
44
|
try { VERSION = require(path.join(PKG_ROOT, 'package.json')).version; } catch (_) { /* keep fallback */ }
|
|
44
45
|
|
|
45
46
|
function loadManifest() {
|
|
@@ -617,31 +618,14 @@ function scanTarget(engine, skillDir, context) {
|
|
|
617
618
|
}
|
|
618
619
|
|
|
619
620
|
// ── 安装 ───────────────────────────────────────────────────────────────────
|
|
621
|
+
const runNpmPackBase = npmPackLib.createPackRunner({ spawnSync, specOf, resolveNpm });
|
|
622
|
+
|
|
620
623
|
function runNpmPack(skill, opts, packDir) {
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
if (flags) args.push(...flags.split(/\s+/));
|
|
625
|
-
const npm = resolveNpm(opts);
|
|
626
|
-
const r = spawnSync(npm.bin, [...npm.prefix, ...args], { encoding: 'utf8', timeout: 180000, maxBuffer: 64 * 1024 * 1024, shell: npm.shell });
|
|
627
|
-
if (r.status !== 0) {
|
|
628
|
-
const raw = (r.stderr || r.stdout || 'npm pack 失败').trim();
|
|
629
|
-
const ll = raw.split(/\r?\n/).filter(Boolean);
|
|
630
|
-
const brief = ll.slice(-4).join(' | ');
|
|
631
|
-
return { error: brief || 'npm pack 失败', detail: raw };
|
|
632
|
-
}
|
|
633
|
-
const lines = (r.stdout || '').split(/\r?\n/).map(l => l.trim()).filter(Boolean);
|
|
634
|
-
let tarball = null;
|
|
635
|
-
for (const l of lines) if (/\.tgz$/.test(l)) tarball = l;
|
|
636
|
-
if (!tarball) {
|
|
637
|
-
try {
|
|
638
|
-
const found = fs.readdirSync(packDir).filter(f => f.endsWith('.tgz'));
|
|
639
|
-
if (found.length === 1) tarball = found[0];
|
|
640
|
-
} catch (_) { /* ignore */ }
|
|
624
|
+
const packed = runNpmPackBase(skill, opts, packDir);
|
|
625
|
+
if (packed.registryFallback) {
|
|
626
|
+
out(' ↳ npm 默认源 404,已用官方源重试成功(' + npmPackLib.OFFICIAL_REGISTRY + ')');
|
|
641
627
|
}
|
|
642
|
-
|
|
643
|
-
const vm = String(tarball).match(/-([0-9]+\.[0-9]+\.[0-9]+)\.tgz$/);
|
|
644
|
-
return { tarball: path.join(packDir, tarball), resolved: vm ? vm[1] : null, spec };
|
|
628
|
+
return packed;
|
|
645
629
|
}
|
|
646
630
|
|
|
647
631
|
function extractTarball(tarball, extractDir) {
|
package/lib/install-pipeline.js
CHANGED
package/lib/npm-pack.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const OFFICIAL_REGISTRY = 'https://registry.npmjs.org/';
|
|
6
|
+
const FALLBACK_HINT =
|
|
7
|
+
'提示:镜像同步延迟时可用官方源重试 —— 设置环境变量 npm_config_registry=' + OFFICIAL_REGISTRY +
|
|
8
|
+
',或 YOTTA_SKILLS_NPM_FLAGS=--registry=' + OFFICIAL_REGISTRY;
|
|
9
|
+
|
|
10
|
+
function isNotFound(raw) {
|
|
11
|
+
const text = String(raw || '');
|
|
12
|
+
return /\bE404\b/.test(text) || /\b404 Not Found\b/i.test(text) || /could not be found/i.test(text);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function hasRegistryFlag(args) {
|
|
16
|
+
return (args || []).some((arg) => arg === '--registry' || String(arg).startsWith('--registry='));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function briefOf(raw) {
|
|
20
|
+
const lines = String(raw || '')
|
|
21
|
+
.split(/\r?\n/)
|
|
22
|
+
.map((line) => line.trim())
|
|
23
|
+
.filter(Boolean);
|
|
24
|
+
return lines.slice(-4).join(' | ');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function findTarball(stdout, packDir, readdirSync) {
|
|
28
|
+
const lines = String(stdout || '')
|
|
29
|
+
.split(/\r?\n/)
|
|
30
|
+
.map((line) => line.trim())
|
|
31
|
+
.filter(Boolean);
|
|
32
|
+
let tarball = null;
|
|
33
|
+
for (const line of lines) if (/\.tgz$/.test(line)) tarball = line;
|
|
34
|
+
if (tarball) return tarball;
|
|
35
|
+
try {
|
|
36
|
+
const found = readdirSync(packDir).filter((name) => name.endsWith('.tgz'));
|
|
37
|
+
if (found.length === 1) return found[0];
|
|
38
|
+
} catch (_) {
|
|
39
|
+
/* ignore */
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 创建 npm pack 执行器。
|
|
46
|
+
*
|
|
47
|
+
* 默认源(国内镜像)拉不到 tarball 时会报 404 —— 此时自动改用官方源重试一次,
|
|
48
|
+
* 并把 registryFallback 标记回传给安装管线(写入证据)。用户已显式指定 registry、
|
|
49
|
+
* 或设置 YOTTA_SKILLS_NO_FALLBACK=1 时不重试。
|
|
50
|
+
*/
|
|
51
|
+
function createPackRunner(deps) {
|
|
52
|
+
const spawnSync = deps.spawnSync;
|
|
53
|
+
const specOf = deps.specOf;
|
|
54
|
+
const resolveNpm = deps.resolveNpm;
|
|
55
|
+
const readdirSync = deps.readdirSync || fs.readdirSync;
|
|
56
|
+
const fallbackDisabled = deps.fallbackDisabled || (() => process.env.YOTTA_SKILLS_NO_FALLBACK === '1');
|
|
57
|
+
|
|
58
|
+
return function runNpmPack(skill, opts, packDir) {
|
|
59
|
+
const spec = specOf(skill, opts.pin);
|
|
60
|
+
const baseArgs = ['pack', spec, '--pack-destination', packDir];
|
|
61
|
+
const flags = (process.env.YOTTA_SKILLS_NPM_FLAGS || '').trim();
|
|
62
|
+
if (flags) baseArgs.push(...flags.split(/\s+/));
|
|
63
|
+
const npm = resolveNpm(opts);
|
|
64
|
+
const attempt = (args) => spawnSync(npm.bin, [...npm.prefix, ...args], {
|
|
65
|
+
encoding: 'utf8',
|
|
66
|
+
timeout: 180000,
|
|
67
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
68
|
+
shell: npm.shell,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
let result = attempt(baseArgs);
|
|
72
|
+
let registryFallback = false;
|
|
73
|
+
if (result.status !== 0) {
|
|
74
|
+
const raw = (result.stderr || result.stdout || 'npm pack 失败').trim();
|
|
75
|
+
if (!fallbackDisabled() && !hasRegistryFlag(baseArgs) && isNotFound(raw)) {
|
|
76
|
+
result = attempt([...baseArgs, '--registry', OFFICIAL_REGISTRY]);
|
|
77
|
+
registryFallback = result.status === 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (result.status !== 0) {
|
|
81
|
+
const raw = (result.stderr || result.stdout || 'npm pack 失败').trim();
|
|
82
|
+
const brief = briefOf(raw) || 'npm pack 失败';
|
|
83
|
+
const hint = isNotFound(raw) ? '\n ' + FALLBACK_HINT : '';
|
|
84
|
+
return { error: brief + hint, detail: raw };
|
|
85
|
+
}
|
|
86
|
+
const tarball = findTarball(result.stdout, packDir, readdirSync);
|
|
87
|
+
if (!tarball) return { error: '未找到 npm pack 产物(' + spec + ')' };
|
|
88
|
+
const versionMatch = String(tarball).match(/-([0-9]+\.[0-9]+\.[0-9]+)\.tgz$/);
|
|
89
|
+
return {
|
|
90
|
+
tarball: path.join(packDir, tarball),
|
|
91
|
+
resolved: versionMatch ? versionMatch[1] : null,
|
|
92
|
+
spec,
|
|
93
|
+
registryFallback,
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
OFFICIAL_REGISTRY,
|
|
100
|
+
FALLBACK_HINT,
|
|
101
|
+
isNotFound,
|
|
102
|
+
hasRegistryFlag,
|
|
103
|
+
createPackRunner,
|
|
104
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yottameta/yotta-skills",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.2",
|
|
4
4
|
"description": "YuanGe (元阁) - orchestration routing, inventory, and one-command installer for the YottaMeta skill family (zero dependencies, Node.js only).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
对每个待装技能:
|
|
9
9
|
|
|
10
10
|
1. 读清单(`skills.json`,默认随包;`YOTTA_SKILLS_MANIFEST` 可覆盖);
|
|
11
|
-
2. `npm pack <pkg>@<spec> --pack-destination
|
|
11
|
+
2. `npm pack <pkg>@<spec> --pack-destination <临时目录>`(默认源返回 404 时自动改用官方源重试一次,
|
|
12
|
+
证据记 `npm_registry_fallback`);
|
|
12
13
|
3. 系统 `tar -xzf` 解压到临时目录(产物应有 `SKILL.md`);
|
|
13
14
|
4. 读取包内 `skill-manifest.json`;没有 manifest 时使用 `skills.json` 的家族默认契约;
|
|
14
15
|
5. 校验 slug / package / version / 权限 / 生命周期脚本路径;
|
package/references/tutorial.md
CHANGED
|
@@ -108,8 +108,8 @@ npx -y @yottameta/yotta-skills rollback --slug yotta-memory --agent codex
|
|
|
108
108
|
|
|
109
109
|
## 10. 常见问题
|
|
110
110
|
|
|
111
|
-
- **npmmirror 全新包 404
|
|
112
|
-
|
|
111
|
+
- **npmmirror 全新包 404**:镜像同步有延迟时安装器会自动改用官方源重试一次(默认行为);
|
|
112
|
+
如需固定在指定源,设置 `YOTTA_SKILLS_NPM_FLAGS=--registry=...` 或 `YOTTA_SKILLS_NO_FALLBACK=1`。
|
|
113
113
|
- **`--agent` 报未收录**:改用 `--dir` 指到该智能体的技能目录(`.agents/skills` 不是
|
|
114
114
|
通用目录)。
|
|
115
115
|
- **某技能安装失败**:汇总报告给出失败原因;可单装该技能排查:
|