鱼皮AI导航
鱼皮AI导航
  • 主页
  • 社区
  • AI工具
  • AI知识库
  • AI提示词
  • MCP
  • Skills
  • AI学习资源
  • AI资讯
  • GitHub开源
登录/注册

dsh-blast-radius

报告 agent 代码修改的语义波及面:哪些符号变了、谁在调用它们、其中哪些调用方没有测试覆盖。

代码评审
访问 GitHub
文档README

dsh-blast-radius

DeepSeek Harness 插件:agent 改了代码,这次改动会波及什么?

diff 告诉你改了 5 行。它不会告诉你这 5 行在一个被另外 3 个文件调用的函数里, 而那些调用点一个测试都没有。前者是文本视角,后者是风险视角。

用真实的 TypeScript 语义分析(tsserver)回答后者:改动落在哪个符号上、谁依赖这个 符号、那些依赖里有多少受测试保护。

▼
text
复制代码
[高] applyDiscount src/money.ts 3 处生产调用点,且该符号没有任何测试引用 影响 2 个其他文件:src/cart.ts、src/pricing.ts ↳ src/cart.ts:6 const total = applyDiscount(subtotal, discountPct) ↳ src/pricing.ts:10 return applyDiscount(cents, 10) ↳ src/pricing.ts:19 return applyDiscount(this.cents, pct)

两条不会妥协的原则

这两条决定了插件的所有行为,也决定了默认配置:

1. 分析失败永不阻断 agent。 TypeScript 没装、tsserver 崩了、查询超时 —— 全部放行。 即使 enforce: true 也一样。一个会因为子进程死掉就卡住 agent 的质量工具,比没有这个 工具更糟。

2. 「不知道」永不伪装成「安全」。 分析不出结论时明确说出来,而不是渲染成一条干净 的结果。这也是 enforce 默认关闭的原因:一个第一天就开始拦你写入的插件,会在赢得 信任之前先被卸载。

功能

  • 语义影响面:tsserver 的 references + navtree,按符号(不是行号)归因
  • 测试覆盖缺口:区分生产调用点与测试引用 —— 这是最值钱的信号
  • 风险分级:低 / 中 / 高,规则确定可复现(不用模型判断)
  • 写入前拦截:tools/pre-execute waterfall,超阈值走 ask
  • 仪表盘:shell.overlay 角落面板,4s 轮询
  • 零额外安装:typescript 包自带 tsserver.js,优先用被分析项目自己的版本

安装

▼
bash
复制代码
dsh plugin --profile web add dsh-blast-radius

默认 report-only:只记录、只显示,不拒绝任何写入。

配置

见 cordis.patch.yml。关键项:

键默认含义
enforcefalse超阈值时是否要求确认。默认只报告
enforceAtRiskhigh触发确认的风险等级:medium | high
timeoutMs3000单次语义查询预算,超时降级为「未分析」并放行
highProductionRefs12调用点超过此数即为高风险(即使有测试)
testPatterns[]追加的测试路径正则(内置已覆盖 *.test.* / test/ / __tests__/)
maxProjectFiles2000无 tsconfig 时扫描上限,触顶会明确报告
verbosefalse每次分析打一行日志,调阈值时有用

风险分级规则

条件等级
无人引用 / 仅被测试引用 / 仅被导入未调用低
有生产调用点,无测试引用,且跨文件高
有生产调用点,无测试引用,但都在本文件内中
有生产调用点且有测试引用,调用面 ≥ highProductionRefs高
有生产调用点且有测试引用中

排序刻意如此:「跨文件且完全没有测试」排在「调用点很多」之前,因为前者是改错了会 静默上线的情形,后者至少有测试兜着。

设计取舍

这些取舍都是在真实仓库上跑出来的,不是设计阶段想出来的。

只分析符号,不分析行

变更行 → navtree 定位所属符号 → 查该符号引用。变更区间用前后缀剪裁计算,分散编辑 会连带包含中间范围。刻意选这个方向:多分析几个符号只是多花几毫秒,漏掉符号就是漏掉 了插件存在的理由。

局部变量不参与分析

第一次在真实文件上跑,30 条结果里大部分是噪音 —— splitSentences.start 报告"2 处生产 调用点",那是个循环变量。

按 kind 过滤不够:模块级 const 和函数内 let 在 tsserver 里 kind 相同。真正的判据是 是否在可调用体内 —— 模块常量能被任何地方读,局部变量跑不出它所在的函数体。修完 30 条降到 6 条真实符号。

import 不算调用点

import { applyDiscount } from './money.ts' 引用了符号,但不依赖它的行为。算进去会让 影响面虚高一倍(fixture 里 3 处真实调用被报成 5 处)。

import 仍计入「波及文件」 —— 依赖关系是真的,只是不是"使用"。

测试文件不算「波及范围」

测试引用一个符号是保护,不是风险传播。算进去会让"测试写得好的符号"看起来比裸符号 更危险,正好反了。

补丁式编辑明确拒绝分析

str_replace_editor 表达的是"把 A 换成 B",不是"文件最终长这样"。要还原结果就得重新 实现一遍该工具的语义,而还原错了的话,下游每条结论都在描述一个不存在的文件。

所以报告为「未分析」、放行、且不记入已审查记录 —— 免得让人以为这次改动被看过了。

无 tsconfig 的项目:合成项目范围,但不落盘

没有 tsconfig.json 时,tsserver 退化成 inferred project,只知道显式打开的那个文件。 实测后果(在一个真实仓库上):

▼
text
复制代码
inferred project: 1 refs -> src/segmenter.ts ← 假的「没有引用」 declared project: 4 refs -> src/segmenter.ts, src/index.ts ✓

用 openExternalProject 在内存里声明项目范围,刻意不写 tsconfig.json 到用户仓库 —— 那会出现在 git status 里、可能被它正在监视的 agent 提交进去、还可能改变项目真实 构建行为。有测试断言分析前后 readdir 结果一致。

代价是范围靠扫描推断,可能漏文件。所以结果带 approximate 标记,且 enforce 时 推断范围的结论不参与拦截 —— 低估风险在"报告"里可以接受,作为"打断别人工作的理由" 则不行。

架构

▼
text
复制代码
tools/pre-execute waterfall └── extract.ts 工具调用 → 待写入内容(认不出的明确报 opaque) └── radius.ts 变更行 → 符号 → 引用 → 分桶 → 分级 └── lsp.ts tsserver 长驻会话(超时/崩溃/未就绪全部降级) └── discover.ts 无 tsconfig 时的有界文件扫描 GET /dsh-blast-radius-api/status → { records, enforce, enforceAtRisk, projectRoot }
文件职责
src/lsp.tstsserver 会话:帧解析、超时降级、崩溃重启、pending 内容同步
src/radius.ts纯逻辑:符号定位、引用分桶、风险分级(不碰子进程)
src/discover.ts无 tsconfig 时的项目文件发现(有界)
src/extract.ts从工具调用还原待写入内容
src/index.ts插件入口:配置、闸门、status 路由
src/client.tsx仪表盘面板

性能

在一个真实仓库上实测:

指标数值
tsserver 冷启动 + 项目加载~450ms(每会话一次)
单符号引用查询1–20ms
一个文件(含多符号)40–120ms

会话长驻、跨编辑复用。冷启动只付一次,所以不会把 0.5s 摊到每次写入上。

测试

▼
bash
复制代码
npm test # 166 用例 npm run typecheck
套件用例说明
src/radius.test.ts65纯逻辑,不碰子进程
src/extract.test.ts28工具调用识别与 opaque 判定
src/client.test.tsx18面板(jsdom)
src/discover.test.ts16文件发现的边界与截断
tests/lsp.spec.ts19真实 tsserver,含无 tsconfig 场景
tests/plugin.spec.ts20真实 cordis,闸门与 status 路由

LSP 层刻意不 mock:它是唯一有真实失败模式的组件(子进程、帧协议、项目加载), mock 掉就等于没测到唯一的难点。

原型工具

仓库里带一个 probe 脚本,可以在任意真实仓库上直接跑分析、打印结果 —— 用来判断信号 质量、调阈值,不需要先装成插件。只在源码仓库里可用(未随 npm 包发布):

▼
bash
复制代码
git clone https://github.com/haoku123/dsh-blast-radius cd dsh-blast-radius && npm install --legacy-peer-deps node scripts/probe.ts ~/your-project src/some-file.ts [symbolName]

需要 Node ≥ 22.6(原生运行 TypeScript)。输出示例见本文开头。

限制

  • 只支持 TypeScript / JavaScript。Python 需要另装 pyright,选型与降级策略完全不同, 架构上留了 provider 接口但 v1 不做。
  • references 拿不到动态调用:反射、字符串索引、eval、跨语言边界。
  • 补丁式编辑工具无法分析(见上)。
  • 无 tsconfig 时项目范围是推断的,可能漏掉调用点。
  • 不做「AI 判断风险」。全部基于确定性事实 —— 一个会给出不可复现结论的质量门是 负资产。

License

MIT

代码评审

快捷安装

复制到终端去安装插件

dshplugin--profilewebaddgithub:haoku123/dsh-blast-radius

温馨提示

装插件等于在本机跑第三方代码,权限与你相同,能读文件、用凭据、访问网络,工具审批管不到。请只装可信来源,并尽量锁定 commit。

站长:程序员鱼皮 老鱼简历 商务合作 增值电信业务经营许可证
2026 鱼皮AI导航 | 沪ICP备19026706号-6
站长:程序员鱼皮 老鱼简历 商务合作 增值电信业务经营许可证
2026 鱼皮AI导航 | 沪ICP备19026706号-6
🔥热门工具
朱雀AI检测朱雀AI检测
朱雀AI检测助手朱雀AI检测助手
LovartLovart
老鱼简历老鱼简历
WritePass官网WritePass官网
面多多面多多
CursorCursor
星月写作星月写作
零感AI零感AI
墨得问题墨得问题
dsh 插件推荐
dsh-code-review
提供 /review、/review-status 和 /review-cancel,用独立原生子 Agent 审查所选 Git 范围(基准分支、未提交更改、某次提交或自定义要求),并把发现报告返回当前会话;报告语言跟随宿主 locale,支持中英文。
AgentsGitFlowController
AI 编码智能体分支角色守卫:可配置集成/预览/生产/归档角色,拦截对受保护分支的直接推送、强推与删除,以及智能体对生产/归档分支的合并。
dsh-github-mcp-hint
GitHub MCP 辅助面板:在「设置 → 插件 → GitHub MCP」展示可复制的示例提示(30 条示例池随机 4 条)、可视化公开仓库的星/fork/语言,并提供 gh_repo_stats / gh_current_user 模型工具。
dsh-github-mcp
把 GitHub 官方远程 MCP server 封装为 DSH 插件:PAT 存入 DSH 凭据中心(.credentials.yaml),提供 github_set_token / github_token_status 模型工具,GitHub 工具以 mcp__github__* 形式可用。
source-code-mgmt
DSH 网页界面的代码管理面板,五步搞定 Git 日常:① 环境检查自动检测 git/gh/ssh,缺工具一键安装(gh 支持镜像下载源加速,Windows 也可用)并带检查更新;② SSH ed25519 密钥生成/连接测试 + 一键写 443 配置绕过 22 端口封锁,Gitee 私人令牌在此配置;③ 查看仓库状态、并排 diff、暂存提交、切换分支、查看/回滚历史,一键新建仓库并推送,自动忽略超 100MB 文件;④ 列出账号名下所有远程仓库一键克隆;⑤ 五步发布 npm 包。支持 GitHub / Gitee 双平台,界面中英文跟随 DSH 设置实时切换。