# dsh-protect-generated-files [English](README.md) | 中文 智能体会去改那些不该手改的文件。它会直接在 `pnpm-lock.yaml` 里改版本号,在 `user.pb.go` 里修错别字,或者"纠正" Prisma 生成的客户端里的类型。改完看起来没问题,直到下一次 `pnpm install` 或 `protoc` 把它冲掉;更糟的是,锁文件和 `package.json` 对不上,要花一下午才能理清。 这个 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 插件会拒绝对生成文件和锁文件的 `write` 和 `edit`,也会拒绝在命令行里原地修改它们(`sed -i`、`perl -pi`、`> file`、`tee file`)。它不是只说一句"不行",而是告诉模型这个文件应该怎么改(提示是英文的,模型能看懂): ``` dsh-protect-generated-files blocked this edit to db/query.sql.go: its header says it is generated (`// Code generated by sqlc. DO NOT EDIT.`). A hand edit will be overwritten the next time it is regenerated, or leave it out of sync with its source. Instead: edit the SQL queries/schema and run `sqlc generate`. ``` ## 安装 ```sh dsh plugin --profile web add dsh-protect-generated-files ``` 这里用的是 `web` 配置(profile),也就是用 `dsh web` 打开的浏览器界面。如果你用别的方式运行 DSH,就换成 `headless`(脚本和 CI)或 `acp`(编辑器集成)。每个配置有自己的插件列表,你用到哪个就装到哪个。装好就生效。卸载用 `dsh plugin --profile web remove dsh-protect-generated-files`。 ### 从源码安装 想试本地改动的话,打个包再装: ```sh git clone https://github.com/acus9345/dsh-protect-generated-files cd dsh-protect-generated-files npm install npm pack dsh plugin --profile web add ./dsh-protect-generated-files-0.2.0.tgz ``` ## 怎么判断一个文件是生成的 有三种情况会被认定为生成文件。 **锁文件,按名字。** `package-lock.json`、`pnpm-lock.yaml`、`yarn.lock`、`bun.lock(b)`、`deno.lock`、`Cargo.lock`、`go.sum`、`poetry.lock`、`uv.lock`、`pdm.lock`、`Pipfile.lock`、`Gemfile.lock`、`composer.lock`、`mix.lock`、`pubspec.lock`、`Podfile.lock`、`flake.lock`、`gradle.lockfile`、`packages.lock.json`、`conan.lock`。每种都配有对应包管理器的正确命令,比如"用 `cargo add / cargo update -p ` 修改依赖"。 **已知的输出路径。** Protobuf 输出(`*.pb.go`、`*_pb2.py` 等)、Dart `build_runner` 的输出、`.Designer.cs`、压缩文件和 source map,以及 `node_modules/`、`__generated__/`、`.venv/`、`site-packages/` 里的所有文件。构建输出目录(`dist/`、`target/`、`.next/`、`vendor/` 等)只有在旁边有 `package.json`、`Cargo.toml` 或 `go.mod` 这类项目清单时才算,所以一个恰好叫 `target` 的源码目录不会被误伤。 **文件头写明了。** 它会读文件的前 15 行,找 `Code generated ... DO NOT EDIT`、`@generated`、`DO NOT EDIT`、`auto-generated`、`This file was generated`、`` 或 `Generated by <工具>` 这样的注释。如果文件头说可以编辑("edit freely"、"safe to edit"),或者是带条件的 `DO NOT EDIT without ...`,就不算。文件头提到它认识的工具时,提示也会点名那个工具:protoc/buf、Prisma、GraphQL Codegen、OpenAPI 生成器、sqlc、`go generate`、Drizzle、Alembic 等。"Generated by hand"和"generated by ChatGPT"不算。 文件头检查只针对已经存在的文件。名字和路径规则对新文件也有效,因为从零手写一个锁文件同样不对。 在 Windows 上,DSH 用 PowerShell 运行命令,插件也会检查 `Set-Content`、`Add-Content`、`Out-File` 和 `Tee-Object`。 ## 什么时候手改是对的 确实有这种时候:解决锁文件的合并冲突,或者等上游修复时在 vendor 代码里临时改一行。模型会被告知,可以把同样的调用原样重发一次来确认,第二次会放行。如果你想自己审批,用 `mode: ask`。如果某个目录看起来像生成的,其实是手工维护的,把它加到 `ignore` 里。 ## 设置 最简单的办法:在 DSH 侧边栏打开 **插件**,点 **dsh-protect-generated-files**,改好后点 **保存**。下一次工具调用就生效,不用重启。 或者在 `~/.dsh/profiles//cordis.patch.yml` 里加一行这样的配置(只影响一个配置),或者加到 `~/.dsh/cordis.patch.yml`(影响所有配置)。没写的项保持默认值。 ```yaml - id: protect-generated-files config: mode: deny # 或 `ask`,改为弹出审批 extraGlobs: # 你自己的生成文件路径,以及给模型的提示 'src/api/client/**': 'edit openapi.yaml and run `npm run gen:api`' ignore: ['vendor/**'] # 永远不视为生成文件 defaultGlobs: true # false:只认锁文件、文件头和 extraGlobs headerLines: 15 guardShell: true # 也检查 sed -i / perl -pi / > / tee allowIdenticalRetry: true # false:拒绝后不能再重试通过 shellTools: [bash, pwsh] # Windows 上 DSH 用的 shell 是 pwsh ``` 最值得设置的是 `extraGlobs`。告诉模型哪个脚本负责重新生成你的代码,它就不用去猜了。提示是给模型看的,用中文或英文写都可以。 ## 开发 ```sh npm install npm test # 检测逻辑的单元测试 npm run test:e2e # 用脚本模拟的本地模型跑真实的 dsh,不需要 API Key ``` 安装测试会执行 `dsh plugin add`,需要 PATH 里有 `pnpm`。 MIT 许可。作者 [acus9345](https://github.com/acus9345)。欢迎在 issues 里报 bug 或提想法。