基于 codebase-memory-mcp 知识图谱的多阶段死代码检测与安全清理。用于清理无用代码、查找并删除死代码、移除未引用文件、进行项目清理或运行基于知识图谱的死代码分析。支持所有编程语言(JS/TS/Vue/React/Python/Java/Go/Rust/C/C++/PHP 等)。
死代码清理器
功能概述
死代码清理器是一项面向实际任务的技能,主要用于基于 codebase-memory-mcp 知识图谱的 11 阶段工作流,安全地识别并移除未被引用的代码;每个候选文件在删除前均通过 N 层验证,级联死代码检测会捕获在其唯一消费者被移除后成为孤儿文件的代码;
核心要点
- 以下引用的所有 MCP 工具均属于 codebase-memory-mcp 服务,通过标准 MCP 工具调用约定使用(如 mcp__codebase-memo。
- 它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。
- 从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。
使用与执行
实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。
结果检查与注意事项
执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
死代码清理器
概述
基于 codebase-memory-mcp 知识图谱的 11 阶段工作流,安全地识别并移除未被引用的代码。每个候选文件在删除前均通过 N 层验证,级联死代码检测会捕获在其唯一消费者被移除后成为孤儿文件的代码。
以下引用的所有 MCP 工具均属于 codebase-memory-mcp 服务,通过标准 MCP 工具调用约定使用(如 mcp__codebase-memory-mcp__index_repository)。
快速开始
用户通过以下短语触发此 skill:
- "清理死代码"
- "移除项目中的无用文件"
- "查找并删除 <项目> 中的死代码"
- "运行死代码分析和清理"
参数解析
三个参数驱动整个工作流。全部自动检测;仅在检测结果有二义性时询问用户。
repo-path — 项目在磁盘上的根目录。
默认值:当前工作目录(pwd)。如果用户指定了项目名,从已知的工作区路径解析。仅在两者都不明确时询问。
index-name — codebase-memory-mcp 中使用的项目标识符。
检测顺序(使用第一个成功的):
package.json→name字段go.mod→ module 路径(module后的第一行)Cargo.toml→[package]下的namepom.xml→(第一个匹配)composer.json→name字段(PHP 项目).csproj/.sln→ 项目文件名(C# 项目,取第一个匹配的.csproj文件名去掉扩展名)Gemfile→ 目录名(Ruby 项目)setup.py/pyproject.toml→name字段- 回退到
repo-path的目录名
app-name — 总结文档中使用的可读名称。
检测顺序(使用第一个成功的):
package.json→description或namecomposer.json→description或name(PHP 项目).csproj所在目录名(C# 项目)- 与
index-name相同 repo-path目录名的 Title Case 格式
Monorepo 处理
通过检查是否存在各自包含独立构建清单(package.json、go.mod、Cargo.toml、composer.json、.csproj、pom.xml 等)的子目录来检测 monorepo 结构。常见模式:microapps/、packages/、apps/、services/、modules/。
当检测到 monorepo 时:
单个子项目(用户明确指定了某一个):仅作用于该子项目,直接在当前 agent 中执行完整流程(阶段 0–10)。
多个子项目(用户选择了多个,或说了"全部"/"整个工作区"):
全局索引(主 agent):先对所有涉及的子项目逐个执行
index_repository mode=full,再执行一次index_repository mode=cross-repo-intelligence target_projects=["*"],建立完整的跨项目引用图谱。此步完成后,每个子项目的 L-cross 验证都有了准确的跨项目引用基线。派发子 agent:主 agent 检测当前环境可用的子 agent 能力,自动选用下表第一种可用方式;不可用时直接串行,不报错停滞。禁止使用 fork_thread(会继承主 agent 上下文,导致多项目污染)。
优先级 环境能力 派发方式 1 内置并行子 agent 派发工具 每个子项目派发一个子 agent,同批并行 2 独立会话创建工具(干净会话,非 fork) 每个子项目创建一个独立会话 3 以上均不可用 主 agent 对各子项目串行执行阶段 0–10 各子 agent 传入相同的 prompt(
<...>替换为实际值):清理以下单个子项目的死代码。必须 @ dead-code-cleaner,先完整读取 SKILL.md 再执行——与主 agent 跑单个子项目时相同的阶段 0–10 流程,逐步执行,不可凭记忆省略或只输出分析结论。 不要处理其他子项目,不要运行 monorepo 检测逻辑。 子项目路径:<子项目路径>(即 repo-path) 索引名:
应用名: 全局索引已完成,阶段 1.1/1.2 跳过。其余阶段与 SKILL.md 正文完全一致: 0 → 1.3 → 1.4 → 1.5 → 1.6 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 阶段 1.4 的 Cypher 结果须按子项目路径过滤(仅保留 path 以「<子项目路径>/」开头的节点)。 阶段 6 必须实际删除文件(rm/git rm),不可只列清单。 rg 命令与验证层详见 references/verification-patterns.md。 完成后按 references/output-template.md 输出完整清理总结。 分批执行:若子项目超过 5 个,每批 3–5 个并行派发,等本批全部完成后再派下一批。
兜底:派发第一批后抽查一个子 agent 的输出。若未按上述流程执行(如跳过阶段、只分析不删除、未读 SKILL.md),则放弃子 agent,改由主 agent 对各子项目串行执行相同流程。
并发执行:同批次的子 agent 并行运行,主 agent 等待全部完成后汇总,不介入各子 agent 的执行过程。
汇总结果:主 agent 执行跨仓库索引更新(阶段 7.3),再按 output-template.md 格式输出合并总结(各项指标按子项目分列,末尾加总计行)。
用户未指定:列出检测到的子项目,询问用户要清理哪一个(或多个)。
前置检查:环境准备
在开始分析之前,确认工具链就绪。
1. 检查 codebase-memory-mcp 是否可用
检查二进制文件是否存在:
which codebase-memory-mcp && codebase-memory-mcp --version
如果未找到,告知用户按照官方指南安装。二进制文件必须位于 $PATH 中。
2. 确认 MCP 服务已配置
通过调用一个轻量工具来验证 MCP 服务连接:
mcp__codebase-memory-mcp__list_projects
- 调用成功 → 继续。
- 调用失败 → 运行
codebase-memory-mcp install尝试修复,然后重新验证。 - 仍失败 → 终止流程。提示用户:codebase-memory-mcp MCP 服务不可用,请检查配置是否正确。修复后重新运行本 skill。
3. 启用 3D 图谱可视化
设置 UI 标志(持久化,重启后仍生效):
codebase-memory-mcp --ui=true
默认端口为 9749。验证其是否响应:
curl -s -o /dev/null -w "%{http_code}" http://localhost:9749
如果端口被占用,更换端口:codebase-memory-mcp --port=<备选端口>。
4. 保存当前状态
建议用户在继续之前提交或暂存当前更改。工作流会删除文件但不会自动提交——用户自行控制版本管理生命周期。
阶段 0:语言栈识别
0.1 扫描项目文件扩展名分布(不限语言,扫描实际文件系统中的源文件。codebase-memory-mcp 索引的是文件系统而非 git,二者需保持一致):
find-type f -not -path '*/node_modules/*' -not -path '*/vendor/*' -not -path '*/.git/*' -not -path '*/dist/*' -not -path '*/build/*' -not -path '*/target/*' -not -path '*/__pycache__/*' -not -path '*/bin/*' -not -path '*/obj/*' -not -name '*.json' -not -name '*.yaml' -not -name '*.yml' -not -name '*.md' -not -name '*.txt' -not -name '*.rst' -not -name '*.lock' -not -name '*.svg' -not -name '*.png' -not -name '*.jpg' | sed 's/.*.//' | sort | uniq -c | sort -rn | head -30
常见映射参考:.vue/.ts/.js/.jsx/.tsx → JS/TS 系列,.py → Python,.go → Go,.java → Java,.rs → Rust,.c/.cpp/.h → C/C++,.rb → Ruby,.php → PHP,.swift → Swift,.kt → Kotlin,.cs → C#,.scala → Scala。
0.2 根据主导扩展名映射到语言栈:
- 在表中:参见语言参考模式表,使用对应的精确验证层。
- 不在表中:codebase-memory-mcp 的图谱索引本身是语言无关的,阶段 1 的孤立节点检测仍然有效。进入阶段 2 时使用通用验证层。
0.3 对于多语言混合项目:所有识别到的语言(表内 + 表外)的验证层都必须执行。
阶段 1:全量索引
1.1 全量重建当前项目索引:
mcp__codebase-memory-mcp__index_repository mode=full repo_path=""
1.2 跨仓库智能索引(仅 monorepo;单仓库跳过):
mcp__codebase-memory-mcp__index_repository mode=cross-repo-intelligence target_projects=["*"] repo_path=""
1.3 通过 mcp__codebase-memory-mcp__get_architecture 获取架构全貌。记录:节点数、边数、路由、入口点、语言分布。
1.4 通过 mcp__codebase-memory-mcp__query_graph 查找未被任何文件引用的 File 节点(入度为 0)。注意:不要求出度为 0——一个文件即使导入了其他模块,只要没有任何文件引用它,它就是死代码:
MATCH (f:File) WHERE f.in_degree = 0 RETURN f.path
此结果构成候选集。
1.5 从候选集中排除以下文件:
- 构建配置文件(
webpack.config.*、vite.config.*、Makefile、CMakeLists.txt等) - 包管理文件(
package.json、go.mod、Cargo.toml、pom.xml、composer.json、Gemfile、requirements.txt等) - 入口文件(
main.*、index.*、app.*、__init__.py等——根据项目约定调整) - 测试文件(
*.test.*、*.spec.*、*_test.*、test_*等) - 类型声明文件(
*.d.ts、*.pyi等) - barrel/重导出索引文件(需人工核实)
- 数据/配置文件(
*.json、*.yaml、*.yml、*.xml、*.toml、*.lock——这些文件可能被图谱索引但通常不是代码入口) - 文档文件(
*.md、*.txt、*.rst)
1.6 重复文件候选扩展:项目迭代中常见将代码复制到新位置而忘记删除原版。字节级相同的文件意味着至少一份是废弃副本,但图谱可能因"两份文件互相无引用"而漏掉其中一份。
# 查找字节级相同的文件对(语言无关,扩展名使用阶段 0 的结果) find-type f ( -name '*.js' -o -name '*.ts' -o -name '*.vue' -o -name '*.py' -o -name '*.go' -o -name '*.java' -o -name '*.php' -o -name '*.cs' ) -exec md5 -q {} ; | sort | uniq -d
对每组重复文件:
- 如果至少一份已在候选集中 → 将组内所有文件加入候选集
- 如果组内所有文件均不在候选集中 → 同样全部加入候选集(两份完全相同且都未被引用,均为死代码嫌疑)
加入后不重复执行 1.5 的排除规则(重复文件不受"非代码文件"排除影响)。
约束:候选集以图谱查询结果为基础,1.6 的 md5 重复检测是对图谱盲区的补充——两份字节级相同的文件互相无引用关系时,图谱无法发现它们之间的关联。除此例外,禁止手动挑选子集。
如果候选集为空(1.5 排除和 1.6 扩展后均无文件):
- 项目代码引用关系完整,未发现可疑死代码。
- 直接跳到阶段 10,输出空报告(清理效果表各项均为 0)。
- 仍然打开 3D 图谱供用户可视化确认。
阶段 2:逐文件 N 层验证
根据阶段 0 的语言识别结果,对候选集中每个文件 F 选择验证策略:
- 语言在参考表中:执行验证模式参考中该语言对应的所有精确验证层。不适用的层跳过(标记 N/A)。
- 语言不在参考表中:执行通用验证层。核心思路是利用图谱已经证明"无入边"的事实,加上文件名全文搜索和相对路径搜索作为最终确认。
验证层一览:
- L-import-abs:绝对路径/别名路径导入
- L-import-rel:相对路径导入(
./和../) - L-dynamic:动态加载(
import()、require()、Class.forName()等) - L-cross:跨项目/跨仓库引用(仅 monorepo)
- L-template-tag:模板标签引用(Vue/React/Angular)
- L-component-reg:组件注册(Vue/Angular)
- L-reflection:反射/运行时引用(Python/Java/PHP/C#/Go)
- L-config-ref:配置文件中的引用(.yaml、.json、.xml、.properties)
同名校验:当 {basename} 在项目中存在多个同名文件时(如 check-list.vue 在 baseline-check/ 和 cloud-baseline-check/ 各有一个),L-import-abs 模式 B、L-template-tag、L-component-reg 的裸 basename 命中无法区分来源。必须执行精确路径反查——仅当命中的 import/标签路径包含正确的 {parent_dir}/{basename} 时才计入有效命中。详见 verification-patterns.md「同名校验」节。
各语言每层对应的精确 rg 模式见 verification-patterns.md。使用 rg 时,根据需要添加 --no-ignore 以搜索包括被 git 忽略的目录,添加 -l 仅列出匹配文件。
Python f-string 正则陷阱:在 Python 中使用 f-string 构建 rg 正则时,{ 和 } 是 Python 格式化占位符。如需在 f-string 中表示字面量 { 或 },必须写为 {{ 和 }}。更推荐的做法是避免在 Python 中构建正则,直接用 shell 变量或裸 rg 命令:
# 推荐:直接用 shell 变量
rel_path="dialogs/upload-certificate"
rg -l "from ['"]@/${rel_path}['"]" src/
# 不推荐:Python f-string 中容易出错
# f"rg "from ['"]@/{{{rel_path}}}['"]""
# ^^^ ^^^ 三重花括号极易写错
阶段 2 验证必须逐个文件输出结果:对每个候选文件,输出各层的命中数。零命中的层标记为 0。结果必须人类可审计——不可仅在脚本内部静默判断。
阶段 3:汇总与交叉验证
3.1 对每层命中结果(L-*),人工逐条核实:
- 子串误匹配:如
vul-list包含ul-list。用grep -v "vul-list"排除。 - 同名异文件:如
a/foo.vue被误判为引用了b/foo.vue。此问题主要在阶段 2 的「同名校验」步骤中解决——当检测到同名文件时,必须用精确路径反查替换裸 basename 匹配(见 verification-patterns.md 同名校验节)。阶段 3 交叉验证时再次确认:逐一检查每个命中的 import/标签路径,确保其引用的文件路径与候选文件完全一致,排除指向同名异文件的所有命中。 - 注释/文档引用:注释或文档中的引用不是代码引用。
- HTML 注释排除(Vue/React 必做):
中的组件标签不算代码引用。L-template-tag 层命中后必须用grep -v "注释包裹。rg "的裸匹配会命中注释中的标签,导致误判为 ALIVE。必须用" grep -v "