bookworm-smart-assistant/scripts/patches/patch-task2-agents-index.js

121 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* Task2 补丁 — 2026-04-20 路由精准度审查
*
* 问题: skills-index-lite.json 只有 skills(87条),无 agents 条目。
* R81/R82 的 boost 因 self-auditor/self-healer 不在结果集中而无效。
* generate-skill-index.js 只写 skills-index.json不写 lite 版本。
*
* 修复方案:
* 1. 修改 generate-skill-index.js — 在 main() 末尾追加:
* a) 扫描 agents/*.md 注入 skills 数组 (type:"agent" 字段)
* b) 写出 skills-index-lite.json (与 skills-index.json 结构相同但含 agents)
* 2. 立即运行生成器刷新 skills-index-lite.json
*
* 幂等: sentinel = 'AGENTS_DIR_SCAN_PATCH_2026_04_20'
*/
'use strict';
const fs = require('fs');
const path = require('path');
const SCRIPTS_DIR = path.join(__dirname, '..');
const TARGET = path.join(SCRIPTS_DIR, 'generate-skill-index.js');
const SENTINEL = 'AGENTS_DIR_SCAN_PATCH_2026_04_20';
function main() {
if (!fs.existsSync(TARGET)) {
console.error('[patch-task2] 目标文件不存在:', TARGET);
process.exit(1);
}
const before = fs.readFileSync(TARGET, 'utf8');
// 幂等检查
if (before.includes(SENTINEL)) {
console.log('[patch-task2] 已打过补丁 (发现 sentinel),跳过');
process.exit(0);
}
// ==== 注入1: 在 OUTPUT_FILE 定义后添加 AGENTS_DIR 和 OUTPUT_LITE 常量 ====
const constAnchor = "const OUTPUT_FILE = path.join(CLAUDE_ROOT, 'skills-index.json');";
if (!before.includes(constAnchor)) {
console.error('[patch-task2] 找不到 OUTPUT_FILE 常量锚点generate-skill-index.js 结构已变更');
process.exit(2);
}
const constInjection =
"const OUTPUT_FILE = path.join(CLAUDE_ROOT, 'skills-index.json');\n" +
"// " + SENTINEL + "\n" +
"const AGENTS_DIR = path.join(CLAUDE_ROOT, 'agents');\n" +
"const OUTPUT_LITE = path.join(CLAUDE_ROOT, 'skills-index-lite.json');";
let after = before.replace(constAnchor, constInjection);
// ==== 注入2: 在 writeFileSync(OUTPUT_FILE...) 之后追加 agents 扫描 + lite 输出 ====
const writeAnchor = " fs.writeFileSync(OUTPUT_FILE, JSON.stringify(index, null, 2) + '\\n');";
if (!after.includes(writeAnchor)) {
console.error('[patch-task2] 找不到 writeFileSync 输出锚点');
process.exit(3);
}
const liteInjection =
" fs.writeFileSync(OUTPUT_FILE, JSON.stringify(index, null, 2) + '\\n');\n" +
"\n" +
" // === " + SENTINEL + " ===\n" +
" // 扫描 agents/*.md将 agent 条目注入 skills 数组type:'agent'),同时写出 skills-index-lite.json\n" +
" try {\n" +
" if (fs.existsSync(AGENTS_DIR)) {\n" +
" const agentFiles = fs.readdirSync(AGENTS_DIR).filter(f => f.endsWith('.md')).sort();\n" +
" let agentCount = 0;\n" +
" for (const file of agentFiles) {\n" +
" const agentPath = path.join(AGENTS_DIR, file);\n" +
" const content = fs.readFileSync(agentPath, 'utf8');\n" +
" const fm = parseFrontmatter(content);\n" +
" if (!fm.name) continue;\n" +
" const keywords = extractKeywords(content);\n" +
" const entry = {\n" +
" name: fm.name,\n" +
" description: (fm.description || '').slice(0, 200),\n" +
" maturity: 'agent',\n" +
" type: 'agent',\n" +
" isComposable: false,\n" +
" allowedTools: (fm['allowed-tools'] || '').split(',').map(s => s.trim()).filter(Boolean),\n" +
" keywords,\n" +
" };\n" +
" index.skills.push(entry);\n" +
" agentCount++;\n" +
" }\n" +
" console.log(' [agents] ' + agentCount + ' agent(s) injected into index');\n" +
" }\n" +
" } catch (e) {\n" +
" console.warn(' [agents] 扫描失败 (非致命):', e.message);\n" +
" }\n" +
"\n" +
" // 写出 skills-index-lite.json (路由引擎实际使用的是 lite 版本)\n" +
" fs.writeFileSync(OUTPUT_LITE, JSON.stringify(index, null, 2) + '\\n');\n" +
" console.log(' [lite] skills-index-lite.json 已同步 (' + index.skills.length + ' entries total)');";
after = after.replace(writeAnchor, liteInjection);
// ==== 原子写入 (.bak 备份 + tmp 文件) ====
const bakFile = TARGET + '.bak.task2.' + Date.now();
fs.copyFileSync(TARGET, bakFile);
console.log('[patch-task2] 备份已写入:', bakFile);
const tmpFile = TARGET + '.tmp';
fs.writeFileSync(tmpFile, after, 'utf8');
fs.renameSync(tmpFile, TARGET);
console.log('[patch-task2] 补丁已应用到:', TARGET);
// 验证 sentinel 存在
const verify = fs.readFileSync(TARGET, 'utf8');
if (!verify.includes(SENTINEL)) {
console.error('[patch-task2] 验证失败: sentinel 未找到!');
process.exit(4);
}
console.log('[patch-task2] PASS — sentinel 验证通过');
}
main();