reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
// lib/capability-index.mjs — 能力层闭环:索引生成与完整性检查
//
// 能力层设计(re-analyze/references/capabilities.md):技能声明 capabilities → 路由按能力匹配。
// 本模块是「声明」与「消费」之间的那一环,产出能力 → 技能索引(路由/检索的查询表),
// 并提供两条完整性检查,防止能力层停留在"只写不读"的状态:
// 1) 注册表标签悬空——注册表里有、没有任何技能声明
// 2) 索引过期——声明变更后未重新生成(`node bin/capindex.mjs`)
import { readdirSync, readFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { parseFrontmatterDocument } from './frontmatter.mjs';
export const INDEX_REL = 're-analyze/references/capability-index.md';
const REGISTRY_REL = 're-analyze/references/capabilities.md';
const SKILL_PREFIX = 're-';
// 机器生成文件头——含生成命令与用途,避免被当作手写文档维护
const HEADER = `# 能力索引(机器生成,勿手改)
> 生成:\`node bin/capindex.mjs\`|校验:\`npm test\`(过期即失败)
> 用途:路由与检索按能力反查技能——能力层的查询表(声明侧见 capabilities.md)
`;
// 注册表标签 → 一行说明
export function collectRegistryTags(root) {
const p = join(root, REGISTRY_REL);
if (!existsSync(p)) return new Map();
const map = new Map();
for (const line of readFileSync(p, 'utf8').split('\n')) {
const m = line.match(/^\-\s+`([a-z0-9-]+)`\s+—\s+(.*)$/);
if (m) map.set(m[1], m[2].trim());
}
return map;
}
// 各技能声明的能力:tag → [技能名](非法写法在此跳过,由 validate 逐技能报错)
export function collectDeclaredCapabilities(root) {
const byTag = new Map();
for (const dir of readdirSync(root, { withFileTypes: true })) {
if (!dir.isDirectory() || !dir.name.startsWith(SKILL_PREFIX)) continue;
const p = join(root, dir.name, 'SKILL.md');
if (!existsSync(p)) continue;
let value;
try {
value = parseFrontmatterDocument(readFileSync(p, 'utf8')).fm.capabilities;
} catch {
continue;
}
if (value === undefined) continue;
const m = String(value).match(/^\[\s*([a-z0-9-]+(?:\s*,\s*[a-z0-9-]+)*)\s*\]$/);
if (!m) continue;
for (const tag of m[1].split(',').map(s => s.trim())) {
byTag.set(tag, [...(byTag.get(tag) ?? []), dir.name]);
}
}
return byTag;
}
// 渲染索引全文(生成与校验共用同一函数,保证比较的是同一事实)
export function renderCapabilityIndex(root) {
const declared = collectDeclaredCapabilities(root);
const registry = collectRegistryTags(root);
const tags = [...declared.keys()].sort();
const missing = [...registry.keys()].filter(t => !declared.has(t)).sort();
// 覆盖率看板:标签覆盖(注册表自洽)与技能覆盖(渐进标注进度)分开计
const declaredSkills = new Set([...declared.values()].flat());
const totalSkills = readdirSync(root, { withFileTypes: true })
.filter(d => d.isDirectory() && d.name.startsWith(SKILL_PREFIX) && existsSync(join(root, d.name, 'SKILL.md'))).length;
const out = [HEADER];
out.push(`## 已声明能力(标签 ${tags.length}/${registry.size}|技能 ${declaredSkills.size}/${totalSkills})\n`);
out.push('| 能力 | 说明 | 提供技能 |');
out.push('|---|---|---|');
for (const t of tags) {
out.push(`| \`${t}\` | ${registry.get(t) ?? '(不在注册表)'} | ${[...declared.get(t)].sort().join(', ')} |`);
}
out.push(`\n## 尚未被声明(${missing.length})\n`);
out.push(missing.length
? missing.map(t => `- ${t} — ${registry.get(t)}`).join('\n')
: '(无——注册表标签全部有技能声明)');
out.push('');
return out.join('\n');
}
// 索引缺失或与当前声明不一致 → 报错(提示重新生成)
export function checkCapabilityIndex(root) {
const p = join(root, INDEX_REL);
if (!existsSync(p)) return [`capability index missing: ${INDEX_REL}(运行 node bin/capindex.mjs)`];
if (readFileSync(p, 'utf8') !== renderCapabilityIndex(root)) {
return [`capability index out of date: ${INDEX_REL}(运行 node bin/capindex.mjs)`];
}
return [];
}