跳到正文

DSCODE

一个建在 DeepSeek Harness 上的 macOS 终端编码 agent:自带一份钉住的 harness profile、把上游终端整包接管并在构建时打补丁,再补上宿主没有的会话层——会话之间可以互相发消息、Ultra 子代理、由独立模型复核的批准、定时运行。

Screenshot of DSCODE
编辑截图, 30 Sep 2026DSCODE ↗

这是什么

DSCODE 是给 macOS 用的终端编码 agent,建在 DeepSeek Harness 上。它的前提是同一台机器上的会话应当彼此可见:一个会话能读另一个的对话记录,用 dscode send <session-id> --steer "review the change in parser.ts and reply" 把活交出去,用 /btw 让一个只读子会话回答旁支问题、而且不进主对话,或者用 /delegate <task> 把任务摊在一块板上、把就绪的部分派给各自 git worktree 里的子代理。默认是 workspace-write 沙箱,批准交给独立模型复核(/permission auto-review)。装法是 npm install -g @toddzheng024/dscode,然后 cd /path/to/project 再敲 dscode;首次启动会从 DSH Plugin Hub 装一份钉住的 preset,/login 把 DeepSeek API key 以 0600 权限存进 ~/.dscode/credentials.yaml。另外还有 Homebrew(brew tap qiz029/tap && brew trust qiz029/tap && brew install dscode)、一行安装脚本和源码检出三条路。环境要求 macOS 14+、Node 22.19+ 或 24+、Git 与 Chrome;dscode exec "prompt" 可以在脚本里跑完一整轮。

谁做的仓库的贡献者列表只有一个人:账号 qiz029,123 次提交全部挂在它名下,提交署名 todd.zheng,邮箱 toddzheng024@gmail.com,MIT 许可证上写的是 Todd Zheng,npm scope 也是同一个 handle。这是字面意义上的一人项目——没有第二位贡献者,没有机器人账号;这份记录所依据的材料里也没有关于作者的其他公开记录。

它是怎么搭起来的

组成 · 6

形状是一层发行外壳套在别人的运行时上,结构大半是这个决定的后果。DeepSeek Harness 提供 agent 运行时和插件宿主;DSCODE 在它上面加三层:一层是安装与钉版——命令包、一个装着插件和改动过的终端的 bundle 包,以及一份带完整性哈希的 Hub profile;一层是 packages/tui 里那份被接管的终端,因为界面需要插件够不到的改动,而改动的方式是构建时从补丁描述生成模块、而不是直接改上游源码,换来的是可重复的安装,代价是每跟进一个上游版本都要走一遍写下来的合并流程;其余全是插件——常驻 shell、各自 git worktree 里的子代理、给批准做复核的独立模型、让同机会话互相看见并发消息的信箱与桥、带持久调度器的触发器、会话指标、记忆与邮件。TUI、CLI 和脚本共用同一份会话运行时,所以在终端里开的会话可以被另一个进程读取、steer 和发消息,而读者不需要拿它的写锁。

packages/tui/
被接管的终端:79 个文件、1,338 KB,全树第二大目录。src/app.ts 一个文件 382,157 字节,是全树最大的代码文件,其后是 src/index.ts(120,925)、src/render/projection.ts(105,398)、src/kernel-panels.ts(68,255)、src/provider-settings.ts(37,703)、src/render/status.ts(37,350),以及两份 32 KB 的语言文件(locales/en.ts 32,615、locales/zh.ts 32,201)和构建时补丁描述 cordis.patch.yml(11,484)。
plugins/
28 个插件目录,最大的是触发器(26 个文件、157 KB,cli.mjs 30,629),其次是会话桥(7 个文件、70 KB:mailbox.mjs 20,129、communication.mjs 14,606、server.mjs 11,799)、OpenRouter(5 个文件、54 KB,wire.mjs 24,178)、TUI 工具(9 个文件、53 KB)、会话指标(8 个文件、43 KB)、Grok(7 个文件、42 KB)、OpenCode Go(9 个文件、41 KB)、dscode 插件本身(2 个文件、41 KB,index.mjs 26,993 与 board.mjs 14,492)以及邮件(10 个文件、40 KB)。
docs/ 与 docs/releases/
25 份文档、333 KB,多数是 README 用中英两份索引列出的用户指南,另有 38 份发布说明、140 KB。最大的几份是 CHANGELOG.md(80,835)、tui-commands.md(26,963)、triggers.md(24,958)、session-messaging-design.md(23,238)、verification.md(19,130)与两份发行指南;AGENTS.md(3,649)写明了发布规则,也划清了哪些是用户指南、哪些是设计记录。
tests/ 与 eval/
76 个测试文件、684 KB 对着发出去的代码,最大的是 session-metrics.test.mjs(33,995)、code-review.test.mjs(29,844)、opencode-go.test.mjs(29,184)、openrouter.test.mjs(28,388)和 dscode.test.mjs(22,228);此外 eval/compaction(24 个文件、711 KB,夹具 212,244 与 162,078 字节)、eval/continuation(36 个文件、99 KB,含二十个小检查脚本与 25,802 字节的 cases-20.json)、eval/deepswe(10 个文件、62 KB)。
research/
七个文档、118 KB,用中文写,和 docs/(AGENTS.md 规定必须英文)刻意分开:上下文压缩现状(30,762)、两份接管上游 dsh-code 的迁移笔记(25,484 与 14,319)、四份系统提示词对比(22,905)、复杂度指标设计(12,663)、自研替换终端的工作量评估(7,558),以及针对自己 v0.7.8 的代码审查(7,389)。
scripts/、Makefile 与 install.sh
51 个脚本、287 KB 的构建与验证管路:patch-runtime.mjs(23,335)领着头,下面有六个 patch-*.mjs,其余是各种探针与校验器(verify-hub.mjs 13,018、verify-login-runtime.mjs 12,818、dscode-probe.mjs 14,456)。install.sh 11,166 字节,Makefile 5,899,发布工作流 .github/workflows/release.yml 5,486。

取舍,以及它替代了什么

  • 终端的改动在构建时按补丁描述生成 替代 直接改写 vendored 源码

    README 把它写成对用户的承诺:bundle 在构建时生成那些被改过的模块,从不在用户的机器上改写第三方源码。代价也写下来了——docs/vendored-tui-upgrade.md(5,058 字节)专门用来吃下上游 dsh-code 的新版本,而它自己写明的边界是「只有冒烟测试能抓到的东西」。

  • 同机会话彼此可见、可以互发消息 替代 让每个 agent 各干各的

    README 用一句话立论:多数编码 agent 都是独自工作,而这个项目建立在相反的假设上。边界被写进设计记录而不是留在暗示里:第一版只覆盖同一台机器、同一个状态目录、一个已加载的根会话,给未加载的会话发消息会返回 target_unavailable;每条链都有上限——深度 3、8 条新消息、一次最终回复、一小时、64,000 字节正文、100 条未认领笔记——撞上就拒绝,不会悄悄丢弃。

  • 批准交给独立模型按用户的指令复核 替代 按规则表判定,或者干脆把确认关掉

    README 写明了它否掉的那个替代方案:独立复核者按「你的指令」而不是按规则表决定。默认值是普通的——workspace-write 沙箱、/permission ask 把决定交回给人——边界也画得清楚:Ultra 不额外给权限,Computer Use 保留人工授权。

  • 所有唤醒方式收敛到一个事件入口 替代 为每种场景写一套钩子

    设计文档自己的说法是「一个入口,而不是一组钩子」:cron、延时、文件变化、轮询、CI 任务,统统归约成「有东西投递了一个事件」,所以入口只有一个、载荷语法只有一套,新增一种来源的代价是一个定义字段而不是一条代码路径。同一份文档也列了这个选择放弃了什么:它不是自动重试引擎,不宣称外部副作用恰好执行一次,而且目前还没有通知器去消费运行日志。

  • 一次发布是一张四项清单 替代 只改一个版本号

    AGENTS.md 开篇就说一次发布不只是改版本号:发布说明、package.json 里的版本、changelog 条目和两份 README 必须在同一次改动里一起走,工具在缺少发布说明时会拒绝而不是硬发。九天里二十个版本,就是这套被写下来并被执行的流程的样子。

依据README.md(28,788 字符,全文读过)、AGENTS.md(3,647 字符)、docs/triggers-design.md(7,448 字符)、docs/session-messaging-design.md 的前 12,000 字符(全文 23,169 字符)、README 里的依赖与发行表格,以及完整的 515 个文件树及其体积和两级的目录汇总。

制作过程

5 个阶段
  1. 01

    十四天,而二十个版本全挤在最后九天里

    仓库建于 2026-09-11 09:40:02Z,59 秒后第一次提交就到了,标题是「Add DSCODE coding harness and npm Hub distribution」;最后一次提交在 2026-09-25,是「Release 0.7.32: OpenCode Go account login and footer usage」。这中间是 123 次提交,全部落在 2026 年 9 月,全部来自同一个账号。版本并不是均匀铺在这两周里的:第一个 v0.7.13 发布于 2026-09-17,最后一个 v0.7.32 发布于 2026-09-25,于是二十个版本全部落在最后九天,而且那九天每天至少一个——2026-09-18 四个、09-19 四个、09-22 四个——最紧的一对 v0.7.26 与 v0.7.27 只隔二十六分钟。另一半解释在发布规则里:AGENTS.md 把一次发布定义成一张四项清单而不是改个版本号,发布说明、package.json 版本、changelog 条目和两份 README 必须在同一次改动里一起走,而 make attach 在缺少 docs/releases/<version>.md 时会直接拒绝。树里确实有 38 份这样的发布说明(从 0.2.0 到 0.7.32),而标签和 release 各只有 20 个——这个落差材料里没有解释。此处日期都取 API 的 UTC 时间。

  2. 02

    这九个版本到底在改什么

    README 的 "What’s new" 覆盖了最后九个版本,从头读到尾其实是三条线,而不是九个功能。第一条是无人值守的运行:0.7.24 让一个事件可以启动会话,定义放在 <state>/triggers/ 和 <workspace>/.dsh/triggers/,事件只携带数据、必须带 eventId,trigger install 会写下一个 launchd LaunchAgent;0.7.26 补上 fresh 与 persistent 两种会话模式、可持久的 cron 与延时任务,以及被监管的脚本来源。第二条是各家 provider 的登录:0.7.29 加了 /account,走系统浏览器给 DeepSeek 线路登录、带一个 loopback 回调,登录过的机器就不再需要 DEEPSEEK_API_KEY;0.7.31 把 OpenCode Go 接进 /provider,带上它的 DeepSeek、GLM、Kimi、MiMo、LongCat、Hy 与 Space Bunny 模型;0.7.32 把那条线路的 console API key 换成 /opencode login,并把订阅的五小时、每周、每月额度放进底栏。第三条是修这个项目赖以成立的那层组合:0.7.27 修的是 Harness 组合生成了一份空的 cordis.yml 之后、全新 Hub 安装装不上的问题;0.7.28 把运行时从 0.1.5-rc.2 抬到 0.1.7-alpha.2,同时把权限预设从 auto 改名 auto-review,因为 DSH 把 auto 这个名字收回去给自己的集成了。功能版和修复版交替出现,而修复版都是小版本:一个坏掉的安装器、一个改了名的开关、一次上游版本跟进。

  3. 03

    在插件宿主上长出来的外壳,以及终端的代价

    宿主是 DeepSeek Harness,README 描述的常规路径是:首次启动从 DSH Plugin Hub 装一份钉住的完整 preset,不需要手工拼插件;启动器会把已装的 bundle 和 Harness 依赖跟推荐组合对一遍,不一致时只打印一条汇总警告,不会去改依赖、也不会降级。DSCODE 加的东西大部分沿着这个模型走——plugins/ 下有 28 个目录,最大的 plugins/triggers 是 26 个文件、157 KB(光 cli.mjs 就 30,629 字节),最小的是像 plugins/ultra/policy.mjs(6,114 字节)这样的单文件插件。终端是它离开插件模型的地方:packages/tui 是一份被接管并改过的界面,79 个文件、1,338 KB,其中 src/app.ts 一个文件 382,157 字节,是全树最大的代码文件。怎么带着这些改动,README 说得很直白:bundle 在构建时生成那些被改过的模块,从不在用户的机器上改写第三方源码。这也是为什么终端包里有一份 11,484 字节的 cordis.patch.yml、config/ 下还有一份、scripts/patch-*.mjs 有六个(最大的 patch-runtime.mjs 23,335 字节),以及为什么会有一整份 docs/vendored-tui-upgrade.md(5,058 字节)专门讲怎么吃下一个上游 dsh-code 新版本——那份文档自己写明的边界是「只有冒烟测试能抓到的东西」。全树 515 个文件,按字节算最大的目录根本不是代码,而是 assets/:两个文件、3,504 KB,几乎全是那个 3,585,589 字节的演示 GIF。

  4. 04

    一个贡献者、123 次提交,和一个中文 research 目录

    123 次提交全部关联到同一个 GitHub 账号 qiz029,署名 todd.zheng、邮箱 toddzheng024@gmail.com,贡献者列表里也只有一条:qiz029,123 次。历史还记下了这份工作有多少是带着模型一起做的——123 次提交里有 43 次带共同作者尾注:26 次写 "Claude Fable 5.1",14 次写 "Claude Opus 5 (1M context)",两次 "Claude Opus 5.5",一次 "Claude Opus 5.5 (1M context)"。这个项目自己留下的工作笔记不在 docs/ 里(AGENTS.md 规定那里必须写英文),而在 research/:七个文档、118 KB、用中文写,题目全是它自己的问题——接管上游终端(dsh-code-vendor-接管-迁移笔记.md 25,484 字节,dsh-code-1.2.0-迁移笔记.md 14,319 字节)、要不要自己重写一个终端(7,558 字节)、四份系统提示词的对比(22,905 字节)、上下文压缩的现状(30,762 字节)、一套给 agent 维护的复杂度指标设计(12,663 字节),以及针对自己 v0.7.8 的代码审查、里面列了优化点与潜在 bug(7,389 字节)。旁边是 eval/:eval/compaction 711 KB 做上下文压缩评测,靠的是 212,244 与 162,078 字节两个夹具;eval/continuation 36 个文件,里头有二十个很小的检查脚本。

  5. 05

    坏过的地方,以及设计文档自己承认做不到的事

    这个仓库有 1,009 个星、一个 fork,issue 和 pull request 都是零,所以「哪里出过错」只能从仓库里读。一部分写在发布说明里:0.7.27 之所以存在,是因为 Harness 组合生成了一份空的 cordis.yml,导致全新 Hub 安装失败;0.7.28 为了 DSH 收回 auto 这个名字而重命名权限预设,直接把用着旧名字的人弄坏;0.7.29 则留下了一句坦白——上一次为了关掉 host-plane 工作流引擎而打的补丁,被一次上游改名悄悄弄失效了,只好再关一次:补丁不再生效,而没有任何检查发现它。AGENTS.md 又补了两条:发布任务在凭据检查那一步大约三十秒就死掉,通常是 npm 上的版本冲突而不是缺少密钥;而一个已经用另一份构建发到 npm 的版本没法重新打标签,只能抬版本号、重新切标签。它还说 make release、make verify 和 npm run doctor 没法在 dscode 会话里跑,嵌套沙箱会被拒,所以发布闸门只能在普通终端里过。设计文档则把自己的边界写了下来:触发机制「不是自动重试引擎」,它的 runs.jsonl 目前没有人消费,通知通道「故意还没定」;agent 之间的消息设计把取消的严格边界定在「认领之前」,给每条链加上上限——深度 3、8 条新消息、一次最终回复、一小时有效期、64,000 字节正文、每会话 100 条未认领笔记与 1 MiB——并且直说它并不把同一个操作系统用户当作安全边界,要挡住刻意绕过还需要沙箱权限隔离,而「第一版不承诺这个」。

相关档案

全部档案 →