61 lines
2.5 KiB
JavaScript
61 lines
2.5 KiB
JavaScript
// lib/probe-tools.mjs — probe.sh 的工具清单:由登记表生成(单一事实源)
|
||
//
|
||
// 背景:probe.sh 曾硬编码 19 个工具,而登记表已有 140 项——环境里装了什么
|
||
// 是 agent 判断"优先用什么"的依据,硬编码清单会随登记表增长而失同步。
|
||
// 做法与能力索引同构:登记表是源,probe.sh 里的清单是生成物,`--check` 校验新鲜度。
|
||
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
||
import { join } from 'node:path';
|
||
|
||
export const REGISTER_REL = 'docs/audit/tool-register.json';
|
||
export const PROBE_REL = '.claude/skills/re-analyze/references/probe.sh';
|
||
export const BEGIN = '# >>> GENERATED-TOOLS';
|
||
export const END = '# <<< GENERATED-TOOLS';
|
||
|
||
/** 从登记表取要探测的工具名(忽略名单之外的 cli 项,按名排序) */
|
||
export function probeToolNames(repoRoot) {
|
||
const reg = JSON.parse(readFileSync(join(repoRoot, REGISTER_REL), 'utf8'));
|
||
const ignore = new Set(reg.ignore ?? []);
|
||
return reg.tools
|
||
.map((t) => t.name)
|
||
.filter((n) => !ignore.has(n))
|
||
.sort((a, b) => a.localeCompare(b));
|
||
}
|
||
|
||
/** 生成标记块(含换行) */
|
||
export function renderBlock(names) {
|
||
return [
|
||
`${BEGIN}(源:${REGISTER_REL};改清单请改登记表后跑 node bin/probelist.mjs)`,
|
||
'# shellcheck disable=SC2034',
|
||
`PROBE_TOOLS="${names.join(' ')}"`,
|
||
END,
|
||
].join('\n');
|
||
}
|
||
|
||
/** 替换 probe.sh 里的标记块;返回是否发生变化 */
|
||
export function writeProbeBlock(repoRoot) {
|
||
const p = join(repoRoot, PROBE_REL);
|
||
const text = readFileSync(p, 'utf8');
|
||
const block = renderBlock(probeToolNames(repoRoot));
|
||
const re = new RegExp(`^${BEGIN}[\\s\\S]*?^${END}$`, 'm');
|
||
if (!re.test(text)) throw new Error(`${PROBE_REL} 里找不到 GENERATED-TOOLS 标记块`);
|
||
const next = text.replace(re, block);
|
||
if (next === text) return false;
|
||
writeFileSync(p, next);
|
||
return true;
|
||
}
|
||
|
||
/** 校验 probe.sh 的清单是否与登记表一致 */
|
||
export function checkProbeBlock(repoRoot) {
|
||
const p = join(repoRoot, PROBE_REL);
|
||
if (!existsSync(p)) return [`找不到 ${PROBE_REL}`];
|
||
const text = readFileSync(p, 'utf8');
|
||
const re = new RegExp(`^${BEGIN}[\\s\\S]*?^${END}$`, 'm');
|
||
const m = re.exec(text);
|
||
if (!m) return [`${PROBE_REL} 里找不到 GENERATED-TOOLS 标记块`];
|
||
const expected = renderBlock(probeToolNames(repoRoot));
|
||
if (m[0] !== expected) {
|
||
return [`${PROBE_REL} 的工具清单与登记表不一致——跑 node bin/probelist.mjs 重新生成`];
|
||
}
|
||
return [];
|
||
}
|