# deepseek-harness-codearts **Repository Path**: hsj1987129/deepseek-harness-codearts ## Basic Information - **Project Name**: deepseek-harness-codearts - **Description**: deepseek-harness的插件,支持codearts登录和模型调用 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 39 - **Created**: 2026-09-14 - **Last Updated**: 2026-09-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # dsh-codearts-auth deepseek-harness 插件:执行 CodeArts(华为云)登录流程,默认走新式 IAM OAuth (portal `/authorize` 授权 → 本地 `/oauth/callback` 回调 → STS token 端点换取含 `refresh_token` 的凭据),到期前静默续期,无需再次打开浏览器;旧 ticket 流程保留 为显式回退(`flow: 'ticket'`)。插件还注册一个 `codearts` LLM provider 路由,使该 凭证可直接用于 CodeArts 后端模型调用。 此外插件内置另外两个 provider 路由: - **buddy(腾讯 CodeBuddy)** — 见 [buddy provider](#buddy-provider); 另支持「一键领取积分」(每日签到)。 - **workbuddy(腾讯 WorkBuddy 国际版)** — 见 [WorkBuddy provider](#workbuddy-provider)。 ## 安装 该包尚未发布到 npm registry。提供两种安装方式:**git 仓库安装**(推荐,自动拉取 并构建)和**源码目录安装**(本地开发联调)。 ### 方式一:从 git 仓库安装(推荐) 先在 profile 的 `pnpm-workspace.yaml` 中放行该包的 build 脚本 (路径形如 `~/.dsh/profiles//pnpm-workspace.yaml`): ```yaml allowBuilds: dsh-codearts-auth@git+https://gitee.com/iJetLi/deepseek-harness-codearts.git: true ``` 再用 `dsh plugin add` 从 gitee 拉取并安装: ```sh dsh plugin --profile add "https://gitee.com/iJetLi/deepseek-harness-codearts.git" ``` `add` 以 `git+https` 方式安装,pnpm 会运行 `prepare` 脚本自动构建 `lib/`,无需 手动 `pnpm build`。每次升级时重新 `add` 即可拉取最新版本并重建。 ### 方式二:从源码目录安装(本地开发) 先在本仓库中构建 `lib/`,再用 `dsh plugin install` 将本地检出安装为 pnpm `link:` 依赖(指向本目录): ```sh pnpm build dsh plugin --profile install ``` > `dsh plugin install` 以 `link:` 方式安装,pnpm 不会为 `link:` 依赖运行 > `prepare` 脚本,因此必须先手动执行 `pnpm build` 生成 `lib/`,否则 dsh 启动时 > 报 `ERR_MODULE_NOT_FOUND: ... dsh-codearts-auth/lib/index.js`。 每次修改 `src/` 后都需要重新执行 `pnpm build`——dsh 启动时不会自动重建。 ### 通用说明 该包声明了 `dsh.bundle` 补丁(`cordis.patch.yml`),因此 profile 的 layer 栈会 自动拾取 `codearts-auth` 行。插件注入由 dsh base 提供的 `credentials`、 `commands` 和 `llm` 服务。 ## 用法 - `/codearts-login` — 在浏览器中打开华为云 portal 授权页;授权后,插件经本地 `/oauth/callback` 回调收取 `code`,并由 STS token 端点换取含 `refresh_token` 的 AK/SK/SecurityToken 凭据。 - `/codearts-status` — 显示 `configured`、`source`、`expiresAt`、 `refreshable` 以及最新的 `refreshError`。 - `/codearts-refresh` — 手动静默续期凭据(refresh_token 换取;无 refresh_token 时提示重新登录)。 - 编程式调用:`ctx.codeartsAuth.login()`、`ctx.codeartsAuth.status()`、 `ctx.codeartsAuth.refresh()`、`ctx.codeartsAuth.logout()`。 ## LLM provider 插件在 `ctx.llm` 上注册了一个 `codearts` provider 路由(OpenAI 兼容端点 `https://snap-access.cn-north-4.myhuaweicloud.com/api/v2`)。每个模型请求都使用 存储的 AK/SK/SecurityToken 按华为 `SDK-HMAC-SHA256` 方案签名,并附带 `Chat-Id`/`Session-Id` 请求头。默认广告的模型为 GLM-5.2、GLM-5.1、 GLM-5、GLM-5.3 Flash(`glm-5.3-flash`,1M 上下文)、盘古 openpangu-2.0-flash (92B) / openpangu-2.0-pro (505B), 以及 DeepSeek V4 deepseek-v4-flash / deepseek-v4-pro(UI 标注每日 1000 万免费 Tokens 福利)。 登录后在 dsh Models 页面选择该 provider 即可。 > 注 1:CodeArts Agent IDE 模型列表显示的 flash ID 为 `deepseek-v4-flash-0731` > (带日期后缀),但后端实际注册的可用 ID 是 `deepseek-v4-flash`(无后缀)。 > 用 `deepseek-v4-flash-0731` 调用会返回 `InferHub.002002009.404 The model is > not registered`,因此本插件只注册无后缀的 `deepseek-v4-flash`。 > > 注 2:`glm-5.3-flash`(GLM-5.3 Flash,2026-08 加入,1M 上下文)是 benefit > (免费额度)模型:其 chat 请求必须携带 `maas_type: benefit` 请求头且该头 > 参与 `SDK-HMAC-SHA256` 签名,否则后端返回 `InferHub.002002009.404 The model > is not registered`。适配器已自动处理,无需手动配置。 > (逆向自 CodeArts Agent IDE mitmproxy 抓包,对齐 deveco-code-rust 90aeb17d。) 凭据来自默认的新式 IAM OAuth 流程(含 `refresh_token`)。请求发起时会解析最新 凭据,若已过期则先静默续期,再用新 AK/SK/SecurityToken 签名,无需重新打开浏览器。 除 `codearts` 外,插件另注册两个独立的腾讯系路由:`buddy`(见 [buddy provider](#buddy-provider))与 `workbuddy`(见 [WorkBuddy provider](#workbuddy-provider))。三者互不覆盖,可同时使用。 ## 凭证 - Ref:`CODEARTS_ACCESS_TOKEN`(POSIX 标识符格式的凭证 ref)。 - 值:JSON 字符串 `{ access_key_id, secret_access_key, security_token, expires_at, domain_id?, user_id?, user_name? }` — AK/SK 对用于给每个 CodeArts 后端 API 请求签名。 - `status()` 报告 `configured`、`source`、`expiresAt`、`refreshable` 和 `refreshError`。 ## 续期(refresh) - 默认登录流程为**新式 IAM OAuth**(PKCE + DPoP):portal `/authorize` 授权 → 本地 `/oauth/callback` 回调收取 `code` → `sts.cn-north-4.myhuaweicloud.com/v1/oauth2/tokens` 换取含 `refresh_token` 的凭据。 - 凭据在过期前 1 小时静默续期(`getFirstRefreshTime` 语义:距过期 ≤1h 立即刷, 否则 `now+1h` 叠加随机秒偏移),全程无浏览器、无人工操作。 - 刷新失败后 10 分钟重试(异常网络 1 分钟);`refresh_token` 失效后停止续期并提示 重新登录(原因会体现在 `status().refreshError` 中)。 - 旧 ticket 流程保留为显式回退:`/codearts-login` 默认走 OAuth;编程式调用 `ctx.codeartsAuth.login({ flow: 'ticket' })`。ticket 凭据没有 `refresh_token`, 其续期仍意味着重新运行浏览器登录流程。 - 手动续期:`/codearts-refresh` 或 `ctx.codeartsAuth.refresh()`。 - 续期定时器是 unref 的,在 `logout()` 和插件卸载时停止。 - 运行时依赖新增 `jose`(用于 DPoP JWS 签发,与 CodeArts Agent 插件实现一致)。 ## 开发 - `pnpm test` — 单元测试(快速,无网络)。 - `pnpm test:e2e` — 针对华为线上端点的真实登录流程;需要在打开的浏览器中由人工 点击授权按钮(续期为静默刷新,无需再次点击)。 - `pnpm typecheck`、`pnpm build`。 ### 构建 - `pnpm build` — 用 tsc 将 `src/` 编译到 `lib/`(生成 `.js`、`.d.ts` 和 source map)。插件入口是 `lib/index.js`,而 `lib/` 已被 gitignore,因此构建是安装或 运行前的必需步骤。 - `pnpm typecheck` — 只做类型检查(`tsc --noEmit`),不产出文件,可在构建前快速 验证。 每次修改 `src/` 后都需要重新执行 `pnpm build`——dsh 启动时不会自动重建。 ### 安装到 profile 之前先构建 详见「安装」小节。`dsh plugin install` 以 `link:` 方式安装,pnpm 不会为 `link:` 依赖运行 `prepare` 脚本,因此必须先 `pnpm build` 生成 `lib/`。 ## 工作原理 默认登录流程(新式 IAM OAuth,PKCE + DPoP): 1. 生成 PKCE 配对与 DPoP ES256 密钥对,并启动本地 `127.0.0.1` 回调服务器。 2. 构造 portal `/authorize` URL 并打开华为云授权页面。 3. 授权后浏览器回调本地 `/oauth/callback`,携带授权码 `code`。 4. 向 STS token 端点(`sts.cn-north-4.myhuaweicloud.com/v1/oauth2/tokens`)用 `code` 换取含 `refresh_token` 的凭据 JSON,并存储到 `CODEARTS_ACCESS_TOKEN` 下。 5. 凭据到期前静默续期(见「续期(refresh)」),无需再次打开浏览器。 旧 ticket 流程保留为显式回退(编程式调用 `ctx.codeartsAuth.login({ flow: 'ticket' })`): 生成 `ticket_id`,打开 `devcloud.cn-north-4.huaweicloud.com/doer/redirect` 认证页, 回调后轮询 snap-manager ticket 端点(120 × 1 秒)获取临时凭证;此类凭据没有 `refresh_token`,其续期仍意味着重新运行浏览器登录流程。 ## buddy provider 独立路由 `buddy`(腾讯 CodeBuddy,OpenAI 兼容端点 `https://copilot.tencent.com/v2/chat/completions`),Bearer `access_token` 鉴权。 登录采用 external-link-v2 轮询式(与 CodeArts 的本地回调服务器不同,CodeBuddy 不起本地端口,而是轮询后端 API): 1. `POST /v2/plugin/auth/state?platform=ide` → 取得 `state` 与 `authUrl`。 2. 打开浏览器到 `https://www.codebuddy.cn/login/?platform=ide&state=...`。 3. 轮询 `GET /v2/plugin/auth/token?state=...`(1 秒间隔、5 分钟超时)→ 令牌; 错误码 `11217` 表示 token 未就绪,继续轮询。 4. 轮询 `GET /v2/plugin/login/account?state=...` → 账户信息;错误码 `12151` 表示账户信息未就绪,继续轮询。 5. 续期:`POST /v2/plugin/auth/token/refresh`,通过 `X-Refresh-Token` 头提交 refresh_token。 - **登录入口:Jet Hub 设置页的 CodeBuddy 面板**(支持多账号与账号池自动切换)。 已不再注册斜杠命令 —— 设置面板已覆盖登录、状态查看与续期,命令式入口冗余。 - 编程式调用:`ctx.buddyAuth.login()` / `status()` / `refresh()` / `logout()` / `fetchModels()`。 - 模型列表:以内置的产品目录为准(`src/product.ts` 的 `fallbackModels`), 远端 `GET /v3/config` 可用时优先采用其元数据。 - 请求头:除 `Authorization: Bearer` 外,还需 `X-Domain`、`X-Product`、 `X-Product-Code` 以及伪装为 `CodeBuddyIDE/1.106.1` 的 `User-Agent`。 - 凭据 ref:`BUDDY_ACCESS_TOKEN`,值为含 `access_token` / `refresh_token` / `expires_at` 的 JSON 字符串。 > **流式工具调用 id 稳定性**:CodeBuddy 仅首个工具调用分片携带真实 id > (`chatcmpl-tool-xxx`),后续参数分片只有 `index`。适配器按 index 缓存并沿用 > 真实 id(缺失时回退 `call_{index}`),保证同一工具的所有分片 id 一致——否则 > 跨轮次(每轮都从 `call_0` 重新编号)会把 `tool/result` 配对到错误的历史条目。 ## WorkBuddy provider(国际版) 独立路由 `workbuddy`(腾讯 **WorkBuddy 国际版 / WorkBuddy AI**),与 [buddy provider](#buddy-provider) **同源**:共用同一 CLI 内核与同一认证协议 (cli-external-link 轮询式),Bearer `access_token` 鉴权。差异收敛在 `src/product.ts` 的产品配置里: | 项 | CodeBuddy(中国) | WorkBuddy(国际版) | |---|---|---| | `endpoint` | `https://copilot.tencent.com` | **`https://www.workbuddy.ai`** | | `platform` | `ide` | **`workbuddy-ai`** | | 登录 URL 附加参数 | 无 | **`version` / `loginSessionId`** | | `pluginVersion` | — | `5.5.2` | **模型列表不能与中国版共用**:两者的路径与响应解析完全相同 (`GET /v3/config` → `data.data.models` / `data.data.agents`),差异只来自 `endpoint` —— 不同区域的后端返回不同模型池(中国版含 glm / hy / deepseek 系, 国际版含 claude / gpt / gemini / kimi 系)。因此 `endpoint` 必须随产品切换, 不能被当成全局常量。 登录流程与 CodeBuddy 一致(`auth/state` → 浏览器授权 → 轮询 `auth/token` → 轮询 `login/account`),仅身份标识与端点按上表区分。`X-Product-Code` 为 `workbuddy`,`X-Domain` 随 `apiDomain` 切换为 `www.workbuddy.ai`。 **没有每日签到积分**:国际版后端不提供签到接口(内核中只有 `/v2/billing/meter/get-dosage-notify` 用量通知),因此 Jet Hub 的 WorkBuddy 面板**不显示「一键领取积分」按钮**;积分领取在 CodeBuddy 面板完成。 - **登录入口:Jet Hub 设置页的 WorkBuddy 面板**(支持多账号与账号池自动切换)。 同样不注册斜杠命令。 - 编程式调用:`ctx.workbuddyAuth.login()` / `status()` / `refresh()` / `logout()` / `fetchModels()`。 - 凭据 ref: - 单账号:`WORKBUDDY_ACCESS_TOKEN`,值为含 `access_token` / `refresh_token` / `expires_at` 的 JSON 字符串(与 `BUDDY_ACCESS_TOKEN` 同构)。 - 多账号:`WORKBUDDY_ACCOUNT_`,由 Jet Hub 设置页「+ 新建账号」 登录时自动生成并登记到账号池;每条账号记录带 `provider: 'workbuddy'`, 与 CodeBuddy 的 `BUDDY_ACCOUNT_*` 相互隔离,不会串用凭据或限流标记。 - **从中国版升级**:本插件早期版本把 `workbuddy` 指向中国版 (`copilot.tencent.com`)。启动时会自动清理凭据 `domain` 与当前 `apiDomain` 不符的旧账号(这类凭据在新端点必然失败),清理结果记入日志, 请在 Jet Hub 重新登录。 - 续期:与 CodeBuddy 共用同一套机制,插件启动后每 30 分钟对可续期账号静默刷新 (`refresh_token` 经 `X-Refresh-Token` 头提交),无需重新打开浏览器。 - 请求头、模型列表拉取与流式工具调用 id 处理均与 CodeBuddy 一致,详见上一节。 ### 与 Jet Hub 设置页的关系 Jet Hub(设置页)的账号面板按 provider 分组展示,WorkBuddy 是其中一栏: - 面板提供账号列表、新建账号(浏览器登录入池)、启用/停用、删除,以及「重测 / 重测所有 / 重置 / 重置所有」限流标记操作,行为与 CodeBuddy 面板一致,但 只操作 `provider: 'workbuddy'` 的账号。 - 账号卡片只展示 credentialRef、有效期(含「自动续期」标记)与限流状态, **不显示任何签到信息**;面板标题栏「一键领取积分」的结果来自 RPC 端点 `credits.claimAll`(实现见 `src/jet-hub-rpc.ts`,签到客户端见 `src/credits.ts`)。 - 后端另实现了 `credits.status`(查询某 provider 下全部启用账号的签到状态), 但**前端尚无消费者**:`plugin-src/client/jet-hub.js` 只调用 `credits.claimAll`, `credits.status` 目前仅供外部脚本或直接 RPC 调用使用。 - 对应 LLM provider 的设置命名空间为 `llm-workbuddy`。 ### 一键领取积分(每日签到) **仅 CodeBuddy 面板提供**该按钮。CodeArts 是华为云账号体系不参与;WorkBuddy 国际版后端没有签到接口,故其面板也不显示(积分领取在 CodeBuddy 侧完成)。 在 Jet Hub → CodeBuddy 面板标题栏点击「**一键领取积分**」,插件会对该面板下 **全部账号**顺序执行每日签到领取: > **含已停用账号。** 停用只影响账号池的自动选择与限流切换,不改变账号本身 > 是否已签到——用户点「一键领取」时期望所有账号都尝试一遍。 1. 先查签到活动状态(`POST /v2/billing/meter/checkin-activity-status`); 2. 活动未开启或今日已签到则跳过领取请求,只报告状态; 3. 否则调用领取端点(`POST /v2/billing/meter/daily-checkin`)领取当日积分。 完成后按钮下方给出结果摘要(如「3 个账号领取成功(+300 积分),1 个今日已领取」)。 领取按账号隔离:单个账号凭据缺失、损坏或请求失败不会中断整批,只计入失败数; 摘要**只显示各类计数**(如「1 个失败」),不展示每个账号的失败原因——原因保留在 `results[].outcome.message` 中,需要时请通过 RPC 响应或日志查看。 几点实现约定: - 领取是**顺序执行**的,避免并发触发风控;账号较多时需要等待片刻。 - 重复领取是幂等的:服务端返回 HTTP 400 + `code 10001`(「今天已签到,请明天 再来」),插件把它识别为 `already-claimed` 而非失败。 - 状态查询用 `checkin-activity-status` 而非 `checkin-status`;后者返回占位数据 (`active:false`、`checkin_dates:null`),会让人误判为活动未开启。 - 请求**不需要** `X-Device-Token`(图灵盾)——已实测验证。 想单独验证领取闭环(会真实改动账号当日签到状态)可运行 `pnpm test:e2e:workbuddy-claim`,说明见 `tests/e2e/README.md`。