@yottameta/yotta-skills 0.4.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
+ ## v0.5.1 (2026-09-06)
2
+
3
+ skills.json 三处滞后同步修复(yotta-skills 0.5.0→0.5.1):元真 0.1.2→0.1.3 / 元忆 0.8.5→0.10.1 / 元守 0.1.1→0.2.1 + updated 改期 2026-09-06 + yotta-skills 四件对齐 0.5.1 + 技能分发清单副本 + 插件同步。
1
4
  # 更新日志
2
5
 
6
+ ## v0.5.0 (2026-08-31)
7
+
8
+ 方案 A(其他已装技能候选编排):路由输出从「只编排元阁组合」扩展为「组合 + 并列候选提示」。
9
+
10
+ - 新增 `--route` / `route_request` 输出「其他已装技能候选」:注册表中非元阁家族的已装技能,按 frontmatter `description` 与需求文本做本地机械匹配(英文词项 + 中文二字组交集),Top N(默认 3)并列展示,标注来源、得分、命中词项与扫描状态。
11
+ - 安全边界:只读 frontmatter `description` 做机械匹配,不读取全文指令、不做语义推理、不自动调用;候选默认标注「未扫描」,使用/安装前需先做装前安全扫描;数据不出本机。
12
+ - 确定性:同输入同输出,无状态、无个人数据;候选不参与组合融合排序,7 个静态组合输出保持不变。
13
+ - CLI 文本输出追加「其他已装技能候选」段;`--json` 追加 `other_skill_candidates` / `other_skills_note` 字段;MCP `route_request` 同步。
14
+ - 测试:路由核心新增候选匹配 / 元技能排除 / Top N 与排序 / 确定性 / 空结果;CLI JSON 与文本输出用例。
15
+ - 版本升至 0.5.0。
16
+
3
17
  ## v0.4.0 (2026-08-31)
4
18
 
5
19
  阶段 C(O1 静态编排 playbook + 路由指引):从「知道装了什么」升级为「给出该用哪几个、什么顺序」。
package/README.md CHANGED
@@ -79,7 +79,7 @@ Requirements: Node.js 18+, npm, and system <code>tar</code> (built into Windows
79
79
  | `update [--agent <name> \| --dir <path>]` | Incremental update: add missing, upgrade version-skewed |
80
80
  | `--inventory` | Inventory installed skills: scan skill directories and update the local registry (self-contained); `--json` for JSON, `--project` adds project-level dirs |
81
81
  | `--reindex` | Re-index the registry: re-scan skill directories and merge changes incrementally (session start / after installing skills; `--rescan` is a synonym); `--json` for JSON |
82
- | `--route <task-summary>` | Static orchestration routing: return a combination, call order, per-skill roles, confidence, evidence, installed/missing status, and an install suggestion; `--json` for JSON, `--project` adds project-level dirs |
82
+ | `--route <task-summary>` | Static orchestration routing: return a combination, call order, per-skill roles, confidence, evidence, installed/missing status, and an install suggestion; also lists other installed (non-YottaMeta) skills as candidates matched mechanically against their frontmatter description, tagged "not scanned", read-only and never auto-invoked; `--json` for JSON, `--project` adds project-level dirs |
83
83
  | `--no-reindex` | Do not re-index the registry automatically after `install` / `update` |
84
84
  | `--dry-run` | Preview the install / update list; no network, no changes |
85
85
  | `--pin` | Lock the exact manifest versions (default: range, latest patch of the same major) |
package/README.zh-CN.md CHANGED
@@ -29,7 +29,7 @@
29
29
  元阁也是全家的**编排策划层**:接到需求先查「编排策划」组合表——该组合哪几个技能、按什么顺序、各自强在哪——再按需安装恰好那几个。决策表随包提供(<code>references/orchestration.md</code>),<code>SKILL.md</code> 中有摘要。
30
30
 
31
31
  - **看清单**--全家技能一览:slug / 中文名 / 包名 / 版本 / 一句话说明。
32
- - **编排路由**--`--route` 按需求摘要输出候选组合、调用顺序、技能角色、置信度、依据、已装/缺失状态与安装命令;只建议安装,不自动安装。
32
+ - **编排路由**--`--route` 按需求摘要输出候选组合、调用顺序、技能角色、置信度、依据、已装/缺失状态与安装命令;非元阁家族已装技能按 frontmatter description 机械匹配作并列候选(标注来源与未扫描状态,只读不自动调用);只建议安装,不自动安装。
33
33
  - **安装**——装全家(或指定技能)到智能体默认用户级目录或任意目录。
34
34
  - **更新**——增量更新:补齐缺失技能、升级版本不一致的技能。
35
35
  - **幂等**——已在清单版本的技能跳过;重复运行安全。
package/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: yotta-skills
3
- version: 0.4.0
4
- description: 元阁 -- 元阁全家技能的总编排策划 + 编排路由 + 一键安装器 + 技能盘点。路由层:--route / route_request 按需求摘要给出候选组合、调用顺序、角色、置信度、依据、已装/缺失状态与安装命令,只建议不自动安装;策划层:按场景给出「该组合哪几个元技能、组合强在哪、怎么自动装+自动用」;安装层:一条命令把 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.5.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 污染全局、不自动安装缺失技能;装前摘要仅供参考,安装决策由用户确认。
5
5
  license: MIT
6
6
  metadata:
7
7
  zh_name: 元阁
@@ -29,7 +29,7 @@ metadata:
29
29
 
30
30
  **元阁全家的总编排策划 + 编排路由 + 一键安装 + 技能盘点**,一句话四层:
31
31
 
32
- - **路由层(该用哪几个)**:`--route "<需求摘要>"` / MCP `route_request` 查本地注册表与静态编排 playbook,输出候选组合、调用顺序、每个技能角色、置信度、依据、已装/缺失状态与安装命令;只建议安装,不自动安装。
32
+ - **路由层(该用哪几个)**:`--route "<需求摘要>"` / MCP `route_request` 查本地注册表与静态编排 playbook,输出候选组合、调用顺序、每个技能角色、置信度、依据、已装/缺失状态与安装命令;非元阁家族已装技能按 frontmatter description 机械匹配作并列候选(标注来源与未扫描状态,只读不自动调用);只建议安装,不自动安装。
33
33
  - **策划层(怎么用)**:接到需求,先按「编排策划」定位命中哪个组合——哪些元技能搭配起来最强、适合什么场景、AI 该怎么自动装并自动用起来。
34
34
  - **安装层(怎么装)**:一条 `npx -y @yottameta/yotta-skills` 把组合/全家装进指定智能体或目录——`--list` 看清单、`install` 装、`update` 增量更新、`--dry-run` 预览、`--pin` 锁版本。
35
35
  - **盘点层(已装了什么)**:`--inventory` / `--reindex` 扫描本机各智能体技能目录,生成/更新本地注册表;装技能后自动 re-index,新装技能自动被发现——自包含扫描,不依赖任何元技能。
@@ -529,11 +529,12 @@ function runReindex(opts) {
529
529
  out('注册表: ' + scan.registryPath());
530
530
  }
531
531
 
532
- /** --route:静态编排路由,输出组合、顺序、角色与缺失技能建议。 */
532
+ /** --route:静态编排路由,输出组合、顺序、角色、缺失技能建议与其他已装技能候选。 */
533
533
  function runRoute(opts) {
534
- const { routeRequest } = require('../lib/route');
534
+ const { routeRequest, defaultYottaSlugs } = require('../lib/route');
535
535
  const { registry } = reindexRegistry(opts);
536
- const result = routeRequest(opts.route, { registry });
536
+ const yottaSlugs = new Set([...defaultYottaSlugs(), ...MANIFEST.map((s) => s.slug)]);
537
+ const result = routeRequest(opts.route, { registry, yottaSlugs });
537
538
  if (opts.json) {
538
539
  out(JSON.stringify(result, null, 2));
539
540
  return;
@@ -552,6 +553,16 @@ function runRoute(opts) {
552
553
  out('安装命令: ' + result.install_command);
553
554
  out('安全提示: 安装前请先执行装前安全扫描;本命令不会自动安装。');
554
555
  }
556
+ if (result.other_skill_candidates.length) {
557
+ out('');
558
+ out('其他已装技能候选(非元阁家族,仅本地机械匹配 frontmatter description):');
559
+ for (const c of result.other_skill_candidates) {
560
+ out(' - ' + c.slug + ' v' + c.version + ' [' + (c.sources || []).join(',') + ']');
561
+ out(' 匹配: ' + c.matched_terms.join('、') + '(得分 ' + c.score + ')· 扫描状态: ' + (c.scan_status === 'not_scanned' ? '未扫描' : c.scan_status));
562
+ out(' ' + (c.description || ''));
563
+ }
564
+ out('安全提示: 其他已装技能只读 frontmatter description 做机械匹配,不读取全文指令、不自动调用;使用/安装前请先执行装前安全扫描,决定权在用户。');
565
+ }
555
566
  out('');
556
567
  out('应用模式: 显式调用(可经用户确认后切换为按场景自动调用)');
557
568
  out('说明: ' + result.disclaimer);
package/lib/route.js CHANGED
@@ -81,6 +81,63 @@ const PLAYBOOKS = [
81
81
  },
82
82
  ];
83
83
 
84
+ const OTHER_SKILLS_NOTE = '其他已装技能仅作并列候选提示:机械匹配 frontmatter description,未做语义推理、未读取全文指令、未自动调用;数据不出本机。';
85
+ const OTHER_SKILL_NOTE = '非元阁家族技能:仅按 frontmatter description 本地机械匹配;不读取全文指令、不自动调用;使用/安装前请先做装前安全扫描。';
86
+ const EN_STOPWORDS = new Set([
87
+ 'a', 'an', 'the', 'and', 'or', 'of', 'to', 'in', 'on', 'for', 'with', 'from',
88
+ 'this', 'that', 'is', 'are', 'was', 'were', 'be', 'been', 'your', 'you', 'our',
89
+ 'we', 'it', 'at', 'by', 'as', 'not', 'no', 'so', 'do', 'does',
90
+ ]);
91
+
92
+ /** 元阁家族 slug 集合:playbook 引用 + 已知不入 playbook 的元技能(如 yotta-chart)。 */
93
+ function defaultYottaSlugs() {
94
+ const set = new Set(['yotta-chart']);
95
+ for (const playbook of PLAYBOOKS) {
96
+ for (const skill of playbook.skills) set.add(skill.slug);
97
+ }
98
+ return Array.from(set);
99
+ }
100
+
101
+ /** 英文词项:≥3 字母的单词,过滤停用词(保留出现顺序、去重)。 */
102
+ function enTokens(text) {
103
+ const tokens = [];
104
+ const seen = new Set();
105
+ for (const m of String(text || '').toLowerCase().match(/[a-z][a-z0-9]{2,}/g) || []) {
106
+ if (EN_STOPWORDS.has(m) || seen.has(m)) continue;
107
+ seen.add(m);
108
+ tokens.push(m);
109
+ }
110
+ return tokens;
111
+ }
112
+
113
+ /** 中文词项:CJK 连续片段内相邻两字 bigram(零依赖确定性分词)。 */
114
+ function cjkBigrams(text) {
115
+ const bigrams = [];
116
+ const seen = new Set();
117
+ for (const m of String(text || '').match(/[\u4e00-\u9fff]+/g) || []) {
118
+ for (let i = 0; i < m.length - 1; i++) {
119
+ const g = m.slice(i, i + 2);
120
+ if (seen.has(g)) continue;
121
+ seen.add(g);
122
+ bigrams.push(g);
123
+ }
124
+ }
125
+ return bigrams;
126
+ }
127
+
128
+ /** 需求与候选文本的词项匹配:英文 token + 中文 bigram 交集,按需求侧出现顺序输出。 */
129
+ function scoreOtherSkill(request, record) {
130
+ const candidateText = [record.description, record.slug].filter(Boolean).join(' ');
131
+ const reqTokens = enTokens(request);
132
+ const reqBigrams = cjkBigrams(request);
133
+ const candTokens = new Set(enTokens(candidateText));
134
+ const candBigrams = new Set(cjkBigrams(candidateText));
135
+ const matched = [];
136
+ for (const item of reqTokens) if (candTokens.has(item)) matched.push(item);
137
+ for (const item of reqBigrams) if (candBigrams.has(item)) matched.push(item);
138
+ return { score: matched.length, matched_terms: matched };
139
+ }
140
+
84
141
  function normalizeText(text) {
85
142
  return String(text || '').toLowerCase().replace(/\s+/g, '');
86
143
  }
@@ -101,6 +158,8 @@ function scorePlaybook(request, playbook) {
101
158
  function routeRequest(request, options) {
102
159
  const registry = (options && options.registry) || { skills: {} };
103
160
  const installed = registry.skills || {};
161
+ const yottaSlugs = new Set((options && options.yottaSlugs) || defaultYottaSlugs());
162
+ const otherSkillsTopN = (options && options.otherSkillsTopN) || 3;
104
163
  const ranked = PLAYBOOKS
105
164
  .map((playbook) => ({ playbook, ...scorePlaybook(request, playbook) }))
106
165
  .sort((a, b) => b.score - a.score || a.playbook.id.localeCompare(b.playbook.id));
@@ -135,6 +194,23 @@ function routeRequest(request, options) {
135
194
  + ' --dir <skills-dir>'
136
195
  : null;
137
196
 
197
+ const otherCandidates = Object.values(installed)
198
+ .filter((record) => record && record.status !== 'gone' && !yottaSlugs.has(record.slug))
199
+ .map((record) => ({ record, ...scoreOtherSkill(request, record) }))
200
+ .filter((item) => item.score > 0)
201
+ .sort((a, b) => b.score - a.score || a.record.slug.localeCompare(b.record.slug))
202
+ .slice(0, otherSkillsTopN)
203
+ .map(({ record, score, matched_terms }) => ({
204
+ slug: record.slug,
205
+ version: record.version || '',
206
+ sources: record.sources || [],
207
+ description: record.description || '',
208
+ score,
209
+ matched_terms,
210
+ scan_status: 'not_scanned',
211
+ note: OTHER_SKILL_NOTE,
212
+ }));
213
+
138
214
  return {
139
215
  request,
140
216
  playbook: {
@@ -154,7 +230,9 @@ function routeRequest(request, options) {
154
230
  note: '默认用户显式调用;切换为按场景自动调用需要用户确认。',
155
231
  },
156
232
  disclaimer: '路由建议不保证完全正确;关键动作应由用户确认,数据不出本机。',
233
+ other_skill_candidates: otherCandidates,
234
+ other_skills_note: OTHER_SKILLS_NOTE,
157
235
  };
158
236
  }
159
237
 
160
- module.exports = { PLAYBOOKS, routeRequest };
238
+ module.exports = { PLAYBOOKS, defaultYottaSlugs, routeRequest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yottameta/yotta-skills",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
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": [
@@ -14,11 +14,11 @@
14
14
  npx -y @yottameta/yotta-skills --route "帮我润色输出,要规范可复制,别有 AI 味"
15
15
  ```
16
16
 
17
- - **输出**:候选组合、调用顺序、每个技能的角色、置信度、命中依据、已装/缺失状态、安装命令与应用模式提醒。
17
+ - **输出**:候选组合、调用顺序、每个技能的角色、置信度、命中依据、已装/缺失状态、安装命令与应用模式提醒;如本机装了非元阁家族技能,还会给出其他已装技能候选(仅按 frontmatter description 机械匹配,标注来源与未扫描状态)。
18
18
  - **缺失技能**:只给安装命令,不自动安装;安装前先做装前安全扫描,决定权在用户。
19
19
  - **应用模式**:默认用户显式调用;切换为「按场景自动调用」需要用户确认。
20
20
  - **无明确匹配**:低置信度回退到「入口 + 安装」组合,先澄清需求再继续。
21
- - **边界**:路由是建议,不保证完全正确;关键动作由用户确认,数据不出本机。
21
+ - **边界**:路由是建议,不保证完全正确;关键动作由用户确认,数据不出本机。其他已装技能候选只读 frontmatter description、不读取全文指令、不自动调用;使用/安装前先做装前安全扫描。
22
22
 
23
23
  ---
24
24
 
@@ -129,3 +129,4 @@ npx -y @yottameta/yotta-skills --route "检查代码质量,别糊弄"
129
129
 
130
130
  输出会告诉你命中哪个组合、按什么顺序调用、每个技能负责什么、哪些已装、哪些缺失,以及缺失技能的安装命令。元阁只给建议,不会自动安装;安装前请先做装前安全扫描,并由用户确认。
131
131
  - `--json` 输出机器可读结果(含新增 / 更新 / 消失),适合脚本与钩子。
132
+ - 如果本机还装了非元阁家族技能,`--route` 会额外列出「其他已装技能候选」:只按 frontmatter description 与需求文本做本地机械匹配,标注来源、得分、命中词项与扫描状态(默认未扫描),不读取全文指令、不自动调用;使用/安装前请先做装前安全扫描。
@@ -24,7 +24,7 @@ import subprocess
24
24
  import sys
25
25
  from pathlib import Path
26
26
 
27
- VERSION = "0.4.0"
27
+ VERSION = "0.5.1"
28
28
  TOOL_NAME = "yotta-skills"
29
29
  CN_NAME = "元阁"
30
30
  MCP_PROTOCOL = "2025-03-26"
@@ -185,6 +185,7 @@ def mcp_tools():
185
185
  _tool_spec(
186
186
  "route_request",
187
187
  "按需求摘要给出静态编排路由建议:候选组合、调用顺序、每个技能角色、置信度、依据、已装/缺失状态与安装命令。"
188
+ "并给出其他已装技能候选(仅按 frontmatter description 本地机械匹配、标注未扫描状态,不读取全文指令、不自动调用)。"
188
189
  "只建议安装,不自动安装;数据不出本机。",
189
190
  {"request": {"type": "string", "description": "用户需求摘要"}},
190
191
  ["request"],
package/skills.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifestVersion": 1,
3
- "updated": "2026-08-30",
3
+ "updated": "2026-09-06",
4
4
  "note": "清单同步要求:每次技能发布新版本后,按 YottaSkills 技能登记表更新本文件(登记表为内部台账,不随包分发)。",
5
5
  "skills": [
6
6
  {
@@ -28,7 +28,7 @@
28
28
  "slug": "yotta-memory",
29
29
  "name": "元忆",
30
30
  "pkg": "@yottameta/yotta-memory",
31
- "version": "0.8.5",
31
+ "version": "0.10.1",
32
32
  "desc": "有权限边界的文件式智能体记忆(FACT/PREF/BOUND/COMMIT)"
33
33
  },
34
34
  {
@@ -70,7 +70,7 @@
70
70
  "slug": "yotta-humanize",
71
71
  "name": "元真",
72
72
  "pkg": "@yottameta/yotta-humanize",
73
- "version": "0.1.2",
73
+ "version": "0.1.3",
74
74
  "desc": "去 AI 味中文写作编辑:检测器引擎"
75
75
  },
76
76
  {
@@ -105,7 +105,7 @@
105
105
  "slug": "yotta-publish-guard",
106
106
  "name": "元守",
107
107
  "pkg": "@yottameta/yotta-publish-guard",
108
- "version": "0.1.1",
108
+ "version": "0.2.1",
109
109
  "desc": "工坊「守」:发布前守门(版本四件对齐 + 三通道查重)"
110
110
  },
111
111
  {