@yottameta/yotta-skills-plugin 0.0.0 → 0.5.1

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.
@@ -0,0 +1,78 @@
1
+ # 安装器工作原理(install-flow)
2
+
3
+ > 面向想了解 yotta-skills 内部机制的开发者;日常使用请读 `SKILL.md` 或中文教程
4
+ > (`references/tutorial.md`)。
5
+
6
+ ## 总体流程
7
+
8
+ 对每个待装技能:
9
+
10
+ 1. 读清单(`skills.json`,默认随包;`YOTTA_SKILLS_MANIFEST` 可覆盖);
11
+ 2. `npm pack <pkg>@<spec> --pack-destination <临时目录>`;
12
+ 3. 系统 `tar -xzf` 解压到临时目录(产物应有 `SKILL.md`);
13
+ 4. 元信装前摘要(若引擎可用;`--skip-scan` 关闭);
14
+ 5. 删除目标 `<dest>/<slug>` 后重新复制(跳过规则见下);
15
+ 6. 汇总报告:✔ 成功 / - 跳过(已是最新)/ ✘ 失败;有失败项时退出码 1。
16
+ 7. 全部完成后自动 re-index 本地技能注册表(`~/.yottaskills/registry.json`):重扫技能根目录并增量合并,
17
+ 新装 / 更新的技能随即进入注册表(`--no-reindex` 可关闭;`--dry-run` 不触发)。
18
+
19
+ ## 复制跳过规则
20
+
21
+ - 顶层跳过:`package.json` / `bin` / `node_modules` / `.git` / `__pycache__`;
22
+ - 任意层级跳过:`.pytest_cache` / `.mypy_cache` 目录、`*.pyc` / `*.pyo` 文件。
23
+
24
+ 因此装进技能目录的是「技能本体」(SKILL.md / references / scripts 等),不含 npm
25
+ 安装器自身、测试夹具与 Python 字节码缓存。
26
+
27
+ ## re-index(装技能后自动重扫注册表)
28
+
29
+ - `install` / `update` 完成后,CLI 自动调用 `--reindex`(同一套 `lib/skills-scan.js` 扫描核心):
30
+ 重扫技能根目录 → 增量合并进 `~/.yottaskills/registry.json`(新增 / 更新 / 消失)。
31
+ - `--no-reindex` 关闭自动重扫;`--reindex` 也可单独手动执行(会话开工 / 新装技能后)。
32
+ - 与 `--inventory` 的区别:`--inventory` 侧重「盘点展示」(文本表格 / JSON 全量),
33
+ `--reindex` 侧重「变化合并」(增量、输出聚焦新增 / 更新 / 消失,适合钩子与脚本)。
34
+
35
+ ## 幂等与版本判断
36
+
37
+ - 读取目标 `<dest>/<slug>/SKILL.md` 的 frontmatter `version`;
38
+ - 与清单 `version` 一致 → 跳过(幂等:第二次安装 22 个全部跳过);
39
+ - `--force` 强制重装;`update` 对「缺失 / 版本不一致」的技能重装。
40
+
41
+ ## 版本策略
42
+
43
+ - 默认 range:spec = `<pkg>@<major>.x`(如 `0.x`),`npm pack` 取同 major 最新 patch;
44
+ - `--pin`:spec = `<pkg>@<清单精确版本>`。
45
+
46
+ ## npm 解析(Windows)
47
+
48
+ - 优先:`where.exe npm.cmd` → 读同目录 `node_modules/npm/bin/npm-cli.js` → 用 node 直接执行
49
+ (npm.cmd 直跑在 Windows 有 EINVAL,`cmd /c` 引号脆弱;npm-cli.js 直跑无 shell 变量坑);
50
+ - `--npm` / `YOTTA_SKILLS_NPM`:`.js` → node 执行;`.cmd/.bat` → 同样解析 npm-cli.js;
51
+ 其它 → 直接执行;
52
+ - `YOTTA_SKILLS_NPM_FLAGS` 追加到 `npm pack` 参数。
53
+
54
+ ## 元信装前摘要
55
+
56
+ - 引擎查找:`--verify` → `YOTTA_SKILLS_VERIFY` → `<dest>/yotta-verify/scripts/yotta_verify.py`;
57
+ - python 查找:`--python` → `YOTTA_SKILLS_PYTHON` → `python3` / `python` / `py`(win32);
58
+ - 执行:`python -B <engine> scan <解压目录> --json`(`-B` 禁止写 `__pycache__`,防止污染
59
+ 引擎所在目录);
60
+ - 输出 verdict + counts(critical / high / medium / low / info);DO NOT INSTALL 额外提示
61
+ 人工复核;仅摘要、不拦截。
62
+
63
+ ## 退出码
64
+
65
+ | 退出码 | 含义 |
66
+ |---|---|
67
+ | 0 | 成功(含全部跳过) |
68
+ | 1 | 安装 / 更新存在失败项 |
69
+ | 2 | 用法错误(未知参数 / 未知技能 / 未收录智能体) |
70
+ | 4 | 未指定目标且当前目录未检测到项目级技能目录 |
71
+
72
+ ## 目标目录解析
73
+
74
+ - `--dir`:直接使用(技能落在 `<dir>/<slug>`);
75
+ - `--agent`:查内置 17 智能体表(codex 特判 `$CODEX_HOME/skills`;opencode 特判
76
+ `$XDG_CONFIG_HOME/opencode/skills`;其余 `~/.<agent>/skills` 或 `~/.config/...`);
77
+ - 都未指定:检测当前目录是否存在项目级技能目录(`.claude/skills`、`.codex/skills`、
78
+ `.agents/skills` 等 17 个),存在则用之;否则退出码 4。
@@ -0,0 +1,88 @@
1
+ # 元阁编排策划(orchestration)
2
+
3
+ > 元阁(yotta-skills)的**编排层**:告诉 AI 智能体「什么时候该组合哪几个元技能、组合起来比单用强在哪、怎么自动安装并按组合契约用起来」。
4
+ > 本页是「每个场景 → 选哪几个技能 → 为什么 → 怎么自动装 + 自动用」的决策表,供 AI 智能体在接到需求时查表执行。
5
+ > 配套:全家清单见 `skill-list.md`;安装用法见 SKILL.md「快速使用」。
6
+
7
+ ---
8
+
9
+ ## 〇、编排路由(--route / route_request)
10
+
11
+ 把需求摘要交给静态 playbook 与本地注册表,得到一组建议:
12
+
13
+ ```bash
14
+ npx -y @yottameta/yotta-skills --route "帮我润色输出,要规范可复制,别有 AI 味"
15
+ ```
16
+
17
+ - **输出**:候选组合、调用顺序、每个技能的角色、置信度、命中依据、已装/缺失状态、安装命令与应用模式提醒;如本机装了非元阁家族技能,还会给出其他已装技能候选(仅按 frontmatter description 机械匹配,标注来源与未扫描状态)。
18
+ - **缺失技能**:只给安装命令,不自动安装;安装前先做装前安全扫描,决定权在用户。
19
+ - **应用模式**:默认用户显式调用;切换为「按场景自动调用」需要用户确认。
20
+ - **无明确匹配**:低置信度回退到「入口 + 安装」组合,先澄清需求再继续。
21
+ - **边界**:路由是建议,不保证完全正确;关键动作由用户确认,数据不出本机。其他已装技能候选只读 frontmatter description、不读取全文指令、不自动调用;使用/安装前先做装前安全扫描。
22
+
23
+ ---
24
+
25
+ ## 一、技能家族全景(24 技能 / 8 家族)
26
+
27
+ | 家族 | 技能(中文名 / slug) | 一句话能力 |
28
+ |---|---|---|
29
+ | 入口与引导 | 元引 yotta-prompt | 意图澄清,串联到对应的元阁技能 |
30
+ | 覆盖与安装 | 元阁 yotta-skills | 全家 / 按需一键安装与更新 |
31
+ | 呈现与表达 | 元呈 yotta-present、元真 yotta-humanize | 输出判型渲染成可复制 Markdown/纯文本;去 AI 味 |
32
+ | 记忆与上下文 | 元忆 yotta-memory、元习 yotta-learn、元史 yotta-logs | 权限记忆、学习沉淀、历史检索 |
33
+ | 工作流与跨会话 | 元序 yotta-workflow | 开工读状态 / 状态就近存 / 会话结束留记录 |
34
+ | 质量与工程 | 元谨 yotta-anti-shallow、元质 yotta-code-quality、元造 yotta-skill-creator、元守 yotta-publish-guard | 防敷衍、代码评审、造技能、发布守门 |
35
+ | 安全与信任 | 元信 yotta-verify(+元信MCP)、元审 yotta-vetter、元安 yotta-security-audit、元链 yotta-chain、元钥 yotta-secret、元鉴 yotta-triage、元察 yotta-logwatch、元情 yotta-intel、元析 yotta-recon、元测 yotta-security-testing、元盾 yotta-guardian、元安全 yotta-agent-hardening | 装前扫描、审查协议、静态检测、供应链、密钥、样本、日志、IOC、侦察、测试、拦截、加固 |
36
+ | 分发与汇总 | 元引(串联)、元阁(安装) | —— |
37
+
38
+ ---
39
+
40
+ ## 二、组合矩阵(哪些和哪些组合,强在哪)
41
+
42
+ > 原则:**单技能是零件,组合才是系统**。下面每个组合给出「一起用效果、单用差在哪、典型场景」。
43
+
44
+ | 组合 | 成员(slug) | 一起用强在哪 | 单用缺什么 |
45
+ |---|---|---|---|
46
+ | **① 输出呈现标准** | yotta-present + yotta-humanize | 先判型渲染成规范、可复制、可复用的输出,再检测 AI 味改写,交付统一且读感自然 | 只有 yotta-present:规范但不祛 AI 味;只有 yotta-humanize:祛 AI 味但输出形态不规整 |
47
+ | **② 长生命周期智能体** | yotta-workflow + yotta-memory + yotta-learn + yotta-logs | 开工恢复上下文、权限记忆、沉淀学习、检索历史,智能体活过会话、越用越懂你 | 缺 yotta-workflow:状态无处放;缺 yotta-memory:记忆无权限边界;缺 yotta-learn:错不沉淀;缺 yotta-logs:历史查不到 |
48
+ | **③ 交付质量门** | yotta-anti-shallow + yotta-code-quality + yotta-publish-guard | 防敷衍、结对评审、发布前守门,交付前多层把关 | 缺 yotta-anti-shallow:容易停留表面;缺 yotta-code-quality:代码质量无人审;缺 yotta-publish-guard:发版无守门 |
49
+ | **④ 装前安全门** | yotta-verify(或元信MCP)+ yotta-vetter + yotta-security-audit | 确定性扫描 + 协议审查 + 深检,装其他来源技能/插件/MCP 前给出可信判定 | 缺 yotta-verify:无确定性扫描;缺 yotta-vetter:无协议审查;缺 yotta-security-audit:无深检兜底 |
50
+ | **⑤ 造技能 / 发版** | yotta-skill-creator + yotta-publish-guard | 脚手架生成合规技能目录,发布前守门 | 缺 yotta-skill-creator:造技能无模板;缺 yotta-publish-guard:造完不知能否发 |
51
+ | **⑥ 安全事件响应** | yotta-logwatch + yotta-intel + yotta-triage + yotta-secret + yotta-chain + yotta-recon | 日志检测攻击链、提取 IOC、初筛样本、扫密钥、校验供应链、侦察资产 | 每项只管一环,单用看不到全链路 |
52
+ | **⑦ 入口 + 安装** | yotta-prompt + yotta-skills | 元引澄清需求串联到对应技能,元阁按场景把组合一口气装好 | 缺 yotta-prompt:需求模糊时不知该用哪个;缺 yotta-skills:要一个个装 |
53
+
54
+ ---
55
+
56
+ ## 三、场景 → 组合映射(AI 接到需求时查表)
57
+
58
+ | 用户场景(触发词) | 该组合 | 自动装 / 自动用动作 |
59
+ |---|---|---|
60
+ | 「让 AI 长期帮我做项目 / 别忘了我 / 跨会话」 | ② 长生命周期 | 装 yotta-workflow yotta-memory yotta-learn yotta-logs;开工恢复上下文、状态就近存、会话结束留记录 |
61
+ | 「帮我写/润色,让输出规范、别 AI 味」 | ① 输出呈现标准 | 装 yotta-present yotta-humanize;默认先判型渲染,检测 AI 味再改写 |
62
+ | 「检查这段代码/报告质量,别糊弄」 | ③ 交付质量门 | 装 yotta-anti-shallow yotta-code-quality yotta-publish-guard;按对应协议执行 |
63
+ | 「我要装一个其他来源技能/插件/MCP」 | ④ 装前安全门 | 装 yotta-verify(+MCP) yotta-vetter yotta-security-audit;装前必扫 |
64
+ | 「我要造一个新 skill 并发布」 | ⑤ 造技能/发版 | 装 yotta-skill-creator yotta-publish-guard;生成 + 守门 |
65
+ | 「我怀疑日志/资产有问题」 | ⑥ 安全事件响应 | 装 yotta-logwatch yotta-intel yotta-triage yotta-secret yotta-chain yotta-recon;按需调用 |
66
+ | 「不知道怎么说 / 一堆技能该用哪个」 | ⑦ 入口+安装 | 装 yotta-prompt yotta-skills;元引澄清→串联→元阁按组合装 |
67
+
68
+ > 组合不是死板套餐:命中「入口+安装」或「输出呈现标准」这类**默认契约**时,AI 应自动应用,不需用户逐次说;命中安全/发版这类**高风险动作**时,AI 应装技能并给出执行方案,由用户确认后执行。
69
+
70
+ ---
71
+
72
+ ## 四、AI 自动安装与组合规则(金标准)
73
+
74
+ 1. **查表**:接到需求,先在「场景→组合映射」里定位命中组合。
75
+ 2. **查已装**:检查当前智能体的技能目录是否存在对应 `<slug>/SKILL.md`;存在即已装,缺失即待装。
76
+ 3. **自动装**:缺失的技能用
77
+ `npx -y @yottameta/yotta-skills install <slug>... [--agent <name> | --dir <path>]`
78
+ 一次性补齐(只装组合所需,不装全家,避免过度安装)。
79
+ 4. **自动用(默认契约)**:命中的是「输出呈现标准」「长生命周期」这类**默认行为契约**时,装完即按组合契约自动调用(如:所有输出先过 yotta-present;开工先恢复上下文 + 读状态文件)。不需用户逐次提醒。
80
+ 5. **用户触发(高风险)**:命中「安全 / 发版 / 造技能」这类**高风险或目的不明**时,AI 装技能 + 给出执行方案,**先征询用户确认**再执行;拿不准就当未装,给出安装命令。
81
+ 6. **边界**:不 `-g` 全局安装;不向未指定位置写文件;拿不准某技能是否已装 → 视为未装并给提示;网络不可用 → 明确报错,不伪造结果。
82
+
83
+ ---
84
+
85
+ ## 五、安装与入口
86
+
87
+ - 安装 CLI 用法见 `SKILL.md`「快速使用」;全家清单见 `skill-list.md`。
88
+ - 版本策略 / 元信装前摘要 / 支持的智能体 / 环境变量 同 SKILL.md。
@@ -0,0 +1,40 @@
1
+ # 全家技能清单(22 个)
2
+
3
+ > 机器权威源:`skills.json`(随包分发);本文件为人工可读副本,新技能发布后须同步更新
4
+ > `skills.json`(登记表为内部台账,不随包分发)。清单更新日期:2026-08-29。
5
+
6
+ | slug | 中文名 | npm 包 | 清单版本 | 说明 |
7
+ |---|---|---|---|---|
8
+ | `yotta-anti-shallow` | 元谨 | `@yottameta/yotta-anti-shallow` | 1.3.4 | 防 AI 敷衍规则引擎(深入分析/根因追溯时激活) |
9
+ | `yotta-code-quality` | 元质 | `@yottameta/yotta-code-quality` | 0.3.4 | 结对式代码质量评审(十二类腐化风险 + 0-100 健康分) |
10
+ | `yotta-workflow` | 元序 | `@yottameta/yotta-workflow` | 0.2.6 | 跨会话/跨项目通用工作流协议(状态就近存) |
11
+ | `yotta-memory` | 元忆 | `@yottameta/yotta-memory` | 0.8.4 | 有权限边界的文件式智能体记忆(FACT/PREF/BOUND/COMMIT) |
12
+ | `yotta-learn` | 元习 | `@yottameta/yotta-learn` | 0.1.4 | 学习沉淀 CLI:错误/纠正/洞见沉淀为 .learnings/ 条目 |
13
+ | `yotta-security-audit` | 元安 | `@yottameta/yotta-security-audit` | 0.1.7 | 安全扫描引擎:13 类检测器 + 系统安全基线 |
14
+ | `yotta-vetter` | 元审 | `@yottameta/yotta-vetter` | 0.1.5 | 安全审查协议:四阶段 review + SAFE TO INSTALL 判定 |
15
+ | `yotta-recon` | 元析 | `@yottameta/yotta-recon` | 0.1.5 | 跨智能体网络侦察:零依赖端口/服务/版本指纹探测 |
16
+ | `yotta-guardian` | 元盾 | `@yottameta/yotta-guardian` | 0.1.2 | 跨智能体危险调用拦截护栏:确定性规则 + 可插拔意图验证 |
17
+ | `yotta-humanize` | 元真 | `@yottameta/yotta-humanize` | 0.1.2 | 去 AI 味中文写作编辑:检测器引擎 |
18
+ | `yotta-logs` | 元史 | `@yottameta/yotta-logs` | 0.2.2 | 跨智能体历史会话 / 记忆日志检索 |
19
+ | `yotta-security-testing` | 元测 | `@yottameta/yotta-security-testing` | 0.1.0 | 有纪律的 AI 安全测试方法论 + Scope Guard 五道防线 |
20
+ | `yotta-agent-hardening` | 元安全 | `@yottameta/yotta-agent-hardening` | 0.1.0 | 防御向 AI 智能体自身安全加固(配置面静态扫描三域) |
21
+ | `yotta-skill-creator` | 元造 | `@yottameta/yotta-skill-creator` | 0.1.0 | 工坊「造」:端到端造技能脚手架 |
22
+ | `yotta-publish-guard` | 元守 | `@yottameta/yotta-publish-guard` | 0.1.1 | 工坊「守」:发布前守门(版本四件对齐 + 三通道查重) |
23
+ | `yotta-logwatch` | 元察 | `@yottameta/yotta-logwatch` | 0.2.7 | 安全日志分析检测引擎(攻击链识别/告警聚合) |
24
+ | `yotta-intel` | 元情 | `@yottameta/yotta-intel` | 0.1.1 | 威胁情报 IOC 提取与规范化引擎(STIX-lite) |
25
+ | `yotta-secret` | 元钥 | `@yottameta/yotta-secret` | 0.1.2 | 密钥 / 凭据泄露源头扫描引擎 |
26
+ | `yotta-chain` | 元链 | `@yottameta/yotta-chain` | 0.1.2 | 供应链依赖校验引擎 |
27
+ | `yotta-triage` | 元鉴 | `@yottameta/yotta-triage` | 0.1.1 | 恶意样本静态初筛引擎(哈希/熵/字符串/PE-ELF) |
28
+ | `yotta-prompt` | 元引 | `@yottameta/yotta-prompt` | 0.1.1 | 意图澄清 + 生态入口(常驻注入,map 串联元阁全家) |
29
+ | `yotta-verify` | 元信 | `@yottameta/yotta-verify` | 0.1.1 | 装前安全扫描器 + audited 徽章(prompt injection + 危险模式) |
30
+
31
+ ## 家族分布
32
+
33
+ - 安全与护栏(12):元安 / 元审 / 元析 / 元盾 / 元测 / 元安全 / 元察 / 元情 / 元钥 / 元链 / 元鉴 / 元信
34
+ - 质量与工程(4):元谨 / 元质 / 元造 / 元守
35
+ - 记忆与上下文(3):元忆 / 元史 / 元习
36
+ - 写作与表达(1):元真
37
+ - 工作流(1):元序
38
+ - 入口与引导(1):元引
39
+
40
+ 合计 22 个已发布技能;本安装器自身(yotta-skills / 元阁)归「分发与安装」家族。
@@ -0,0 +1,132 @@
1
+ # 元阁中文教程(新手全流程)
2
+
3
+ > 配套技能:元阁 yotta-skills(全家技能一键安装 CLI,依赖 Node.js 18+ / npm / 系统 tar)。
4
+ > 目标:把元阁已发布的 22 个 `yotta-*` 技能一次装进指定智能体或目录,并学会预览、更新、
5
+ > 锁版本与常见排查。
6
+
7
+ ## 1. 教程目标与前置
8
+
9
+ - 学会 `--list` / `install` / `update` / `--dry-run` / `--pin` / `--force` 的用法;
10
+ - 理解版本策略(range 与 --pin)与幂等行为;
11
+ - 掌握元信装前摘要的开关与配置;
12
+ - 前置:Node.js 18+、npm、系统 tar(Windows 10+ 自带);网络可访问 npm 注册表
13
+ (国内可配置镜像或代理)。
14
+
15
+ ## 2. 查看全家清单
16
+
17
+ ```bash
18
+ npx -y @yottameta/yotta-skills --list
19
+ ```
20
+
21
+ 输出 22 个技能:slug / 中文名 / 包名与版本范围 / 清单版本 / 一句话说明。
22
+ 确认某个技能在不在清单里,可加技能名过滤:
23
+
24
+ ```bash
25
+ npx -y @yottameta/yotta-skills --list yotta-memory
26
+ ```
27
+
28
+ ## 3. 安装全家到智能体
29
+
30
+ 推荐用 `--agent` 装到指定智能体默认用户级目录(如 Codex):
31
+
32
+ ```bash
33
+ npx -y @yottameta/yotta-skills install --agent codex
34
+ ```
35
+
36
+ 支持 17 个智能体键名:`claude` / `cursor` / `codex` / `gemini` / `goose` / `amp` /
37
+ `opencode` / `windsurf` / `workbuddy` / `kiro` / `trae` / `trae-cn` / `qwen` / `comate` /
38
+ `codebuddy` / `kimi` / `agents`。未收录的智能体用 `--dir` 指到它的技能目录。
39
+
40
+ ## 4. 安装到任意目录
41
+
42
+ ```bash
43
+ npx -y @yottameta/yotta-skills install --dir ~/my-skills
44
+ ```
45
+
46
+ 每个技能落在 `<dir>/<slug>`(如 `~/my-skills/yotta-memory/`)。
47
+ 只装个别技能:
48
+
49
+ ```bash
50
+ npx -y @yottameta/yotta-skills install yotta-memory yotta-verify --dir ~/my-skills
51
+ ```
52
+
53
+ ## 5. 更新已装技能
54
+
55
+ ```bash
56
+ npx -y @yottameta/yotta-skills update --agent codex
57
+ ```
58
+
59
+ - 缺失的技能 → 补装;版本不一致的技能 → 按当前版本策略重装;
60
+ - 已是最新的技能显示「已是最新」并跳过(幂等)。
61
+
62
+ ## 6. 安装前预览
63
+
64
+ ```bash
65
+ npx -y @yottameta/yotta-skills --dry-run
66
+ ```
67
+
68
+ dry-run 只打印将要执行的清单(含目标与版本策略),不联网、不写任何文件。
69
+
70
+ ## 7. 版本策略:range 与 --pin
71
+
72
+ - 默认 range:按同 major 最新 patch(如 `0.x`),维护性更新随最新;
73
+ - 想完全可复现 → 加 `--pin` 锁死清单精确版本:
74
+
75
+ ```bash
76
+ npx -y @yottameta/yotta-skills install --agent codex --pin
77
+ ```
78
+
79
+ ## 8. 强制重装与跳过元信摘要
80
+
81
+ ```bash
82
+ npx -y @yottameta/yotta-skills install --agent codex --force # 已是最新也重装
83
+ npx -y @yottameta/yotta-skills install --agent codex --skip-scan # 跳过装前摘要
84
+ ```
85
+
86
+ 元信(yotta-verify)已安装时默认会对每个待装技能输出装前摘要(verdict + 计数),仅提示
87
+ 不拦截;verdict 为 DO NOT INSTALL 时会提示人工复核。
88
+
89
+ ## 9. 验证安装结果
90
+
91
+ - 看安装汇总:成功 N / 跳过 N / 失败 N;
92
+ - 抽查技能目录:`ls ~/.codex/skills/yotta-memory/SKILL.md`;
93
+ - 复核版本:每个技能 SKILL.md 的 frontmatter `version` 应与 `--list` 一致(这也是幂等
94
+ 判断的依据)。
95
+
96
+ ## 10. 常见问题
97
+
98
+ - **npmmirror 全新包 404**:镜像同步有延迟。设置环境变量 `YOTTA_SKILLS_NPM_FLAGS` 为
99
+ `--registry=https://registry.npmjs.org/`(国内需代理)再执行,或等待镜像缓存后重试。
100
+ - **`--agent` 报未收录**:改用 `--dir` 指到该智能体的技能目录(`.agents/skills` 不是
101
+ 通用目录)。
102
+ - **某技能安装失败**:汇总报告给出失败原因;可单装该技能排查:
103
+ `install <slug> --dir <path>`。
104
+ - **目标未指定**:当前目录没有项目级技能目录时报错(退出码 4),加 `--agent` 或
105
+ `--dir`。
106
+ - **已有旧版本**:默认按 range 覆盖升级到最新 patch;`--pin` 则锁定清单版本。
107
+
108
+ ## 11. 盘点已装技能与 re-index(新装技能自动被发现)
109
+
110
+ ```bash
111
+ # 盘点本机已装技能(文本表格)
112
+ npx -y @yottameta/yotta-skills --inventory
113
+
114
+ # 重扫注册表(会话开工 / 新装技能后,增量合并变化)
115
+ npx -y @yottameta/yotta-skills --reindex
116
+ ```
117
+
118
+ - `install` / `update` 完成后会自动重扫注册表(`~/.yottaskills/registry.json`),新装 / 更新的
119
+ 技能随即出现在 `--inventory` / `--reindex` 里;`--no-reindex` 可关闭自动重扫。
120
+ - 建议每会话开工先跑一次 `--reindex`(快速增量,只合并变化),让后装的技能自动被看见。
121
+
122
+ ## 编排路由(--route)
123
+
124
+ 当你不知道「这个需求该用哪几个技能」,可以先把需求摘要交给元阁:
125
+
126
+ ```bash
127
+ npx -y @yottameta/yotta-skills --route "检查代码质量,别糊弄"
128
+ ```
129
+
130
+ 输出会告诉你命中哪个组合、按什么顺序调用、每个技能负责什么、哪些已装、哪些缺失,以及缺失技能的安装命令。元阁只给建议,不会自动安装;安装前请先做装前安全扫描,并由用户确认。
131
+ - `--json` 输出机器可读结果(含新增 / 更新 / 消失),适合脚本与钩子。
132
+ - 如果本机还装了非元阁家族技能,`--route` 会额外列出「其他已装技能候选」:只按 frontmatter description 与需求文本做本地机械匹配,标注来源、得分、命中词项与扫描状态(默认未扫描),不读取全文指令、不自动调用;使用/安装前请先做装前安全扫描。
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """yotta-skills-mcp.py — 元阁(yotta-skills)技能盘点 MCP server。
4
+
5
+ stdio MCP server(JSON-RPC 2.0,换行分隔),把元阁技能扫描核心暴露为 MCP 工具:
6
+ list_installed_skills 盘点本机已装技能(读本地注册表;未生成则先扫描一次)
7
+ describe_skill 查看单个技能详情(slug / 版本 / 功能 / 来源)
8
+ reindex 强制重新扫描并更新注册表
9
+ route_request 按需求摘要给出静态编排路由建议
10
+
11
+ 自包含原则:扫描由元阁自带核心(bin/yotta-skills.js --inventory / --reindex)完成,
12
+ 不依赖任何元技能;数据只写本机 ~/.yottaskills/registry.json,不出本机。
13
+
14
+ 运行:python scripts/yotta-skills-mcp.py
15
+ MCP 客户端配置:
16
+ {"mcpServers":{"yotta-skills":{"command":"python",
17
+ "args":["<绝对路径>/scripts/yotta-skills-mcp.py"]}}}
18
+ """
19
+
20
+ import json
21
+ import os
22
+ import shutil
23
+ import subprocess
24
+ import sys
25
+ from pathlib import Path
26
+
27
+ VERSION = "0.5.1"
28
+ TOOL_NAME = "yotta-skills"
29
+ CN_NAME = "元阁"
30
+ MCP_PROTOCOL = "2025-03-26"
31
+ SERVERS = {TOOL_NAME: {"name": TOOL_NAME, "cn": CN_NAME, "version": VERSION}}
32
+
33
+ _HERE = Path(__file__).resolve().parent
34
+ BIN_JS = (_HERE.parent / "bin" / "yotta-skills.js").resolve()
35
+ REGISTRY_FILE = Path(os.path.expanduser("~/.yottaskills/registry.json"))
36
+
37
+
38
+ def _tool_error(message, extra=None):
39
+ payload = {"error": message}
40
+ if extra:
41
+ payload.update(extra)
42
+ return {"content": [{"type": "text", "text": json.dumps(payload, ensure_ascii=False, indent=2)}],
43
+ "isError": True}
44
+
45
+
46
+ def _tool_spec(name, description, properties, required=None):
47
+ return {
48
+ "name": name,
49
+ "description": description,
50
+ "inputSchema": {
51
+ "type": "object",
52
+ "properties": properties,
53
+ **({"required": required} if required else {}),
54
+ },
55
+ }
56
+
57
+
58
+ def _run_cli(args):
59
+ """运行元阁 CLI(Node),返回 stdout 文本;失败抛 RuntimeError。"""
60
+ node = shutil.which("node")
61
+ if not node:
62
+ raise RuntimeError("未找到 node 可执行文件(元阁 CLI 依赖 Node.js 18+)")
63
+ proc = subprocess.run(
64
+ [node, str(BIN_JS)] + args,
65
+ capture_output=True, text=True, encoding="utf-8",
66
+ timeout=120,
67
+ )
68
+ if proc.returncode != 0:
69
+ raise RuntimeError("yotta-skills CLI 失败(exit %s):%s" % (proc.returncode, (proc.stderr or proc.stdout).strip()[:500]))
70
+ return proc.stdout
71
+
72
+
73
+ def _read_registry():
74
+ if not REGISTRY_FILE.is_file():
75
+ return None
76
+ try:
77
+ return json.loads(REGISTRY_FILE.read_text(encoding="utf-8"))
78
+ except Exception: # noqa: BLE001
79
+ return None
80
+
81
+
82
+ def _ensure_registry():
83
+ """注册表不存在时先扫描生成一次;返回注册表 dict。"""
84
+ reg = _read_registry()
85
+ if reg is not None:
86
+ return reg
87
+ _run_cli(["--inventory"])
88
+ reg = _read_registry()
89
+ if reg is None:
90
+ raise RuntimeError("技能注册表生成失败(~/.yottaskills/registry.json)")
91
+ return reg
92
+
93
+
94
+ def _skills_list(registry):
95
+ return sorted(
96
+ [s for s in registry.get("skills", {}).values() if s.get("status") != "gone"],
97
+ key=lambda s: s.get("slug", ""),
98
+ )
99
+
100
+
101
+ def _tool_list(arguments): # noqa: ARG001
102
+ registry = _ensure_registry()
103
+ skills = _skills_list(registry)
104
+ payload = {
105
+ "count": len(skills),
106
+ "registry": str(REGISTRY_FILE),
107
+ "skills": skills,
108
+ }
109
+ return {"content": [{"type": "text", "text": json.dumps(payload, ensure_ascii=False, indent=2)}],
110
+ "isError": False}
111
+
112
+
113
+ def _tool_describe(arguments):
114
+ slug = str(arguments.get("slug") or "").strip()
115
+ if not slug:
116
+ return _tool_error("describe_skill 需要 slug 参数")
117
+ registry = _ensure_registry()
118
+ skill = registry.get("skills", {}).get(slug)
119
+ if not skill or skill.get("status") == "gone":
120
+ return _tool_error("未找到技能: %s" % slug)
121
+ payload = {"skill": skill}
122
+ return {"content": [{"type": "text", "text": json.dumps(payload, ensure_ascii=False, indent=2)}],
123
+ "isError": False}
124
+
125
+
126
+ def _tool_reindex(arguments): # noqa: ARG001
127
+ stdout = _run_cli(["--reindex", "--json"])
128
+ try:
129
+ data = json.loads(stdout)
130
+ except json.JSONDecodeError as e:
131
+ return _tool_error("reindex 输出解析失败:%s" % e)
132
+ payload = {
133
+ "count": data.get("count", len(data.get("skills", []))),
134
+ "changes": data.get("changes"),
135
+ "errors": data.get("errors"),
136
+ "registry": str(REGISTRY_FILE),
137
+ }
138
+ return {"content": [{"type": "text", "text": json.dumps(payload, ensure_ascii=False, indent=2)}],
139
+ "isError": False}
140
+
141
+
142
+ def _tool_route(arguments):
143
+ request = str(arguments.get("request") or "").strip()
144
+ if not request:
145
+ return _tool_error("route_request 需要 request 参数")
146
+ stdout = _run_cli(["--route", request, "--json"])
147
+ try:
148
+ payload = json.loads(stdout)
149
+ except json.JSONDecodeError as e:
150
+ return _tool_error("route_request 输出解析失败:%s" % e)
151
+ return {"content": [{"type": "text", "text": json.dumps(payload, ensure_ascii=False, indent=2)}],
152
+ "isError": False}
153
+
154
+
155
+ TOOL_HANDLERS = {
156
+ "list_installed_skills": _tool_list,
157
+ "describe_skill": _tool_describe,
158
+ "reindex": _tool_reindex,
159
+ "route_request": _tool_route,
160
+ }
161
+
162
+
163
+ def mcp_tools():
164
+ return [
165
+ _tool_spec(
166
+ "list_installed_skills",
167
+ "盘点本机已装技能:返回技能列表(slug / 版本 / 功能一句话 / 来源)。"
168
+ "读本地注册表 ~/.yottaskills/registry.json;未生成则先扫描一次。"
169
+ "扫描由元阁自带核心完成,不依赖任何其他技能。数据不出本机。",
170
+ {},
171
+ [],
172
+ ),
173
+ _tool_spec(
174
+ "describe_skill",
175
+ "查看单个技能的详情(slug / 版本 / 功能 / 来源目录)。",
176
+ {"slug": {"type": "string", "description": "技能 slug(如 yotta-memory)"}},
177
+ ["slug"],
178
+ ),
179
+ _tool_spec(
180
+ "reindex",
181
+ "强制重新扫描所有技能目录并更新本地注册表,返回本次变化(新增 / 更新 / 消失);CLI 等价命令:yotta-skills --reindex。",
182
+ {},
183
+ [],
184
+ ),
185
+ _tool_spec(
186
+ "route_request",
187
+ "按需求摘要给出静态编排路由建议:候选组合、调用顺序、每个技能角色、置信度、依据、已装/缺失状态与安装命令。"
188
+ "并给出其他已装技能候选(仅按 frontmatter description 本地机械匹配、标注未扫描状态,不读取全文指令、不自动调用)。"
189
+ "只建议安装,不自动安装;数据不出本机。",
190
+ {"request": {"type": "string", "description": "用户需求摘要"}},
191
+ ["request"],
192
+ ),
193
+ ]
194
+
195
+
196
+ def handle_message(msg):
197
+ """处理一行 JSON-RPC 消息,返回响应 dict;通知返回 None。"""
198
+ if not isinstance(msg, dict) or msg.get("jsonrpc") != "2.0":
199
+ rid = msg.get("id") if isinstance(msg, dict) else None
200
+ return {"jsonrpc": "2.0", "id": rid, "error": {"code": -32600, "message": "invalid request"}}
201
+ method = msg.get("method")
202
+ rid = msg.get("id")
203
+ if rid is None: # JSON-RPC 通知(无 id)不响应
204
+ return None
205
+ if method is None:
206
+ return None
207
+ params = msg.get("params") or {}
208
+
209
+ if method == "initialize":
210
+ return {
211
+ "jsonrpc": "2.0", "id": rid,
212
+ "result": {
213
+ "protocolVersion": MCP_PROTOCOL,
214
+ "capabilities": {"tools": {}},
215
+ "serverInfo": {"name": TOOL_NAME, "version": VERSION},
216
+ },
217
+ }
218
+ if method == "ping":
219
+ return {"jsonrpc": "2.0", "id": rid, "result": {}}
220
+ if method == "tools/list":
221
+ return {"jsonrpc": "2.0", "id": rid, "result": {"tools": mcp_tools()}}
222
+ if method == "tools/call":
223
+ name = params.get("name")
224
+ arguments = params.get("arguments") or {}
225
+ handler = TOOL_HANDLERS.get(name)
226
+ if not handler:
227
+ return {
228
+ "jsonrpc": "2.0", "id": rid,
229
+ "result": {"content": [{"type": "text", "text": "未知工具: %s" % name}], "isError": True},
230
+ }
231
+ try:
232
+ return {"jsonrpc": "2.0", "id": rid, "result": handler(arguments)}
233
+ except Exception as e: # noqa: BLE001
234
+ return {
235
+ "jsonrpc": "2.0", "id": rid,
236
+ "result": {"content": [{"type": "text", "text": "工具执行异常:%s" % e}], "isError": True},
237
+ }
238
+ return {"jsonrpc": "2.0", "id": rid, "error": {"code": -32601, "message": "Method not found: " + str(method)}}
239
+
240
+
241
+ def main():
242
+ """stdio 主循环:读行 -> JSON-RPC -> 响应行。"""
243
+ try:
244
+ sys.stdin.reconfigure(encoding="utf-8")
245
+ sys.stdout.reconfigure(encoding="utf-8")
246
+ sys.stderr.reconfigure(encoding="utf-8")
247
+ except Exception: # noqa: BLE001
248
+ pass
249
+ for line in sys.stdin:
250
+ line = line.strip()
251
+ if not line:
252
+ continue
253
+ try:
254
+ msg = json.loads(line)
255
+ except json.JSONDecodeError:
256
+ sys.stdout.write(json.dumps(
257
+ {"jsonrpc": "2.0", "id": None, "error": {"code": -32700, "message": "parse error"}},
258
+ ensure_ascii=False) + "\n")
259
+ sys.stdout.flush()
260
+ continue
261
+ resp = handle_message(msg)
262
+ if resp is not None:
263
+ sys.stdout.write(json.dumps(resp, ensure_ascii=False) + "\n")
264
+ sys.stdout.flush()
265
+
266
+
267
+ if __name__ == "__main__":
268
+ main()