Back to marketplace

dsh-connect-qoder

Models & Data

hdhgsysh/dsh-connect-qoder

Bridges locally logged-in Qoder and Qoder CN models into DeepSeek Harness as model providers, reusing the desktop app's existing credentials.

  • deepseek
  • deepseek-harness
  • dsh-plugin
  • model-provider
  • qoder
GitHub Stars
10GitHub
Views
0DSH Plugin Hub
Forks
1GitHub
Open issues
2GitHub Issues
Manifest version
0.2.0dsh-connect-qoder
Latest push
Sep 29, 2026GitHub
License
NOASSERTIONJavaScript
Plugin type
Host + ClientRuns in both Host and Web Client

Verification and compatibility

This section shows evidence collected by the catalog. Undeclared information is labeled as unknown.

Static checked
01Exact source: npm · dsh-connect-qoder@0.2.002Validated: Sep 22, 202603Verified Harness: 0.1.0-rc.7
Current-version compatibility
Verified on the catalog Harness version
Declared Harness range
Not declared
Declared platforms
Not declared
Profiles
web
Build approval
Unknown
Permissions
Not declared
External services
Not declared
Telemetry
Unknown
No known risk flags found

This is not a security endorsement. Review source, permissions, and configuration before installing.

View evidence and scope

Verification covers only the named source, version, and Harness environment. It does not guarantee future compatibility.

  • dsh-connect-qoder@0.2.0
  • The manifest and static structure passed checks; a runtime load check has not completed.

README

View source

DSH Connect Qoder

把本机已登录的 Qoder 模型接入 DeepSeek Harness, 零配置即可在 DSH 的模型选择器里使用你的 Qoder 账号额度。

国内版 Qoder CN 与国际版 Qoder 是两个并行的 provider(qoder-cn / qoder), 装哪个就出现哪一组模型,两个都装就两组并存,各自使用自己的账号与额度。

工作原理

DSH PiAiAdapter(每个区域一套)
  -> 安全 loopback shim(随机端口 + 进程内随机 secret)
  -> COSY 签名 + 自定义 base64 编码
  -> 国内版 https://gateway.qoder.com.cn/
  -> 国际版 https://api3.qoder.sh/
  -> Qoder 双层包装 SSE
  -> OpenAI SSE
  -> DSH 本地执行工具并回传结果

Qoder 不是 OpenAI 兼容端点,所以需要三样东西:

  1. COSY 签名头 —— 每个网关请求都带 Cosy-* 头与 Authorization: Bearer COSY.<payload>.<sig>, 签名是对 base64 负载、RSA 包装的 AES 密钥、时间戳、请求体与签名路径做 MD5。
  2. 置换 base64 请求体 —— 查询串里的 Encode=1 表示 JSON 体要先 base64、再按换过的字母表 逐字符替换、最后按三分之一旋转。
  3. 双层 SSE —— 每个 data: 帧是一个信封对象,它的 body 字段本身又是 JSON 字符串, 里面才是 OpenAI 风格的 chunk。

凭据来源

插件复用 Qoder 桌面应用自己的登录状态,不启动额外的 OAuth 流程,也不写入应用的文件 (凭据文件以只读方式打开)。

Qoder 把登录信息放在 Chromium OSCrypt 格式的凭据文件里(v10 + nonce + 密文 + tag,AES-256-GCM)。 新版(0.3.x)的凭据直接保存在 <userData>/auth.v1.dat,旧版(0.2.x 及更早)则放在 VS Code 风格的 state.vscdb SQLite 数据库里。两种布局都支持,新版优先尝试。 密文用的密钥保存在应用的 Local State 中,由操作系统 keystore 包裹 —— Windows 上是当前用户 作用域的 DPAPI,因此同一用户下的进程都能解开它。 Node 没有内置 DPAPI 绑定,这一步交给 PowerShell,并通过临时文件交换结果(不使用管道), 这样在禁止管道 stdio 的沙箱里同样可用。

没有桌面应用登录时,可以用官方文档的 PAT 兜底:设置 QODERCN_PAT(国内版)或 QODER_PAT(国际版),插件会用它换取 job token。

平台边界:零配置路径只在 Windows 成立。 解密链路是 PowerShell + DPAPI(Crypt32.dll), lib/ 里没有任何 macOS / Linux 解包分支——在其它平台上应用目录找得到(应用数据根目录 已按平台解析,见下),但凭据读不出来(loadCredential 返回 undefined,该区域不注册), 只剩上面的 PAT 兜底。

这不是"没有跨平台客户端",而是客户端已跨平台、插件尚未跟上:Qoder 桌面版在 macOS 12+ / Linux (.deb/.rpm) / HarmonyOS 上都有下载(qoder.com.cn/download), 但 lib/ 只实现了 Windows 这一条解密链。缺口在两处,全部登记在 docs/KNOWN_GAPS.md 第 6 条(跨平台凭据链未实现):

  1. OS keystore 封装(含 key 派生):Windows 走 DPAPI;macOS 需 Keychain(security), 且 Chromium 在 macOS 上对 encrypted_key 还要做 PBKDF2-HMAC-SHA1 派生("peanuts" 常量 + 1003 次迭代)——与 DPAPI 直解是两种算法,不是换个命令;Linux 需 libsecret(secret-tool) 或 Chromium 在 Linux 上的 peanuts 硬编码 key 兜底。
  2. 跨平台 CI 与实机验证:GitHub Actions 的 macos / ubuntu runner 可以编译并跑单测,但 Keychain 弹窗、签名打包、secret-tool 的 D-Bus session 都得在实机或 runner 上验。

已修的两项(原缺口共四处):应用数据根目录现在按平台解析(Windows %APPDATA、 macOS ~/Library/Application Support、Linux $XDG_CONFIG_HOME/~/.config)——此前直接读 process.env.APPDATA,而该变量在 macOS 上不存在,于是探测得到空串、把"应用装着但读不出密钥" 谎报成"您没登录";MACHINE_OS 也补上了 darwin 档(本机实测过网关对 x86_64_darwin / aarch64_darwin 一律正常应答)。

剩下的是实机工作:service 名、PBKDF2 参数、Linux 的变体都必须实测确认,写出来就是盲代码。 macOS / Linux 用户只能走 PAT 兜底,或自行从本仓库移植。

CI 的 Ubuntu 绿灯说明测试在那边能跑,不等于零配置在 Linux 上存在。

安装

从 npm 安装(推荐)

dsh plugin --profile web add @eghrhegpe/dsh-connect-qoder

从 DSH 市场安装(DSH 桌面用户)

本仓库是 hdhgsysh/dsh-connect-qoder 的 fork。

可在 DSH 的「插件市场」里粘贴这个源:

github:eghrhegpe/dsh-connect-qoder

注意:npm 上不带 scope 的 dsh-connect-qoder 由上游发布,装到的是上游那份; 本 fork 自己发的是 scoped 包 @eghrhegpe/dsh-connect-qoder(上面那条),二者不是同一个包。

或本地开发模式:

dsh plugin --profile web add <本仓库路径>

安装后需要重启 DSH 进程:bundle 的 patch 在启动时读取。

凭据安全

插件不存储任何凭据:

  • 复用本机已登录的 Qoder 桌面应用的凭据文件(新版 auth.v1.dat / 旧版 state.vscdb, 均以只读方式打开,不做任何写入)。
  • 进程内随机 bearer token 绑定 loopback 端口;Qoder 真实的 RSA 包装 key 与 session key 不会离开本插件的沙箱。

已知行为

  • 始终思考的模型:部分模型(如 GLM-5.3-Flash、Kimi-K3)声明了推理档位但不允许关闭思考, 对它们发送 enable_thinking: false 会被上游以 provider_error 1210 拒绝。插件从模型目录 识别这类模型并完全省略该字段,让模型使用自己的默认档位。
  • 上游错误可见:上游失败时返回的是普通 200 帧里的错误对象,而不是 chunk。插件把它翻译成 一条可读的错误,而不是让用户看到一个空的助手回合。
  • 今日请求次数用完(不是"排队"):Qoder 每天有请求次数上限,用满后上游会带一个以小时计的 重试提示(约两小时)把它伪装成排队。此前插件照单全收,显示成"重试延迟:7350 毫秒", 而这个等待怎么等都没用——次数要到日期切换才重置,不是排队排空的。现在它是一个独立状态: 不重试、不显示误导性的延迟,明确告知约几小时后重置,并指出仍然有效的两条路: 22:00-08:00 的错峰价(折后价,通常不计入或少计日次数)与每日签到。 状态码也从此前的 502("Qoder 坏了")改为 429("今天用完了")。判别点在 lib/errors.js 的 classifyUpstreamError:先认 110、再认队列标记—— 顺序是承重的,因为这个报文本身带着全部队列标记,由 test/daily-limit.test.js 钉住。
  • 国际版额度:国际版的试用额度可能已用尽(isQuotaExceeded),此时目录请求会返回 403 Login expired,该区域就不会显示模型;国内版不受影响。
  • 账号状态四档与卡片重读:插件入口读不出登录凭据的区域不注册 provider(启动日志会说 原因)。卡片顶部的「当前账号」面板收敛成版本条(对齐 WorkBuddy 的 tab 条):每个 区域一个胶囊——状态点(ok 绿 / expired 红 / needs-app 琥珀 / signed-out 中性)+ 区域名 +「模型」开关;点哪个胶囊,账号详情、用量与模型列表都只看那一版,区域名因此 在卡片上只出现一次(模型行的区域 badge 已随之移除)。身份详情只带 name / email / 到期日,不带任何凭据(判定在 lib/account-state.js,纯本地证据、可注入可直测)。 两个按钮各管一件事:「重读登录」 让宿主丢弃凭据缓存、重读应用存储,并把启动时未能上线的区域现在就上线(重建并重新 注册 adapter,失败时回滚到原注册,不影响已在服务的区域)——重新登录后不必再重启 DSH; 面板每次渲染只读已缓存的密钥,不会同步起 PowerShell(那会阻塞整个 DSH 进程,最坏 30 s), 所以解不开的机器也能立刻看到"读不到"和原因;即便真的需要解包(点「重读登录」时)也是 异步等待——本机实测调用 29 ms 就返回、等待期间 DSH 照常响应别的请求,而同步版本会冻结 490 ms;「重读登录」是您主动点的,那一次是真读,不受缓存与失败窗口限制。 密钥缓存与 Local State 文件绑定,Qoder 重装换掉主密钥后插件会立刻重新解包,不必重启 DSH; 「在线确认」是账号流程里唯一的联网调用(fetchUserInfo),回答「上游现在还认不认 这个登录」,失败按 classifyUpstreamError 分档(sign-in-expired / 其他)。
  • 每一版的模型可以单独关掉(enabledRegions,版本条上的「模型」开关,对齐 WorkBuddy 的 per-tab 供应商开关):取消勾选的一版向 DSH 提供零个模型,它的 模型组按「空目录即隐藏」的同一条规则从选择器消失,但登录、用量与模型筛选全部 保留,重新勾选即恢复,无需重启 DSH;卡片模型列表与选择器用同一个 regionEnabledFor 谓词过滤,两个界面不会打架。
  • 刷新失败会说出来,而不是留着旧数据装作没事:
    • 上游当前没有模型(账号被收窄 / 模型全部下线)是结果不是故障——插件会照实把目录清空, 并把该版本的模型组从选择器撤下。此前这两种情况走同一条静默路径,于是旧名单永远留着, 点"刷新计费"也不可能有任何变化。
    • 抓取失败(网络、凭据、上游 5xx)保留上一份好数据,并把卡片上的时间标成 「上次更新:X(刷新失败)」,而不是给一个全新的时间假装刚更新过。
    • Qoder 改了接口格式(HTTP 200 但返回的信封不认识,例如分组改名)是一档独立状态, 卡片直接说"请更新插件(重新登录没有用)",且不显示时间戳——它不会被当成"排队"慢慢重试。 判别边界取自实测(probe/model-shape.mjs,两端真实账号):空分组用 [] 表达, 所以"0 个模型"是可信结果、必须落盘,而"分组键缺失/类型变了"才是格式变化。
  • 卡片接口只接受同源请求(安全):七条路由里三条是 POST 且能改状态——「签到领积分」 (真实账号变更)、「保存模型勾选与图像模式」、「重读登录」。这些接口此前只按"来源主机名是不是 本机"判断,因此本机任意端口上的任意 HTTP 服务都能让它的网页代为调用(浏览器会挡跨域 读响应,但操作已经发生)。现在要求来源的地址与端口与请求实际拨到的地址一致 (比对请求自己的 Host 头,所以不写死端口、DSH 换端口也不用改),且必须是回环地址。 判定在 lib/routes.js 的 loopbackRequest,由 test/route-gates.test.js 覆盖。
  • 依赖 Qoder 客户端接口(非官方开放 API),Qoder 更新后插件可能需要随之调整。
  • 设置命名空间由宿主决定,不能自选(0.1.7 起):describe() 用 Loader 条目 id 作为 ns(本 bundle 是 llm-qoder,不是 dsh-connect-qoder),而「设置 → 模型」 页按精确匹配查 namespaces.get(entry.settingsNs)。若插件宣告的命名空间与宿主实际 服务的不一致,该 provider 会被判为「未配置」,整行从页面上消失——不报错、不灰显, 而插件本身仍在正常注册和应答,非常难查。因此 settingsNs 一律经 settingsNamespaceOf(ctx) 从 ctx.fiber.entry.options.id 推导,常量只作为宿主不暴露 条目 id 时的回落值(对齐 WorkBuddy 2.1.0 的同款修复)。
  • 设置保存走插件的 __save 主机端点 + 读回校验(对齐 WorkBuddy 0.1.7 修复):DSH 0.1.7 的 客户端 settingsScope.set() 在原子写重试耗尽后会静默返回成功而不落盘,卡片改为「主机端点 权威写、本地写仅作镜像、写后读回确认」,保存按钮只会显示真实结果。在宿主未为本插件注册设置 命名空间行的环境(如 link: 开发安装)下端点会 503,卡片如实显示失败而不是假"已保存"; 正式(registry)安装下该端点可用。
  • 每日签到:Qoder 每天 10:00(UTC+8)给每个账号发一轮 CLAIM_BENEFIT 活动,一轮只能领一次, 重复领取是幂等的(replayed,不再发放)。卡片在「我的用量」里显示一行签到 + 三态按钮 (立即签到 / 签到中… / 今日已签到)——只有你点才会领,插件不会自动签到。每次点击都先重读一次 活动列表取当轮 id,绝不复用渲染时的旧 id(一天一轮,旧 id 就是上一轮的);领取后用量缓存作废 重读,因为 Credits 落在同一块面板显示的 Add-on 资源包里。两个过滤器是照真实返回加的:同一账号 下的另一个 VIEW_DETAILS 活动同样带着 claimStatus: "CLAIMED" 却没有 benefit,只按状态挑会对 它去领;而列表顶层的 claimable 在「已领过」和「没有活动」时都是 false,不能当判据。 按钮文案落到 addOnQuota 旁边,是因为国内版免费层的计划额度为 0,签到攒的资源包是它唯一的额度。
  • 国际版签到行需要 umid 机器身份:国际版 GET /sash/api/v1/me/campaigns 把每日 CLAIM_BENEFIT 轮次按机器身份下发——请求须携带桌面应用 umid 服务的 Cosy-MachineToken/Code/Type 头,否则只回常驻的 VIEW_DETAILS 横幅,签到行按 active: false 设计隐藏。插件在 OpenAPI 请求上自动附加这组头(Windows 上定位安装 目录的 resources\umid\runtime-info.exe 读取,失败静默降级为原头组;国内版与 PAT 不受影响;发现与验证记录在 docs/KNOWN_GAPS.md 第 8 条(国际版 campaigns 端点按 umid 机器身份门控每日签到))。

目录

文件作用
lib/credentials.js从 Qoder 应用读取并解密登录凭据(密钥缓存与 Local State 绑定、失败窗口 60 s、只读缓存的变体、不阻塞的异步解包)
lib/upstream.jsCOSY 签名、请求体编码、目录与对话流
lib/shim.js面向 pi-ai 的 OpenAI 兼容回环端点
lib/adapter.jspi-ai provider 与 PiAiAdapter profile(被关的 provider 以零模型组呈现,由 DSH 自行隐藏)
lib/catalog-entry.js目录条目的归一化、模型过滤(含按区域开关)与卡片行投影(无 peer 依赖)
lib/catalog-store.js目录的磁盘缓存与原子落盘(无 peer 依赖)
lib/catalog-refresh.js一次目录刷新的结果如何落地:空目录也是结果(照实清空并推进 fetchedAt),只有失败才保留上一份,且失败按 credential / no-credential / fetch / protocol-shape-changed 分档(无 peer 依赖)
lib/credential-cache.js凭据缓存与「登录失效后重读」规则(无 peer 依赖)
lib/account-payload.js账号面板三条路由共用的那份应答:逐区域状态 + 开关映射,以及「渲染读缓存 / 重读登录读真」这一个开关(从 index.js 抽出以便直测,无 peer 依赖)
lib/account-state.js每区域账号状态四档判定(ok / expired / needs-app / signed-out;纯本地证据、不含凭据,无 peer 依赖);三种读取模式(默认 / cachedOnly 不解包 / force 忽略失败窗口)
lib/settings-save.js设置命名空间的解析(0.1.7 由宿主推导,插件不能自选)、设置写入、按区域合并与落盘读回校验(无 peer 依赖)
lib/pi-model.jspi-ai 模型描述符的构造(纯函数,无 peer 依赖)
lib/adapter-models.js单个区域向 DSH 提供的模型列表:区域开关(只认显式 true)、勾选过滤、最大上下文开关、逐模型图像模式(从 adapter.js 抽出以便直测,无 peer 依赖)
lib/region-gate.js一个区域能否作为 provider 上线:三档拒绝(无登录 / 已过期 / 读不到)各自的判定与日志级别(从 index.js 抽出以便直测,无 peer 依赖)
lib/lifecycle.js插件 fiber 退出时要撤销的东西:路由注册的注销句柄收集与释放(宿主是否随 fiber 回收无法从插件侧确认,故两种语义都正确;无 peer 依赖)
lib/preferences.js四个设置项的读取与 volatile 解包(enabledRegions 区域开关:缺失/非对象一律读作开启,只有显式 false 才关)
lib/offpeak.js错峰窗口与费率算术(无 peer 依赖)
lib/single-flight.js同类异步任务的并发合并:刷新在途时,后来的调用并入同一次请求(目录/用量刷新用,无 peer 依赖)
lib/claim.js每日签到:当轮活动的挑选、可领状态判定与领取结果的归一化(纯函数,无 peer 依赖)
lib/errors.js上游错误帧的判定:105(登录没了)与 10605(在排队)的分诊,队列提示的提取,以及协议形状变化这一档(ProtocolShapeChangedError,retryable: false 所以它不会被当成"排队"慢慢等)(无 peer 依赖)
lib/time.js上游时间戳的单一换算(秒 / 毫秒 / RFC 3339 → epoch 毫秒),曾经的两份副本行为不一致(无 peer 依赖)
lib/volatile.js0.1.7 volatile 活引用 { get() } 的解包,此前散在三处(无 peer 依赖)
lib/http-utils.js回环路由共用的 JSON / OpenAI 形状错误响应(no-store,卡片轮询读不到陈旧数据;无 peer 依赖)
lib/routes.js每条卡片路由共用的两道闸:方法检查(405 带 Allow、HEAD 交给 GET)与同源来源检查(403;比对 Host 头,POST 路由靠它挡住本机其它端口的网页),以及带 64 KiB 上限的 JSON body 读取器(无 peer 依赖)
lib/index.js按区域注册 provider 的插件入口,与模型/用量/保存/账号状态路由(账号路由含「重读登录」的上线与回滚)

lib/client.js 是注入到宿主设置页的那张卡片的构建产物(react 由宿主提供,产物不打包它)。 它的源码在 src/client/,npm run build 从源码重建它:

| src/client/paths.ts | 卡片用到的五条插件路由 | | src/client/styles.ts | 卡片样式与 installStyles(dsm-* 一套与 dsh-connect-workbuddy 逐字一致,原因见文件头) | | src/client/settings-write.ts | 「写入后读回校验」的浏览器半边 | | src/client/copy.ts | 卡片文案聚合入口(中/英),index.ts 与 card.ts 只从这里取 | | src/client/copy-row.ts copy-usage.ts copy-account.ts | 按面板拆分的三段文案:模型行与错峰、用量与签到、账号与区域标签条 | | src/client/card.ts | 卡片的纯函数与五个组件(QoderPluginCard / QoderUsagePanel / QoderAccountPanel / RegionUsage / QuotaBlock) | | src/client/index.ts | 注册入口(apply / inject / name) |

这些源码不是原始手稿,是还原出来的:2026-09 用 docs/history/restore-client-src.mjs 把当时的 产物按 //#region 标记机械切分而成,模块边界来自产物,card.ts 那一段在产物里没有标记、 是按引用关系推断的。还原后做过一次对拍——把卡片里每个纯函数用同一组输入各调一遍,新旧产物的 返回值与抛错逐条一致(方法记录在 docs/issues/17-client-source-restore.md;现在的探针清单与 调用数以 npm run verify:bundle 的输出为准,不再在文档里写死数字)。

产物是构建输出:改源码重建,不要手改产物。test/client-bundle.test.js 从产物里提取并 执行卡片的纯函数,所以产物一改那里的断言就得跟着看一眼。

probe/ 下是一次性只读探针,每个文件头写明 WHY 与 Run,不参与构建、也不被测试收集。 其中 probe/host-compat.mjs 回答的是「本机装的 DSH 是什么版本、本仓库的 peer 声明它还认不认」—— 宿主把代码打在 app.asar 里,这件事从仓库内部看不出来。手法与三个会浪费时间的坑记在 docs/howto/host-version-probe.md。

测试

npm run verify          # 下面三条串起来,全过才算过
npm test                # node --test "test/*.test.js"
npm run test:coverage   # 同上 + 覆盖率门槛(行 68 / 分支 85 / 函数 66,跌破即失败)
npm run verify:deploy   # 比对已部署副本与本仓库,报告漂移
npm run build           # 从 src/client 重建 lib/client.js

npm run verify 跑三件事,每件回答一个不同的问题:

步骤回答什么全过时的输出
npm test卡片逻辑与宿主半边没被改坏最后一行 # fail 0
build --tsdown(不写)lib/client.js 确实由 src/client/ 生成MATCH: … byte-for-byte identical
verify:bundle重建产物与 HEAD 的行为一致behaviour: IDENTICAL

中间那条是最要紧的:它不写产物,只比较。它过了,就说明产物不是手抄进来的副本——改 src/ 而产物不变的情况会在这里红。

绿灯不等于门禁有效。 这三道门禁每条都用故意的破坏验过:build 缺关键串时会拒绝写入 (第一次构建摇掉全部模块、只剩 84 行,bundler 仍然退出 0);verify:bundle 把探针下界从 Math.max(0, …) 改成 1,就会在 formatCountdown|undefined|0 上报出 00:00:00 → 00:00:01 并以非 0 退出。怀疑门禁时照这个法子再破一次,比看它绿不绿有用。

npm run build 需要构建器(tsdown),它是 devDependency,跑之前先 npm install。 测试仍然不需要安装任何东西(裸 node --test),两者是 CI 里分开的两个 job:一个证明 测试无依赖,一个证明产物可重建。

对拍覆盖不到渲染:JSX 被 stub 成 null,所以改了 UI 仍然要在浏览器里看一眼(展开卡片 → 切区域 → 改图像档位 → 保存 → 看错峰倒计时)。

.npmrc 里的 legacy-peer-deps=true 是必需的、不是随手加的:本包的 peer 依赖是 @deepseek-ai/*,由宿主在运行时提供,不在公共 registry 上,npm 自动安装 peer 会在装到 devDependencies 之前就失败。

verify:deploy 存在的理由和上面那些测试一样:一台机器上可以同时装着好几个版本的本插件。 link: 安装是指向本仓库的符号链接、永远最新;市场安装是复制,停在安装那一刻, 而且两边 package.json 的 version 一样——任何按版本判断新旧的升级路径都会认为「已是最新」。 该脚本比对 lib/** 的内容哈希、文件清单,以及三个由真实缺陷换来的标记 (错峰 active 门、账号状态模块、账号路由),并把「版本号相同但内容不同」单独标出来。 test/deploy-drift.test.js 用假目录树钉住这套判定。

CI 在 Node 22.19 / 24 × Ubuntu / Windows 上跑(.github/workflows/test.yml)—— Windows 不是冗余:shim 绑定回环监听、目录缓存依赖 rename 覆盖、凭据读取要调 PowerShell,这些在别的平台上行为不同。

测试只用 Node 内置的 node:test,不需要安装任何依赖——也不需要安装 peer 依赖, 这是刻意的:lib/ 中凡是纯逻辑的部分都放在无 peer 依赖的模块里(见上表), 这样它们才能被直接 import 并断言真实的实现,而不是在测试里手抄一份。

几个文件存在的理由,都是因为曾经出过问题:

  • test/catalog-fields.test.js 与 test/model-row.test.js —— 错峰机制曾因 promotion.active / promotion.timezone 在 Host 投影时被丢掉而全程哑火, 而当时的测试是绿的,因为它测的是自己手抄的副本。同一个毛病在客户端又犯过一次: 卡片自己算窗口时漏看 promotion.active,把拿不到的折扣价显示给用户, 而模型选择器按 before 价计费,两个界面自相矛盾。 model-row.test.js 现在逐状态对拍两个门控;client-bundle.test.js 更进一步, 直接从产物里提取卡片的 offPeakState 并执行——删掉那行门控会让它变红, 而只会让 model-row.test.js 保持绿色。副本不是防线。
  • test/credential-cache.test.js —— 「重新登录无需重启」这条卖点的完整链路: 网关拒绝 → 谓词判定 → 置失效标志 → 下次请求重读。此前只有两端被测。
  • test/credential-invalidation.test.js —— 上面那条链路上的两个纯谓词。
  • test/account-state.test.js —— 账号状态四档判定(lib/account-state.js): 全注入的存储读器 + 真实临时目录跑目录存在性检查,钉住「判定只信本地证据」 与「状态记录不含任何凭据材料」两条不变量。
  • test/errors-classify.test.js —— 105 与 10605 的优先级决定了「提示用户重新登录」 还是「排队等待」,两者弄反的代价完全不同。
  • test/settings-save.test.js —— DSH 0.1.7 上 set() 会静默成功而不落盘; 这段代码用「写入→读回→深比较」把假成功变成显式失败,测试里直接模拟 「mutate 成功但文档没变」的那个场景。也钉住了两件靠肉眼会漏的事: 命名空间只做全等匹配(llm-qoder-extra 不算我们的),字段白名单用 Object.hasOwn(constructor 不是一个字段)。
  • test/pi-model.test.js —— toPiModel 抽离成纯函数后的直接覆盖: compat.supportsDeveloperRole: false 与「不声明 maxTokens」这两处, 失效时每个请求都会 403,或长回复被截成 finish: max-tokens。
  • test/catalog-store.test.js —— 目录缓存的原子落盘,用真实临时目录跑, 在 CI 所在的平台上实测 rename 覆盖行为,而不是在注释里假设。
  • test/shim.test.js —— 回环端点的鉴权与 /v1/models 过滤;对着真实 HTTP 服务器说话,Host 头用裸 socket 发送(fetch 禁止设置该头)。
  • test/oscrypt.test.js —— 凭据解密往返;夹具用真实 AES-256-GCM 构造, key 是固定哈希,失败可复现。
  • test/upstream-protocol.test.js —— 编码与签名。两个盲区是原理上不可测的, 已在文件头写明。
  • test/upstream-messages.test.js —— 消息与工具调用翻译,注释里自称 「最重要的一件事」,此前零覆盖。

尚未覆盖的部分集中登记在 docs/KNOWN_GAPS.md,不在各文件里重复叙述—— 重复三处正是「手抄副本」那类问题的文档版。

免责声明

仅供个人学习研究使用,仅驱动使用者自己的 Qoder 账号在本机调用。使用者需遵守 Qoder 的服务条款, 因使用本项目产生的后果由使用者自行承担。本项目与 Qoder、DeepSeek 均无关联。

插件除「每日签到」外的所有请求都是只读的;签到是它唯一会对 Qoder 账号产生变更的操作(领取 Qoder 正在向你自己的账号发放的额度),它不会自动执行,每次都要手动点击。是否使用它、以及它是否符合 Qoder 当前的服务条款,请自行判断。

许可证

MIT

Comments

0
Newest first