DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Account Switch — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
A

dsh-account-switch

Account Switch

DeepSeek Harness multi-account plugin: log in to multiple accounts once and switch the active account at any time (hot switching, no restart required)

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:chenzi666/dsh-account-switch#3207248ae5bd33c31a41612bf4ea931ca3fe65d9
READMECompatibilityVersions

Compatibility and provenance

Account Switch is published as dsh-account-switch and currently resolves to version 0.1.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
10/6/2026

Versions

0.1.0stable
10/6/2026

Related plugins

Loading related plugins…

Latest
0.1.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/6/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in security-access.

Experimental Auto Review@deepseek-ai/dsh-experimental-auto-reviewPer-tool LLM authorization review for the DeepSeek Harness Auto permission presetCc Safety Netcc-safety-netA coding agent CLI hook - block destructive commands and secret file accessDoctor@linxin666/dsh-doctorTransactional rescue mode for DSH profiles with a supervised launcher, isolated recovery capsule, deterministic repairs, health monitoring, and a local Web recovery consoleMobiledsh-mobileDeepSeek Harness mobile adaptation and secure access plugin, supporting LAN, remote connections, Android App, and mobile browsers.

README

dsh-account-switch

DeepSeek Harness 多账号插件 —— 一次登录多个账号,随时热切换,不重启、不重新登录。

这个插件解决的是最后一环。 DeepSeek Harness 官方活动:新用户首次登录送 6 元额度;接码平台一个手机号 0.2–0.3 元。账号多得起来、便宜得下来,但官方 UI 一次只认一个账号,退出还会注销 token —— 所以你需要一个东西把这些账号管住,让它们变成一个连续可用的额度池。那就是它。

切换后下一个模型请求立即用新账号。已登录的账号不会被顶掉——它们在凭证库里各自有一个存档槽位。

额度烧干时自动换到下一个还有钱的账号,并让失败的那一步原地重跑:会话不断、上下文不丢、工具状态不动。

切换前  default ──▶ 账号 A(已烧干)
切换后  default ──▶ 账号 B            ← 下一个请求直接生效,进程没重启过

功能

功能说明
多账号共存任意多个账号的 token 同时存在凭证库里,互不覆盖、互不顶号
热切换dsh-account use <账号> 立即生效,无需重启、无需重新登录
额度自动换号当前账号额度用尽时自动切到下一个可用账号,并让失败的那一步原地重跑
账号冷却刚被判没钱的账号进冷却(默认 5 分钟)不再被选中,避免来回横跳;充值后自动回到候选
切换留痕每次自动换号写一行 JSON 日志(切到谁、什么错、哪个会话的第几步)
指纹化存档账号 id 由 sha256(token) 前缀派生,同一 grant 永远映射同一槽位,归档天然幂等
昵称管理给账号起中文名,use 主号 比 use acct-af3bded5 好记
CLI + 插件 APIdsh-account 命令行,另有 ctx.accountSwitch 供其它插件调用
零内核改动全部走公开 seam,不 patch 官方包,Harness 升级不会把它冲掉
不额外存秘密registry.json 只有指纹;list --json 不输出 token

先说清它做不到什么

切换是全局的。

Harness 的账号是一个进程级的单例服务:ctx.deepseekAccount(实现为 PlatformAccount)持有唯一的账号状态,deepseek-account 这个模型 provider 每次请求都向它要 token。官方把活跃账号硬编码在 deepseek-account-platform/default 这一个槽位上,没有任何按会话区分的维度。

所以:

  • ✅ 多个账号的 token 可以共存,切换是瞬时的、热生效的
  • ❌ 不能让 A 会话用账号 1、B 会话用账号 2 同时跑——切了就是全切
  • ❌ 额度用尽时的自动换号切的是同一个全局槽位。A 会话先撞上额度打满而换号,B 会话的下一个请求也会跟着用新账号。这是全局单例的语义,不是本插件的取舍

要「同时并行」只能开第二个 Harness 实例,让它用另一个 DSH_HOME(于是另一份 .credentials.yaml)。但 Desktop 的 Electron 单实例锁是否会放行第二份实例,需要实测,--user-data-dir 未必够。本插件不尝试绕过这一层。

如果哪天需要真正的按会话绑定,那要动的是内核里 resolveToken() 的取用维度——那是另一件事,不是插件能做的。


为什么走「注册新用户」这条路

因为 DeepSeek Harness 官方活动:新用户首次登录送 6 元额度。

这不是钻空子,是官方自己掏的拉新预算。一个账号就是一个 6 元额度的容器,而拿到它只需要一个能收验证码的手机号。

于是整条路的成本结构简单到离谱:

项目金额
接码平台收一条验证码(一个手机号)0.2 – 0.3 元
新账号首次登录,官方赠送6 元额度
净得≈ 5.7 元额度
投入产出比约 20 – 30 倍

注册 10 个号:成本约 2.5 元,到手约 57 元额度。 注册 30 个号:成本约 7.5 元,到手约 171 元额度。

但账号越多,官方 UI 越不够用。

它一次只认一个账号,已登录状态下只给一个「退出登录」按钮——而退出还会向平台注销 token,那个账号就废了。想切回去?重新走一遍登录。

所以最后一环必须有人补上:

  1. 接码平台解决「账号从哪来」——0.2–0.3 元一个,成本可以忽略
  2. dsh-account-switch解决「账号怎么用」——一次登录全部存档,随时热切换,额度烧干自动换下一个并原地重跑

两者接起来,官方送的那 6 元额度才真正变成你可以连续使用的算力:额度用尽的那一刻,会话不会断,插件自己就换号了。

📱 接码:好助码 · 在线接码平台

项目说明
单价0.2 – 0.3 元 / 条(按号段和项目浮动,下单页实时显示)
覆盖国内外主流号段,注册/登录类短信验证码
到货网页实时收码,不用等、不用抢
注册入口https://h5.haozhuma.com/reg.html?action=weichen666

完整流程:

  1. 打开 https://h5.haozhuma.com/reg.html?action=weichen666 注册并充值(几十块够用很久)
  2. 选号 → 拿到手机号 → 在 Harness 官方 UI 里用它登录新账号 → 6 元额度到账
  3. 插件自动把新账号归档入库(autoCaptureOnSignIn: true,无需手工操作)
  4. dsh-account park 撤下它腾出位置,回到第 2 步换下一个号;重复 N 次
  5. dsh-account list 看总账,dsh-account use <昵称> 随时切到任意一个

插件本身与接码平台无技术耦合——它只负责管账号,不负责造账号。手机号从哪来由你决定,这里给的是最省事的一条路。


它怎么做到的

全部走公开 seam,不改内核、不 patch 官方包,所以 Harness 升级不会把它冲掉。

三层事实:

  1. 凭证服务是通用的。 ctx.credentials 按 <scope>/<id> 寻址,id 段只要求匹配 /^[a-z][a-z0-9-]*$/。官方只用了 default 和 device,剩下的 id 段没人占——account-<指纹> 就是我们的地盘。

  2. 目录变了会自动广播。 dsh-credentials-local 带 fs watcher:.credentials.yaml 一变就 reconcileFromDisk(),对每条变化的记录发 credentials/record-updated。而 PlatformAccount 自己就监听这个事件。所以写文件 = 通知到位。

  3. token 没有跨请求缓存。 PlatformAccount.resolveToken() 每个请求都重读 default。所以覆盖那一行,下一个请求就是新账号。

于是切换的全部动作就是:把目标槽位的内容写回 default。

存档槽位

version: 1
records:
  client-connection/browser-session: { ... }          # 官方持有,本插件不碰
  deepseek-account-platform/device:  { ... }          # 官方持有,本插件不碰
  deepseek-account-platform/default:                  # ← 活跃账号,官方唯一的读写口
    kind: grant
    payload: { version: 1, token: <当前账号>, issuer: https://platform.deepseek.com }
  deepseek-account-platform/account-acct-af3bded5:    # ← 本插件的存档槽位
    kind: grant
    payload: { version: 1, token: <账号 A>, issuer: ... }
  deepseek-account-platform/account-acct-f6b06859:    # ← 又一个存档槽位
    kind: grant
    payload: { version: 1, token: <账号 B>, issuer: ... }
refs:
  DEEPSEEK_API_KEY: sk-...                            # 官方持有,本插件不碰

账号 id 直接由 sha256(token) 的前缀派生,所以同一个 grant 永远映射到同一个 id——归档天然幂等,不需要一张需要维护的映射表。

昵称等元数据存在 $DSH_HOME/accounts/registry.json,只放指纹,不放 token 明文。之所以不塞进 .credentials.yaml:官方解析器对文档做严格白名单校验,顶层只允许 version/refs/records、每条记录只允许 kind/payload,多一个字段就让整篇解析失败——那是启动级故障。


安装

1. 把包放进 profile 的 node_modules

这个 profile 的 node_modules 是「解压出来的真实目录」结构——.pnpm 里只有一个 lock.yaml,dsh-proxy-boot、dsh-web-search-ddg 全是这么放的。所以不要跑 pnpm / npm:它们会按依赖树重建整个目录,把那些不在 lock 里的包清掉。

用脚本复制成真实目录:

powershell -NoProfile -File scripts/sync-install.ps1

必须是真实目录,不能用目录联接。 这是实测结论,不是偏好:同一个包以 junction 形态放进 node_modules 时,Harness 根本不会加载它——连插件自己的 apply() 都不会被调用,而且不报任何错。把完全相同的文件复制成真实目录后立刻正常。当时靠三个对照探针(真实目录 / junction / 完整插件)一次重启锁死了这个结论:真实目录那个写出了留痕,另外两个什么都没写。原因在 dsh-app-boot 的 linkedProfileRoots 那一层,没有继续深挖。

代价是改了源码要重跑脚本。脚本会连同 node_modules/yaml(唯一的运行时依赖)一起复制——Harness 的解析层不会替插件装依赖。

卸载:Remove-Item -Recurse 掉那个目录,再从 patch 里删掉条目。

2. 在 profile 的 patch 里挂上插件行

$DSH_HOME/profiles/desktop/cordis.patch.yml 末尾追加:

- insert:
    - id: dsh-account-switch
      name: dsh-account-switch
      config:
        enabled: true
        autoArchiveOnStart: true
        autoCaptureOnSignIn: true
        verbose: false

多个 - insert: 块都会被处理(dsh-app-boot 里是 for (const patch of patches) patch.insert?.forEach(visit)),所以它和 profile 里原有的 proxy-boot / web-search-ddg 那个 insert 块互不干扰。

3. 重启 Harness

实测改完 patch 后插件没有自动挂载——patchReload: live 不覆盖新增的插件行。需要重启一次。

关于 @deepseek-ai/*

插件里 import '@deepseek-ai/cordis' 和 '@deepseek-ai/schemastery' 由 Harness 运行时提供,部署时插件的 node_modules 里不该有 @deepseek-ai 目录。

这里踩过一个坑:npm 7+ 默认会自动安装 peerDependencies,而 @deepseek-ai/cordis 在公共 registry 上有包,npm install 就在插件下塞进了第二份 cordis。那意味着插件的 Service 基类来自另一个模块实例,跟宿主 ctx 不是同一个——挂载时才炸,而且只在运行时暴露。所以本仓库带了 .npmrc(legacy-peer-deps=true),插件目录里只应存在 yaml。

命令行

node bin/dsh-account.js list

安装时动过的东西:

路径备份
$DSH_HOME/.credentials.yaml同目录 .pre-account-switch.bak
$DSH_HOME/profiles/desktop/cordis.patch.yml同目录 .pre-account-switch.bak
$DSH_HOME/profiles/desktop/package.json未改动(不需要改)
$DSH_HOME/profiles/desktop/node_modules/dsh-account-switch新增真实目录

用法

加第二个账号

官方 UI 在已登录状态下只会给「退出登录」,而退出会向平台注销 token(revokeAccount),把存档一起废掉。所以用 park:

dsh-account list                       # 看看现在有什么
dsh-account park --label 主号          # 撤下当前账号,官方 UI 回到未登录态
                                       # token 未注销,存档完好
… 在 UI 里登录第二个账号 …             # 插件自动把它归档进账号库
dsh-account park --label 小号          # 想再加就继续
dsh-account list                       # 两个都在

park 之后插件也会在 default 变化时自动捕获新账号,不需要手工 capture。

切换

dsh-account use 主号          # 按昵称切(昵称必须唯一)
dsh-account use acct-af3bded5 # 按 id 切

切完下一个模型请求就用新账号。不需要重启任何东西。

额度用尽自动换号

不用手动盯着。当前账号额度烧干时,插件会自动切到下一个还有钱的账号,并让失败的那一步原地重跑——会话不断,上下文不丢,工具状态不动。

[account-switch] 账号额度用尽,已切到 acct-f6b06859(小号),本步将自动重跑

怎么做到的:官方 dsh-agent-loop 在模型请求失败后广播 agent/request-error,把「这次要不要重来」交给插件链决定——dsh-llm-retry 的退避重试就挂在这个点上。我们挂同一处,听到额度错误就换号,然后回一个 { kind: 'retry' },agent-loop 于是 continue 重跑这一步;而 resolveToken() 每次请求都重读 default,新账号的 token 自然生效。全程只用公开 seam,不改内核、不 patch 官方包。

认两个错误码,都由官方定义:ACCOUNT_QUOTA(账号侧专用)和 QUOTA(通用码,status === 402 或响应文本命中 insufficient balance / quota exceeded 一类措辞)。

冷却:按账号记时间戳。某个账号刚被判没钱,就会在 quotaChainResetMs(默认 5 分钟)内不再被选中——这同时解决两件事:所有账号都烧干时不会来回横跳(试完一轮就如实报错),以及充值之后过了冷却它又会自动回到候选里。

留痕在 $DSH_HOME/accounts/quota-switch.log,一行一条 JSON(切到谁、什么错、哪个会话的第几步)。换号是你看不见的副作用,不留痕的话事后查「账号怎么自己变了」会毫无头绪。

配置(cordis.patch.yml 的 dsh-account-switch 行里):

- id: dsh-account-switch
  config:
    autoSwitchOnQuota: true     # 关掉它就回到「额度烧干即中断」的官方行为
    quotaChainResetMs: 300000   # 单个账号的冷却时长

添加账号:弹窗,而不是一点就跳浏览器

点击「添加账号」弹出一个对话框,三个按钮:复制链接 / 打开浏览器 / 取消。

链接只能由宿主向平台申请(PKCE 挑战、state、本地回调地址都在宿主侧),没有第二条路凭空造一条链接,所以两个按钮都会调同一个 startSignIn;区别只在拿到链接之后——一个进剪贴板,一个显式 window.open 交给系统浏览器。

但 Desktop 外壳有一段常驻 watch,授权链接一出现就直接 shell.openExternal(app/lib/main.js 里对账号状态的订阅:无条件、无开关、随进程存活)。那段代码不在插件里,插件层拦不住它。所以这套交互要真正成立,得给外壳加一个 21 字节的补丁:

- if (attempt?.phase === "waiting-browser" && attempt.authorizeUrl !== void 0 && openedAttempt !== attempt.id) {
+ if (attempt?.phase === "waiting-browser" && attempt.authorizeUrl !== void 0 && openedAttempt !== attempt.id && !enteredWorkspace) {

enteredWorkspace 是同作用域里已有的变量(进工作区时置 true,退回 welcome 时复位),所以这个补丁不引入任何新状态、不需要新 import;而且首次引导的体验原样保留——还没进工作区时,登录依然会自动打开浏览器。

装法(必须先关掉 Harness:归档被运行中的进程独占,替换会报「另一个进程正在使用此文件」):

powershell -NoProfile -File scripts/swap-desktop-asar.ps1
powershell -NoProfile -File scripts/swap-desktop-asar.ps1 -Revert   # 回滚

脚本会校验 SHA256、保留 app.asar.pre-autoswitch.bak、失败自动回滚。归档本身只长了 24 字节(21 字节补丁 + 对齐),其余 11470 个条目逐字节未动。

官方更新会换掉 asar,补丁随之失效——重打一次即可。

其它

dsh-account status                       # 状态与存储位置
dsh-account rename acct-af3bded5 工作号  # 改昵称
dsh-account remove 工作号                # 移除(活跃账号需要 --force)
dsh-account identify                     # 补全平台身份并合并重复记录
dsh-account list --json                  # 给脚本用

插件内使用

宿主侧暴露了 ctx.accountSwitch,任何插件都能调:

await ctx.accountSwitch.overview()        // { accounts, activeId, warnings, ... }
await ctx.accountSwitch.use('主号')       // 切换
await ctx.accountSwitch.park()            // 撤下当前
await ctx.accountSwitch.capture()         // 归档当前

验证

node --test                    # 36 项单元测试,全部在隔离 tmp 目录里跑
node scripts/drill.mjs <隔离 home> --i-know-this-writes-files

scripts/drill.mjs 是拿一份真格式的凭证库副本跑完整流程(归档 → 幂等 → 模拟登录第二个 → 切换 → 校验官方持有的部分逐字未动)。它默认拒绝在 $DSH_HOME 上运行——这类工具最容易犯的错就是把真人正在用的凭证库当演练场。

另有一项只在装配时做的验证:用内核自己那份 cordis / schemastery 加载插件,并让内核的 schemastery 实例去解析插件声明的 Config。这能一次性证伪「插件自带第二份 cordis、Service 基类跟宿主不是同一个」这类只在运行时才暴露的问题——.npmrc 里的 legacy-peer-deps=true 就是为了防它复发。


踩过的坑:目录联接会让包整个不被加载

一度把插件以 junction(New-Item -ItemType Junction)挂进 profile 的 node_modules,图的是改代码立即生效、不用同步。结果是:Harness 完全不加载它,连插件自己的 apply() 都不会被调用,全程没有任何报错——从外部看和「插件根本没装」一模一样。

定位靠三个对照探针,一次重启:

探针形态结果
probe-min-dir真实目录写出了留痕
probe-min-link目录联接什么都没写
完整插件目录联接什么都没写

三个包除了形态之外没有别的差别。改成真实目录后立刻正常。

先前读代码时判断 junction 应该没问题(canonicalPath 走 realpathSync、linkedProfileRoots 会扫符号链接),是实验推翻了它。所以现在一律用 scripts/sync-install.ps1 复制真实目录,改完代码重跑一次。


踩过的坑:export default 会让插件静默失效

第一版装上去之后什么都没发生——没有产物、没有报错、凭证库纹丝不动。

原因在 cordis-plugin-loader 的 unwrapExports():

unwrapExports(exports) {
    if (isNullable(exports)) return exports;
    exports = exports.default ?? exports;   // ← default 优先于 apply
    if (!exports.__esModule) return exports;
    return exports.default ?? exports;
}

当时插件同时导出了 apply 和 export default AccountSwitch。加载器取走了那个类并把它当插件实例化:super(ctx, 'accountSwitch') 照常注册服务、不报任何错,而 apply() 从头到尾没被调用。对照 dsh-proxy-boot——它只有 name + apply,所以一切正常。

所以这个插件不导出 default,也不导出静态 inject(静态 inject 会让插件在依赖不就绪时静默挂起,连「我到底有没有被加载」都无从判断)。credentials 的等待改成 apply 里显式 ctx.inject()。

为了下次不用靠推理:apply() 的第一件事是写 $DSH_HOME/accounts/load-probe.json。它存在就等于 apply 真的被 cordis 调用了;不存在就说明插件压根没进加载列表——这两种失败在外部表现上一模一样,留痕是唯一能一刀切开它们的东西。


已知边界

情况结果
官方 UI 点「退出登录」default 被删,槽位不受影响;但那次 revoke 会让该账号的 token 在服务端失效,切回去会 401
token 过期或被平台拒绝官方 rejectToken() 只清 default,槽位里的存档仍在(内容已失效,需要重新登录)
切换时目标槽位为空拒绝切换并保持原状——清掉 default 等于当场把登录弄丢
default 里是坏记录拒绝归档,只告警;坏记录交给官方处理,插件不替它做决定
有人在 Harness 之外改了凭证库下次 list 会点名报出「槽位存在但注册表没有对应条目」
并发写CLI 与 Harness 抢的是同一把锁(<file>.lock、wx 创建、内容为 pid,与官方 @deepseek-ai/dsh-atomic-write 约定一致)
账号库里只有一个账号自动换号无事可做,额度错误照常报出——它不会凭空造一个账号出来
所有账号都烧干一轮试完即收手,把原始错误如实交给官方;冷却期内不会重复切换,不会来回横跳
充值之后过了 quotaChainResetMs 冷却,那个账号自动回到候选里,不需要重启也不需要手工清状态

安全

.credentials.yaml 里是 token 明文,跟官方行为一致(官方就是这么存的),所以保护它的手段就是文件权限。

装之前值得知道的一件事:这个文件的 ACL 里可能有 CodexSandboxUsers: ReadAndExecute。也就是说跑在 Harness 沙箱里的任何进程都能直接读走里面的 token 和 API key。要收紧就把那条继承来的 ACE 摘掉。

本插件自己不额外复制秘密:registry.json 只有指纹,list --json 也不输出 token。

本仓库的忽略规则:.credentials.yaml、accounts/、registry.json、quota-switch.log、key_pool.json、*.token 等一律在 .gitignore 里。克隆下来放到你自己的机器上,账号池是你自己的,不会跟着仓库走。


License

MIT