需已安装并登录 ZCode CLI。把 ZCode CLI agent 接入 DeepSeek Harness 作为模型提供方。常驻 app-server 会话逐回合流式转发,模型清单从 CLI 实时读取,因此上下文窗口、图片支持与 provider 路由都跟随已安装的 CLI 和账号。工具权限请求默认拒绝;未知的 approval/permission 方法始终拒绝,全自动需显式启用。DSH 自带的审批界面不会介入这个独立 spawn 的 app-server 进程,该策略也不构成操作系统沙箱。
安装
# npm 包(预构建)
dsh plugin --profile web add dsh-zcode-plan-bridge
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:tangyixiao/dsh-zcode-plan-bridge
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
把 DeepSeek Harness(DSH) 的模型请求转交给 ZCode CLI 自带的 agent 执行的本地插件。
provider zcode-cli 背后是一个常驻的 zcode app-server 会话(stdio JSON-RPC,真流式)。
CLI 自己管着登录账号,插件只是把该账号能服务的模型清单原样转述给 DSH ——
烧的是 ZCode 账号的额度,不需要 API Key,也不需要自建网关。
本仓库:https://github.com/tangyixiao/dsh-zcode-plan-bridge · 上游原版:https://github.com/kyle123740/dsh-zcode-cli-proxy(AGPL-3.0)
与上游 0.3.x 的差异(v0.4.x,基于实机逆向重写通道层)
上游假定「DSH 侧注入 Start Plan 账户 + 硬编码模型清单」,实测在 npm 版 CLI (
zcode-app-cli)上这两条都错:
- CLI 处于 standalone 模式,拒绝宿主注入。
provider/updateAccountConfig直接回Error: Standalone Account 由本进程管理,不接收 Host 覆盖。账号本来就被 CLI 自己管着, 注入既不可能也没必要 —— 已删除。- 同时设
ZCODE_BUILTIN_PROVIDER_CONFIG_FILE与ZCODE_PERSONAL_PROVIDER_CONFIG_FILE会让 CLI 直接起不来,stderr 固定为Error: Bundled 与 Active ZCode Built-in Release 均不可用, 而且不服务任何请求。桌面客户端写出的 builtinrevision一旦超过当前 CLI 能解的 schema, 就必然踩中。已彻底不再注入任何ZCODE_*环境变量。- 模型清单改为读 CLI 上报。
session/create的settings.model.available是权威清单; 上游硬编码的200000 / 64000 / [FALLBACK_MODELS]与实机差 5 倍(真实contextWindow=1000000、maxOutputTokens=128000),provider id 也不同。- provider id 不再硬编码。上游写死
account:zai-start-plan,但 standalone 下该 provider 不进入 registry;实机是account:zai-individual-coding-plan。通道逻辑(回合锁、自愈、事件流、图片物化)沿用上游的逆向结论并补了对应改造,版权归上游作者。
DSH Agent ──► provider "zcode-cli" ──► ZcodeAppServerAdapter
│ spawn zcode.cjs app-server --stdio(常驻)
├─ session/create 拿 settings.model.available(模型清单)
├─ session/subscribe desktop-continuous 事件流
├─ session/setModel 仅在目标模型与当前不同时切换
├─ session/send 发回合(真流式)
└─ interaction/requestProviderRuntimeHeaders 回 OAuth 鉴权
└──► zcode.z.ai/api/v1/zcode-plan/anthropic
用法
- 装一份 ZCode CLI(
npm i -g zcode-app-cli,或桌面客户端自带的zcode.cjs),并登录有额度的账号。 - 把本插件装进 DSH profile,重启 DSH。
- DSH 设置 → 模型(Models)→ 提供方 ZCode CLI (account bridge) → 选模型。
可用模型不是插件写死的,而是 CLI 当前账号能服务的那批。本机实测(2026-10-22):
| provider | model | context | max output | image |
|---|---|---|---|---|
account:zai-individual-coding-plan |
GLM-5.3 | 1000000 | 128000 | ✓ |
account:zai-individual-coding-plan |
GLM-5.3-Flash | 1000000 | 128000 | ✓ |
ccc6dfb9-…(个人 deepseek) |
deepseek-v4-flash | 1000000 | 384000 | ✓ |
同一 model id 出现在多个 provider 上时(如上表 GLM-5.3 同时在 account: 与 zai-api 上),
插件优先 account: 开头的路由 —— 那条烧计划额度,zai-api 那条按 API Key 计费。
想指定确切路由,就在 cliModels 里给条目写 id: "zai-api/GLM-5.3"(providerId/modelId 形式)。
- 真流式(text/reasoning delta 直接转发)、工具调用、图片输入(图片以本地文件随消息附上,agent 用 Read 读图)
- 多轮会话按 DSH 的 sessionId 复用 app-server 会话
- 会话标题这类辅助调用在本地生成,不消耗额度
- 前置条件:本机能跑起 ZCode CLI,且它已登录有额度的账号
安全须知(装之前必读)
这个「模型提供方」的真身是一个以你当前用户权限运行、且带全套工具执行能力的 agent。它不在 DSH 的工具权限边界内运行:DSH 的权限模式和浏览器审批界面只处理 DSH Host 自己发起的工具调用,不能确认 ZCode app-server 发起的授权请求;本插件也没有自己的交互式确认窗口。
- 两种策略都会将会话设为 ZCode 的
build权限模式,确保授权请求经过插件处理;模式设置失败时本轮停止。该策略不构成操作系统沙箱,也不阻止无需额外授权的 agent 操作。 - 默认
authorizationPolicy: deny:插件对interaction/requestPermission回复deny,不会弹确认框;需要授权的工具调用会失败。 - 只有显式设置
authorizationPolicy: allow-all才会自动批准已知的interaction/requestPermission请求。该设置允许 agent 以当前用户权限执行 Bash、文件读写和联网操作,不要在不可信任务中启用。 - 名称包含
approval或permission的未知 app-server 请求始终拒绝,即使启用了全自动模式;如果 ZCode 将来改变权限协议,相关调用会失败关闭。 - agent 的输入是 DSH 拍平后的整段对话(包括网页抓取、工具结果等外部内容)。提示注入仍可能诱导全自动模式执行恶意操作;默认拒绝减少了授权面,但不能消除未经过授权请求的副作用。
- 子进程环境变量按白名单透传(系统基础变量、
ZCODE_*、NODE_EXTRA_CA_CERTS),不继承 DSH 宿主的全部 env;确有需要可用配置项childEnvAllow追加变量名。 - 鉴权 token(
zcodejwttoken)只经本机 stdio JSON-RPC 交给 agent 进程,不发往任何第三方。
通道原理(全部实机逆向验证)
- spawn
zcode app-server --surface terminal --no-color时不注入任何ZCODE_*。 实测三种环境(零变量 / 只ZCODE_SERVICE_AUTHORITY_MODE/ 再加ZCODE_BASE_URL) 产出的模型清单完全相同;而注入 builtin/personal 文件路径会引入上面说的启动失败。 session/create的返回里settings.model.available是模型清单,session.model是当前模型。 条目形状:{ref:{providerId,modelId}, label, providerLabel, contextWindow, maxOutputTokens, reasoning:{levels:[{value}],defaultLevel}, properties:{inputFormat:{supportsImage}}}—— 没有inputModalities字段,图片能力要看properties.inputFormat.supportsImage。session/subscribe用{deliveryKind:'desktop-continuous', afterSeq:0, includeSnapshot:true}。session/setModel要求对象式{providerId, modelId, options:{reasoningLevel}};reasoningLevel取自条目上报的档位(本机是 low/high/max,默认 max)。- agent 发模型请求前回调
interaction/requestProviderRuntimeHeaders要鉴权 —— 回共享凭证里的zcodejwttoken(oauth:zai:access_token已过期,回它上游 401)。agent 自己算签名,能过 WAF。 session/event的事件类型在 params.type 顶层(不是 payload.type),turn.failed也要处理 (错误码在payload.error.attribution.providerErrorCode),replayState里不能有undefined字段(lossless JSON 校验会炸)。- 服务端请求必须应答,否则
session/create挂起:session/requestRuntimePreferences回{nativeSearchEnhancementsEnabled:false, memoryEnabled:false, askUserQuestionAutoResolutionEnabled:true, modelContextBudgetStrategy:'preflight-v1'}就够。
HTTP 直连计划端点会被无痕验证拦 —— 只有 agent 二进制自己发的签名请求能过, 所以「反代」的形态是托管 agent 进程而不是自建 HTTP 网关。
回合锁与自愈
app-server 一个会话同时只允许一个在途回合。上一轮被中止 / 超时 / 静默丢弃时它不会自己释放,
下一轮 session/send 就被拒成 A prompt is already running for this session。通道层做六件事兜底:
- 补发
session/stop:本轮只要没正常结束(超时 / 被中止 / 发送失败 /turn.failed), 生成器finally一定补一刀,不把锁留给下一轮; - 撞锁自愈:
send被回「already running」→ 补 stop → 等 1.5s → 原会话重试一次; 被回「session … not found」(会话被回收 / 进程重启)→ 丢弃缓存条目、新建会话,firstTurn语义自动重放整段对话,历史不丢; - 回合串行化:同一 DSH 会话的两轮排队跑(最多等 60s,超时放行交给 2 处理);
- 进程退出即作废 + 快败:app-server 子进程退出(含 spawn 失败)时清空会话映射, 在途的流会立刻收到一个回合失败收尾,不用干等回合超时;
- 会话分叉检测:每轮 send 都记录当时的消息列表指纹;下一轮续接前先比对前缀, DSH 侧编辑 / 回退过历史就重建会话、按首轮语义重放新分支;
- 模型映射:DSH 选的模型 id 经 catalogue 解析成
{providerId, modelId}; 同一会话中途换模型时在原会话上重发session/setModel,解析不出来就保留会话默认模型并记 warn。
诊断命令
插件带一个不依赖 DSH 宿主的诊断入口(只用 Node 内置模块,插件因版本不兼容加载失败时也能用):
node bin/dsh-zcode-plan-bridge.js # 列出子命令
node bin/dsh-zcode-plan-bridge.js doctor # 本地前置条件体检(离线,不耗额度)
node bin/dsh-zcode-plan-bridge.js models # 打印 CLI 上报的完整模型清单
node bin/dsh-zcode-plan-bridge.js protocol # 起 app-server 走一遍握手,验证协议没变
node bin/dsh-zcode-plan-bridge.js turn "hi" # 真发一个回合(消耗额度)
node bin/dsh-zcode-plan-bridge.js image <file> # 发一张图(消耗额度)
通用参数:--cli-path <zcode.cjs>、--data-dir <~/.zcode 的上级>、--model <id>、--json、
--allow-tools。
--allow-tools 默认关闭,和插件本身的 authorizationPolicy: deny 一致。诊断命令会真的用你的
账号起一个 app-server agent,所以不带这个 flag 时,探针会对 agent 的工具权限请求回 deny:
turn / image 能验证通道和用量,但 agent 跑不了 Bash、写不了文件、上不了网。确实需要让探针
执行工具时再显式加上它。名称含 approval/permission 的未知请求两种情况下都拒绝。
doctor 会检查 node 版本、CLI 定位、builtin release(只读检查,不喂给 CLI)、
凭证(只打印长度与是否 JWT,绝不打印 token 本体)、以及 CLI 上报的模型清单。
这五个子命令取代了上游
scripts/probe-*.cjs那十个一次性脚本。那些脚本各自硬编码了作者 本机路径、改一次才能问另一个问题,已删除。
配置(设置 → 插件)
| 字段 | 默认 | 说明 |
|---|---|---|
enabled |
true |
总开关 |
zcodeCliPath |
自动探测 | zcode.cjs 路径;空 = 从 ZCODE_CLI_PATH、桌面客户端常见安装位置、zcode-app-cli 全局包依次探测 |
zcodeCliNode |
node |
运行 zcode.cjs 的 node 可执行文件 |
cliModels |
[] |
留空 = 跟随 CLI 上报的清单(推荐)。填了就等于把清单钉死成这份,只用 cliModelId 决定 CLI 侧路由 |
authorizationPolicy |
deny |
deny 会拒绝 ZCode 的权限请求且不提供交互确认;只有你明确接受无人值守工具执行时才设为 allow-all。未知 permission/approval 方法始终拒绝 |
cliCwd |
空 | app-server 会话的工作目录;空 = 用户主目录 |
zcodeDataBaseDir |
空 | ZCode 数据根目录;空 = 用户主目录(即 ~/.zcode/v2) |
childEnvAllow |
[] |
额外透传给子进程的环境变量名 |
appServerTimeoutMs |
120000 |
单次 JSON-RPC 请求超时(毫秒) |
zcodeCliTimeoutMs |
900000 |
单回合超时(毫秒) |
maxTokens |
128000 |
仅作兜底:CLI 未上报 maxOutputTokens 时使用 |
defaultContextWindow |
1000000 |
仅作兜底:CLI 未上报 contextWindow 时使用 |
开发
npm test # 纯函数单测(不 spawn CLI、不耗额度)
npm run typecheck # tsc --checkJs 全量类型校验(零构建,装进 profile 免编译)
npm run diagnose # 诊断命令入口
改了代码怎么生效:DSH 的 loader 只在行 name 变化时重新 import 插件模块,
而 Node ESM 以完整 URL(含查询串)为缓存键。仓库里的 cordis.patch.yml 写的是包名
(npm / link: 装配的正确形态);本地目录式开发装配时把它换成 file:// URL 加 ?v=N:
- insert:
- id: dsh-zcode-plan-bridge
name: 'file:///D:/path/to/dsh-zcode-plan-bridge/lib/index.js?v=N'
改完 lib/*.js 后把 ?v=N 递增,然后在插件管理里对 bundle 禁用 → 启用(或重启 DSH)。
目录结构
lib/index.js 插件装配:Config schema、provider 注册、模型清单来源决策
lib/app-server.js app-server 通道:JSON-RPC 客户端 + LlmAdapter(事件流/回合锁/鉴权)
lib/zcode-runtime.js CLI 发现、catalogue 归一化与路由选择(只用 Node 内置模块)
lib/messages.js 消息工具:图片物化、对话拍平、泄漏工具调用清洗
lib/credentials.js 解密 ~/.zcode/v2/credentials.json
lib/diagnostics.js 五个诊断子命令(doctor/models/protocol/turn/image)
bin/ 可执行入口
test/ 纯函数单测(node --test)
许可
AGPL-3.0。本仓库是 kyle123740/dsh-zcode-cli-proxy 的衍生版:app-server 通道的逆向结论(回合锁、事件流、鉴权回调)源自上游, v0.4.x 依实机重新验证并改写了账号/模型层。历史来源致谢 liu5269/zcode2api,其代码已不再随本仓库分发。
链接
同类插件
Ebony-Vinyl/dsh-our-free-model★ 34394
为 dsh 接入免费模型车道(含 DeepSeek V4.1 Flash、Kimi K3 等),无需登录、注册或填写 API Key,并提供本地 OpenAI 兼容网关、降级路由与用量看板。
V1ki/dsh-plugin-subscriptions★ 491
把 ChatGPT(Codex)、Claude、Grok 订阅当作 DeepSeek Harness 的 LLM 提供方:设置页登录、模型目录、用量展示,以及 image_generate、video_generate 与 x_search 工具。
Mars-Sea/dsh-commandcode-provider★ 423
非官方 Command Code 模型接入插件:注册 `commandcode` 路由,带实时模型目录与推理强度支持。
dingminhua/dsh-connect-workbuddy★ 372
将本机登录的 WorkBuddy 模型接入 DSH,支持逐模型图片输入开关、账号切换,以及带每日签到的只读积分概览。
FishBottle7/opencode2dsh★ 319
将 OpenCode Zen 免费模型接入 DeepSeek Harness,无需 API Key。
cv-superding/dsh-deepseek-web-login★ 294
新增 deepseek-web provider,把 chat.deepseek.com 网页端模型接入 DSH:浏览器登录抓取、PoW 请求签名、SSE 流式传输与基于提示词的工具调用。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。