npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-patch-apply

v1.0.0

Published

dsh-patch-apply — apply structured unified diffs (git format) to the real filesystem inside DeepSeek Harness: multi-file/multi-hunk parsing, fuzzy hunk location with line-offset correction, all-or-nothing application with precise conflict reports, automat

Readme

dsh-patch-apply

在 DeepSeek Harness(dsh)以及任何 Node 运行时中,将结构化 unified diff(git 格式)应用到真实文件系统。

English documentation: README.md

dsh 官方只提供字符串级的 edit/write 工具,没有任何会落盘的结构化 diff 应用工具。dsh-patch-apply 填补了这一空白:它解析 unified diff,逐 hunk 应用(含模糊匹配与行号偏移修正),让整个过程要么全成功、要么全回滚,并在应用前生成反向补丁以实现字节级精确回滚(undo)。

零运行时依赖。TypeScript 源码、纯对象工具定义、使用 Node 内置测试运行器。


特性一览

  • 完整的 git diff 覆盖 —— 多文件、多 hunk、±/上下文/新增/删除、/dev/null 新建与删除、rename from/to、copy from/to、old mode/new mode、index SHA、\ No newline at end of file、二进制标记(Binary files … differ、GIT binary patch)、带空格引号路径。同时支持经典的无 git 头的裸 ---/+++ 补丁。
  • 自研解析器 —— 无重型依赖;解析器会把 hunk 头与实际行数严格校验,遇到格式错误立即给出精确的补丁行号。
  • 精确的 hunk 定位 —— 锚点精确匹配 → 全文精确匹配(行号偏移修正)→ 模糊匹配(前导上下文容错,GNU patch 风格)。删除行永远不会被模糊丢弃,因此模糊匹配绝不会误删内容。
  • 全有或全无的原子性 —— 任何写入发生之前,所有文件都在内存中完成解析与校验;一旦存在 hunk 冲突或结构性违规,什么都不写。
  • 版本守卫 —— 复用与官方 dsh 文件系统完全相同的身份配方(dev:ino:size:mtimeNs:ctimeNs,见「与官方 dsh fs 的版本守卫协同」);每次写入在发布前会重新校验身份,一旦漂移即报 STALE 并中止。
  • 随处可撤销 —— 在变更前计算反向补丁,并先写入 undo 日志;undo 可以字节级还原。同样覆盖新建、删除、重命名、复制与权限变更。
  • dry-run 模式 —— 静态校验可应用性;逐 hunk 报告冲突(期望/实际内容、hunk 序号、补丁行号),不改文件。
  • CRLF / LF 保真 —— 文件按<行, 各自行终止符>建模;未被触动的区域逐字节原样往返,包括混合换行与文件末尾无换行的情况。
  • 二进制安全 —— 二进制标记的文件会被跳过并报告;指向二进制目标的文本补丁会被识别(NUL 字节 / 非法 UTF-8)并跳过,绝不会破坏数据。

安装

作为 dsh bundle(推荐)

本包是标准 dsh bundle:package.json 声明 "dsh": { "bundle": { "patch": "./cordis.patch.yml" } },补丁会插入一行 Cordis 插件项,其模块导出 { name, inject, apply },并在工具注册表(ctx.tools) 上注册四个工具。

# 已发布到 registry
dsh plugin --profile <name> add dsh-patch-apply

# 或直接从此仓库安装
dsh plugin --profile <name> add github:JohnXu22786/apply-patch

# 或使用本地检出目录
dsh plugin --profile <name> add /path/to/apply-patch

无需其他配置——patch_apply、patch_dry_run、patch_reverse、patch_stat 立即可供模型调用。

可选插件配置(在 profile 中针对 patch-apply 行的后续补丁层,或直接写在该行的 config 中):

- config:
    id: patch-apply
    defaultRoot: /abs/path/to/workspace   # 相对补丁路径的基准目录(默认:process.cwd())
    io: node                              # node | ctx-fs(见下文)
    fuzzContext: 3                        # 模糊匹配最多可丢弃的前导上下文行数
    undo: true                            # patch_apply 是否持久化 undo 日志
    strictSha: false                      # 是否把 index 行 SHA-1 不匹配视为硬冲突

作为独立 CLI

npm install dsh-patch-apply          # 或从本地检出目录 link
npx dsh-patch --help

作为库

npm install dsh-patch-apply
import { applyPatchText, applyUndo, parsePatch, statPatch } from 'dsh-patch-apply'

使用

1. dsh 工具

| 工具 | 用途 | |---|---| | patch_apply | 应用 unified diff,全有或全无,带 undo 日志。 | | patch_dry_run | 校验可应用性;报告所有冲突;不写任何东西。 | | patch_reverse | 只生成反向补丁(先校验),不应用。 | | patch_stat | 汇总补丁(文件、hunk、+/−/上下文行数),不访问文件系统。 |

公共参数:

  • patch (string,必填) —— unified diff 文本。
  • cwd (string,可选) —— 相对路径的基准目录(默认:config.defaultRoot)。
  • dry_run / verify_sha (boolean,可选) —— dry-run 模式 / 硬性 SHA-1 校验。

patch_apply 返回:

{
  "ok": true,
  "dryRun": false,
  "files": [{ "path": "...", "operation": "modify", "hunks": [{ "hunkNumber": 1, "status": "offset", "atLine": 12 }] }],
  "conflicts": [],            // [{ file, hunkNumber, sourceLine, reason, expected[], actual[], anchorLine }]
  "errors": [],               // [{ code, path, message }]
  "notes": [],                // 信息性说明,例如 SHA-1 预检不匹配
  "reversePatch": "diff --git ...",
  "undoFile": "/abs/.dsh-patch-undo.json"
}

files 会列出每个已准备的文件操作及其逐 hunk 状态——成功时是已应用的结果, dry-run 时则是将要应用的结果。「全有或全无」的含义:只要 ok 为 false (conflicts/errors 任一非空),就保证什么都没写入;成功时则每个文件的每个 hunk 都已定位并提交。

2. CLI

dsh-patch <command> [options] <file>

Commands
  apply   <patch>    应用 unified diff(默认写入 undo 日志)
  dry-run <patch>    校验可应用性;报告冲突;绝不写入
  reverse <patch>    打印反向补丁(或用 --out 写入文件)
  stat    <patch>    汇总补丁,不访问文件系统
  undo    <journal>  应用 undo 日志中记录的反向补丁
  help               显示帮助

Options
  --root <dir>      相对补丁路径的基准目录(默认:cwd)
  --dry-run         apply 命令等同 dry-run 行为
  --no-undo         不写入 undo 日志
  --undo-file <p>   apply 的 undo 日志路径(默认:<root>/.dsh-patch-undo.json)
  --fuzz <n>        模糊匹配最多可丢弃的前导上下文行数(默认:3)
  --strict-sha      把 index 行 SHA-1 不匹配视为硬冲突
  --out <file>      反向输出写入文件而非 stdout
  --json            在 stdout 输出机器可读 JSON
  --help            显示帮助

退出码:0 成功 · 1 补丁无法应用 · 2 用法错误。

dsh-patch apply changes.patch --root /workspace
dsh-patch dry-run changes.patch
dsh-patch reverse changes.patch > revert.patch
dsh-patch undo .dsh-patch-undo.json

3. 库

import { applyPatchText } from 'dsh-patch-apply'

const report = await applyPatchText(patchText, {
  root: process.cwd(),          // 相对路径的绝对基准目录
  fuzzContext: 3,               // 模糊容错
  dryRun: false,                // 是否只校验
  undo: true,                   // 是否写入 undo 日志
  undoFile: '.dsh-patch-undo.json',
  strictSha: false,             // index SHA-1 不匹配是否视为硬冲突
})

其他导出:parsePatch、statPatch、applyUndo(journal)、 readJournal / writeJournal、blobSha、文件系统接缝 IoAdapter/NodeIoAdapter/CtxFsIoAdapter,以及各类带类型的错误类。


错误码

| 代码 | 含义 | |---|---| | PARSE | diff 格式错误;消息内包含补丁行号。 | | CONFLICT | hunk 无法安全定位;携带 hunk 附近的 期望/实际 内容。 | | VALIDATION | 应用前的结构性问题(覆盖已存在文件、目标缺失、路径越界)。 | | STALE | 校验与提交之间文件身份发生变化(版本守卫被触发)。 | | IO | 文件系统操作失败(写/chmod/unlink/…)。 | | BINARY | 二进制目标 / 二进制标记——跳过,绝不破坏。 | | UNSUPPORTED | 超出解析范围(如合并 diff --cc)或后端能力不足的动词。 |


工作原理

解析器(parse.ts)

一个状态机理解 git diff 的每个块以及经典的无头 ---/+++ 形式。每个 @@ 头都会在实际消费其正文行时核对行数——欠供或超供的 hunk 会立刻抛出带补丁行号的 PARSE 错误,因此被截断或损坏的补丁绝不会悄然误应用。

hunk 定位(locate.ts、engine.ts)

对每个文件,按顺序对当前内存缓冲逐 hunk 应用:

  1. exact —— 旧侧块在锚点(头行号减一,并按此前 hunk 的净增量平移)处匹配;
  2. offset —— 完整旧侧块在别处精确匹配;取离锚点最近者(修正行号漂移);
  3. fuzzy —— 允许丢弃最多 fuzzContext 行前导上下文来寻找螺栓。只有 上下文行可被丢弃(删除行必须精确匹配),且旧、新两侧丢弃同一前缀, 因此模糊匹配绝不会误删内容,也不会重复插入被模糊掉的上下文行。

若不存在安全位置,该 hunk 会作为冲突上报:包含 1 起始的 hunk 序号、补丁行号、 以及期望/实际内容的短摘录——整个补丁随即被拒绝,磁盘不被触碰。

原子性与回滚(apply.ts、io.ts)

  • 所有文件在内存中首先完成解析、读取与转换。任何冲突或结构性问题 ⇒ 什么都不写。
  • 反向补丁与(启用时的)undo 日志会在第一次变更之前写入,因此即使 提交中途崩溃,也始终存在完整的还原路径。
  • 内容写入逐文件原子(临时文件 + rename),按需创建父目录;随后做权限 变更;最后做删除 / 重命名源清理(先确保目标完整写好后,源才消失)。
  • 若提交中途任何一次写入/chmod/unlink 失败,会把已变更的每个文件从内存中的 原始内容恢复(尽力而为)并上报错误。跨多个 rename 无法用单次文件系统调用 实现物理原子性;提交前的校验才是把保证变为结构性的关键。

与官方 dsh fs 的版本守卫协同

官方 @deepseek-ai/dsh-fs 后端用 stat 身份与新鲜度派生出不透明的 FsVersion: dev:ino:size:mtimeNs:ctimeNs。本包在 NodeIoAdapter.probe().identity 中复刻了 完全相同的配方,因此这里产生的版本令牌与 Harness 产生的是同一含义。每次受守卫 写入前会在发布时重新探测身份,一旦漂移即以 STALE 中止并回滚——与官方 writeText(…, { kind: 'replaceIfVersion' }) 的过期保护契约一致。

两点配置说明(刻意保持解耦):

  • 默认 io: node —— 通过 NodeIoAdapter 直接访问主机。CLI 与整个测试套件 均在此模式下运行。
  • io: ctx-fs —— 解析/stat/读取/写入经由已挂载的 Harness ctx.fs 服务 (CtxFsIoAdapter),把受守卫的写入映射到后端自己的 createIfAbsent / replaceIfVersion 意图上,即版本守卫由后端自己执行。由于官方 Service Definition 没有 unlink/rename/chmod/mkdir 动词,需要这些操作的补丁会在 任何变更之前以精确的 UNSUPPORTED 报错,而不是做一些出人意料的事。 需要完整覆盖删除 / 重命名 / 权限变更时,请使用 io: node。

行尾符

文件被表示为 { text, sep } 行列表,sep 是该行自身的逐字终止符(\r\n、 \n,或末尾无换行时的 '')。补丁行仅按文本匹配,因此 CRLF 与 LF 文件都能 干净应用;补丁插入的新行继承文件的主导换行;\ No newline at end of file 标记(旧、新两侧独立)会把文件末尾无换行的状态正确传递下去。


开发

npm install
npm test          # 先 tsc 构建,再 node --test 运行 build/test/*.test.js
npm run build     # tsc -> build/
npm run typecheck # tsc --noEmit

测试布局:parse(格式覆盖 + 畸形输入定位精度)、apply(单/多文件、CRLF、 新建/删除/重命名/复制/权限、二进制、dry-run 纯净性、undo 往返)、fuzzy (偏移 / 模糊 / 拒绝路径、SHA-1)、conflict(报告精度)、rollback (全有或全无、注入 I/O 失败后的物理回滚、STALE 守卫)、cli(退出码、 JSON、reverse/undo 流程)。

许可证

MIT —— 见 LICENSE。© 2026 dsh-patch-apply contributors。