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-file-claim

v0.2.0

Published

Write in parallel, never overwrite — file claim / protection for concurrent DeepSeek Harness (DSH) sessions working the same workspace: claim/release, heartbeat stale takeover, and an async pending merge area (git 3-way merge)

Readme

dsh-file-claim

English 简体中文

npm version npm downloads CI License: MIT node

并行写作,永不覆盖。 同一工作区并行 DeepSeek Harness (DSH) 会话的文件认领/保护插件。

多个 DSH 会话并行操作同一工作区时,彼此毫无感知:两个会话可能覆盖同一文件、崩溃会话留下 陈旧状态、想改他人已占文件的会话只能干等或赌。dsh-file-claim 把一套久经验证的协调协议做成 原生 DSH 工具、生命周期事件与写入守卫——让并行 Agent 协作而非互相踩踏。

claim_files({ paths: ["README.md"] })   # 「我来改这个文件」
write / edit ...                          # 写他人认领的文件会被拒绝
release_files({ paths: ["README.md"] })  # 「改完了」——等待中的 pending 编辑现在自动合并

目录

特性

  • 🔒 claim / release —— 会话在编辑前声明对文件路径的独占认领;重复认领幂等合并,目录 认领覆盖其下所有路径,'.' 认领整个工作区。
  • ❤️ 心跳 + stale 接管 + 孤儿自愈 —— 心跳经 agent 生命周期事件自动刷新;崩溃/强杀的会话 认领在下一次活动时立即清除(按进程 pid 检查),心跳间隔兜底清扫;staleMs(2h,针对 无 pid 的旧记录)与 --force 接管仍是慢速兜底。
  • 🧩 异步 pending 合并区 —— 不阻塞:会话把「改好的新内容 + git HEAD base」写入待合并区; 持有者 release 后自动尝试 git 三路合并(current × base × pending),无冲突即落盘; 冲突时 pending apply 手动处理。
  • 🛡️ 写入守卫 —— tools/pre-execute 拒绝写他人活跃认领文件的工具调用,附建议 (等待 / stale 后接管 / 写入 pending),并有可选的 commit 级守卫。
  • ⚡ 零自动化负担 —— agent/created / agent/status 自动刷新心跳,agent/disposed 自动释放离开会话的全部认领。
  • 📦 纯 Host 插件、零依赖 —— 无 Browser 侧、无构建步骤,只用 node: 内置模块; Windows 友好。
  • 🧾 审计日志 —— 每次 claim / release / 接管 / pending 变更追加一行 JSON,供追溯与 崩溃后核对。

为什么需要它

DSH 宿主无内建跨会话文件保护;505 个 dsh-plugin topic 仓库全量扫描零命中 文件认领/协调类插件。pending 合并区——现在写下改动、持有者释放后干净合并——在 agent 文件锁品类内独有。这是填补空白而非重复造轮子。

与同类方案对比

对照 11 个 Claude Code / Codex 文件锁与协调工具(claude-code-file-locks、parallel-sessions、 guardex、agent-orchestrator、blackboard-mcp、mclaude、ruah-orch、knot 等):

| 差异化 | dsh-file-claim | 同类方案 | | --- | --- | --- | | 冲突处理 | pending 异步区 + git 三路合并——先写入、对方释放后干净合并 | 只能等待/拒绝(「锁→写→释放」) | | 目标平台 | DSH 原生——身份、工具、事件、守卫、命令全集成 | Claude Code / Codex hooks;无一面向 DSH | | 平台支持 | 零依赖 Node,Windows 友好 | Bash/jq/flock 方案偏 macOS/Linux;guardex 无原生 Windows | | 存储 | 工作区边车——<file>.dshclaim 贴在被保护文件旁(.agentlock 惯例) | 中央状态目录(.coord/、~/.claude/…)或 worktree 硬隔离 | | 强制层 | 工具层协作式护栏(fail-open,与品类事实标准一致) | hook 拦截/声明式锁;头部工具退化为 worktree 硬隔离 |

安装

dsh plugin add dsh-file-claim

开发/手工验证(本地 checkout):

dsh plugin --profile web add -w link:<仓库路径>

要求 DSH 环境 node >= 18,且 git 在 PATH 中(仅三路合并时使用)。

快速开始

  1. 先认领,再落笔。 要改文件?先调用 claim_files 声明独占认领,其他会话就不会碰它。
  2. 放心写。 自己的认领永不阻塞自己;写入被其他活跃会话认领的文件会被拒绝,并附带提示 (等待 / 对方 stale 后接管 / 写入 pending)。
  3. 文件被占?别干等——写入 pending。 用 pending_write 把改好的内容(含 git HEAD base) 放进待合并区。持有者 release_files 后自动三路合并(无冲突即落盘);冲突时 pending_apply 手动处理。
  4. 写完释放。 release_files 清空认领、自动合并等待中的 pending 条目,并浮出需要手动 处理的条目。
claim_files({ paths: ["README.md", "src/"] })
write / edit ...
release_files({ paths: ["README.md"] })

使用示例

两个会话,一个工作区。 会话 A 持有 README.md;会话 B 也想改它:

// 会话 A
claim_files({ paths: ["README.md"], note: "重写文档" })
write  ...  README.md          // 允许:自己的认领
release_files({ paths: ["README.md"] })

// 会话 B —— 同时进行
who_claims({ paths: ["README.md"] })          // → 被 A 认领
write ... README.md                           // → 拒绝并附提示
pending_write({ path: "README.md", content: "..." })  // 异步,不阻塞
// A release 后条目自动三路合并(或浮出供手动 pending_apply)

从崩溃会话恢复。 会话 A 中途崩溃;其认领在 staleMs(默认 2h)后过期:

claim_status()                      # → A 显示 [stale]
claim_files({ paths: ["README.md"], force: true })   # 接管

工具

8 个模型可见工具(身份即调用会话,无需 --as):

| 工具 | 用途 | | --- | --- | | claim_files | 编辑前独占认领文件/目录(paths、可选 note、stale 接管用 force) | | release_files | 释放指定路径(paths)或全部(all) | | who_claims | 只读:查询路径被谁认领 | | claim_status | 只读:会话登记、认领、待合并区总览与最近审计 | | pending_write | 异步写:目标被其他活跃会话占用时,把改好的内容(+ git HEAD base)写入待合并区 | | pending_apply | 三路合并 current × base × pending 落盘;无冲突自动清除,冲突写标记 | | pending_show | 只读:查看某待合并条目的元信息与内容 | | pending_drop | 丢弃某待合并条目(不合并) |

命令

人工可用的斜杠命令(与上述工具同语义——模型不可用或习惯命令行时使用)。命令名后的行按 引号感知分词,含空格的路径与备注可用(--note "多 行 备注")。命令执行只记入会话日志, 绝不进模型历史。

| 命令 | 用途 | | --- | --- | | /claim <path>... [--note <备注>] [--force] | 独占认领文件/目录;--force 接管 stale 持有者 | | /release [<path>... \| --all] | 释放指定路径或全部 | | /claim-status | 只读:会话登记、认领与待合并区总览 |

纯逻辑核心同时提供 CLI:node claim.mjs status | audit [n] | claim ...——语义相同, 无需 DSH 环境。

写入守卫

tools/pre-execute 拒绝 write / edit / bash / pwsh 调用中目标路径被其他活跃会话 认领的情况。拒绝信息带持有者与建议:等 release_files、对方 stale 后 claim_files(force: true) 接管、或 pending_write 异步写入。read 不拦截——读取是观察不是修改,认领契约只保护写面。 shell 路径解析(bash/pwsh)为尽力而为:只提取重定向目标与显式写命令的目标参数 (pwsh Set-Content / Add-Content / Out-File / New-Item / Copy-Item / Move-Item / Remove-Item / Rename-Item;bash tee / dd of= / cp / mv / rm)。引号字面量绝不 视为写目标——它们是数据/URL/模式,不是要写的文件;解析不出目标即放行(fail-open)。

开启 guardCommit: true 后,git commit 显式提交其他会话活跃认领路径(git commit -- <path> 或老语法 git commit <path>)也会被拒绝;提交信息(message)绝不检查,裸 git commit(无路径) 放行——其改动范围无法获知。

配置

在 bundle(cordis.patch.yml)中作为插件 config 传入:

| 键 | 默认 | 含义 | | --- | --- | --- | | staleMs | 7200000(2h) | 心跳过期多久视为 stale | | guard | true | 设 false 关闭 pre-execute 写入守卫 | | guardCommit | false | 可选:额外拦截 git commit 显式提交其他会话活跃认领的路径 | | heartbeatMs | 600000(10min) | 兜底心跳间隔 |

- insert:
    - id: dsh-file-claim
      name: dsh-file-claim
      config:
        staleMs: 3600000        # 1 小时
        guardCommit: true       # 同时守卫显式 git commit

0.2.0 起状态以工作区边车文件存储——锁状态贴着被保护的文件走(对标 claude-code-file-locks 的 .agentlock 惯例;之所以不造命名空间目录,是因为 DSH 并没有在工作区保留任何 .dsh/ 之类的约定目录):

README.md.dshclaim                 认领边车(JSON:version, path, tag, note, startedAt, lastSeenAt, pid)
README.md.dshpending/              待合并边车(content / base / meta.json),与被保护文件同目录
.dsh-file-claim.audit.jsonl        工作区全局审计日志(追加式,位于仓库根)
.dsh-file-claim.lock               瞬态跨进程互斥锁(仅在变更时短暂存在)

建议加入 .gitignore:

*.dshclaim
*.dshpending/
.dsh-file-claim.audit.jsonl
.dsh-file-claim.lock

工作区仍存在 ≤0.1.7 的平铺 .dsh-file-claim/ 目录(或未发布 0.2.0 的 .dsh/dsh-file-claim/)时,第一次 工具/命令调用会迁移成边车(旧目录原样保留——确认无误后可手动删除;其 registry.json 改名为 registry.json.migrated 作为幂等标记);迁移发生前的写入守卫也直接读旧注册表,升级期间保护无缝衔接。 状态跨重启保留;绝不触碰 .git/。

审计日志

每个业务变更——claim、接管、release、pending 写/apply/drop、prune、drop——都以一行 JSON 追加到 .dsh-file-claim.audit.jsonl({ at, tag, type, paths/path, detail }),供追溯与崩溃后核对。 心跳刻意不记(避免噪音)。node claim.mjs audit [n] 打印最近 n 条(默认 10); claim_status 恒显示最近 3 条。审计只追加、不参与也不改变认领语义;审计写入失败只会提示 警告行,不阻断操作。文件超过 1MB 自动轮转(保留最近一半 + 新条目),不会无限增长。

Pending 合并区

存储布局(被保护文件旁的边车目录):

<relpath>.dshpending/content     待合并的新文件内容
<relpath>.dshpending/base        写入时 git HEAD 版本(合并 base)
<relpath>.dshpending/meta.json   { pender, claimedBy, at, baseSha }

写入条件:pending_write 要求目标被其他会话活跃认领——否则应 claim_files 后直接写。 base 仅在 git HEAD 含该路径时记录;无 base 是刻意标注的不可自动合并条目。

apply 语义(pending_apply):用 git merge-file 对 current × base × pending 三路合并 (三个真实文件快照暂存临时目录)。无冲突 → 合并内容落盘并清除条目;有冲突 → 带冲突标记的 合并结果落盘且条目保留供手动解决;缺 base → 拒绝,绝不盲合;任一会话仍活跃占用 → 拒绝直至释放。

release_files 带解锁检查:指向被释放路径(或释放会话)的待合并条目会自动尝试三路合并 ——无冲突即落盘并清除条目;无法自动合并(仍被占用 / 缺 base / 冲突 / 文件缺失)的条目保留, 并附 pending_apply / pending_show / pending_drop 手动处理提示。

拦截边界

守卫是协作式护栏,不是强制锁:任意 shell 命令(echo > file、git checkout、脚本)、 外部编辑器、IDE/git 操作完全绕过工具栈。它把「靠 AGENTS.md 自律」升级为「工具层护栏 + 模型可见状态」,与整个品类的 fail-open 定位一致。

常见问题

bash/pwsh 写入能完全拦截吗? 不能。只解析重定向目标与显式写命令的目标参数;任意 shell、 脚本、外部编辑器与 IDE/git 操作都绕过工具栈。这是文档化的协作边界,不是缺陷——见 拦截边界。

崩溃会话的认领多久清除? 正常立即:每个会话记录携带进程 pid,任何会话活动 (claim / release / sync / prune)都会清扫 pid 已死的记录——崩溃/强杀在下一次活动时即刻 清除,无需等待。agent/disposed 对正常离开的会话即时释放;staleMs(默认 2h)只是无 pid 旧记录(如旧版本写入)的慢速兜底。

支持多仓库并行吗? 支持。认领根 = 会话 cwd 解析出的工作区(workspaceRegistry), 无工作区时回退 cwd——多仓库天然隔离。

状态存在哪? 工作区边车文件:每个被认领文件旁的 <目标>.dshclaim、每个待合并目标旁的 <目标>.dshpending/、仓库根的 .dsh-file-claim.audit.jsonl。按上面的 gitignore 规则加入 .gitignore;跨重启保留,绝不触碰 .git/。从 ≤0.1.7 升级的工作区,旧 .dsh-file-claim/ 里的状态会在第一次工具/命令调用时迁移成边车(旧目录保留,确认后可手动删除)。

为什么模型看不到 claim 工具? 模型可见工具取决于部署的工具展示/限制(与所有插件工具 相同)。插件经 ctx.tools.register 全局注册,与官方工具包同一路径。

pending 条目无法合并怎么办? 条目保留并附原因(仍被占用 / 缺 base / 冲突 / 文件缺失)。 用 pending_show 查看、pending_apply / pending_drop 处理——绝不盲合。

认领边车与审计文件会无限增长吗? 不会。stale 会话的边车在心跳间隔被自动清理(离开会话的 记录不会累积);.dsh-file-claim.audit.jsonl 超 1MB 自动轮转。两者在正常使用下都保持有界。

开发

npm test        # node --test:claim.mjs 单测(20)+ index.mjs mock ctx 集成(13)
npm pack --dry-run

结构:claim.mjs 是零依赖纯逻辑核心(可移植,保留 CLI 入口);index.mjs 是唯一宿主面文件; test/ 覆盖两者。CI 跑测试、双语 README 结构同步检查与 pack dry-run。

相关项目

  • dsh-chat-import —— 姊妹 DSH 插件,本插件的 session.mjs 协调协议移植并增强自该项目。
  • awesome-dsh-plugin —— DSH 插件生态索引 (本项目调研时扫描过 505 个仓库)。
  • @deepseek-ai/dsh —— DeepSeek Harness 宿主。

许可证

MIT —— 见 LICENSE。