查清一次代码改动波及哪些符号与引用位置
30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/21 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Locael123/dsh-code-impact该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 7 处,展示前 7 条)
- 发起网络请求client.js:181
const response = await fetch(url, { headers: { accept: 'application/json' } }); - 发起网络请求client.js:188
const response = await fetch(url, { - 读取本地文件lib/files.js:85
entries = await readdir(dir, { withFileTypes: true }); - 读取本地文件lib/files.js:118
info = await stat(entry.abs); - 读取本地文件lib/files.js:125
buf = await readFile(entry.abs); - 发起网络请求web/app.js:55
const response = await fetch(url, { headers: { accept: 'application/json' } }); - 发起网络请求web/app.js:62
const response = await fetch(`${API}/${route}`, {
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DeepSeek Harness 智能体的编辑后影响检查——符号索引和引用图,告诉你一次编辑动了什么,不用重扫仓库。
README
由 DeepSeek 最新模型翻译生成dsh-code-impact
给 DeepSeek Harness 用的改动影响分析插件 —— 符号索引、引用图、继承模型,回答"这次改动影响了什么",而不是全仓重扫一遍。
它解决什么
小改动也要全量验证,问题不在"全量"这个目标,而在于用扫描的方式去做全量。
索引把这件事倒过来:
- 全仓的引用关系平时就在内存里,所以"全量检查"是一次查询,不是一次扫描;
- 改完之后只重解析改过的文件,再沿引用边算出必须复核的站点;
- 回答里不带"大概没问题",而是给出 file:line、可信度、以及明确列出的未验证部分。
两个工具
两个工具注册进每个 agent 会话;同一份索引还提供了一个可视化页面(设置 → 代码影响分析)。
展开完整文档(README 剩余 1 节)
dsh-code-impact
给 DeepSeek Harness 用的改动影响分析插件 —— 符号索引、引用图、继承模型,回答"这次改动影响了什么",而不是全仓重扫一遍。
它解决什么
小改动也要全量验证,问题不在"全量"这个目标,而在于用扫描的方式去做全量。
索引把这件事倒过来:
- 全仓的引用关系平时就在内存里,所以"全量检查"是一次查询,不是一次扫描;
- 改完之后只重解析改过的文件,再沿引用边算出必须复核的站点;
- 回答里不带"大概没问题",而是给出 file:line、可信度、以及明确列出的未验证部分。
两个工具
两个工具注册进每个 agent 会话;同一份索引还提供了一个可视化页面(设置 → 代码影响分析)。
code_query
| op | 用途 |
| find | 按名字(addNode / Graph.addNode / ts:src/x.ts#Graph.addNode)定位声明 |
| outline | 一个文件的声明骨架(含行号、导出性、继承子句) |
| refs | 谁提到了这个符号——逐个解析过滤,同名局部变量不会算进来 |
| hierarchy | extends / implements / 子类型 / 成员(含继承与 override) |
| search | 名字与签名的子串检索 |
| status | 索引规模、根目录、缓存位置、引擎模式、解析失败数 |
find "parseTimeout" — 1 match
ts:src/config.ts#parseTimeout
variable src/config.ts:1-1 exported refs:3
parseTimeout = 30 ;
refs ts:src/config.ts#parseTimeout — 3 sites (exported, refs:3) variable src/config.ts:1 parseTimeout = 30 ; confidence: exact 3 · resolved 0 · heuristic 0 · unresolved mentions 0
src/policy.ts:4 value in RetryPolicy
timeout = parseTimeout;
src/service.ts:5 value in makeService
const policy = buildPolicy({ timeout: parseTimeout });
code_verify
编辑之后调用,代替重扫。它只重解析磁盘上有变化的文件(缺省时顺带发现新建文件),然后报告符号级差异:
verify — verdict: internal 1 file changed (0 deleted) · +0 -0 symbols · 1 body-only
body-only (signature unchanged, callers unaffected):
ts:src/config.ts#parseTimeout refs:6
verify — verdict: breaking 1 file changed (0 deleted) · +1 -1 symbols · 1 contract
symbols that no longer exist:
ts:src/config.ts#parseTimeout
references that no longer resolve:
dangling src/policy.ts:4 parseTimeout
verdict 四档:clean(没有变化)、internal(只动了实现)、contract(签名/导出变了,调用方可能要改)、breaking(有引用已经解析不到)。
只有原本确实指向这个符号的提及,才会在它消失后被判为 dangling。那些一开始就解析不到的名字——filepath.Base、没装的包、启发式只是猜过的名字——不会被报出来:误报的代价比漏报大。
契约判定的一条关键规则:const timeout = 30 改成 = 60 是取值变化,按 body-only 处理,不会误报成契约变更;类/接口/struct 这类容器本身不计入变更列表(成员的变化已经表达了它),避免一次小改动就背上整个类。
code_verify 是增量的:它报的是"自索引上次同步以来"的变化,所以连续调两次而中间没有编辑,第二次就是 clean。要的就是这个语义——每次编辑后问一次,答案就是你刚做的事。
索引页(可视化)
同一份索引可以直接看:设置 → 代码影响分析(Code Impact)。四个视图,数据全部来自索引,不会重新扫描仓库:
| 视图 | 回答什么 |
| 架构图 | 按符号数加权的目录 treemap,按语言着色——代码实际堆在哪里 |
| 依赖图 | 文件级 import 关系的弦图,悬停某个文件会高亮它的边 |
| 继承图 | 按继承深度分层的类型 DAG,implements 用虚线 |
| 会话 | 哪些会话用过这个插件、问了什么、返回了什么 |
点文件列出它的符号(kind、签名、行号);点类型显示它的父类型、子类型和声明文件。顶部一排 "诚实标签":文件数 / 符号数 / 名字数 / 语言分布 / 索引构建时间 / 有文件被跳过时的警告,外加一个 刷新 按钮——刷新会先核对磁盘再重画。
会话页是这个插件自己的审计记录:每次 code_query / code_verify 都按会话记下来(会话 id、工作目录、调用次数,以及最近 40 次的查询目标和一行结果)。它写在 $DSH_HOME/cache/code-index/usage.json,所以重启不丢,也能看到本进程没见过的会话。它只记录这个插件自己的调用——不是"agent 做过什么"的权威记录——清空 只清记录,不动索引。
全屏打开 会把同一张图放进浏览器新标签页(/code-impact/app),空间更大、背后没有设置页的框;两边共用同一批路由和同一份索引。
页面一次画一个已建索引的工作区,要换项目用标题下面那个目录框:填绝对路径(D:\work\my-project)回车,它为这个目录建索引并切过去,之后也能在下拉框里选回来。这是"agent 没用过工具"也能进页面的唯一入口——如果某个会话的 cwd 就是那个项目,它第一次跑 code_query 时也会顺带建好索引。
它是 bundle 的客户端半(client.js,React,只用主题 token——没有 iframe、不拼 HTML),通过读路由、一条建索引路由和会话记录路由和宿主通信。独立的页面(web/app.html + web/app.js,纯 DOM + SVG)由同一个宿主提供:
GET /code-impact/api/roots
GET /code-impact/api/overview?root=<绝对路径>&refresh=1 GET /code-impact/api/file?root=<绝对路径>&path=<仓库相对路径> POST /code-impact/api/index {"root": "<绝对路径>"} GET /code-impact/api/usage?limit=100 POST /code-impact/api/usage/clear {} GET /code-impact/app 全屏页 GET /code-impact/app.js
读路由是白名单:页面只能读已建索引的目录,或当前会话的工作目录。POST /index 是唯一会干活的路由——它只为你点名的那个目录建缓存,拒绝相对路径 / 不存在的目录 / 普通文件(返回 400 并带上原因),并且永远不会往你的仓库里写东西。
安装与配置
dsh-code-impact 是一个 DSH host bundle:零依赖、纯 ESM、一行 patch 记录。
从 GitHub 装(或任何已发布的 tarball / registry 包)
dsh plugin --profile desktop add github:Locael123/dsh-code-impact
dsh web # 重启:插件的宿主半只在启动时 import 一次
从本地 checkout 装 plugin_manager install_bundle <绝对路径>/dsh-code-impact
手工安装——只在该包已经能从 profile 的 node_modules 解析到时可用(plugin_manager 会替你做好这件事,光加一行 cordis.yml 不够):
- id: dsh-code-impact
name: dsh-code-impact
config:
maxFiles: 20000
bundle 自带 cordis.patch.yml,所以优先用插件管理器——它会写好 patch 记录、链好目录,并保证 files[] 完整。
| 配置 | 默认 | 说明 |
| maxFiles | 20000 | 单次建索引的文件上限,超出会截断并在 status 里显示 |
| root | 会话工作目录 | 覆盖被索引的根目录 |
缓存位置:$DSH_HOME/cache/code-index/<hash(root)>/(内容寻址的 facts/ + manifest.json)。
改一个文件只重写一份 fact。它是缓存:随时删,删了自动重建,绝不写进被索引的仓库。
精度契约
每条结果都带上下界,而不是一个自信的答案:
- confidence: exact | resolved | heuristic | ambiguous——exact 是能落到具体声明的证据, heuristic 是唯一名/就近推断;
- total / truncated——截断了就说截断了;
- unverified:——这一条回答没有覆盖什么(跨语言、动态引用、类型级兼容性)。
某个文件解析失败时它不会静默消失:code_query op=status 会带上 warning: N file(s) could not be parsed and are NOT indexed,code_verify 会在 unverified: 里声明"有变更文件没有被分析"。索引少算了东西,你必须知道。
宁可给候选,也不说"没有"。
支持范围与边界
- 语言:TypeScript / JavaScript / Go(.ts .tsx .mts .cts .js .jsx .mjs .cjs .go)。
- 模块解析:相对路径 + 扩展名 + /index 探测、tsconfig/jsconfig 的 baseUrl + paths、 go.mod 的 module 前缀 + 同包目录。
- 跳过:node_modules .git dist build out vendor target __pycache__ .venv 等目录、超过 512 KiB 的文件、二进制。
- 刻意近似:TS 的 implements 与 Go 的接口满足是结构化/隐式的,只能给候选集并标 heuristic——这是全工具唯一一处明知的猜测。
- 不建模:跨语言引用(Go interface → 实现者、JSON schema → consumer)、动态派发、生成代码。
实现要点
- 只存事实,不存图:每个文件只记录"本文件说了什么"——imports、exports、 decls(含 heritage 与成员)、refs(名字 + 位置 + 角色 + 词法作用域)。磁盘上没有目标 ID,名字→定义是查询时解析的,所以编辑一个文件恰好失效一个文件。
- 稳定 SymbolId:<lang>:<path>#<qualname>,不含行号。重命名/移动会改变 ID,而 ID 的变化本身就是信号。
- 新鲜度:返回前对答案里出现的文件做 stat(mtime + size),所以它报出来的东西不会是旧的; code_verify 驱动增量重建;外部编辑靠同一套 stat 比对;结构性变更靠 manifest 版本戳触发全量重建。
- 没有原生模块、没有 LSP、没有子进程:手写词法器 + 按语言的作用域解析器,冷启动是几百毫秒,整个插件零依赖。
实测(本仓库 42 个 TS/Go 文件):冷建 276 ms / 883 符号;查询 1–4 ms;5 文件 fixture 的 warm start 3 ms。
开发
node test/selftest.mjs # 索引 + 工具,36 条断言
node test/addroot.mjs # 页面"给目录建索引"的路径,含各种拒绝
node test/usage.mjs # 会话记录:按会话记账、持久化、清空
node test/webcheck.mjs <仓库路径> # 页面调的那几条 JSON 路由
node test/clientsmoke.mjs # 客户端半能正确注册设置页
自测在系统临时目录里复制 test/fixture(一个刻意造的小 TS + Go 工程,带 tsconfig 路径别名、类继承链、两包 Go module),真实建索引并跑 36 项断言:取值改动不算契约变更、重命名导出后悬空引用被报出来、目录改名不算悬空、新文件被拾取、删除文件被报告、Go 跨包引用为 exact、 warm start 从 manifest 加载、以及"提到 constructor 的文件依然能解析"这条原型链回归(那是真 bug:用普通对象当分隔符栈,撞上了 Object.prototype.constructor)。
许可
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Locael123/dsh-code-impact
查清一次代码改动波及哪些符号与引用位置
相关插件 · 开发 / 工程
隐私简历生成器reactive-resume/reactive-resume
Reactive Resume 已迁至 GitHub 上的…
★ 45,125已汉化MCP
71.7
AI 架构文档生成器sopaco/deepwiki-rs
🚀 Litho 已进化为 Terrain —— 给你的 AI 智能体一张会呼吸的代码库地图。
★ 3,157已汉化DSH
70.8
长时任务执行闭环AMAP-ML/LongHorizon-Harness
面向 Computer-Use Agent 的 Loop Engineering
★ 1,764已汉化DSH
70.5
AI 编程纪律方法包GanyuanRan/Aegis
让 AI 编程 agent 变得可信:少返工、更安全、说“完成”前先给证据。
★ 1,384已汉化DSH
69.6
多代理编排运行时Enderfga/claw-orchestrator
面向编程智能体的运行时。把 Claude Code、Codex、Antigravity、Grok…
★ 586已汉化MCP
69.4
记忆进化插件csyangwen/dsh-memory-evolve
dsh-memory-evolve 使用场景指南
★ 461已汉化DSH
67.9