资讯动态

第 4 篇:Profile / Bundle / Patch 三件套

发布时间:2026/10/30 4:55:04 来源:尧图企业网站定制
第 4 篇Profile / Bundle / Patch 三件套本篇结论dsh 的定制只有一条正路 ——Profile 决定「叠哪几层 Bundle」Bundle 决定「基础插件树长什么样」Patch 决定「你在上面改哪几行」。三层自上而下覆盖最后写入者胜。读完你能得到能独立写出一份cordis.patch.yml知道自己的改动会盖住谁、会被谁盖住以及避开三个新手必踩的坑。开篇装修套餐、建材包、图纸上的红笔假设你在装修房子。Profile套餐名—— 装修公司给你的方案名比如「现代简约全包」。它本质上是一张建材包清单写着「先来基础包再来厨房包再来卫浴包」。Bundle建材包—— 一层实实在在的建材。基础包给你水电、墙面、地板厨房包给你橱柜、灶台、油烟机。包是有顺序的厨房包必须在基础包之上。Patch图纸上的红笔修改—— 你在图纸上用红笔圈掉「主卧用白色乳胶漆」改成「用莫兰迪灰」。改的是已经存在的某一项或者新增一项「客厅加个投影仪」。dsh 的定制模型就是这个三段式。而且这三者的关系非常清晰Profile 持有「有序的 Bundle 列表」「你自己的 Patch」每个 Bundle 自己携带一份Patch。4.1 三者各是什么一句话版 证据版Profile一句话$DSH_HOME/profiles/名字/下的一个命名组合。目录里有什么$DSH_HOME/profiles/my-app/ ├── package.json # dsh.profile.bundles有序 Bundle 列表 patchReload 策略 ├── cordis.patch.yml # 你自己的改动层 └── node_modules/ # 额外装的插件通过 dsh plugin 装package.json里的关键字段长这样packages/bundle/base/README.md给了最小示例{name:my-profile,private:true,dsh:{profile:{bundles:[deepseek-ai/dsh-base]}}}术语小卡片patchReload这个 Profile 的 Patch 改动是热生效还是只有重启才生效。live—— 改了cordis.patch.yml立刻重排插件树不用重启startup—— 只在启动时应用一次自定义 Profile默认live。官方自带的web是 live而headless/sdk/acp是 startup —— 因为一次性或 stdio 应用跑起来后换依赖会让它已经接手的活儿失效。Bundle一句话一个 npm 包用dsh.bundle.patch字段指向一份cordis.patch.yml贡献「配置行 这些行挂载的代码」。{dsh:{bundle:{patch:./cordis.patch.yml}}}一个容易震惊的事实dsh-base这个包的 JS 代码是空的export {}。它的全部实质就是那份 YAML 文件。官方文档这么说packages/bundle/base/README.mdThe bundle is a static patch document: oneinsertlist applied over the empty profile root. It mounts no service, emits no events, and holds no mutable state.这个 Bundle 就是一份静态补丁文档一个应用到空 Profile 根上的insert列表。它不挂服务、不发事件、不持有可变状态。所以 Bundle 不是「一个功能模块」是「一张装配清单」。真正的代码在它点名的那些包里。Patch一句话cordis.patch.yml补丁清单 —— 按id定位某一行重写它的整个 config或者insert新行。两种操作# 操作一改已有的一行按 id 定位整体替换 config-id:system-promptconfig:personaPrefix:你是一个代码助手# 操作二插入新行-insert:-id:tool-str-replace-editorname:deepseek-ai/dsh-tool-str-replace-editorconfig:maxOutputChars:160004.2 装配顺序四层从下往上盖④ 临时覆盖层命令行 --patch每次运行临时指定优先级最高③ 机器级$DSH_HOME/cordis.patch.yml这台机器上所有 Profile 都生效② Profile 用户层$DSH_HOME/profiles/名字/cordis.patch.yml你自己对这个套餐的修改① Bundle 层dsh.profile.bundles 列表里每个 Bundle 的 cordis.patch.yml按列表顺序后者盖前者根空的 cordis.yml []从白纸开始箭头方向 覆盖方向。越往上优先级越高。用装修的话说建材包铺好 → 你在图纸上改 → 你老婆家里统一规矩再改 → 开工当天工长拿到的临时变更单再改。最后改的说话。记住这条推论Home 级③能盖过 Profile 级②。所以如果你发现自己的 Profile 改动「不生效」第一件事就是去看看$DSH_HOME/cordis.patch.yml是不是有一行同样的 id 把它盖了。六个内置 BundleBundle作用用在哪些 Profiledsh-base共享基座模型连接、全套工具、会话持久化、沙箱与审批策略、设置、凭据、遥测web/headless/sdk/acp的共同第一层dsh-web-app加浏览器应用webdsh-headless加一次性命令行执行器无服务器headlessdsh-sdk-app加 SDK JSON-RPC stdio 服务sdkdsh-acp-app加自动化专用的 ACP stdio 服务acpdsh-sdk-minimal例外一个包自带完整精简树不套basesdk-minimal对应的 Profile 模板packages/boot/app-boot/src/profile.tsweb: [base, web-app] patchReload: live headless: [base, headless] patchReload: startup sdk: [base, sdk-app] patchReload: startup acp: [base, acp-app] patchReload: startup sdk-minimal: [sdk-minimal] patchReload: startup ← 不套 base看懂这张表就看懂了 dsh 的所有官方产品形态。它们不是五个不同的程序是同一个基座上叠了五种不同的「表面」。4.3 真实例子逐行读一份 Patch来看packages/bundle/headless/cordis.patch.yml31 行这是dsh-headless这个 Bundle 的全部实质# 改已有的一行system-prompt-id:system-promptconfig:personaSuffix:Your working directory is{{cwd}}.personaPrefix:-You are a coding agent powered by the{{model}}model.# 改已有的一行tools-id:toolsconfig:mode:!!jsprocess.env.DSH_TOOLS_MODE# ← JS 表达式挂载时求值# 插入两行新的-insert:-id:headless-startupname:deepseek-ai/dsh-headless/startup-id:headless-runnername:deepseek-ai/dsh-headlessinject:[headlessStartup]# ← 声明依赖config:task:!!jsctx.headlessStartup.task# ← 挂载时才求值四个值得学的点① 它只做了三件事。改提示词、改工具模式、插入两个新行。所有别的模型连接、会话、文件工具、bash 工具……一概不碰 —— 因为那些是dsh-base已经铺好的。这就是「分层」的正确姿势每层只管自己该管的。②{{cwd}}和{{model}}是提示词变量。由agent-loop注册组装时替换。③!!js是 JavaScript 表达式挂载时求值。所以!!js ctx.headlessStartup.task能读到运行时才存在的值。这是 dsh 配置灵活性的关键 —— 你的配置不是死的字符串可以「活」的。④inject: [headlessStartup]在配置里也能写。第 1 篇讲过inject决定加载顺序这里就是它在 YAML 里的样子。一个可直接抄的片段官方给的「加一个str_replace_editor工具」示例packages/bundle/base/README.md-insert:-id:tool-str-replace-editorname:deepseek-ai/dsh-tool-str-replace-editorconfig:maxOutputChars:16000这段可以直接贴进你 Profile 的cordis.patch.yml。4.4 ⚠️ 一个必须澄清的术语陷阱仓库根目录下有个patches/文件夹里面有三个.patch文件。它们和本篇讲的 Patch 毫无关系。这是初学者最容易混淆的地方请务必分清这三个东西东西是什么作用对象Cordis Patch本篇讲的cordis.patch.yml补丁清单改 dsh 的插件组合patches/*.patchpnpm 的patchedDependencies机制标准 git diff改第三方 npm 依赖yao-pkg/pkg、node-pty、electron/osx-sign在pnpm install时的源码vendor/内置的 Cordis 框架源码改Cordis 框架本身记忆口诀patches/→ 修别人的包第三方依赖vendor/→ 修框架本体cordis.patch.yml→ 修你自己的插件组合三者分属完全不同的机制不要互相联想。4.5 三个新手必踩的坑坑一Patch 是整体替换不是字段合并这是第一大坑。# 假设 base 里原本是-id:system-promptconfig:personaPrefix:你是助手personaSuffix:工作目录{{cwd}}# 你只想改 personaPrefix于是写-id:system-promptconfig:personaPrefix:你是代码专家结果personaSuffix消失了。因为你的补丁整体替换了那一行的 config不是合并。正确写法想保留的字段必须全部重写一遍。-id:system-promptconfig:personaPrefix:你是代码专家personaSuffix:工作目录{{cwd}}# ← 必须重写官方原话packages/boot/app-boot/README.mdA user patch replaces the whole matched config — an id-targeted patch does not deep-merge.坑二同一服务不能双重注册第 2 篇讲过fs-local和fs-sandbox都注册ctx.fs同时挂会让Profile 拒绝加载。遇到「Profile 加载失败」第一反应查这个。坑三每一行配置只应属于一层官方的设计约定packages/bundle/base/README.mdRows whose value differs by mode do not live here: each mode bundle restates its complete configuration, keeping any single row down to one bundle layer plus the user’s.因模式而异的行不会放在基座里每个模式 Bundle 会重述它的完整配置让任何一行都只属于「一层 Bundle 用户层」。为什么因为「整体替换」语义下如果一行配置散落在三层里你就得在每一层都重写全部字段很快失控。给你的实践建议不要图省事把同一行的配置复制到多层。想改某一行就在你自己的 Profile 层重述它的完整配置让它只存在于「基座 你」这两层。4.6 两条保命命令# 1. 不启动应用直接看最终会加载成什么样dsh--profileweb --dump-config# 2. 给某个 Profile 装一个外部 Bundledsh plugin--profilemy-appadd包名--dump-config是你最重要的调试工具。它的输出会带注释标明每一行来自哪个文件、被哪一层改过。你的 Patch 到底生效没有一眼就能看出来。改配置的正确节奏永远是改 →--dump-config验证 → 再跑。不要跳过中间那步。还有一个创建 Profile 的命令dsh--profilemy-app --from-default-profile headless从官方模板复制出一个你自己的 Profile然后在这个基础上改名字不能用官方保留的那几个也不能用desktop。动手试试练习 1跑dsh --profile web --dump-config在输出里找一行注释看看它标注了这行来自哪个文件。然后打开$DSH_HOME/profiles/web/cordis.patch.yml大概率是空的[]确认「用户层」现在什么都没改。练习 2进阶给你的 headless Profile 加一行自定义 persona# $DSH_HOME/profiles/headless/cordis.patch.yml-id:system-promptconfig:personaPrefix:你是一个说话简短的技术助手personaSuffix:Your working directory is{{cwd}}.注意personaSuffix是必须重写的坑一。然后用--dump-config验证再跑一次任务看看语气变了没有。本篇小结Profile$DSH_HOME/profiles/名字/持有「有序 Bundle 列表」在package.json的dsh.profile.bundles「你自己的cordis.patch.yml」patchReload策略。Bundle 一个 npm 包dsh.bundle.patch指向一份cordis.patch.yml。dsh-base的 JS 代码是空的 ——Bundle 的实质就是那张装配清单。Patch 按id定位、整体替换config或insert新行。支持!!js表达式挂载时求值。四层覆盖从下到上Bundle 层 → Profile 用户层 → 机器级 →--patch临时层。最后写入者胜。六个内置 Bundlebase共享基座 四个「表面」sdk-minimal例外不套 base。术语陷阱patches/*.patch是 pnpm 改第三方依赖与 Cordis Patch无关。三个坑整体替换非合并 / 同 key 不可双重注册 / 一行只属一层。保命命令--dump-config验证dsh plugin add装包。下篇预告理论全都齐了。你已经知道dsh 由插件组成一切可换第 1 篇250 个包分五层你要动的在顶层第 2 篇启动是装配、执行是循环第 3 篇定制靠 Profile Bundle Patch第 4 篇缺的只剩一件事亲手做一遍。[第 5 篇动手实战 —— 组装你自己的产品]—— 我们从零拼一个「每周代码巡检小助手」并配一份排错手册。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑