Files
writing-agent/tools/st-request-diff/read-preset-scripts.mjs
T
chenmoranzhi 1a5ef3b2bc 抓包对比工具补一批一次性脚本:拆预设、对请求、跑 A/B 与拒答抽样。
这些脚本都是我对着酒馆真实请求手工核对用的,留在仓库里方便下次重跑;跑出来的本地数据目录含接口 key,已经写进忽略规则。
2026-10-26 01:09:56 +08:00

68 lines
3.5 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.
// 把预设里所有「像脚本」的东西挖出来:完整路径、长度、以及它碰了哪些酒馆 API。
// 用法: node read-preset-scripts.mjs <preset.json> [输出目录]
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
const presetFile = process.argv[2];
const outDir = process.argv[3] || path.join(path.dirname(presetFile), "script-dump");
const preset = JSON.parse(readFileSync(presetFile, "utf8"));
mkdirSync(outDir, { recursive: true });
const APIS = [
"TavernHelper", "tavernHelper", "SillyTavern", "getContext", "eventOn", "eventOnce", "eventEmit",
"registerFunctionTool", "unregisterFunctionTool", "getPrompts", "setPrompts", "replacePrompts",
"injectPrompt", "uninjectPrompt", "getVariables", "setVariables", "getChatMessages", "setChatMessages",
"createChatMessages", "deleteChatMessages", "substituteParams", "formatAsTavernRegexedString",
"getLorebookEntries", "getCharLorebooks", "getCharacter", "getCurrentCharacterId", "triggerSlash",
"getLastMessageId", "generate", "generateRaw", "stopGeneration", "getPreset", "getPresetNames",
"loadPreset", "jQuery", "$(", "document.", "window.", "localStorage", "fetch(", "XMLHttpRequest",
"postSysPrompt", "getTavernRegexes", "getWorldbook", "setWorldbook", "toastr", "console.log",
"import(", "require(", "createElement", "addEventListener", "MutationObserver", "setTimeout",
"__TAVERN", "stscript", "getAudio", "voice", "playAudio", "getRequestHeaders", "saveSettingsDebounced",
];
const candidates = [];
function walk(node, trail, depth) {
if (node == null || depth > 8) return;
if (Array.isArray(node)) {
node.forEach((v, i) => walk(v, [...trail, String(i)], depth + 1));
return;
}
if (typeof node === "string") {
if (node.length > 200 && /(function|=>|await |const |let |var |TavernHelper|SillyTavern|\$\()/.test(node)) {
candidates.push({ path: trail.join("."), code: node });
}
return;
}
if (typeof node !== "object") return;
for (const [k, v] of Object.entries(node)) walk(v, [...trail, k], depth + 1);
}
walk(preset, ["preset"], 0);
// 也把所有 extensions 下的键结构打出来(含数组长度),判断「脚本」挂在哪个键
const extKeys = [];
(function scan(node, trail, depth) {
if (node == null || depth > 6) return;
if (Array.isArray(node)) { extKeys.push([trail.join(".") + "[]", node.length]); return; }
if (typeof node === "object") {
for (const [k, v] of Object.entries(node)) scan(v, [...trail, k], depth + 1);
return;
}
if (typeof node === "string" && node.length > 3000) extKeys.push([trail.join("."), node.length]);
})(preset.extensions, ["extensions"], 0);
console.log("=== extensions 下的大对象 / 长字符串(可能是脚本宿主) ===");
for (const [p, n] of extKeys.slice(0, 60)) console.log(" " + p + " → " + n);
console.log("\n=== 候选脚本 " + candidates.length + " 段 ===");
let k = 0;
for (const c of candidates) {
k += 1;
const hits = APIS.map((a) => [a, (c.code.match(new RegExp(a.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g")) || []).length]).filter(([, n]) => n > 0);
console.log("\n--- [" + k + "] " + c.path + " (" + c.code.length + " 字符) ---");
console.log(" 碰到: " + (hits.length ? hits.map(([a, n]) => a + "×" + n).join(", ") : "(无已知 API)"));
const file = path.join(outDir, "script-" + String(k).padStart(2, "0") + "-" + c.path.replace(/[^\w.\-]+/g, "_").slice(-60) + ".js");
writeFileSync(file, c.code, "utf8");
console.log(" 落盘: " + file);
console.log(" 头 300 字: " + JSON.stringify(c.code.slice(0, 300)));
}