DSH-Search-Citation-Auditor
Audit citation sources in AI responses – extract URLs from the reply, score and rank them by threat level, and output a detailed report. Domains on your blocklist will be genuinely blocked – web tools such as web_search and web_fetch will directly refuse to access them. The blocklist is fully maintained by you.
- Stars
- 1
- Language
- TypeScript
- Created
- Sep 1, 2026
- Updated
- Sep 1, 2026
Introduction
Citation Auditor
Cordis 函数插件,可被 DeepSeek Harness 直接加载。业务内核(scanner / scorer / report)是纯函数,脱离 dsh 也能复用。
工作方式
扫描文本 → 提取 URL → PSL 解析注册域(eTLD+1)→ 0–100 打分 → 出报表。
三种模式:
- 白名单模式:名单内绿,名单外全红。最严。
- 简单模式:2023 年前注册的可信,之后标红。
- 普通模式:多信号综合评分(TLD、连字符/数字个数、域名长度、注册年龄)。
命中拦截名单的域名直接标红,不参与评分。域名匹配统一按注册域:en.wikipedia.org → wikipedia.org。年龄查不到时只记"可疑"(ageQuery 未启用或查询失败),只有确认是新域名才从严标红。
真实拦截:拦截名单(含 .shop 这类 TLD 条目)会在 tools/pre-execute 阶段拦截 web 工具(web_search / web_fetch 等),命中即拒绝调用并告知模型原因——加入名单后模型就访问不了该网页了。只拦 web 工具;pwsh/curl 等 shell 通道属沙箱层,不在拦截范围。名单增删(界面按钮或直接改 blocklist.json)即时生效,无需重启。
向 dsh 注册两个工具:
| 工具 | 作用 |
|---|---|
citation_audit | 审计一段文本,返回结构化结果 + 纯文本报表 |
citation_manage | 查状态、启停、切模式、增删名单、测试年龄片段 |
Web 界面
- 设置页卡片:三种模式单选、各模式拦截名单开关、白名单免查加速、插件总开关、年龄片段 [编辑JS代码] 与 [测试](固定 wikipedia.org)。名单旁的 [查看/编辑] 用系统默认程序打开对应 JSON,改完即生效。
- 交互报表:会话里
citation_audit渲染成可点报表,非可信域名带 [➕ 加入拦截名单] / [➕ 加入白名单] / [忽略];拦截名单开关关闭时弹窗三选(开启并保存 / 仅保存 / 取消)。写入后按钮变灰,可再点确认移除。 - 悬浮窗:右下角可拖动球(有可疑域名时显示红色角标),点击展开最近回复的网址列表与分数;面板内含 ⚙ 设置入口和同样的名单按钮。
所有设置/名单读写都走插件自有的同源端点 /api/citation-auditor/*(status / audit / list / settings / test-age / open-file),直接落盘 settings.json,不依赖 harness 的 settings 服务。
年龄查询片段(唯一联网点)
一段你自己写的 JS,在 worker 线程执行,5 秒超时直接 terminate(同步死循环也拖不垮主线程)。契约:必须返回 { creationDate: <ISO 日期或毫秒> } 对象,查不到返回 undefined。先测试后启用,默认关闭。
按 TLD 分发注册局直连的 RDAP 示例(可直接粘贴进 ageQuery.js):
async (domain, fetch) => {
const tld = domain.split('.').pop();
const regs = {
com: 'https://rdap.verisign.com/com/v1/domain/',
net: 'https://rdap.verisign.com/net/v1/domain/',
org: 'https://rdap.publicinterestregistry.org/rdap/domain/',
top: 'https://rdap.centralnic.com/domain/',
xyz: 'https://rdap.centralnic.com/domain/',
};
const base = regs[tld] || 'https://rdap.org/domain/';
try {
const res = await fetch(base + domain, { signal: AbortSignal.timeout(4000) });
if (!res.ok) return undefined;
const j = await res.json();
const ev = (j.events || []).find((e) => e.eventAction === 'registration');
return ev ? { creationDate: ev.eventDate } : undefined;
} catch { return undefined; }
}
局限:RDAP 只认注册域(已按 PSL 归一化,天然满足);.cn 等部分 ccTLD 无公开 RDAP 或被网络阻断会查不到;新 gTLD(如 .top)数据不一定齐全。
数据与安全
名单、设置、年龄缓存各自存成独立 JSON 文件(默认 ~/.citation-auditor/,配置 statePath 可改),外加可编辑的 ageQuery.js。写入走临时文件 + fsync + rename 原子发布;损坏先备份为 *.corrupt-* 再处理,绝不覆盖;每次读取检查 mtime,直接改文件保存即生效。旧版单文件 state.json 首次启动自动迁移。
报表永不改写 AI 原文;全项目唯一的联网点是你的年龄查询片段。
构建与安装
npm install
npm run typecheck # tsc --noEmit
npm run test # 构建 + node:test(41 项)
npm run verify # dsh-plugin-standard 合规自检(社区自研规范,非官方认证)
安装进 dsh profile:发布 npm 包或 dsh plugin --profile web add github:AndKinoko/DSH_WEB_Citation-Auditor(prepare 脚本自动构建)。配置只有一个字段:
- insert:
- id: dsh-citation-auditor
name: dsh-citation-auditor
config:
statePath: "" # 留空用 ~/.citation-auditor
client 半边要求宿主 dsh.engines.dsh >= 0.1.1-rc.1(host 工具无此门槛)。
目录结构
src/
├── index.ts # Cordis 插件入口(name/inject/Config/apply + 两个工具)
├── storage.ts # 目录化键值存储(每 key 一文件 + mtime 热重载 + 原子写)
├── routes.ts # /api/citation-auditor/* 数据端点
├── settingsSection.ts # 设置命名空间 host 半边
├── client/ # 浏览器半边(设置卡片 / 交互报表 / 悬浮窗)
├── test/ # node:test 一致性测试
└── auditor/ # 业务内核(scanner/scorer/report 纯函数 + rules/cache/ageQuery)
License
MIT,见 LICENSE。