第 2 篇:整体组成与模块职责

第 2 篇:整体组成与模块职责

本篇结论 :dsh 的 250 个包不是一盘散沙,而是五层金字塔 ------ 地基、脊梁、能力接缝、具体实现、消费者。你要改的东西几乎永远在顶层两层,底层几乎不用碰。读完你能得到:一张能定位「我要的东西在哪一层」的地图,以及看懂「能力接缝三件套」在真实代码里长什么样。


开篇:一家餐厅的岗位表

想象你要开一家餐厅。

打开 dsh 仓库看见 250 个包时的眩晕感,大概等于第一次拿到一家米其林餐厅的完整岗位表:主厨、副厨、切配、打荷、冷盘、热菜、面点、洗碗、传菜、领班、收银、采购、库管......两百多号人。

但如果你按层级看,其实就五层:

  • 店面和基础设施(水电燃气、POS 机)------ 地基
  • 后厨主线(接单 → 做菜 → 出餐这条主干)------ 脊梁
  • 岗位标准(「切配岗」的定义,谁都能来应聘)------ 能力接缝
  • 具体的人(张三做川菜,李四做粤菜)------ Provider
  • 对客的岗位(服务员、外卖窗口、电话接单)------ Consumer

dsh 的包结构,就是这个结构。下面一层一层看。


2.1 先看仓库最上面一层

复制代码
D:/dsh-master-probe
├── apps/        可部署的应用成品:CLI / Web / 桌面端(Electron)
├── packages/    ★ 主体:约 250 个 @deepseek-ai/dsh-* 包,分 56 个分组
├── python/      Python SDK 和运行时
├── native/      Node 原生模块(Win32 进程/PTY 等底层系统调用)
├── vendor/      ★ Cordis 框架本体(被内置进来并改了作用域)
├── docs/        官方文档(部分是脚本从源码生成的)
├── scripts/     质量门禁和代码生成脚本
├── benchmarks/  性能基准用例
├── snapshots/   录制的会话快照,供无密钥回放测试
└── website/     VitePress 文档站

你要记住的两条:

  1. 真正的业务逻辑全在 packages/ 和 vendor/。 apps/ 只是「把某个组合打包成可部署形态」的容器。官方文档说得很硬:只有 dsh CLI + 命名 Profile 才是合法的应用启动方式,有个脚本专门拦截绕过 dsh 的启动路径。
  2. vendor/ 是框架本体。 dsh 把 Cordis 的源码整包搬进仓库,改了 npm 作用域(cordis → @deepseek-ai/cordis)重新发布。所以你在 vendor/README.md 里能看到「19 处本地修改」的记录 ------ dsh 是按自己需要改造过 Cordis 的。

2.2 五层金字塔

#mermaid-svg-GTVSP953jTkSa0Uk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GTVSP953jTkSa0Uk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GTVSP953jTkSa0Uk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GTVSP953jTkSa0Uk .error-icon{fill:#552222;}#mermaid-svg-GTVSP953jTkSa0Uk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GTVSP953jTkSa0Uk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GTVSP953jTkSa0Uk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GTVSP953jTkSa0Uk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GTVSP953jTkSa0Uk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GTVSP953jTkSa0Uk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GTVSP953jTkSa0Uk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GTVSP953jTkSa0Uk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GTVSP953jTkSa0Uk .marker.cross{stroke:#333333;}#mermaid-svg-GTVSP953jTkSa0Uk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GTVSP953jTkSa0Uk p{margin:0;}#mermaid-svg-GTVSP953jTkSa0Uk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GTVSP953jTkSa0Uk .cluster-label text{fill:#333;}#mermaid-svg-GTVSP953jTkSa0Uk .cluster-label span{color:#333;}#mermaid-svg-GTVSP953jTkSa0Uk .cluster-label span p{background-color:transparent;}#mermaid-svg-GTVSP953jTkSa0Uk .label text,#mermaid-svg-GTVSP953jTkSa0Uk span{fill:#333;color:#333;}#mermaid-svg-GTVSP953jTkSa0Uk .node rect,#mermaid-svg-GTVSP953jTkSa0Uk .node circle,#mermaid-svg-GTVSP953jTkSa0Uk .node ellipse,#mermaid-svg-GTVSP953jTkSa0Uk .node polygon,#mermaid-svg-GTVSP953jTkSa0Uk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GTVSP953jTkSa0Uk .rough-node .label text,#mermaid-svg-GTVSP953jTkSa0Uk .node .label text,#mermaid-svg-GTVSP953jTkSa0Uk .image-shape .label,#mermaid-svg-GTVSP953jTkSa0Uk .icon-shape .label{text-anchor:middle;}#mermaid-svg-GTVSP953jTkSa0Uk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GTVSP953jTkSa0Uk .rough-node .label,#mermaid-svg-GTVSP953jTkSa0Uk .node .label,#mermaid-svg-GTVSP953jTkSa0Uk .image-shape .label,#mermaid-svg-GTVSP953jTkSa0Uk .icon-shape .label{text-align:center;}#mermaid-svg-GTVSP953jTkSa0Uk .node.clickable{cursor:pointer;}#mermaid-svg-GTVSP953jTkSa0Uk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GTVSP953jTkSa0Uk .arrowheadPath{fill:#333333;}#mermaid-svg-GTVSP953jTkSa0Uk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GTVSP953jTkSa0Uk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GTVSP953jTkSa0Uk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GTVSP953jTkSa0Uk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GTVSP953jTkSa0Uk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GTVSP953jTkSa0Uk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GTVSP953jTkSa0Uk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GTVSP953jTkSa0Uk .cluster text{fill:#333;}#mermaid-svg-GTVSP953jTkSa0Uk .cluster span{color:#333;}#mermaid-svg-GTVSP953jTkSa0Uk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GTVSP953jTkSa0Uk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GTVSP953jTkSa0Uk rect.text{fill:none;stroke-width:0;}#mermaid-svg-GTVSP953jTkSa0Uk .icon-shape,#mermaid-svg-GTVSP953jTkSa0Uk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GTVSP953jTkSa0Uk .icon-shape p,#mermaid-svg-GTVSP953jTkSa0Uk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GTVSP953jTkSa0Uk .icon-shape .label rect,#mermaid-svg-GTVSP953jTkSa0Uk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GTVSP953jTkSa0Uk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GTVSP953jTkSa0Uk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GTVSP953jTkSa0Uk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} L5 组合分发层

bundle/*(补丁层) · boot/*(启动胶水) · test-support/*
L4 消费者层

tool-*(面向模型的工具) · client/*(51 个 UI 包) · api/* · sdk/*
L3 具体实现层 Provider

fs-local · fs-sandbox · bash-local · llm-deepseek · session-persistence-jsonl
L2 能力接缝层 Service Definition

ctx.fs · ctx.shell · ctx.web · ctx.skill · ctx.subagents · ctx.workflow
L1 核心脊梁

session(147) · agent(93) · tools(58) · system-prompt(51) · agent-loop(40)

scope(32) · llm(115) · session-projection(70) · invariants(47)
L0 地基

vendor/cordis(插件框架本体) · util/*(15 个零依赖工具包)

括号里的数字是入度------有多少个包依赖它。数字越大越是「脊梁」,越底下越不能动。

一句话概括各层的性格:

层 性格 你会碰它吗
L0 地基 零内部依赖,谁都用 几乎不碰
L1 核心脊梁 不可约简的最小集合 很少碰,但要理解
L2 能力接缝 薄薄一层接口标准 想加新能力时碰
L3 Provider 可热插拔的实现 经常碰(换个实现)
L4 Consumer 面向模型/用户的工具 经常碰(加个工具)
L5 组合分发 决定最终装什么 最常碰(写配置)

这张表是本篇最实用的一张。 你以后有一个需求,先问自己「这属于哪一层」,就能立刻知道该动什么、不该动什么。


2.3 L1:核心脊梁,六个包撑起全部

官方文档有一张「Core packages」表(docs/architecture.md:59-68),我把它翻成白话:

包 通俗职责 ctx 上的 key
core/session 流水账本。只追加的事件日志,模型能看到的历史全从它派生 ctx.sessions
core/agent Agent 的花名册 。定义 Agent 接口、维护实时注册表、发 agent/* 事件 ctx.agents
core/tools 工具柜。工具的注册表 + 带守卫的执行管线 ctx.tools
core/system-prompt 提示词装配线。把各插件贡献的段落和工具 schema 拼成系统提示词 ctx.systemPrompt
core/agent-loop 那个主循环 。实现了 core/agent 定义的接口 ------ 就是第 1 篇说的「Agent 循环本身也是插件」 ctx.agentLoop
core/scope 隔离罩。让某个注册只对一个 Agent 生效 纯库,不占 key
llm/llm 模型调用的抽象。消息和流的词汇表 + 适配器接缝 ctx.llm

两个细节值得单独说:

**① core/agent 和 core/agent-loop 是分开的。**这不是多此一举。core/agent 定义「Agent 应该长什么样」(接口 + 注册表 + 事件词表),core/agent-loop 是「一个具体的实现」。

好处:你想换一种完全不同的 Agent 驱动方式(比如不做 React 循环,改做状态机),只要写一个新的实现挂在 ctx.agentLoop 上,所有依赖「Agent」这个概念的地方都不用改。

用餐厅的话说:core/agent 是「厨师岗」的岗位说明书,core/agent-loop 是现在上岗的这位张三。换李四来,岗位说明书不用改。

**② core/session 被 147 个包依赖,是全仓第一脊梁。**为什么?因为第 1 篇讲过的那条铁律 ------ 模型可见即已落日志。既然所有送给模型的东西都必须能从日志重建,那所有跟「给模型看什么」有关的包,都得依赖会话日志。

session 组的 19 个包就是围绕这本账本的全套服务:持久化(存成 JSONL)、投影(把事件折叠成可读状态)、标题生成、统计、遥测、格式迁移(v0→v1→v2→v3)......


2.4 L2/L3:能力接缝 ------ 三件套在真实代码里长什么样

第 1 篇讲过 Seam = Service Definition + Provider + Consumer。现在拿文件系统这个接缝走一遍,看它在仓库里具体是哪些包。
#mermaid-svg-w2LCgBXMRgU0dNNp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-w2LCgBXMRgU0dNNp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-w2LCgBXMRgU0dNNp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-w2LCgBXMRgU0dNNp .error-icon{fill:#552222;}#mermaid-svg-w2LCgBXMRgU0dNNp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-w2LCgBXMRgU0dNNp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-w2LCgBXMRgU0dNNp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-w2LCgBXMRgU0dNNp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-w2LCgBXMRgU0dNNp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-w2LCgBXMRgU0dNNp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-w2LCgBXMRgU0dNNp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-w2LCgBXMRgU0dNNp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-w2LCgBXMRgU0dNNp .marker.cross{stroke:#333333;}#mermaid-svg-w2LCgBXMRgU0dNNp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-w2LCgBXMRgU0dNNp p{margin:0;}#mermaid-svg-w2LCgBXMRgU0dNNp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-w2LCgBXMRgU0dNNp .cluster-label text{fill:#333;}#mermaid-svg-w2LCgBXMRgU0dNNp .cluster-label span{color:#333;}#mermaid-svg-w2LCgBXMRgU0dNNp .cluster-label span p{background-color:transparent;}#mermaid-svg-w2LCgBXMRgU0dNNp .label text,#mermaid-svg-w2LCgBXMRgU0dNNp span{fill:#333;color:#333;}#mermaid-svg-w2LCgBXMRgU0dNNp .node rect,#mermaid-svg-w2LCgBXMRgU0dNNp .node circle,#mermaid-svg-w2LCgBXMRgU0dNNp .node ellipse,#mermaid-svg-w2LCgBXMRgU0dNNp .node polygon,#mermaid-svg-w2LCgBXMRgU0dNNp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-w2LCgBXMRgU0dNNp .rough-node .label text,#mermaid-svg-w2LCgBXMRgU0dNNp .node .label text,#mermaid-svg-w2LCgBXMRgU0dNNp .image-shape .label,#mermaid-svg-w2LCgBXMRgU0dNNp .icon-shape .label{text-anchor:middle;}#mermaid-svg-w2LCgBXMRgU0dNNp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-w2LCgBXMRgU0dNNp .rough-node .label,#mermaid-svg-w2LCgBXMRgU0dNNp .node .label,#mermaid-svg-w2LCgBXMRgU0dNNp .image-shape .label,#mermaid-svg-w2LCgBXMRgU0dNNp .icon-shape .label{text-align:center;}#mermaid-svg-w2LCgBXMRgU0dNNp .node.clickable{cursor:pointer;}#mermaid-svg-w2LCgBXMRgU0dNNp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-w2LCgBXMRgU0dNNp .arrowheadPath{fill:#333333;}#mermaid-svg-w2LCgBXMRgU0dNNp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-w2LCgBXMRgU0dNNp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-w2LCgBXMRgU0dNNp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w2LCgBXMRgU0dNNp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-w2LCgBXMRgU0dNNp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w2LCgBXMRgU0dNNp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-w2LCgBXMRgU0dNNp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-w2LCgBXMRgU0dNNp .cluster text{fill:#333;}#mermaid-svg-w2LCgBXMRgU0dNNp .cluster span{color:#333;}#mermaid-svg-w2LCgBXMRgU0dNNp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-w2LCgBXMRgU0dNNp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-w2LCgBXMRgU0dNNp rect.text{fill:none;stroke-width:0;}#mermaid-svg-w2LCgBXMRgU0dNNp .icon-shape,#mermaid-svg-w2LCgBXMRgU0dNNp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w2LCgBXMRgU0dNNp .icon-shape p,#mermaid-svg-w2LCgBXMRgU0dNNp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-w2LCgBXMRgU0dNNp .icon-shape .label rect,#mermaid-svg-w2LCgBXMRgU0dNNp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w2LCgBXMRgU0dNNp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-w2LCgBXMRgU0dNNp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-w2LCgBXMRgU0dNNp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Consumer(用电器)
Provider(插头厂商)
Service Definition(插座标准)
packages/fs/fs

定义 ctx.fs 该有哪些方法

声明 fs/write-intent 等事件
fs-local

直接读写本地磁盘
fs-sandbox

受沙箱策略约束的读写
fs-e2b

远程 E2B 沙箱里的文件系统
tool-fs

暴露给模型的文件工具
tool-fs-search
tool-str-replace-editor

关键观察:Consumer 那三个箭头,全部指向 DEF,没有一个指向某个具体的 P。

这就是接缝的全部秘密。三个文件工具只知道「有个 ctx.fs,它有 read/write/list」,完全不知道背后是本地磁盘还是远程沙箱。

于是威力出现了。 官方举的例子(docs/architecture.md:129):

文件系统和子进程共享同一个执行世界,所以把它们指向一个远程沙箱时,Bash、PTY 和 LSP 会跟着一起搬过去,不需要 fork 任何 Provider。

翻译成人话:你把「文件在哪」和「进程在哪」这两个 Provider 一起换成远程版,那么「执行 bash」这个功能就自动变成「在远程机器上执行 bash」了。你一行工具代码都没改。

用餐厅的话说:你把「食材仓库」和「灶台」都搬到了分店,那么「炒菜」这个动作自然就在分店发生了 ------ 厨师的菜谱一个字都不用改。

主要的接缝一览

接缝 ctx key 常见 Provider 常见 Consumer
模型调用 ctx.llm llm-deepseek、llm-pi-ai agent-loop
文件系统 ctx.fs fs-local、fs-sandbox、fs-e2b tool-fs、tool-fs-search
Shell ctx.shell bash-local、bash-sandbox、pwsh-local tool-bash、tool-pwsh
联网 ctx.web web-fetch-http、web-search-deepseek tool-web
技能 ctx.skills skill-filesystem、skill-badge tool-skill
子智能体 ctx.subagents subagent-acp、claude-code、codex、fork-in-process tool-subagent
工作流 ctx.workflowEngine workflow-worker-thread tool-workflow
会话持久化 ctx.sessionPersistence session-persistence-jsonl session 相关包
沙箱 ctx.sandbox sandbox-local、sandbox-windows-acl shell/fs 的沙箱版

这张表是你以后「想加能力」的索引。 想加一个新模型?在 ctx.llm 上注册适配器。想加一个新的搜索源?在 ctx.web 上注册 Provider。


2.5 L4:消费者层 ------ 工具、UI、远程接口

这一层是「把能力暴露出去」的地方,分三拨:

① tool-* ------ 暴露给模型的工具。 每个工具在 ctx.tools 上注册自己,同时把 schema 贡献给提示词装配,这样模型才知道有这么个东西可用。

② client/* ------ 51 个 UI 包。 整个 Web / 桌面界面。ui-chat、ui-session、ui-settings、ui-skill、ui-subagent、ui-workflow-run......这是 Cordis 的「客户端编译面」,和 Host 端是分开编译的。

③ api/* + sdk/* ------ 跨进程边界。 api 是远程 BFF 装配 + Typert RPC 网关;sdk 是 stdio JSON-RPC 协议 + 客户端 + 服务端,让 Python 或别的进程能驱动 dsh。

术语小卡片:Typert dsh 的类型图生成器 + 运行时注册表 + RPC 网关协议。作用一句话:让 Host 端的能力能跨进程暴露给 Client 端,而且类型是打通的。你不用深究,只要知道 Web 界面和后端就是靠它通信的。


2.6 L5:组合分发层 ------ 决定最终装什么

只有三组,但极其重要(第 4 篇整篇都在讲它):

组 职责
bundle/* 6 个可安装的补丁层包:base、headless、web-app、sdk-app、acp-app、sdk-minimal
boot/* 启动胶水:app-boot(Profile/应用启动)和 cmdline(CLI 参数解析)
test-support/* 测试基础设施:假模型服务器、会话快照、Loader 冒烟测试等

2.7 一个必须记住的坑

fs-local 和 fs-sandbox 不能同时挂。

原因回到原理二:两个 Provider 都去注册 ctx.fs 这个 key,就冲突了。dsh 会让整个 Profile 加载失败,而不是随便挑一个。

官方原话(packages/bundle/base/README.md):挂载 dsh-fs-local 会和 fs-sandbox 双重注册 ctx.fs,导致加载失败。二选一。

这个坑的通用形式 :任何两个注册了同一个 ctx key 的插件都不共存。以后遇到「Profile 拒绝加载」,第一反应就是查是不是撞 key 了。

顺带一个相关规则:Windows 上默认用 PowerShell 工具,Mac/Linux 上默认用 bash 工具 ,同一台机器只有一套。你非要在 Windows 上换回 bash,就必须同时禁用两个 pwsh 行、再启用两个 bash 行 ------ 只改一半会加载失败。


动手试试

练习 1 回到 --dump-config 的输出,试着给每一行标注它属于哪一层(L0--L5)。你会发现绝大多数行是 L3 的 Provider 和 L4 的 tool-*,L1 脊梁只有寥寥几行 ------ 但那几行是整棵树真正的承重墙。

练习 2 挑一个你感兴趣的接缝(比如 ctx.web),在 packages/web/ 目录下看一眼它的包结构。你会发现它天然分成三类:web(定义)、web-search-*(Provider)、tool-web(Consumer)。这个「三件套」的形状在 dsh 里到处都是,认一次就终身受用。


本篇小结

  • 仓库主体在 packages/(250 包 / 56 分组),框架本体在 vendor/cordis。 apps/ 只是部署容器。
  • 五层金字塔 :L0 地基(Cordis + util)→ L1 核心脊梁(7 个包,session 被 147 包依赖)→ L2 能力接缝(薄接口)→ L3 Provider(可换实现)→ L4 Consumer(工具/UI/远程)→ L5 组合分发(bundle/boot)。
  • 你要改的东西几乎都在 L3/L4/L5,底层很少碰,但 L1 必须理解。
  • 能力接缝三件套:Consumer 只依赖 Definition,从不 import Provider。换 Provider 就换掉整条产品线(fs + subprocess 一起换 → bash/PTY/LSP 全跟着搬)。
  • 坑 :同一 ctx key 不能双重注册(fs-local 和 fs-sandbox 二选一)。

下篇预告

你现在手里有了一张静态地图:dsh 由什么组成、谁负责什么。

但地图是死的。从你敲下回车那一刻,到 Agent 把答案吐出来,中间到底发生了什么?那些插件是怎么被一个个装配起来的?一个「任务」是怎么变成一次模型调用、一次工具执行的?

👉 第 3 篇:运行机制与启动流程 ------ 从餐厅开门营业,到一桌客人吃完整顿饭。

相关推荐
apple_692658851 天前
零基础 DeepSeek Harness 养鱼教程:插件安装与 QQ/B站联动配置
dsh
古雨蓝枫2 天前
DeepSeek Harness(DSH)使用指南:功能、自定义模型与插件
ai·ai编程·deepseek·dsh
古雨蓝枫2 天前
DeepSeek Harness 插件开发进阶:从 Host 工具到 Client UI
ai·ai编程·deepseek·dsh
我才是银古6 天前
让 Agent 把视频做出来:DeepSeek Harness × DeepSeek-V4.1-Flash 视频生产流水线
deepseek·dsh
invicinble7 天前
dsh对比codex的机制
dsh
我才是银古9 天前
OpenGIS 技能插件开发与使用:在 DeepSeek Harness 里按需加载 GIS 知识
ai·gis·dsh
钝挫力PROGRAMER12 天前
Chrome-devtools-mcp:闭环Agent的自我验证
ai·agent·chrome devtools·mcp·dsh
月走乂山14 天前
DSH 桌面版用 DeepSeek 报 REQUEST_EXTENSION 的根因定位与修复
electron·node.js·插件系统·deepseek·bug排查·dsh·deepseek harness
猿来如此呀15 天前
DeepSeek Harness(DSH)保姆级入门与原理详解:从跑到用再到讲得清
dsh