配置与报告
本页适用于 0.35.0。
Deslop 从两处读取设置:
.deslop.toml— 与代码放在一起、并纳入版本管理的文件。项目级策略写在这里:跳过什么、隐藏什么、何时让 CI 失败。- 命令行参数 — 单次运行的覆盖项。参数始终优先于对应的配置键。
本页是一份参考手册。需要循序渐进的教程,请从快速开始读起。
.deslop.toml 文件
文件位置
Deslop 会在扫描根目录(你指向的目录)中查找 .deslop.toml。用 --config 可以指向别处:
deslop . # 若存在则使用 ./.deslop.toml
deslop ./src --config ci.toml # 显式指定配置,文件名任意
缺少配置文件不算错误 — Deslop 会按下文的内置规则运行。
格式
TOML 格式:一个共享的 [defaults] 区段,外加可选的按语言覆盖区段和四个行为区段。模式是带 gitignore 语义的 glob 模式,相对扫描根目录解析 — 无论仓库在磁盘上位于何处,subdir/** 都匹配 <扫描根>/subdir/...。
exclude 与 report_hide — 核心区别
这两层做的事不同,区别很关键:
| 会发生什么 | 适用于 | |
|---|---|---|
exclude |
文件在分析前被丢弃 — 既不解析,也不指纹化。 | 第三方代码、构建产物,以及任何你永远不想参与比较的内容。 |
report_hide |
文件会被分析,但每处出现都被标记为隐藏。只有当一个簇的全部成员都是隐藏的时,它才会从报告中移除。 | 生成的代码。你仍然想知道何时手写代码与某个生成文件重复了。 |
这种不对称是刻意的。report_hide 让"生成代码与自身重复"不进入头条,同时仍然暴露"你的代码与生成代码重复"的情况 — 因为那个簇至少有一个非隐藏成员,所以它会保留下来。
[defaults]
应用于每个文件,与语言无关。
[defaults]
exclude = [
"**/node_modules/**",
"**/dist/**",
"vendor/**",
]
report_hide = [
"**/*.snapshot.cs",
]
[defaults.boilerplate]
imports = "report"
| 键 | 类型 | 默认值 | 含义 |
|---|---|---|---|
exclude |
glob 列表 | [] |
从发现阶段丢弃的文件。与内置 exclude 叠加。 |
report_hide |
glob 列表 | [] |
会被分析但从渲染报告中隐藏的文件。与内置隐藏规则叠加。 |
boilerplate.imports |
"suppress" | "report" |
"suppress" |
如何处理仅由 import / 序言构成的克隆。suppress 静默丢弃;report 仍抑制克隆告警,但发出一条低严重度的整洁度提示。 |
[language.<name>]
按语言的覆盖区段。名称是解析器的语言 id:csharp、rust、python、dart、javascript、typescript、tsx、php、fsharp 或 go。这里的模式扩展默认值 — 永不替换 — 因此一个 .cs 文件会同时针对 defaults.exclude 加上 language.csharp.exclude 进行测试。
[language.csharp]
report_hide = ["**/Migrations/**"]
[language.python]
exclude = ["**/conftest.py"]
[language.dart.boilerplate]
imports = "report"
每个覆盖区段都接受与 [defaults] 相同的三个键:exclude、report_hide 和 boilerplate.imports。
[threshold] — CI 门禁
[threshold]
max_duplication_percent = 20
| 键 | 类型 | 范围 | 含义 |
|---|---|---|---|
max_duplication_percent |
浮点数 | 0.0–100.0 |
当全仓库的 duplication_percent 超过此值时,deslop 以 3 退出并使 CI 失败。 |
这是唯一需要显式启用的失败路径。没有 [threshold] 区段(且没有 --fail-over)时,无论发现多少重复,deslop 始终以 0 退出。命令行 --fail-over 参数会覆盖此键;--no-fail-over 会在单次运行中清除它。参见下文的退出码。
[analysis]
[analysis]
allow_cross_language_comparison = false
include_dependencies = false
incremental = true
| 键 | 类型 | 默认值 | 含义 |
|---|---|---|---|
allow_cross_language_comparison |
布尔 | false |
为 true 时,候选克隆对可以跨越不同语言。默认关闭,使报告聚焦于同语言重构。 |
include_dependencies |
布尔 | false |
连依赖树一起分析。默认关闭:否则最严重者优先的排序会把你无法修改的重复排在自己的代码之上。 |
incremental |
布尔 | true |
复用磁盘上的解析缓存。设为 false 则每次运行都完整重新解析,且对所有入口生效 —— CLI、编辑器与智能体皆然。 |
max_average_line_bytes |
整数 | 200 |
用于识别大型压缩构建产物的平均行字节数上限。 |
[report]
[report]
split_by_language = false
| 键 | 类型 | 默认值 | 含义 |
|---|---|---|---|
split_by_language |
布尔 | false |
将 HTML 报告按语言划分为各自的区段。--split-by-language 参数也能开启它 — 任一来源都会生效。 |
[ranking]
克隆按重复质量排名:参考语法树节点数 × 额外可见副本数。类别和置信度不会乘入质量。
隐藏仅供参考的形状匹配:
[ranking]
structural_only = "ignore"
structural_only 接受 demote(默认)、ignore 或 keep。可见的仅形状匹配仍排在克隆之后,重复质量为零;任何设置都不会让它计入重复率。VS Code 设置优先于此文件。data_clones = "ignore" 会在排名前排除数据类发现。
内置规则(始终生效)
压缩和打包产物还会根据已识别的文件后缀及可配置的平均行长度检查被排除。体积大但可读的源码仍可分析。生成文件标记从解析后的注释中读取,字符串中的标记不算文件头。
这些规则先于用户模式生效。排除规则移除待分析文件;报告隐藏规则保留分析,但隐藏出现位置。
构建产物与工具缓存,一律排除且无法重新纳入 —— 它们都不是你写的源码:
target dist build __pycache__ .dart_tool .git .claude
依赖树,除非你设置 [analysis] include_dependencies = true,否则一律排除:
node_modules vendor .cargo .pub-cache .venv
始终从报告中隐藏(会被分析,但不进入头条):
- 目录组件
generated/。 - 相邻组件对
alembic/versions、test/fixtures、tests/fixtures— 除非该对本身就是你的扫描根,从而让你能够刻意分析一个夹具语料库。 - 文件后缀:
.g.cs、.generated.cs、.designer.cs、.pb.cs、.openapi.cs、.generated.py、_generated.py、.g.dart、.freezed.dart、.gr.dart、.config.dart、.gen.dart、.mocks.dart、.pb.dart、.pbenum.dart、.pbjson.dart、.pbserver.dart、.pbgrpc.dart。 - 任何以生成器横幅开头的文件——横幅必须是位于第一行代码之上的一整行注释,例如
// GENERATED CODE - DO NOT MODIFY BY HAND、// Code generated … DO NOT EDIT.、// <auto-generated>、// @generated或# Generated by the protocol buffer compiler. DO NOT EDIT!。句子中的短语、字符串或位置更靠后的注释都不算,因此仅仅提到生成器的手写文件仍会留在报告中。完整的横幅列表见规范;不在列表中的生成器,只需添加一条report_hide模式即可隐藏。
一个完整示例
# 在各处跳过第三方代码和构建产物。
[defaults]
exclude = [
"**/node_modules/**",
"**/dist/**",
"third_party/**",
]
report_hide = [
"**/*.snapshot.cs",
]
# 对仅由 import 构成的克隆给出整洁度提示,而非静默丢弃。
[defaults.boilerplate]
imports = "report"
# C# 数据库迁移是生成的 — 分析但隐藏它们。
[language.csharp]
report_hide = ["**/Migrations/**"]
# 全仓库重复超过 20% 时让 CI 失败。
[threshold]
max_duplication_percent = 20
# 将 HTML 报告按语言拆分。
[report]
split_by_language = true
# 隐藏仅供参考的形状匹配。
[ranking]
structural_only = "ignore"
命令行参数
每次运行也接受参数。在该次运行中,参数会覆盖对应的 .deslop.toml 键。
| 参数 | 默认值 | 含义 |
|---|---|---|
PATH |
. |
要分析的目录(位置参数)。 |
--min-nodes <N> |
30 |
构成克隆候选的最小 AST 子树节点数。越大 = 克隆越少、越大。 |
--output <PREFIX> |
.deslop/deslop-report |
报告的基路径;会追加 .json / .txt / .html。日志一并写入 <dir>/logs/。 |
--config <FILE> |
<root>/.deslop.toml |
显式配置文件。 |
--split-by-language |
关 | 每种语言一个 HTML 区段(等同于 [report] split_by_language)。 |
--nojson / --notext / --nohtml |
全开 | 抑制单一输出格式。至少需保留一种。 |
--fail-over <PERCENT> |
— | 重复超过 PERCENT 时以 3 退出。覆盖 [threshold]。 |
--no-fail-over |
— | 在该次运行中清除任何阈值;绝不以 3 退出。 |
--technical |
关 | 在 stderr 上显示研究者视图(分类 id、信号字母、节点数)。 |
--diff <FILE> |
— | 将报告限定到统一 diff 的新增行;- 表示从 stdin 读取。扫描仍覆盖整棵树。与该树不匹配的 diff 会被拒绝。 |
--only-changed |
关 | 丢弃未命中 diff 的簇,并让 --fail-over 按 diff 范围内的占比判定,使历史欠债无法让合并前检查失败。需要 --diff。 |
比较两个出现位置
--compare 在 0.35.0 中加入。传入两个 <path>:<start_byte>:<end_byte> 端点,使用 JSON 报告中的确切字节范围:
deslop . --compare "::" --compare "::"
命令先扫描根目录,重新计算配对证据,再向 stdout 输出 JSON 判定。偏移量按字节而非行计,结束位置不包含在范围内。范围必须对应已生成指纹的出现位置;簇 ID 不能用作端点。
嵌入
混合嵌入层默认关闭;Deslop 不依赖它即可提供结构与词法信号。在你有可用提供方时再开启。
| 参数 | 默认值 | 含义 |
|---|---|---|
--embeddings <MODE> |
off |
off 跳过嵌入;auto 探测提供方,不可用时带告警回退;required 在提供方不可达时硬失败。 |
--embedding-provider <ID> |
ollama |
提供方注册键。目前仅实现了 ollama。 |
--embedding-model <MODEL> |
nomic-embed-text |
提供方所理解的模型 id(对 Ollama 即 ollama list 中的名称)。 |
--embedding-endpoint <URL> |
http://127.0.0.1:11434 |
提供方端点。 |
日志与颜色
| 参数 | 默认值 | 含义 |
|---|---|---|
--log-to-console |
关 | 将日志发往 stderr,而非带时间戳的 deslop-<timestamp>.log 文件。 |
--log-level <LEVEL> |
info |
error | warn | info | debug | trace。被 RUST_LOG 覆盖。 |
--no-color |
关 | 关闭 stderr 前导与摘要中的颜色。 |
--no-incremental |
关 | 禁止读写 <root>/.deslop/cache/ 下的磁盘指纹缓存和嵌入缓存。报告和日志仍会正常写出。 |
开发与模拟参数
这些参数绕过或重放流水线,不属于常规使用:--from-report <FILE> 将已有的 JSON 报告重新渲染为 .txt/.html;--debug-ast <FILE> 打印单个文件的归一化 AST 后退出;--rerun-touch、--rerun-remove 和 --rerun-add 通过增量会话重放文件变更,以演练实时更新路径。
优先级与环境
当同一项设置来自多处时,由谁胜出如下:
- 阈值:
--no-fail-over→--fail-over <n>→[threshold] max_duplication_percent→ 关闭。 - 按语言拆分:
--split-by-language参数或[report] split_by_language— 任一项都会启用。 - 排名(
structural_only): VS Code 扩展设置覆盖.deslop.toml。
另有两个环境变量同样生效:
RUST_LOG— 以标准tracing过滤器语法覆盖--log-level。NO_COLOR— 即使没有--no-color也关闭颜色。当 stderr 不是终端时也会自动抑制颜色。
报告输出
普通扫描默认生成 JSON、文本和 HTML,除非禁用了某种格式。JSON 才是产品本身;文本和 HTML 是基于同一份数据的渲染器。TXT 或 HTML 中不会出现任何 JSON 里没有的结论。
JSON — 规范格式
deslop-report.json 是智能体读取的内容,也是 schema 消费方应当解析的内容。逐字段的完整结构参见面向 AI → 读取 JSON。
保证:
- schema 中标记为
optional的字段可能缺失。标记为required的字段始终存在。 - 克隆按
mass降序排列,相同时用稳定 ID 排序。参考信息排在克隆之后,没有克隆排名。 - UTF-8。无 BOM。LF 行尾。
TXT — 终端格式
deslop-report.txt 是供终端和 CI 日志读取的逐行报告。克隆条目按排名显示类型、整数质量、出现次数和源位置。配对相似度需要单独请求;报告不会声称提取必然安全。
HTML — 可移植格式
deslop-report.html 是单个文件。所有 CSS 均已内联。无网络请求。把它放进 CI 工件、用邮件发送、在飞机上打开 — 它都能渲染。
HTML 渲染器使用与 JSON 和 TXT 相同的排名和相同的簇摘要。它额外提供:
- 语法高亮的示例代码片段,过长的片段和额外的出现位置会折叠进可展开的开关中
- 每个重复组上的「AI 匹配」徽章和影响力标签
- 在可折叠的「运行详情」页脚中,每组一张信号表(结构 / 词元 / 嵌入 / 融合)
它不会额外提供:JSON 中没有的评分、超出 summary 字段的评论,或指向外部服务的链接。
文件写到哪里
Deslop 写出的一切都会进入被扫描项目根目录下的单个 .deslop/ 目录,或你通过 --output 传入的前缀。若只想生成 JSON 报告,请抑制另外两种格式:
deslop . --notext --nohtml # 写入 .deslop/deslop-report.json
诊断信息与报告是分开的。默认情况下,诊断信息通过带结构化字段的 tracing 写入一个带时间戳的日志文件(.deslop/logs/deslop-<timestamp>.log);传入 --log-to-console 可改为将其发送到 stderr。人类可读的前言和摘要始终输出到 stderr。
退出码
| 退出码 | 含义 |
|---|---|
0 |
已完成。重复低于阈值,或未设置阈值。 |
1 |
运行时错误 — 扫描路径不存在、分析失败、I/O 错误,或一个标记为 required 的嵌入提供方无法访问。 |
2 |
用法错误 — 未知标志,或超出范围 / 非有限的阈值,在运行开始前即被拒绝。 |
3 |
阈值被突破。 完整报告仍会写入磁盘,以便呈现这些重复。 |
失败通过这些退出码和 stderr 上的结构化错误呈现。
退出码 3 是 CI 门禁。它只在你主动启用时才会触发 — 通过传入 --fail-over <percent>,或设置 [threshold] max_duplication_percent。详见基于重复阈值设置 CI 门禁的演练,或直接使用 GitHub Action。