DSH 桌面端使用指南与排错手册

在上一篇云服务器部署文章里,我记录了 DSH 的部署过程。这一篇转向桌面端:先完成模型接入与文件读写,再介绍权限、扩展和配置,最后按具体症状整理排查方法。
DSH 的许多问题都有相似的表象:插件已经安装,配置也改了,功能却没有按预期工作。要找到原因,先得分清配置是否被读取、插件是否参与组装,以及运行时实际执行了什么。
本文基于 DeepSeek Harness 桌面版 0.2.0-rc.2,测试环境为 Windows 11 25H2 / Electron 44。路径、报错和统计数字来自该环境的实测记录;配置规则参考了这一版本
app.asar内各@deepseek-ai/dsh-*包附带的中文文档。其他版本的界面、默认值和加载行为可能不同,复现前请先核对版本。
阅读范围: 正文以 Windows 桌面端为主。来自 Debian 12 云服务器的交流记录集中放在附录,供同时使用 CLI 与 systemd 的读者对照;这些记录不属于本机 Windows 桌面端复测。
按需要选择阅读路线:
- 首次使用: 从“开始之前”和“快速开始”读起,完成登录、模型回复和文件读写,再看第二节日常功能。
- 已经遇到故障: 先查第六节速查表,按对应编号进入第三节排错。
- 需要深入诊断或升级: 先读第一节配置机制,再使用第四节工具箱和第五节回退清单。
本文的 Windows 桌面记录、Debian 云端案例和示例配置分别标明来源;示例中的安装路径、包名及模型 ID 需要换成实际值。
目录
- 开始之前:适用读者与准备工作
- 快速开始:完成第一个桌面任务
- 一、认识 DSH:运行面、配置层与 CLI 入口
- 二、日常使用:界面、权限、模型、指令文件与扩展
- 三、排错手册:14 类常见问题及检查顺序
- 四、工具箱:配置诊断、独立运行面、日志解压与归档读取
- 五、修改配置与回退:日常修改与跨版本升级验收
- 六、速查表
- 附录:Debian 云端对照案例
- 官方参考文档
开始之前:适用读者与准备工作
本文面向在 Windows 上使用 DSH 桌面端的读者,既介绍首次安装和模型接入,也提供已有问题的排查方法。日常使用部分不要求编程基础;涉及 YAML、PowerShell 和日志诊断的进阶内容,可按需阅读。
开始前准备好以下几项:
- 64 位 Windows 电脑。 从 DeepSeek Harness 官网下载 Windows 64 位安装包。本文的实测环境是 Windows 11 25H2;它是测试环境,并非官方公布的最低系统要求。
- 可正常联网的环境和浏览器。 账号登录需要跳转浏览器,模型请求也需要连接相应服务。DSH 在本机运行工具,但本文介绍的模型接入仍依赖远程服务。
- 一种模型接入方式。 可以登录 DeepSeek 账号,也可以准备官方 API Key;已有第三方服务或网关的读者,则准备对应的密钥、接口地址和模型 ID。先选一种完成配置即可,具体步骤见 2.3。
- 一个练习文件夹。 例如在资源管理器中创建
D:\dsh-demo,用于第一次读写文件。后文命令中的D:\harness是作者的安装位置,照做时要换成自己的路径。
桌面安装包自带运行环境,完成入门流程不需要另装 Node.js、Python 或 pnpm。 后文的 CLI、技能脚本和扩展开发属于进阶操作,需要时再处理相关依赖。安装方式与运行时说明见官方桌面端文档。
快速开始:完成第一个桌面任务
第一步:安装并打开 DSH
运行官网提供的安装包,按提示完成安装,然后从开始菜单或安装目录打开 DeepSeek Harness。打开设置页的“通用”分区,记下当前版本,便于对照本文的实测记录。
第二步:接入模型
首次启动时,可以按欢迎页提示通过浏览器登录 DeepSeek 账号,也可以选择 API Key 配置入口,填入密钥后“保存并继续”。若暂时跳过,可稍后在设置中完成配置。账号登录、官方 API Key 和第三方接口的详细步骤见 2.3。
账号登录后若出现额度、用途等引导,按页面提示完成;提供“跳过”选项时,可以暂时跳过。这些页面可能随版本和账号状态变化。完成引导后,仍需在输入区核对当前选中的模型。
第三步:添加工作区并新建会话
如果侧边栏已经有默认工作区,可以直接打开;为了复现下面的练习,也可以使用“添加工作区”,选择已经创建的 D:\dsh-demo 文件夹,再打开一个新会话。工作区决定任务主要围绕哪个本地目录展开;仅在对话里提到一个路径,不等于已经切换工作区。
在输入区的模型选择器中确认提供商和模型。先发送“请用一句话介绍你自己”,收到正常回复后,再进行文件操作。正常回复只说明模型调用成功,下一步还需检验本地工具是否正常工作。
第四步:让它读取文件并保存结果
在练习文件夹中创建 notes.txt,写入几条便于核对的内容,例如:
本周完成了 DSH 桌面端安装。已经配置好模型,并收到了一次正常回复。下一步学习工作区中的文件读写。然后在会话中发送:
读取当前工作区的
notes.txt,把内容整理成三条 Markdown 列表,保存到同目录的summary.md。保留notes.txt的原文,完成后告诉我结果文件的路径。
保持默认权限设置;若出现读写文件的批准提示,核对目标路径和操作后再批准。权限模式与沙箱范围的说明见 2.2。
第五步:核对是否完成
在资源管理器中打开练习文件夹,检查 summary.md 是否存在、内容是否对应原文,并确认 notes.txt 未被修改。会话里也应能看到读取和写入文件的工具记录。以实际文件和工具结果作为完成依据,不能只看模型回复“已完成”。
完成这一步,就验证了模型接入、工作区选择和文件读写三条基本链路。若聊天失败,先按 2.3 核对接入方式、密钥和模型;若聊天正常但文件操作失败,先查工作区与 2.2 的权限设置,再进入第三节排错。
2026-10-03 补充人工确认: 本机已完成登录、收到正常中文回复,并完成工作区内的文件任务,结果文件为 D:\dsh-work\tmp\dsh-practice\summary.md。本次使用已有练习目录,上文的 D:\dsh-demo 则是供读者参考的示例路径;操作时以实际打开的工作区为准。这次检查补充了桌面操作记录,未重新测试安装程序或所有模型接入方式。
一、认识 DSH:先理解配置如何生效
DSH(DeepSeek Harness)是一个通过插件组合能力的本地智能体运行环境。模型接入、工具、会话持久化、权限与沙箱,都有对应的插件组件。本机安装包中共有 289 个 @deepseek-ai 作用域包,其中 278 个以 dsh- 开头,另有 dsh 启动器和框架工具包。这个数量只描述该安装版本。
日常使用不必逐个理解这些包,但排错时需要知道:一个功能是否可用,取决于相关插件是否被正确组装和激活。
1.1 三个核心概念
| 概念 | 含义 | 位置 |
|---|---|---|
profile | 一套运行配置:按顺序组合的插件层与用户覆盖层 | %DSH_HOME%\profiles\<名字>\ |
bundle | 插件组合包,声明需要加载的插件条目 | profile 的 node_modules |
| patch 层 | 覆盖、新增或禁用插件条目的配置层 | cordis.patch.yml |
配置合成顺序如下,后者覆盖前者:各 bundle 的 patch → profile 用户层 cordis.patch.yml → home 级 $DSH_HOME\cordis.patch.yml → 命令行 --patch。
注意:home 级 patch 的优先级高于 profile 级 patch。如果两处覆盖了同一个条目,最终会采用 home 级的配置。因此,排查配置未生效时,也要检查 home 目录里的 cordis.patch.yml。同一 id 出现多次时,最后一次写入生效;patch 条目的排列顺序不等同于插件的加载顺序。
另一条关键规则是:patch 会整块替换目标插件的 config,不会深度合并其中的字段。即使只修改一个键,也要在覆盖项中保留其他仍需使用的键;未写出的字段会回到默认值。示例见 3.2。
1.2 安装目录与用户数据目录
以下是本机目录示例。D:\harness 是本文使用的安装位置;%DSH_HOME% 表示 DSH 实际采用的数据目录,没有自定义时通常为 %USERPROFILE%\.dsh。PowerShell 中读取环境变量使用 $env:DSH_HOME,请按自己的安装路径替换示例。
D:\harness\ # 安装根目录├─ DeepSeek Harness.exe├─ version # Electron 版本(本机 44.0.0)└─ resources\ ├─ app.asar # 应用代码,注意:这是【文件】不是目录 └─ runtime\ ├─ cli\bin\dsh.cmd # CLI 入口(排错主力) ├─ pnpm\ # 内置 pnpm ├─ primary-runtime\ # 内置 node/python 运行时 └─ versions.json # node 24.18.1 / pnpm 11.7.0
%USERPROFILE%\.dsh\ # 默认 DSH_HOME(未自定义时)├─ profiles\{desktop,web,...}\ # 各运行面的 package.json + cordis.patch.yml + node_modules├─ sessions\<工作区>\<会话id>\session.v4.jsonl.zstd # 会话日志├─ skills\ # 技能目录├─ storages\ # 存储域(workspace.json 等)├─ attachments\ cache\ dsh-runtimes\└─ .credentials.yaml # 凭据DSH_HOME 的解析优先级为:显式路径 > 环境变量 $DSH_HOME > ~/.dsh,空白的环境变量值会被忽略。会话、技能和日志目录的位置取决于实际采用的数据目录,排错前应先确认其路径。
使用这些路径时,还需注意:
app.asar是文件。在普通 PowerShell 或独立 Node.js 中,不能把app.asar\dsh\...当作常规目录访问。4.4 提供仅读取指定文件的最小脚本,以及保存、运行和查阅版本对应 README 的步骤。desktopprofile 由 Electron 应用独占,CLI 不能直接启动它,详见 3.10。- 内置 Node.js 不在 PATH 中。需要从命令行运行脚本时,使用绝对路径
%DSH_HOME%\dsh-runtimes\dsh-primary-runtime\dependencies\node\bin\node.exe。
1.3 CLI 入口
$dsh = 'D:\harness\resources\runtime\cli\bin\dsh.cmd'& $dsh --version # 0.2.0-rc.2& $dsh --helpdsh [--profile] <name> [options] [app-args...] --profile <name> 启动 $DSH_HOME/profiles 下的某个运行面 --from-default-profile <name> 用官方模板创建一个新 profile --patch <path> 追加一层覆盖(可重复) --dump-config 打印合成后的完整配置树并退出 --dump-config-schema 只打印 schema,不挂载插件 --dump-default-config 打印不含用户层的配置树dsh plugin --profile <name> <pnpm-args...> # 直接对 profile 执行 pnpm 操作桌面应用通常通过双击 exe 启动,底层使用 desktop profile。CLI 可以提供更完整的配置诊断信息,但 desktop 有 Electron 独占限制;需要复现桌面配置时,先按 3.10 创建诊断副本。后文中的 <profile名> 是占位符,执行时应换成实际可由 CLI 使用的名称。
二、日常使用
2.1 界面速览
- 侧边栏:底部是固定的设置(Settings)入口。会话列表默认按“最近更新”排序,也可切换为手动排序。展开的工作区默认显示 5 条空闲会话;运行中的会话始终显示,不计入这 5 条的显示数量。
- 会话行:悬停操作区或
...菜单提供置顶(pin)、重命名(rename)、分叉(fork)和归档(archive)。Fork 会从源会话最后一个已完成轮次处创建新会话,标题自动递增。 - 输入区:
Enter按当前投递模式发送,Ctrl+Enter按另一种模式发送;忙碌时可选择“排队”或“插话”,本机使用steer插话模式。Shift+Enter换行;/打开命令菜单,Tab确认,Esc退出。点击模型选择控件可打开模型列表。 - 停止当前轮次:连按两次
Esc,默认间隔不超过 500 ms。这是内置固定快捷键,不能修改绑定。 - 设置页:由各功能包注册的分区组成,常见分区包括通用、模型、插件、插件清单、Web search、会话日志、子智能体、Agent 循环和账户。通用分区可查看当前发布版本。
常用快捷键(Windows 桌面端):
| 操作 | 快捷键 |
|---|---|
| 快捷键速查表 | Mod+/ |
| 打开设置 | Mod+, |
| 搜索会话 | Mod+K |
| 重命名当前会话 | Mod+Alt+G |
| 停止当前轮次 | Esc Esc |
Mod 在 Windows 上表示 Ctrl。可自定义的快捷键保存在 Electron 用户数据目录下的 keybindings.json;停止当前轮次的双 Esc 例外。
2.2 权限与沙箱:按任务选择模式
DSH 把“沙箱范围”和“审批策略”打包成预设。本文版本的随附配置提供三种预设,人工确认的中文名称为“仅可查看”(read-only)、“工作区内修改”(workspace-write)和“完全权限”(danger-full-access)。插件字段说明里的默认表只列后两项,不等于随附配置的实际选项。
日常先通过界面操作:
- 在当前会话输入
/permission,查看可用选项并切换当前会话的权限。输入区的权限控件也用于当前会话。 - 需要改变以后新建会话的默认值时,再到“设置 → 通用”中的默认权限设置调整。本机人工确认:修改默认值后,当前会话保持原权限,新会话采用新默认值。
- 本次练习中,“仅可查看”下请求写文件出现了提权提示;切换到“工作区内修改”后,文件成功生成。出现提权提示时,先核对操作和目标路径,再决定是否批准。
需要用 YAML 固定预设时,先备份将要修改的 cordis.patch.yml,再核对同一个目标 profile 的合成配置。按 4.1 的方法运行 --dump-config,定位 id: permission,读取当前完整的 config.presets 和 defaultPreset。desktop 不能直接由 CLI dump,需按 3.10 建立诊断副本;不能把 web 的权限配置当作桌面端当前配置。
patch 会整块替换 config,因此即使只调整 defaultPreset,也必须在覆盖项中保留自己的完整预设表及其他仍需使用的字段。优先在界面调整新会话默认值(见上面的步骤 2);只有明确需要固定 YAML 时,才把核对后的覆盖项写入 %DSH_HOME%\profiles\<profile>\cordis.patch.yml。
下面只演示将新会话默认值设为“工作区内修改”。 本机原默认值为“完全权限”,照抄此段会改变默认值;它不是保留当前设置的模板。预设名称、沙箱与审批策略均应以自己的 dump 为准,再有意识地决定需要修改哪些值:
- id: permission name: '@deepseek-ai/dsh-permission-presets' config: presets: read-only: sandbox: read-only approval: ask workspace-write: sandbox: workspace-write approval: ask danger-full-access: sandbox: danger-full-access approval: never defaultPreset: workspace-write本文版本中,三种沙箱模式的主要行为如下:
| 模式 | 行为 |
|---|---|
read-only | 拒绝写入(/dev/null 等必要的输出目标除外) |
workspace-write | 允许写工作区根目录与后端分配的临时区域 |
danger-full-access | 绕过隔离,直接以原始 argv 启动子进程 |
还需区分以下三点:
- 这些模式主要约束文件影响。 官方说明不提供网络限制;进程可见性因后端而异,文件读取也会受到具体后端与系统权限的影响,不能概括为“全部不受限制”。选择
read-only后,仍需考虑命令会读取哪些数据。 - 修改默认预设只影响新会话。
defaultPreset在创建会话时读取并记录,之后修改默认设置不会改变已有会话的权限。要修改当前会话,使用/permission;不带参数时可查看当前值与可选项。 - 审批策略只有
ask和never两个值。 授权仅对本次调用有效,没有“始终允许”选项。never会拒绝所有审批请求:需要审批的操作会被拒绝,模型也不会申请提权。无人值守时,需确认任务能在已有权限内完成。
Windows 上的沙箱通过受限令牌和 Low 完整性标签实现:子进程使用 WRITE_RESTRICTED 令牌,写入与删除受限,临时目录也会替换为按会话或工作区隔离的私有目录。本机观察到以下现象:
- 受限模式下某些 CIM 类命令(如
Get-ComputerInfo)不可用; read-only下 PowerShell 使用ConstrainedLanguage模式,Add-Type、部分 .NET 静态调用、COM 和反射会失败;- 受限进程通过管道捕获孙进程输出(
stdio: 'pipe')时会报EPERM,继承或忽略 stdio 时则正常。
调用被拒后如何处理? 拒绝信息会包含 [sandbox: file access denied under <mode> mode] 标记和提权提示。允许的升级路径为:read-only → workspace-write 或 danger-full-access;workspace-write → danger-full-access。应在这些路径内选择满足操作所需的最低权限,保持命令与参数不变,重试一次,不能更换命令。
本机测试时使用了 danger-full-access 默认预设,命令直接以宿主权限执行。日常在项目内修改文件,可以先选择 workspace-write;任务确实需要越界写入时,再核对目标路径和当前审批策略。
2.3 模型接入与思考强度
DSH 可以同时接入多个模型提供商。初次使用时,先通过下面的一种方式完成配置,再按需添加其他提供商。界面字段以当前版本为准,完整说明见官方模型接入指南。
2.3.1 使用 DeepSeek 账号登录
桌面端欢迎页或“设置 → 账户”提供登录入口。点击登录后,在打开的登录页面选择微信扫码或手机号登录,再按页面提示返回 DSH。微信扫码与手机号登录是本机本次人工确认的可用方式;如果浏览器没有自动打开,可以使用界面提供的“复制登录链接”手动访问。
回到 DSH 后,检查账户页是否显示已登录,并在输入区选择“DeepSeek 账号”提供的模型。这种方式使用账号登录状态,无需在模型设置中另填 API Key 或接口地址。若此前配置过其他提供商,登录成功后不一定会自动切换,需手动核对模型选择器。账号相关说明见官方账户文档。
2.3.2 使用 DeepSeek 官方 API Key
- 前往 DeepSeek 开放平台,登录后在 API Keys 页面创建密钥。
- 打开 DSH 的“设置 → 模型”,找到官方 DeepSeek 提供商卡片,填入密钥本身,点击保存或应用。
- 回到会话输入区,选择该提供商下的可用模型,发送一条简短消息验证。
这里填写的是实际密钥,不是 DEEPSEEK_API_KEY 之类的环境变量名称。保存后界面通常不会回显完整密钥;是否保存成功应结合保存状态和实际请求判断。
账号登录与开放平台 API Key 是两种接入方式,不能互相替代。 模型调用还需要对应服务的可用额度,按实际账户页面核对。
官方 DeepSeek 卡片会使用适配器的默认协议和地址,通常无需手工填写。本文版本的官方卡片默认走 Messages 接口,地址为 https://api.deepseek.com/anthropic;开放平台文档同时提供 OpenAI 兼容入口 https://api.deepseek.com。两者对应不同协议,不能把地址和协议随意混用。参考DeepSeek API 文档及DSH 模型设置说明。
2.3.3 接入模型目录中的第三方提供商
在“设置 → 模型”中点击“添加模型提供商”,选择“第三方模型提供商”,再从目录中选中服务商,填写该服务商的 API Key 并保存。目录会提供默认接口、协议和模型信息;回到会话输入区选择模型后即可测试。
第三方密钥应由对应服务商提供。若使用的是自建网关或公司统一接口,应使用下面的“自定义模型 API”,填写实际网关地址。
2.3.4 接入自定义模型 API
在“添加模型提供商”中选择“自定义模型 API”,依次填写:
- 提供商 ID 与显示名称。 ID 用于识别模型路由,必须唯一且使用小写,创建后不能直接修改。显示名称用于界面展示。
- 接口地址与协议。 按服务商文档填写。OpenAI Chat Completions 对应
openai-completions,OpenAI Responses 对应openai-responses,Anthropic Messages 对应anthropic-messages。同一提供商只使用一种协议。 - API Key。 填入目标服务的实际密钥。
- 至少一个模型 ID。 ID 必须与服务端接受的值一致,显示名称可以另行填写。可先点击“获取可用模型”,选择后“添加所选”;若服务不支持列出模型,也可以按服务商文档手动添加。
- 保存并测试。 回到会话输入区选择新提供商和模型,先验证一条文本请求。
例如,OpenAI 兼容网关常使用 https://gateway.example/v1 作为 base URL;是否需要 /v1 要按网关说明确认。模型列表获取失败并不能单独证明聊天接口不可用;实际请求能否成功才是最终验证。
上下文长度、最大输出长度和图片输入等能力应按模型实际支持情况填写。勾选图片输入只是在配置中声明能力,不会让一个纯文本模型获得看图能力。
2.3.5 选择模型与保存默认值
日常选择模型在会话输入区的模型选择器完成。选择模型及其支持的推理强度后,该选择也会保存为新会话的默认值;已有会话会保留各自的选择。正在运行的请求仍使用启动时的模型与强度,切换对下一次请求生效。
若需要通过 YAML 固定默认模型,可覆盖 agent-default-model。以下示例以已配置名为 mygateway 的提供商,且其模型目录中存在 some-model 为前提:
- id: agent-default-model name: '@deepseek-ai/dsh-agent-default-model' config: provider: mygateway model: some-model上面的名称是占位示例,要替换为实际提供商 ID 和模型 ID;仅写默认模型条目不会自动创建提供商或保存密钥。需要固定强度时,可在 config 内增加 reasoningEffort,其值必须是该模型公布的可选等级。参考默认模型配置说明。
2.3.6 进阶:自定义思考强度与凭据来源
本机同时使用账号接入(dsh-llm-deepseek-account)和自定义网关接入(dsh-llm-pi-ai)。日常操作优先通过界面完成;需要适配网关的推理参数时,再检查下面的 YAML 配置。
需要自定义思考强度档位时,可以在模型配置中声明映射(脱敏示例):
- id: llm-pi-ai name: '@deepseek-ai/dsh-llm-pi-ai' config: providers: mygateway: apiKeyEnv: MY_GATEWAY_API_KEY api: openai-completions baseURL: https://your-gateway.example.com/v1 reasoning: 'off' models: - id: some-model name: Some-Model contextWindow: 262144 reasoningEfforts: off: none low: low high: high max: xhigh实测要点:
- 思考强度的取值由目标网关和模型决定。 本机所用网关接受
none / low / high / xhigh / max,传入medium或minimal时返回 400。这个结果不能推广到所有网关;应按自己端点的支持范围填写reasoningEfforts。 reasoningEfforts的键是选择器显示的等级,值是实际请求使用的参数值。例如,max: ultra将界面中的max映射为请求中的ultra,前提是目标端点接受该值。省略整个字段会保留模型目录自带的能力声明;将reasoningEfforts设为false则表示该模型不支持推理,界面不显示 Effort 行。- 手工声明的路由必须同时提供
api、baseURL和非空的models列表,否则保存配置时会被拒绝;modelOverrides与models同时存在也会被拒绝。 - 同一条模型路由只能使用一种协议格式。 如果注册的路由名已被其他适配器占用,插件会加载失败。
- 模型选择只对下一次请求生效。 正在执行的步骤仍使用启动时的模型与强度;修改后若当前步骤没有变化,先核对它是否在切换前就已开始。
- 推理强度不能任意填写。 界面只提供适配器为该模型公布的等级;没有推理元数据时,不会显示 Effort 行。
- 提供商编辑页不负责选择推理强度;应在会话输入区的选择器中调整。默认模型配置由
agent-default-model保存,GUI 选择也会更新新会话默认值;需要可复现的配置时,再通过cordis.patch.yml管理。
要确认强度是否生效,需要观察 DSH 实际发出的请求或网关侧的请求记录,核对 reasoning_effort 等字段。开发者可在自定义适配器中加入发送前的调试代码;onPayload 属于底层 SDK 的开发接口,本文版本的 DSH 官方配置没有把它列为可直接填写的用户选项。向网关发送最小请求可以确认网关是否接受该值,但不能单独证明 DSH 发出了相同字段。调试输出只保留所需字段,避免记录凭据与私人对话。
密钥配置采用引用名与凭据值分离的方式:配置中写入 apiKeyEnv: MY_GATEWAY_API_KEY 这样的引用名,实际值按以下优先级查找:
启动时的环境变量 > %DSH_HOME%\.credentials.yaml > 调用目录\.env > %DSH_HOME%\.env凭据配置还需注意:
- 启动环境变量是冻结的快照。启动后在 shell 中改变量不会改变 DSH 已读取的值;更换这种来源的凭据需要退出并重新启动。通过 GUI 或凭据服务保存的密钥则会在下一次请求生效,无需重启;本地凭据文件默认也启用变更监听。启动环境中的同名值优先,可能遮蔽后来保存的密钥。
- 空字符串按缺失值处理。 清除某个来源中的密钥时,应删除对应条目;查找时仍会按优先级检查其他来源。
- 在模型(Models)设置页输入的密钥只供保存,不回显完整值。配置使用 profile 中的凭据引用;没有引用时,会派生
<ROUTE>_API_KEY作为引用名。引用名与实际凭据分开存储,因此模型配置中没有明文密钥,并不表示保存失败。
2.4 指令文件:AGENTS.md / CLAUDE.md
DSH 会将指令文件注入上下文,加载规则如下:
- 默认按
AGENTS.md、CLAUDE.md、AGENTS.local.md、CLAUDE.local.md的顺序加载同目录内所有存在的候选文件;内容不同的AGENTS.md与CLAUDE.md都会加载,并非二选一; - 加载范围包括用户全局文件
%DSH_HOME%\AGENTS.md,以及从项目根目录到当前工作目录的祖先链上的同名文件; - 项目根目录是从当前工作目录(cwd)向上找到的第一个含
.git的目录;找不到时,使用 cwd; - 同目录内的文件按去除空白后的内容判重,跨目录不合并。默认预算为 65536 字节,超出时优先丢弃作用范围较广的指令。
指令刷新依赖文件访问与步骤检查,没有独立的文件监听器。 在外部编辑器中修改 AGENTS.md 后,需要等到相关文件读写、会话恢复时的状态核对,或下一次步骤开始前的检查(pre-step),更新才会被发现。通过 bash 修改目录中的其他文件,也不会自动触发嵌套指令发现。需要及时应用新指令时,可以让 DSH 读取对应文件。
实践建议:跨项目通用的要求写入用户全局文件,项目特有的要求写入仓库根目录文件。本机分别配置了全局和工作区指令;两者可有部分重叠,但作用范围不同。
2.5 长会话与上下文
会话以仅追加的事件日志保存,模型看到的历史根据日志还原。因此:
- 压缩(compaction)会遮蔽部分历史,使其不再直接进入模型上下文,但不会删除原始日志;回放仍可重现相同状态。
- 自动压缩阈值按以下参数计算:窗口
W、输出上限O、余量B(默认 65536 tokens),阈值为floor(min(W × 0.8, W − O − B));逐字保留的近期历史默认为W − O的 16%。 - 溢出兜底:提供方确认”上下文溢出”后,会先压缩再重试该请求一次。
- 手动压缩使用
/compact。命令不会作为普通聊天轮次进入模型历史,但生成摘要时会发起辅助模型请求,消耗 token;若仅裁剪工具结果就已足够,则可能跳过摘要请求。完成后会显示减少的历史项数量与预计节省的 token。此命令只在会话空闲时可用,忙碌时会显示提示;压缩期间发送的消息会排队,结束后再处理。
会话还有一套用于异常恢复的检查点机制:模型请求前、顶层工具执行前、每个 pre-step 都会写检查点。如果中途崩溃,恢复时:
- 有
tool/call但没有结果的调用 → 标记为TOOL_OUTCOME_UNKNOWN(结果未知); - 尚无启动记录的工具调用 → 标记为
TOOL_NOT_STARTED(尚未开始)。
这两种调用都不会自动重试。只读或幂等操作可以直接重跑;可能产生副作用的操作,必须先核对外部状态。应用崩溃或断电后,应先检查命令是否已经产生结果,再决定是否重跑。
2.6 会话与工作区管理
- 会话归档:本文版本提供归档操作。若会话仍有进行中的轮次、子代理、后台任务或定时提醒,归档会被拒绝,并提示“停止并归档”。
- 移除工作区不会删除数据:文件夹、文件和会话历史都会保留,相关会话进入未分组(Ungrouped)列表。重新添加同一目录会创建新的工作区记录,旧会话不会自动归入其中。
- 用
@path引用文件:在输入开头或空格后输入@可触发补全;带空格的路径写为@"my file.txt"。选中候选只会添加引用,不会读取文件内容;模型仍需调用文件工具才能看到内容。 - 附件:图片会在消息被接受前校验并规范化,支持 PNG、JPEG、WebP 和 GIF;任一图片不合法,整条消息都会失败。其他文件按原始字节保存,模型只收到文件位置提示。本文版本不会自动清理已存储的附件,长期使用时需留意存储占用。
- 导出会话:在会话头部的“更多操作”中选择“下载 Session 日志”,或在会话中输入
/export。两种方式都会将**整个会话树(会话本体、子会话和附件)**打包为 ZIP,由浏览器下载,文件名形如dsh-session-<id>.zip。/export不接受参数,因此不能使用/export <路径>,也不会直接写入 Host 磁盘。
2.7 扩展:技能 / 插件 / MCP / 定时任务
技能向模型提供操作说明,插件向运行时注册能力。先看两者的区别,再选择需要的扩展方式:
| 比较项 | 技能(Skill) | 插件(Plugin) |
|---|---|---|
| 形态 | 一个目录 + SKILL.md | 一个 npm 包(cordis 插件) |
| 位置 | %DSH_HOME%\skills\<name>\ 等 | profile 的 node_modules 与 bundles 列表 |
| 生效 | 目录变动在下一个模型步骤刷新 | 启用 HMR 的 profile 可重新组合;仅启动期组装的 profile 要重启 |
| 能力 | 向模型提供按需加载的操作说明,可附带脚本 | 注册工具、服务、UI、模型提供方 |
| 适合 | 固定流程、领域知识、脚本化操作 | 新能力、新界面、新数据源 |
2.7.1 技能:加载操作说明与脚本
技能目录按以下优先级扫描:<项目根>/.dsh/skills → <项目根>/.agents/skills → 配置的 customSkillDirs → %DSH_HOME%\skills → <agentsHome>/skills。只识别目录下一层的 <name>/SKILL.md 或 <name>.md,不递归扫描更深层目录。文件顶部的 YAML 元数据(frontmatter)必须包含 name、description,可选字段有 whenToUse、disable-model-invocation、user-invocable。
格式错误的技能可能被跳过。 加载阶段会产生警告,但模型侧的技能目录不会逐条显示失败原因。修改后应同时检查技能是否仍出现在目录中,以及加载日志是否存在格式警告。
技能脚本若使用运行时自带的 Python,还要检查依赖。本机运行时没有预装 requests 等常用包;安装时应明确指定该 Python 对应的 pip,避免装进其他环境。
2.7.2 插件:安装、启停与生效边界
插件的安装与启停有三个入口:
- 界面:侧边栏的“插件”页,可启停单个插件条目、勾选组合包,以及安装或删除外部组合包。设置页的插件列表只供查看,启停操作应在侧边栏插件页完成。本次人工测试中,将所测插件禁用后再启用,功能恢复且未要求重启;这一结果只适用于该次启停操作,不能据此判断安装、卸载或包版本替换是否需要重启。
- 智能体工具:
plugin_manager。随附预设仅在 Creator 模式下启用此工具,其他预设默认禁用。每次操作都需要danger-full-access权限,或针对本次调用的批准。 - CLI:
dsh plugin --profile <profile> add <包>,参数直接透传给 pnpm。
不同启停操作会修改不同的配置文件,有时也会改变配置优先级:
- 禁用单个插件时,只会将
cordis.patch.yml中最后一条匹配覆盖项的disabled设为true,不会删除依赖; - 禁用和重新启用组合包时,修改的是
package.json中有序的bundles列表。重新启用会将它追加到末尾,因此可能改变它与其他组合包之间的覆盖优先级; - 新安装的组合包默认启用。
pnpm 11 默认阻止未获授权的依赖构建脚本。安装时会列出 pendingBuilds,插件页提供“允许这些脚本并重试”操作。这会授权脚本以宿主用户权限执行,点击前应核对包名。
2.7.3 MCP:连接外部工具服务
本次人工检查未在桌面界面找到 MCP 添加入口,本文因此不将“从插件管理页添加”列为已验证步骤。需要接入时,可按官方 MCP 客户端说明配置 dsh-mcp-client 条目:每台服务器对应一条记录,transport 支持 stdio 和 streamable-http,默认没有启用的服务器。工具名形如 mcp__<serverName>__<name>。服务器连接失败不会阻止 DSH 启动,但对应工具不会出现;断线后会按指数退避重连,连续失败 10 次后停止重试。独立 headless 运行面的回显工具调用已在补充核查中验证,桌面 GUI 添加流程尚未验证。
2.7.4 子代理、后台作业与定时任务
- 子代理:工具未单独指定深度时,默认最大委派深度为 1。
maxActiveSubagents默认 8,限制同一名额池内存活的可续接子代理,等待后代、待收件箱处理及正在停止的实例也占名额;一次性与外部提供方运行不受这项限制。新建或冷恢复时容量满了直接拒绝,不排队。 - 后台作业:
job_output/job_list/job_kill,任务 id 形如bash-1;只能被所属会话访问,结束后不会自动从列表消失。 - 定时任务:默认运行组合未启用这项实验性能力,需在插件管理页的“官方”分组启用对应 bundle;宿主进程必须保持运行,提醒才能投递。
2.7.5 Plan 模式:调整协作方式
使用 /plan 进入,/plan off 退出。它只引导模型的工作方式,不会禁用工具;实际操作限制仍由沙箱模式和审批策略控制。
三、排错手册
3.0 先确定检查顺序
先检查配置与组装,再检查运行行为。
遇到“安装并重启后功能仍未出现”,先确认相关 bundle 是否参与组装。一个实用的排查顺序是:
配置是否被读到 → bundle 是否被跳过 → 插件是否激活 → 实际行为是否正确 合成配置 跳过报告 启动/运行日志 请求体与对照实验用证据区分症状与根因。
一次搜索插件排查中,我先后将 bundle 的提供方绑定(pin)复制到用户层、为搜索提供方增加输出截断,并向 node_modules 手动放入宿主包。复盘发现,输出截断修正了一处实现问题,但插件未生效的主要原因是升级后的版本预检。复制 pin 并未解决版本预检问题,手动放入的包还可能被包管理器清理。
这个案例说明,组装问题和实现缺陷可能同时存在。修改前先读宿主诊断,可以避免把两类问题混在一起。
3.1 症状:插件已安装并重启,仍不生效
首先检查:bundle 是否被版本预检跳过。
组装时,DSH 会将每个 bundle 声明的 @deepseek-ai/dsh* 依赖兼容范围(peerDependencies)与运行时版本进行 semver 比较,预发布号也参与比较。不匹配时,整个 bundle 会被跳过:其插件条目不会插入,随附 patch 也不生效。GUI 中可能没有明显报错,但诊断输出和启动控制台会记录跳过信息。
诊断:
& $dsh --profile <profile名> --dump-config *> dump.txtSelect-String -Path dump.txt -Pattern 'skipping profile bundle'如果看到 skipping profile bundle ...,继续核对被跳过的包和未满足的 peer 范围。合成配置中出现了插件条目,也不代表该插件已成功激活。
两个关键细节:
- 运行时版本以
@deepseek-ai/dsh-app-boot的version为准,不能以其他清单文件中的版本代替; - 兼容声明需使用匹配当前预发布版本的精确版本或版本范围。
~0.2.0、^0.2.0都不匹配0.2.0-rc.2,编写兼容声明时应特别核对预发布号。
按以下优先级处理:
① 优先更新兼容的插件版本。 检查插件发布的兼容声明,选择覆盖当前运行时的版本。若你是插件作者,应先验证实现兼容,再修正 peer 范围,例如使用精确的 0.2.0-rc.2 或包含该预发布版本的范围。仅修改声明不能修复代码不兼容。
② 通过“版本豁免”授权指定版本。 用于兼容性测试的豁免记录保存在 profile 目录的 compatibility.json 中,将 包名@版本 精确映射到允许的 DSH 运行时版本列表:
# 查看当前运行时版本与已有授权& $dsh plugin --profile desktop version-exemptions
# 授权(会先打印风险警告;必须显式带上 --accept-risk)& $dsh plugin --profile desktop allow-version <包名@版本> --dsh-version <运行时版本> --accept-risk
# 撤销& $dsh plugin --profile desktop revoke-version <包名@版本> --dsh-version <运行时版本>三点要注意:
- 授权只适用于指定的插件版本与运行时版本组合。 插件或 DSH 升级后,原授权不再覆盖新的组合,需要重新授权。
- 授权在下一次组合时生效。 支持在线重新组合的 profile 会挂载插件并返回
applied;仅支持启动期组装的 profile 会返回restart-required。 - 版本豁免只改变预检判定,不能证明实际兼容。 peer 不匹配说明兼容声明未覆盖当前运行时,继续加载可能导致崩溃或数据丢失。授权命令会先显示风险警告,应在明确了解兼容性风险后使用。
兼容性拒绝的错误码为 incompatible-version,记录中会包含每个被拒包的 name、version、runtimeVersion 和未满足的 peers。可据此核对并修正插件的兼容声明。
这次云端记录只查看了版本豁免机制,没有授予豁免。上文授权命令是操作说明,不能作为本次已执行或已验证兼容的证据。
3.2 症状:patch 写了,配置没变
依次检查以下四项:
① 覆盖目标的 id 不存在。 覆盖已有条目的前提是该 id 已存在于某个 bundle 的默认层。否则 DSH 会打印 patch: entry ... not found 并跳过该项,不会因此终止启动。需要新增条目时,应使用 insert::
# 覆盖既有行:要求这个 id 已在某个 bundle 的默认层里存在- id: ui-chat name: '@deepseek-ai/dsh-client-ui-chat' config: transcriptView: compact
# 新增行:id 不在任何默认层里时,必须用 insert- insert: - id: my-hook name: '@deepseek-ai/dsh-hooks-claude-code' config: { }② 覆盖时遗漏了仍需保留的键。 patch 条目会整块替换 config,不会深度合并。修改一个字段时,需一并保留其他仍需使用的字段,否则它们会回到默认值。
③ 相关 bundle 被跳过了。 先按 3.1 处理 bundle 的兼容性问题;只向用户层补充提供方绑定(pin),不能代替完整组装。
④ 文件为空或只有注释。 cordis.patch.yml 不允许为空,空文件或纯注释文件会导致启动失败。如果不需要这一层提供覆盖项,应写入空 YAML 数组 [],不要清空文件。
遇到 entry not found 时,先确认提供原条目的 bundle 是否参与组装,再判断是否真的需要新增条目;不要直接把旧覆盖改成 insert:。
3.3 症状:修改配置或代码后,无法判断是否需要重启
启用热重载(HMR)后,DSH 会监视 profile 的补丁层,cordis.patch.yml 的修改通常可在不重启应用的情况下生效。具体仍取决于改动类型和插件的响应方式:
| 改动 | 生效方式 |
|---|---|
| 改某个已挂载插件的 config | 无需重启应用;各插件响应方式不同,有的在每次请求时重读配置,有的需要重载插件 |
在 dsh.profile.bundles 新增 bundle 行 | HMR 启用时监听有序 bundle 列表变化并重新组合;未启用时要重启 |
| 改插件自己的源码 / 依赖 | 源码只有配置了相应监听目录时才可热重载;替换已安装包版本仍需重启 |
改技能目录里的 SKILL.md | 下一个模型步骤刷新(无需重启) |
HMR 监视 profile manifest,以及 profile 级和 home 级两份用户 patch 文件。配置文件写入默认有约 2 秒的稳定窗口,因此连续快速编辑可能合并为一次更新。通过插件管理器执行操作时,不需要等待文件事件。
不要把“纯 insert 才能热挂载”或某次接口返回的 supported: false 当作所有桌面版本的规则。官方共享插件管理器区分配置重新组合与已安装包版本替换:前者取决于 HMR,后者仍需重启。以本次操作返回的 applied、restart-required、警告与实际激活情况判断;需要重启时先保存结果,完全退出应用后重新打开。
3.4 症状:Hook 完全不执行,退出码是 3221225794 / 0xC0000142
本机曾因 Windows 子进程环境问题遇到 Hook 启动失败。相同退出码也可能由其他原因引起,应先对照运行环境。DSH 自带的桥接插件可读取并执行现有 Claude Code hooks.json 中的配置,示例如下:
- name: '@deepseek-ai/dsh-hooks-claude-code' config: configPath: ./.claude/hooks.json # hooks.json,或含 hooks 键的 settings 文件 pluginRoot: ./.claude/plugins/my-plugin # 用于替换命令里的 ${CLAUDE_PLUGIN_ROOT} projectDir: . # 用于替换 ${CLAUDE_PROJECT_DIR},并设同名环境变量Electron 宿主会在子进程的 PATH 开头加入 <安装目录>\resources\runtime\bin。目录中的 node(无扩展名)和 node.cmd 是转发启动命令的 shim,内容大致如下:
set ELECTRON_RUN_AS_NODE=1"%DSH_DESKTOP_NODE_EXECUTABLE%" --expose-internals %*本机故障中,DSH_DESKTOP_NODE_EXECUTABLE 只在前述子进程环境中设置。Hook 进程继承了修改后的 PATH,却没有该变量,于是 Hook 命令中的裸 node 命中了 shim,但启动所需的变量为空,导致进程启动失败。手动运行同一脚本时退出码为 0,在 DSH 中则返回 0xC0000142(STATUS_DLL_INIT_FAILED),且 stderr 为空。
本案例的修复:将 Hook 命令中的裸 node 替换为可用 node.exe 的绝对路径。
本机通过以下对照步骤定位了问题:
- 手动运行 Hook 脚本,确认脚本本身能够正常执行;
- 尽量复现 DSH 的命令参数(argv)、工作目录(cwd)和环境变量,再运行一次,同时提供 stdin 并收集 stdout,对照执行结果;
- 每次只改变一项条件,例如路径中的正反斜杠、cwd 或 SystemRoot,逐项对照,定位影响执行的因素。
排查 Hook 时,还需注意以下规则:
- Hook 配置作用于整个进程,且仅在启动时读取一次。 修改
hooks.json后,需要重启 DSH 才能生效,不支持热更新。 - Hook 在会话工作区目录中执行;脚本中的相对路径以工作区为基准,不是 DSH 的启动目录。
- 退出码 0 表示脚本正常退出,桥接会解析该事件支持的 stdout 或 JSON;退出码 2 表示阻塞结果,效果取决于事件。
UserPromptSubmit会阻塞提示词提交,PreToolUse会在工具执行前拦截,PostToolUse只能影响已执行工具的结果与反馈,不能撤销工具动作;Stop的阻塞会强制模型再执行一步,SubagentStop仅作观测。其他非零退出码记为非阻塞失败。排查时需同时核对事件名、退出码与输出。 - 本文版本中,桥接传入的
transcript_path始终为空字符串:默认会话日志经过 Zstandard 压缩,Hook 脚本无法直接读取,持久化层也未暴露产物路径。 - 本文查阅的该版本文档未说明上述 Windows shim 问题,因此这部分结论来自本机对照实验。
3.5 症状:HTTP 状态码为 200,功能仍不正常
检查响应体是否包含业务错误。 本机曾遇到火山搜索端点鉴权失败却返回 HTTP 200 的情况:响应体实际包含错误信息,插件因缺少预期的结果字段,将其转述为“没有搜索结果”。
处理时可直接向端点发送请求,查看原始响应。本机故障中,插件只提示缺少结果字段,原始响应则明确包含 invalid_api_key。
当状态码与客户端表现不一致时,应同时记录 HTTP 状态和业务错误字段,再判断请求是否成功。
3.6 症状:切换模型或思考强度后,看不出变化
按以下顺序检查:
- 强度值是否在目标网关与模型的支持范围内(本机网关的取值见 2.3);
- 核对 DSH 实际请求中的字段,可查看适配器调试输出或网关请求记录。直接用 curl 请求网关只能验证网关能力,不能代替对 DSH 请求的检查;
- 切换模型与强度只对下一次请求生效,正在执行的步骤保留启动时的设置;
- 确认修改的是当前会话的选择,还是新会话的默认值;已有会话仍保留各自记录的选择。
不同模型对思考强度的响应可能不同,输出长度也不能直接证明参数是否生效。可使用相同提示词、只改变强度做 A/B 对照,记录 token 数与输出长度作为辅助指标;主要证据仍是 DSH 实际请求中的字段。
3.7 症状:搜索正常返回,结果却来自其他提供方
一种典型情况是:插件通过 bundle 自带的 patch,将搜索提供方绑定到自己的实现。一旦 bundle 被版本预检跳过(见 3.1),绑定也会失效,搜索便回落到内置提供方。此时可能没有明显报错,也能返回结果,但结果来源已发生变化。
这一版本内置搜索提供方的实现,也有助于理解报错来源:DSH 内置的 DeepSeek 搜索提供方走的是 Anthropic 兼容的 Messages API,一次搜索要消耗一个完整的模型轮次(本文所查阅实现没有使用独立的公开检索端点)。它只从结构化的 web_search_tool_result 块里取结果,缺这个块时直接抛错而不是降级,错误码是 WEB_PROVIDER_ERROR(凭据缺失则是 WEB_PROVIDER_CREDENTIAL_MISSING)。需要直接调用独立检索 API 时,可以接入对应的 provider。
要判断实际调用了哪个搜索提供方,可结合以下三类证据:
- 用相同输入做 A/B 对照:同一查询词分别经 DSH 实际调用链路和目标 API 直连请求,比对结果的 URL 集合;
- 对照结果格式:不同实现可能带有独特标记,例如某个实现每条结果均包含
标题 — 摘要 (ISO 时间),另一个只包含标题和链接; - 核对配置与跳过报告:运行
--dump-config,检查合成配置及skipping profile bundle报告。
本机用这套方法核对了实际调用:DSH 返回的 8 条中文来源,与直连目标 API 的结果 URL 完全重合,交集为 8/8;此前使用内置提供方时,交集为 0/8。
同一次排查也留下了一个教训:第一次对照用了不同查询词,因而不能根据结果差异判断提供方是否正确。A/B 对照应使用相同输入,并尽量控制请求时间与其他参数。
3.8 症状:命令被拒,提示 [sandbox: file access denied under ...]
该标记表示调用被沙箱拒绝。先核对当前权限模式,以及命令实际涉及的路径:
read-only:不允许常规文件写入;需要写入时,通过/permission切换到workspace-write。workspace-write:可能是在写工作区之外的路径。- 需要临时扩大权限时,在允许的升级路径内选择满足操作所需的最低权限,保持命令与参数不变,重试一次。允许的路径为
read-only → workspace-write或danger-full-access、workspace-write → danger-full-access,不能同时更换命令。
以下现象也可能来自沙箱限制:受限模式下,Get-ComputerInfo 等 CIM 命令不可用,因为授权列表中没有 Authenticated Users;read-only 下 PowerShell 使用 ConstrainedLanguage,Add-Type、反射和部分 .NET 静态调用会失败。确认任务确实需要这些能力后,再按权限流程选择合适模式。
本机排查还发现,受限模式涉及的 Windows 完整性标签和 ACL 条目可能在 DSH 退出后继续保留,工作区改名后也要检查残留权限。它与 danger-full-access 绕过隔离是两个不同问题;遇到退出后仍无法写入的情况,应检查目录权限,而不是只调整会话预设。
3.9 症状:MODULE_NOT_FOUND / 路径不存在
先用 Test-Path 核对实际文件位置。两处容易混淆的情况是:
app.asar是文件,在普通文件系统工具中,不能把app.asar\dsh\...当作目录路径;- 文档、旧笔记甚至运行环境提示里的”检出位置”都可能过期。
Test-Path 'D:\harness\resources\app.asar' # True:文件存在Test-Path 'D:\harness\resources\app.asar\dsh' # False:它不是目录3.10 症状:CLI 报 profile is managed exclusively by the Electron application
desktop profile 归 Electron 应用管,CLI 会拒绝直接启动和配置 dump;npm 安装的 CLI 也不能管理它的插件。Desktop 内置 CLI 可在应用完全退出后管理已初始化的 desktop 插件。想从命令行查看相似配置,下面是本机采用的诊断副本方法,并非官方提供的 Desktop 启动入口:
- 在
%DSH_HOME%\profiles\下新建目录,名字以_开头; - 复制 desktop 的
package.json和cordis.patch.yml; - 若用 junction 引用原
node_modules,只做配置诊断,不在副本中执行包安装、更新或卸载;共享依赖会影响原 profile; - 用完先解除 junction 再删目录。
创建和清理诊断副本时,本机发现两项注意事项:
- JSON 序列化与文件编码要分开考虑。
ConvertTo-Json负责生成文本,BOM 是否出现取决于写入方式和 PowerShell 版本。本机曾因带 BOM 的package.json遇到Unexpected token;保存时应明确使用 UTF-8 无 BOM。 - 清理前核对 junction 的实际目标;先移除链接本身,再删除诊断目录,避免误处理被引用的依赖。
3.11 症状:抓不到网页 / 提示非公网 IP
本地代理启用 fake-ip 后,域名可能解析为 198.18.x.x 等保留地址。工具层的 SSRF 校验会将其判定为非公网 IP 并拒绝请求。此时 web_fetch 失败,并不表示网络连接本身不可用。
先检查代理的 DNS 模式和域名解析结果,再用正确配置代理的 curl.exe 或其他可用通道验证连通性。若确认是 fake-ip 导致,应优先为相关域名调整代理解析规则,使工具获得真实公网地址。
排查时,应区分工具层拒绝请求与网络连接失败;两者可能表现相似,但处理方式不同。
3.12 症状:重启应用中断了当前会话
重启承载当前会话的进程会中断任务。先保存结果与验证步骤,再按实际运行环境操作。
Windows 桌面端:关闭窗口与完全退出
桌面端会话任务由 Host 承载,需要重启时,应由用户从桌面界面完全退出应用后再打开。
本次 Windows 桌面端人工检查中,点击主窗口的关闭按钮(×)后,应用直接在后台继续运行,没有显示后台运行提示。托盘图标仍在,从托盘打开后会回到原会话。因此,是否隐藏成功应结合托盘图标和重新打开后的状态判断,不能仅以是否弹出提示判断。需要完全退出时,右键系统托盘图标,选择“退出 DeepSeek Harness”。本次操作后应用确实退出;重新启动后,旧会话仍可打开并正常回复。
通过 systemd 承载 DSH 的云端重启步骤见附录 A.3;桌面端按上面的托盘退出流程操作。
3.13 症状:DSH 启动失败,或启动后缺少功能
这两种情况的检查重点不同,需要分别处理。
① 应用启动失败。 本机此类失败的退出码为 1。DSH 会打印错误摘要,并将完整诊断写入 $DSH_HOME\logs\startup-<时间戳>-<uuid>.log:
Get-ChildItem "$env:USERPROFILE\.dsh\logs" | Sort-Object LastWriteTime -Descending | Select-Object -First 3 Name, Length, LastWriteTime阅读和分享启动诊断时,注意以下两点:
- 报告开头会提示:原始诊断可能包含插件错误中的配置或凭据值,分享前需检查。发到群聊或 issue 前,应先查看并处理敏感内容。
- 先找失败条目和原因,再判断影响范围。 已启用的必需条目激活失败会终止启动;普通条目失败通常只产生警告。具体必需 id、错误分类与处理规则见官方启动与重载失败说明,本文不复制完整清单。仓库主分支可能更新;核对本机版本时,按 4.4 读取
@deepseek-ai/dsh-app-boot/README.zh.md,同时查看“启动应用”和“启动与重载失败”两节。
② 应用正常启动,但缺少功能。 先检查是否有 bundle 被跳过,见 3.1。启动控制台只会打印一次跳过列表,排查时应保留并回看这份输出。
桌面端致命错误会提供恢复选项。选择禁用第三方插件并备份 profile patch 的恢复操作后,才会将 profile 的 cordis.patch.yml 改名为 cordis.patch.yml.bak-<时间戳> 并保留;不是每次致命错误都会自动改名,home 级 patch 也不会被修改。发现”配置消失了”时,核对是否执行过恢复操作,并查找同目录备份。
3.14 症状:依赖清单里有插件,运行时却没有对应能力
检查安装、组装和激活三层状态。 dependencies 中有包,说明 profile 声明了依赖;dsh.profile.bundles 决定哪些组合包参与配置;实际激活记录和工具调用才说明能力可用。
检查时,先核对实际 profile 的 package.json 中这两份清单,再看合成配置、跳过报告和启动日志。官方 CLI 文档说明,插件增删与更新成功后会按包的 bundle 元数据同步列表;手动改文件或跨版本升级后仍需核对实际结果。
界面插件需要分别核对三项证据:
- 宿主激活: 相关条目已在运行时激活。
- 客户端注入: 所需模块已进入客户端资源。
- 界面验收: 组件实际显示,交互和对应功能正常。
云端“依赖仍在、工具未恢复”的具体记录见附录 A.4;验收界面插件时,应完成上述三步。
四、工具箱
4.1 三个配置诊断命令:先定位条目,再判断是否生效
| 命令 | 用途 | 实际读法 |
|---|---|---|
--dump-config | 查看合成后的配置树(含用户层) | 按条目 id 或包名定位,展开整个 config;结合 stderr 检查组合包跳过原因 |
--dump-default-config | 排除用户覆盖层,查看官方默认配置 | 定位同一个条目,与完整 dump 对照,判断差异是否来自用户覆盖 |
--dump-config-schema | 不挂载插件,输出配置 JSON Schema | 查字段约束;先检查根节点 x-cordis.complete 与诊断信息,不用文件大小判断是否完整 |
先把配置输出与诊断信息分开保存。 下面沿用 1.3 的 CLI 变量 $dsh,web 只是目标 profile 示例;排查哪个 profile,就使用它的名字。检查桌面配置时,先按 3.10 创建诊断副本,再把 $profile 改成副本名:
$profile = 'web'& $dsh --profile $profile --dump-config 1> .\dsh-effective.yml 2> .\dsh-diagnostics.txt$dumpExitCode = $LASTEXITCODE"dump exit code: $dumpExitCode"
# 示例:定位权限条目的行号,并显示附近内容Select-String -LiteralPath .\dsh-effective.yml -Pattern 'id:\s*permission\s*$' -Context 3,30
# 查看跳过报告与错误原因;没有匹配结果时,仍应阅读完整诊断文件Select-String -LiteralPath .\dsh-diagnostics.txt -Pattern 'skipping profile bundle|incompatible|error' -Context 2,8Select-String 给出的上下文只是定位窗口,不代表条目已经显示完整。用编辑器打开 dsh-effective.yml,从匹配行读到这个 YAML 条目结束,重点核对:
- 条目是否存在。 按准确 id 搜索;不知道 id 时先搜包名。没有匹配项,再查目标 bundle 是否在 profile 的
dsh.profile.bundles中,以及 stderr 是否说明它被跳过。 - 值是否符合预期。 查看该条目的
name、disabled和整个config。权限条目要同时读取presets与defaultPreset;其他插件则核对具体字段、文件路径与模型 ID。需要查默认值时,再对同一个 profile 单独运行--dump-default-config,定位同一条目进行对照。 - 运行时是否真的启用。 合成配置中有条目,仍需回看兼容性拒绝报告、启动日志与一次真实调用。dump 的
disabled字段也不能单独证明 Loader 已激活它。
三个命令会输出诊断后退出,不启动应用。准备阶段仍可能创建缺失的 profile 文件;schema 导出还会导入模块。因此,使用前应确认目标 profile 与目录权限,不能将这些命令视为完全只读。
使用前还需注意:
--dump-config打印的是合成配置,不是实际激活的插件清单。被 Loader 拒绝激活的插件条目仍可能出现在其中,但组合阶段被跳过的 bundle 不会提供条目。判断 bundle 是否被跳过,需查看skippedBundles对应的 stderr 报告,区分“条目未激活”和“组合包未参与配置”。--dump-config-schema导入模块时会执行模块顶层代码,也可能留下模块句柄;应对可信的 profile 使用。- 三个 dump 参数互斥,均不接受应用参数;
--dump-default-config不能与--patch同时使用。
本机曾在退出码为 1 时得到可解析的 schema JSON,但这不足以证明输出完整。官方说明允许返回部分输出并以 1 退出。应检查根节点的 x-cordis.complete、diagnostics,以及条目的 partial、unsupported、error 状态。有效 JSON 可用于诊断,complete: true 也不保证应用能够成功启动。
4.2 用独立 profile 做端到端验证
可以使用独立的测试运行面,验证插件是否能够正确组装并调用:
# 1) 从官方模板初始化测试运行面,输出配置后退出,不启动任务& $dsh --profile _probe --from-default-profile headless --dump-config
# 2) 用插件命令把目标组合包及其依赖安装到测试运行面# 将 <目标组合包> 换成真实包名;本步骤不复用 desktop 的 node_modules& $dsh plugin --profile _probe add <目标组合包>
# 3) 跑一个真实任务& $dsh --profile _probe "用 web_search 查一下 xxx,把来源 URL 列出来"headless profile 的第一个参数是任务字符串,不是子命令;缺少任务时会报用法错误。--from-default-profile 仅用于目标目录尚不存在时,初始化后重试需去掉该参数。上述测试可验证普通 headless 宿主中的插件组装与调用,但可能受 home 级 patch 和共享凭据影响,也不能单独证明 Electron 宿主兼容性。
云端独立实例的检查记录见附录 A.7。
只复制配置文件也未必复刻了原 profile 的依赖解析环境,应核对目标 bundle 能否在副本中解析。上面的 headless 示例安装插件后,还应检查目标包是否进入该 profile 的 dsh.profile.bundles,并完成最后一步真实任务;需要验证界面组件时,再到实际宿主检查界面。
4.3 解压会话日志:注意多帧 Zstandard
会话日志文件为 session.v4.jsonl.zstd。在本文样本中,直接对整个文件调用 zstdDecompressSync 只解出了首帧,输出仅有 192 个字符,容易被误判为日志为空。
日志由多个独立的 Zstandard 帧拼接而成:首帧只包含 header,后续持久化批次继续追加新帧。如果只解出首帧,很容易误判日志内容不完整。
4.3.1 先检查解压所用的 Node.js
运行脚本前,可以检查所用 Node.js 是否提供该 API:
// 保存为 check-zstd.mjs,使用实际用于解压的 Node.js 运行import * as zlib from 'node:zlib';console.log(process.version, typeof zlib.zstdDecompressSync);第二项应为 function。zstdDecompressSync 从 Node.js 22.15.0 / 23.8.0 加入,具体版本说明见 Node.js 官方 Zlib 文档。只写“Node 22”不足以保证支持;当前官方文档也说明解压器支持连接的帧,因此“整块解压只返回首帧”应限于文中的样本与运行时,不能推广到所有 Node.js 版本。
4.3.2 读取压缩日志
下面的脚本按解压器报告的输入消耗量推进,避免把压缩内容中的魔数误认成帧边界;遇到损坏数据时会直接报错,不会静默跳过。不同运行时可能一次消耗多个连接帧,输出中的“帧数”统计应结合所用解压器判断。
// dump-session.mjs —— 用法: node dump-session.mjs <session.v4.jsonl.zstd>import fs from 'node:fs';import zlib from 'node:zlib';
const buf = fs.readFileSync(process.argv[2]);const chunks = [];let offset = 0;
while (offset < buf.length) { const result = zlib.zstdDecompressSync(buf.subarray(offset), { info: true }); const consumed = result.engine.bytesWritten; if (!Number.isInteger(consumed) || consumed <= 0) { throw new Error('无法确定当前帧消耗的输入字节数,停止解压'); } chunks.push(result.buffer); offset += consumed;}
const text = Buffer.concat(chunks).toString('utf8');const lines = text.split('\n').filter((line) => line.trim());console.log(`帧数=${chunks.length} 字符=${text.length} 行数=${lines.length}`);lines.slice(0, 3).forEach((line) => console.log(line.slice(0, 200)));4.3.3 对照 Windows 样本
Windows 原稿样本大小为 1489734 字节,记录的解压结果如下;这些数字不代表其他会话:
[对照] 整块解压 -> 192 chars帧数=1215 字符=4603787 行数=2164行类型分布:session / permission/preset / model/selection / turn/start / hook/invoked / hook/result / tool/call / tool/result / step/end ...解压后是 JSONL,每行带有 type 字段。按类型过滤,可以核对工具调用、Hook 执行和模型选择;日志中的事件记录比会话里的回忆更适合用于排错。
Debian 样本与旧格式文件的对照记录见附录 A.8。
4.4 读 app.asar 里的官方代码与文档
app.asar 是应用归档。下面的最小脚本按头部目录和文件偏移读取一个指定文件,无需解包整份应用。先将代码保存为 UTF-8 文件 asar-cat.mjs;它只处理普通文件,不展开目录,也不跟随归档内的链接。
// asar-cat.mjs —— 用法: node asar-cat.mjs <app.asar> </dsh/package.json>import fs from 'node:fs';import path from 'node:path';
const [asarPath, target] = process.argv.slice(2);const buf = fs.readFileSync(asarPath);
// ASAR 头部使用带长度的 Pickle 格式;文件数据区位于完整头部之后。const headerSize = buf.readUInt32LE(4);const jsonSize = buf.readUInt32LE(12);const header = JSON.parse(buf.subarray(16, 16 + jsonSize).toString('utf8'));const segments = target.split('/').filter(Boolean);
let entry = header;for (const segment of segments) entry = entry?.files?.[segment];if (!entry || entry.files || entry.link) { throw new Error('目标不是普通文件:' + target);}
if (entry.unpacked) { process.stdout.write(fs.readFileSync(path.join(asarPath + '.unpacked', ...segments)));} else { const start = 8 + headerSize + Number(entry.offset); process.stdout.write(buf.subarray(start, start + Number(entry.size)));}在保存脚本的目录中打开 PowerShell,再执行:
# 按实际 DSH_HOME 定位内置 Node.js,无需额外安装 Node$dshData = if ([string]::IsNullOrWhiteSpace($env:DSH_HOME)) { Join-Path $env:USERPROFILE '.dsh'} else { $env:DSH_HOME}$nodeExe = Join-Path $dshData 'dsh-runtimes\dsh-primary-runtime\dependencies\node\bin\node.exe'$asar = 'D:\harness\resources\app.asar' # 改成自己的安装路径
# 先读运行时 package.json,核对版本与包含的包& $nodeExe .\asar-cat.mjs $asar '/dsh/package.json'
# 再读本机版本的启动文档& $nodeExe .\asar-cat.mjs $asar '/dsh/node_modules/@deepseek-ai/dsh-app-boot/README.zh.md'第二条命令会把 README 输出到终端。需要保存时,在命令末尾加 > .\app-boot-README.zh.md,再用编辑器查找“启动应用”和“启动与重载失败”。查其他插件时,替换最后一个参数中的包名与文件名即可。
本文所用 Windows 安装包的运行时版本为 0.2.0-rc.2,上述两个归档内路径均已核对可读取。若其他版本提示“目标不是普通文件”,先核对包名和目录是否变化;若 Node 路径不存在,先在资源管理器中核对实际数据目录。脚本只读取安装包,不改动应用文件。
归档内容有两类常见用途:
- 核对插件接口:同一安装版本中,官方同类插件的
lib/index.js可用于检查真实接口与调用方式; - 查阅官方说明:对应包附带的
README.zh.md可用于核对配置项。对某个配置项含义有疑问时,可先读取该安装版本归档中的 README。
4.5 插件开发中的离线验证
插件开发时,可先进行离线验证:
- 从
app.asar提取官方同类插件的实现,用于核对接口约定; - 使用真实的
schemastery、模拟宿主包和registerHooks,在测试环境中挂载插件; - 检查 Config 解析、
apply()执行及最终请求的字段与结构。
这样可在不重启 DSH 的情况下检查接口连接与请求构造。仍需端到端验证的部分,再按 4.2 使用独立测试 profile 检查。
五、修改配置与回退
5.1 日常修改:保留配置来源与恢复记录
常用覆盖配置保存在 %DSH_HOME%\profiles\<profile>\cordis.patch.yml,但 home 级 patch、profile manifest 与插件依赖也会影响结果。修改时可以遵循四个步骤:
- 备份涉及的文件。修改前保存带时间戳的 patch 与 manifest 副本,或确认已有可用的版本记录,便于恢复原配置。
- 一次验证一类改动。配置与插件代码分开修改,记录预期行为,再用诊断输出和实际调用核对结果。
- 区分禁用、卸载与版本回退。临时停止功能可先禁用插件;完整撤销安装时,应核对
package.json的dependencies、dsh.profile.bundles和对应用户 patch,并通过插件管理页或包管理器同步依赖。手动创建的 junction 单独解除,避免直接删除共享依赖目录。需要回到旧版本时,恢复先前版本与配置,再按加载边界重启。 - 核对异常恢复备份:在原生致命错误弹窗中选择禁用第三方插件并备份 profile patch 的恢复操作后,会将 profile 的
cordis.patch.yml改名为同目录的cordis.patch.yml.bak-<时间戳>;不是报错后自动发生。发现配置变化时,对照这份备份、手动备份与启动日志,再决定是否恢复。
5.2 跨版本升级:备份之后逐项验收
升级前既要保存回退材料,也要记录恢复步骤;备份存在与回滚已经验证是两件事。云端升级记录见附录 A.2。
升级时可以沿用以下检查顺序:
- 记录基线并保存备份。 确认实际安装位置、数据目录和运行入口;备份涉及的配置、锁文件及依赖版本,并记录服务的启动方式。升级可能改动会话存储时,也应先保存相关数据。
- 在空闲时逐步隔离第三方扩展。 禁用工具插件可能影响当前任务,先保存任务结果,并记录原 bundle 顺序与对应 patch。基础运行正常后,再逐项恢复扩展。
- 让副本覆盖需要验证的环境。 核对依赖解析、配置组装和临时实例启动;随后完成认证、真实消息与目标工具调用。单次 dump 成功或 HTTP 响应,只覆盖其中一部分。
- 重启后核对实际进程。 对照新进程的启动时间、启动日志和版本,再检查模型、工具及界面。若出现异常,按事先记录的版本与配置恢复,并重新验证;不能用安装命令成功代替验收。
六、速查表
常见症状与首要检查项
| 症状 | 首要检查 |
|---|---|
| 插件装了没生效,也不报错 | 分开保存 dump 的 stdout 与 stderr,按 id 查配置、在诊断文件中查 bundle 跳过原因(4.1) |
| patch 写了没反应 | 检查 id 是否存在(新增条目使用 insert:),并核对需要保留的配置字段 |
| 改了配置没变化 | 确认 HMR 是否启用:配置与 bundle 列表可重新组合;已安装包版本替换要重启 |
Hook 不跑 / 0xC0000142 | 先对照 Hook 环境;本案例将裸 node 换成 node.exe 绝对路径 |
| HTTP 200 但功能异常 | 直接请求端点并检查原始响应,不只依赖插件的错误提示 |
| 模型/强度改了没反应 | 只对下一次请求生效;查网关支持域;抓请求体 |
| 搜索结果”来源不对” | 核对合成配置与跳过报告,并用同输入 A/B、结果格式和运行日志交叉验证 |
[sandbox: file access denied ...] | 在允许的升级路径内选择最低所需权限,保持命令与参数不变,重试一次 |
| 路径不存在 / MODULE_NOT_FOUND | Test-Path 先确认;app.asar 是文件不是目录 |
| CLI 拒绝 desktop profile | 用普通测试 profile 验证;诊断副本若共享依赖,只做配置检查 |
| 抓不到网页,提示非公网 IP | 核对代理 fake-ip 与 DNS 结果,用 curl.exe 验证连通性,再调整解析规则 |
| 想重启 DSH | 保存当前结果,从系统托盘选择“退出 DeepSeek Harness”后再打开;关闭主窗口可能只是隐藏 |
| 启动失败 / 功能整个不见 | 读 %DSH_HOME%\logs\startup-*.log,并回看启动时打印的跳过 bundle 列表 |
| 配置文件”自己消失了” | 核对是否选择过恢复操作,查找同目录的 cordis.patch.yml.bak-<时间戳> |
| 改了 hooks.json 不生效 | Hook 配置仅在进程启动时读取,修改后需重启 |
| 依赖里有包,但会话里没有工具 | 核对实际 profile 的 dependencies、dsh.profile.bundles、激活日志与工具清单(3.14) |
| 诊断或 npm 查询报 EACCES | 按报错路径区分 profile 写权限与 npm 缓存权限;Debian 案例见附录 A.5 |
| 消息报 prompt variable 缺失 | 根据 section 定位模板与变量来源,核对模型选择和相关插件;云端案例见附录 A.6 |
| 云端重启结果显示未知 | 从独立终端核对 systemd 状态、进程启动时间与 journal,再测试功能(附录 A.3) |
常用路径
安装根 D:\harness\CLI D:\harness\resources\runtime\cli\bin\dsh.cmd内置 node %DSH_HOME%\dsh-runtimes\dsh-primary-runtime\dependencies\node\bin\node.exe运行面 %DSH_HOME%\profiles\<name>\用户覆盖层 %DSH_HOME%\profiles\<name>\cordis.patch.yml会话日志 %DSH_HOME%\sessions\<工作区>\<会话id>\session.v4.jsonl.zstd技能 %DSH_HOME%\skills\<name>\SKILL.md用户指令 %DSH_HOME%\AGENTS.md凭据 %DSH_HOME%\.credentials.yaml启动诊断日志 %DSH_HOME%\logs\startup-<时间戳>-<uuid>.log排错时记住这条顺序
遇到“改了没生效”,依次核对配置来源、bundle 跳过报告、插件激活记录和实际请求。每次修改都对应一条可验证的预期,才能分清组装问题与实现缺陷。
附录:Debian 云端对照案例
本附录来自用户提供的 Debian 12 云服务器交流材料:CLI 全局安装、Node.js 22.23.2、web profile,由 dsh.service 承载,记录了从 0.1.7-rc.2 升至 0.2.0-rc.2 的过程。它补充 CLI、升级与 systemd 场景,不属于 Windows 桌面端复测;下面的 Bash 命令只用于 Linux shell。
A.1 安装位置、服务数据目录与凭据来源
Debian 云端记录:先分清安装位置与服务的数据目录。 这台服务器使用全局 npm 安装,代码位于 /usr/lib/node_modules/@deepseek-ai/dsh,使用系统 Node.js;Windows 桌面端则使用应用归档和自带运行环境。云端路径不能直接替换进本文的 PowerShell 命令。
在 Linux 上,DSH_HOME 未设置时仍需按默认 ~/.dsh 查找,不能把空环境变量直接拼成 /profiles/web/…。systemd 服务采用的用户、主目录和环境还可能与当前 SSH shell 不同,应先确认正在运行的服务实际使用哪份配置。本文标注为 Bash 的命令仅用于 Linux shell;Windows 读者使用对应的 PowerShell 写法。
Debian 云端记录:查不到凭据文件中的条目,不等于功能没有配置。 材料中的一次语音功能排查,最初只查看 .credentials.yaml,随后才确认相关配置来自 systemd 的 EnvironmentFile 和插件读取的配置文件。排查时应沿服务实际启动环境和该插件的凭据规则追踪,再用一次真实调用验证;不要把桌面模型适配器的查找顺序套到所有第三方插件上。记录配置来源与变量名即可,不必打印密钥值。
A.2 升级兼容、残留 patch 与回退材料
Debian 云端记录:优先寻找兼容的新插件版本。 升级时,dsh-audio-kit@0.2.2 声明的 @deepseek-ai/dsh-tools 范围为 ^0.1.6-alpha.2,未覆盖 0.2.0-rc.2;dshmarket@1.65.1 也因旧 peer 范围被拒绝。材料随后记录,dshmarket@1.66.6 的声明已包含 ^0.2.0-rc.1。因此,应先检查插件是否发布了兼容版本,再考虑测试用豁免;直接手改已安装包的 peer 声明会在后续安装时被覆盖,也不会修复实际代码不兼容。
Debian 云端记录:先查 bundle,再决定是否新增条目。 升级前临时移除了第三方 bundle,但保留了用户 patch;隔离诊断因此打印 patch: entry "meow-memory" not found。材料记录,恢复对应 bundle 后该警告消失。这个案例中缺少的是提供原始条目的组合包,应先恢复其组装来源;不能一看到 entry not found 就把旧覆盖改成 insert:,否则可能引入重复条目。
Debian 云端记录: 这次升级前保存了约 518 MB 的安装目录备份,以及 profile 的 manifest、patch、生成配置和锁文件,并记录旧版本、新版本、CLI 入口指向与备份位置。它证明准备了回退材料,不等于已经演练并验证回滚成功。
A.3 从服务外部核对重启
Debian 云端记录:服务重启可能同时终止发起操作的智能体。 如果当前 DSH 会话和命令进程都属于 dsh.service,停止服务时,它们可能一起收到终止信号。systemd 默认的 KillMode=control-group 会在停止阶段终止该单元中的剩余进程;nohup 或 setsid 本身不会把进程移出服务的控制组。该行为见 systemd v252 的进程终止说明。
材料记录了两种容易混淆的结果:一次重启命令被 SIGTERM 中断,后续步骤未完成;另一次工具结果显示“未知”,但外部 journal 中已有对应的 Stop/Start 记录。因此,工具回复不能单独证明服务重启成功或失败,应从独立 SSH 会话或外部管理终端核对服务状态。
以下为 Linux 上的查询命令;若服务名不同,请替换 dsh:
systemctl show dsh -p ActiveState -p SubState -p MainPID -p ExecMainStartTimestamp --no-pagerjournalctl -u dsh -n 30 --no-pager -o short-iso核对新进程的启动时间、启动日志和版本信息,再验证模型与目标工具。安装目录已更新、端口已监听,都不能单独证明新代码已加载或功能恢复。查询历史日志时,--since 应包含完整日期和时间;只写时分秒可能落到另一天。若需要从 DSH 所在服务内部安排重启,应让外部管理终端或独立服务单元承接操作,先保存结果与回退信息。
A.4 依赖仍在,但 bundle 与工具尚未恢复
Debian 云端记录: 升级后,4 个第三方包仍在依赖清单中,但 dsh.profile.bundles 只保留了 @deepseek-ai/dsh-base 和 @deepseek-ai/dsh-web-app。它们是升级前被临时禁用的 bundle,不能因安装状态仍在就认定已经恢复。
检查时,先核对实际 profile 的 package.json 中这两份清单,再看合成配置、跳过报告和启动日志。当前官方 CLI 文档说明,插件增删与更新成功后会按包的 bundle 元数据同步列表。因此,这个现场不能泛化为“CLI 永远只装依赖、从不更新 bundle”;不同版本和修改入口应以实际清单及运行结果为准。
材料还记录,禁用这些 bundle 后,当前会话少了 8 个记忆工具和 5 个音频工具;后来在恢复 bundle 并重启后重新核对。它没有单独验证“只加回 bundle、不重启”能否恢复当前会话的工具列表。桌面端人工确认的插件启停结果见 2.7,不能据此替代云端验证。
材料只提供了宿主激活与客户端注入两层的部分记录,尚未完成界面验收;不能用脚本已注入代替界面可用性检查。
A.5 诊断或 npm 查询报 EACCES
环境:Debian 云端。
先看失败的路径与操作。 云端记录中,--dump-config 和 dsh web --help 都曾在准备阶段尝试写入 /root/.dsh/profiles/web/cordis.yml,并因权限受限失败。另一次 npm view 则因无法访问 /root/.npm/_cacache 失败。这些错误分别指向 profile 写权限和 npm 缓存权限,不能直接归为插件加载失败。
对 profile 路径,应核对运行用户、目录所有权、挂载方式与当前沙箱限制;对 npm 缓存,可以指定当前用户可写的临时缓存再查询。材料使用过下面的 Bash 写法:
npm_config_cache=/tmp/npm-cache-upg npm view @deepseek-ai/dsh version该命令查询 registry 中的版本,不会更新正在运行的服务。诊断和帮助命令也未必完全只读;不要只因命令名是 --help 就排除准备阶段的文件写入。
A.6 真实消息报提示词变量缺失
Debian 云端记录: 升级后的会话出现了以下报错:
prompt variable "{{model}}" has no value for this assembly (section "deployment:persona-prefix")这条信息说明,提示词组装所需的 model 变量没有获得值。排查时应先根据 deployment:persona-prefix 找到对应模板与配置来源,再核对当前模型选择、变量提供方和插件的版本兼容情况;必要时在独立 profile 中减少相关扩展,观察是否仍能复现。
材料没有通过隔离实验确定具体责任插件,也没有验证通用修复方案。因此,不能据此断言重新安装某个插件一定有效。服务启动成功与一次真实消息成功,是两个需要分别验证的步骤。
A.7 独立 Web 实例的验证范围
Debian 云端记录:隔离检查只证明已检查的阶段。 使用独立 DSH_HOME 和临时端口测试时,材料记录 --dump-config 退出码为 0、合成配置有 296 个条目,临时 Web 实例约 6 秒后返回 HTTP 401。这说明配置输出成功、HTTP 服务已有响应;401 只表明请求未通过认证,不能证明模型调用或第三方工具成功。
A.8 多帧日志与旧格式文件
Debian 云端记录:检查运行时能力,再判断日志是否完整。 材料中的另一个压缩样本大小为 334492 字节,整块解压只得到约 193 个字符;逐帧处理记录了 210 帧、约 106 万字符。这与本文 Windows 样本的统计是两组独立记录,不能互相替代。
材料还记录,同一会话目录可能同时留有 session.v3.jsonl.zstd 和 session.v4.jsonl.zstd。读取时应核对实际文件、header 和事件内容,不要只根据文件名判断会话是否已经迁移,也不要因为短输出就删除日志。
官方参考文档
以下为本文使用的官方文档入口。桌面配置以本机 0.2.0-rc.2 安装包附带说明为版本依据;2026-10-01 对照仓库文档,2026-10-03 补查 CLI、Node.js 与 systemd 相关行为。仓库主分支持续更新,阅读时请核对适用版本。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!

