分离宿主拦截与模型拒绝,供红队受控评测
29.4/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/11/2 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/wufeng0105/dsh-purge-desktop.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 6 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 228 处,展示前 107 条)
- 读取本地文件lib/redteam/index.js:78
if (!existsSync(paths.setupScript)) return { action: 'missing', path: target } - 读取本地文件lib/redteam/index.js:81
wanted = readFileSync(paths.setupScript, 'utf8') - 写入本地文件lib/redteam/index.js:86
mkdirSync(redteamDataDir(), { recursive: true }) - 读取本地文件lib/redteam/index.js:87
if (existsSync(target)) { - 读取本地文件lib/redteam/index.js:89
try { current = readFileSync(target, 'utf8') } catch { current = '' } - 写入本地文件lib/redteam/index.js:92
try { chmodSync(target, 0o755) } catch { } - 写入本地文件lib/redteam/index.js:95
writeFileSync(target, wanted, { encoding: 'utf8', mode: 0o755 }) - 写入本地文件lib/redteam/index.js:98
writeFileSync(target, wanted, { encoding: 'utf8', mode: 0o755 }) - 读取本地文件lib/redteam/index.js:168
if (!existsSync(home)) continue - 读取本地文件lib/redteam/index.js:182
if (!existsSync(paths.skills)) return { action: 'missing', path: targets[0], copied: 0 } - 写入本地文件lib/redteam/index.js:186
mkdirSync(target, { recursive: true }) - 写入本地文件lib/redteam/index.js:193
writeFileSync(dest, wanted) - 读取本地文件lib/redteam/store.js:47
const pkg = JSON.parse(readFileSync(new URL(rel, import.meta.url), 'utf8')) - 读取本地文件lib/redteam/ui.js:76
if (!existsSync(raw)) continue - 读取本地文件lib/redteam/ui.js:78
const md = readdirSync(real).filter((f) => f.endsWith('.md')) - 读取本地文件lib/redteam/ui.js:196
const left = existsSync(a) ? realpathSync(a) : resolve(a) - 读取本地文件lib/redteam/ui.js:197
const right = existsSync(b) ? realpathSync(b) : resolve(b) - 读取本地文件lib/redteam/ui.js:232
const cwd = typeof options.cwd === 'string' && options.cwd !== '' && existsSync(options.cwd) ? options.cwd : undefined - 执行外部命令来自配置/变量lib/redteam/ui.js:235
child = spawn(needsShim ? `${command}.cmd` : command, args, { - 执行外部命令固定命令lib/redteam/ui.js:261
execFileSync('taskkill', ['/T', '/F', '/PID', String(child.pid)], { - 读取本地文件lib/redteam/ui.js:384
return JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) - 写入本地文件lib/redteam/ui.js:709
mkdirSync(root, { recursive: true }) - 写入本地文件lib/redteam/ui.js:712
writeFileSync(scriptPath, restartScript(process.pid, port, command, rest, logPath, process.cwd()), { encoding: 'utf8', mode: 0o755 }) - 执行外部命令来自配置/变量lib/redteam/ui.js:713
const child = spawn(process.execPath, [scriptPath], { detached: true, stdio: 'ignore', windowsHide: true }) - 读取本地文件lib/redteam/tools.js:73
if (!pkg || !existsSync(pkg)) continue - 读取本地文件lib/redteam/tools.js:503
if (existsSync(envFile)) { - 读取本地文件lib/redteam/tools.js:523
if (existsSync(toolkit)) { - 读取本地文件lib/redteam/tools.js:532
const hasMarker = existsSync(markerFile) - 读取本地文件lib/redteam/tools.js:533
const hasSetupScript = existsSync(setupScript) - 读取本地文件lib/redteam/tools.js:538
const hasVps = existsSync(vpsKey) - 执行外部命令固定命令lib/core.js:492
execFileSync("schtasks", ["/Query", "/TN", "DSH Doctor Supervisor"], { - 执行外部命令固定命令lib/core.js:502
execFileSync("schtasks", ["/Delete", "/F", "/TN", "DSH Doctor Supervisor"], { - 执行外部命令来自配置/变量lib/core.js:4192
const child = spawn(cmd, args, { - 执行外部命令固定命令lib/skills.js:495
const result = spawnSync("tar", ["-tf", archivePath], { - 执行外部命令固定命令lib/skills.js:502
const unzip = spawnSync("unzip", ["-Z1", archivePath], { - 执行外部命令固定命令lib/skills.js:533
const result = spawnSync("tar", ["-xf", archivePath, "-C", dest], { - 执行外部命令固定命令lib/update.js:311
execFileSync("git", ["-C", dir, "rev-parse", "--is-inside-work-tree"], HIDDEN); - 执行外部命令固定命令lib/update.js:324
return execFileSync("git", ["-C", dir, "rev-parse", "HEAD"], HIDDEN).trim(); - 发起网络请求lib/update.js:469
const req = lib.request(parsed, { - 执行外部命令固定命令lib/update.js:904
const out = execFileSync( - 执行外部命令固定命令lib/update.js:928
return execFileSync("git", ["-C", dir, ...args], { - 执行外部命令来自配置/变量lib/update.js:1034
run = spawnSync(process.execPath, ["--expose-internals", cli], { - 读取本地文件lib/redteam/role-section.js:96
const id = safeEngagementId(readFileSync(join(root, 'current'), 'utf8')) - 读取本地文件lib/redteam/role-section.js:98
if (!existsSync(join(root, 'engagements', id, 'agents'))) return '' - 读取本地文件lib/redteam/role-section.js:110
if (!existsSync(path)) return '' - 读取本地文件lib/redteam/role-section.js:111
return readFileSync(path, 'utf8').trim() - 读取本地文件lib/drill-grant.js:16
if (!existsSync(file)) return { granted: false, path: file }; - 读取本地文件lib/drill-grant.js:18
const raw = JSON.parse(readFileSync(file, "utf8")); - 写入本地文件lib/drill-grant.js:31
mkdirSync(dirname(file), { recursive: true }); - 写入本地文件lib/drill-grant.js:34
writeFileSync(tmp, `${JSON.stringify({ granted: true, at }, null, 2)}\n`, "utf8"); - 读取本地文件lib/drill-grant.js:36
if (existsSync(file)) unlinkSync(file); - 删除本地文件lib/drill-grant.js:36
if (existsSync(file)) unlinkSync(file); - 写入本地文件lib/drill-grant.js:37
renameSync(tmp, file); - 删除本地文件lib/drill-grant.js:39
try { unlinkSync(tmp); } catch { } - 读取本地文件lib/drill-grant.js:48
if (!existsSync(file)) return false; - 删除本地文件lib/drill-grant.js:49
unlinkSync(file); - 读取本地文件lib/redteam/platform-config.js:88
if (!existsSync(file)) return Object.assign({}, base, { path: file, exists: false }) - 读取本地文件lib/redteam/platform-config.js:90
const raw = JSON.parse(readFileSync(file, 'utf8')) - 写入本地文件lib/redteam/platform-config.js:122
mkdirSync(dir, { recursive: true }) - 写入本地文件lib/redteam/platform-config.js:149
writeFileSync(file, JSON.stringify(next, null, 2), 'utf8') - 读取本地文件lib/redteam/platform-config.js:163
if (c.nucleiTemplatesDir && existsSync(c.nucleiTemplatesDir)) return resolve(c.nucleiTemplatesDir) - 读取本地文件lib/redteam/platform-config.js:188
if (!dir || !existsSync(dir)) return null - 读取本地文件lib/redteam/platform-config.js:192
if (existsSync(p)) { - 读取本地文件lib/redteam/platform-config.js:194
const st = statSync(p) - 读取本地文件lib/redteam/preset-composition.js:388
return readFileSync(join(dir, name), "utf8"); - 读取本地文件lib/redteam/store-core.js:182
if (!existsSync(path)) return undefined - 读取本地文件lib/redteam/store-core.js:184
for (const line of readFileSync(path, 'utf8').split('\n')) { - 写入本地文件lib/redteam/store-core.js:203
writeFileSync(path, lines.join('\n') + '\n', 'utf8') - 写入本地文件lib/redteam/store-core.js:948
mkdirSync(this.engagementsDir, { recursive: true }) - 读取本地文件lib/redteam/store-core.js:957
const raw = readFileSync(this.currentPath(), 'utf8').trim() - 读取本地文件lib/redteam/store-core.js:958
if (raw && existsSync(this.dbPathOf(raw))) return raw - 读取本地文件lib/redteam/store-core.js:966
if (!id || !existsSync(this.dbPathOf(id))) return false - 写入本地文件lib/redteam/store-core.js:967
mkdirSync(this.root, { recursive: true }) - 写入本地文件lib/redteam/store-core.js:968
writeFileSync(this.currentPath(), String(id), 'utf8') - 读取本地文件lib/redteam/store-core.js:987
if (!existsSync(this.dbPathOf(id))) { - 写入本地文件lib/redteam/store-core.js:989
mkdirSync(this.dirOf(id), { recursive: true }) - 写入本地文件lib/redteam/store-core.js:1014
mkdirSync(this.engagementsDir, { recursive: true }) - 发起网络请求lib/redteam/store-core.js:4019
const res = await fetch(s.url, { method: 'GET', redirect: 'manual', signal: controller.signal }) - 删除本地文件lib/redteam/store-core.js:4372
if (existsSync(p)) rmSync(p, { force: true }) - 删除本地文件递归lib/redteam/store-core.js:4867
rmSync(dir, { recursive: true, force: true }) - 读取本地文件lib/redteam/skill-availability.js:58
if (existsSync(expandSkillPath(raw, { ...env, DSH_HOME: home }))) return true - 读取本地文件lib/redteam/skill-availability.js:125
try { names = readdirSync(dir) } catch { continue } - 读取本地文件lib/redteam/skill-availability.js:132
try { content = readFileSync(filePath, 'utf8') } catch { content = '' } - 读取本地文件lib/redteam/skill-availability.js:167
try { entries = readdirSync(dir, { withFileTypes: true }) } catch { return [] } - 读取本地文件lib/redteam/skill-availability.js:183
if (seen.has(name) || !existsSync(filePath)) continue - 读取本地文件lib/redteam/skill-availability.js:185
try { content = readFileSync(filePath, 'utf8') } catch { continue } - 读取本地文件lib/redteam/settings.js:29
if (!existsSync(settingsPathOf(root))) return {} - 读取本地文件lib/redteam/settings.js:30
const parsed = JSON.parse(readFileSync(settingsPathOf(root), 'utf8')) - 写入本地文件lib/redteam/settings.js:38
mkdirSync(String(root || '.'), { recursive: true }) - 写入本地文件lib/redteam/settings.js:39
writeFileSync(settingsPathOf(root), JSON.stringify(next, null, 2) + '\n', 'utf8') - 执行外部命令固定命令lib/desktop.js:378
text = execFileSync("powershell.exe", ["-NoProfile", "-Command", REGISTRY_INSTALL_SCRIPT], { - 执行外部命令固定命令lib/desktop.js:483
text = execFileSync("powershell.exe", ["-NoProfile", "-Command", PROCESS_EXE_SCRIPT], { - 执行外部命令固定命令lib/desktop.js:542
text = execFileSync("powershell.exe", ["-NoProfile", "-Command", SHORTCUT_EXE_SCRIPT], { - 执行外部命令来自配置/变量lib/desktop.js:865
const child = spawn(process.execPath, [helper], { - 执行外部命令固定命令lib/desktop.js:1071
const child = spawn( - 执行外部命令固定命令lib/desktop.js:1097
const child = spawn("/bin/sh", [script, asar, exe, lock], { - 执行外部命令来自配置/变量lib/host/paths.js:69
return execFileSync(bin, args, HIDDEN_EXEC).trim(); - 执行外部命令来自配置/变量lib/zip-extract.js:106
execFileSync(file, args, { - 发起网络请求lib/redteam/client.js:572
const openDir = (kind) => fetch('/dsh-purge/open', { - 发起网络请求lib/redteam/client.js:578
const api = (req) => fetch('/redteam/api', { - 写入剪贴板lib/redteam/client.js:743
await navigator.clipboard.writeText(value) - 执行外部命令固定命令lib/restart-desktop.js:84
const out = execFileSync("tasklist", ["/FI", `IMAGENAME eq ${image}`, "/FO", "CSV", "/NH"], { - 执行外部命令固定命令lib/restart-desktop.js:108
return execFileSync("defaults", ["read", path.join(bundle, "Contents", "Info"), "CFBundleName"], { - 执行外部命令固定命令lib/restart-desktop.js:117
return execFileSync("plutil", ["-extract", "CFBundleName", "raw", infoPlist], { - 执行外部命令固定命令lib/restart-desktop.js:132
out = execFileSync("ps", ["-Ao", "pid=,command="], { - 执行外部命令固定命令lib/restart-desktop.js:169
out = execFileSync("ps", ["-Ao", "pid=,command="], { - 执行外部命令固定命令lib/restart-desktop.js:244
execFileSync(
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DeepSeek Harness 插件:把宿主拦截与模型拒绝分开,用可复算的方式改造官方桌面端(设置页五页签 + 演练台)
README
由 DeepSeek 最新模型翻译生成DeepSeek Harness 网络安全红队工具
v2.3.2 · 让所有模型都能破甲,不同模型可换不同提示词
中文 · English
装一次,之后不用再点任何按钮:补丁在宿主启动时自己应用,界面是宿主设置里新增的一节,加主区一个演练台。
这一页只回答三件事:怎么装、装完在哪看、怎么退回去。要改这个仓库,读 AGENTS.md 与 文档索引。
这是什么
装在官方 DeepSeek Harness 桌面端上的插件,用于网络安全红队评测。
Harness 不只是把问题交给模型:它还会在运行时改提示词、审批门、沙箱和会话格式。只看「模型答不答」,会把宿主拦截误当成模型拒绝。这个插件把两层分开——补丁把宿主那侧的拦截挪开或改写成可继续,模型那侧的回答才反映模型本身。用于受控评测,也用来看默认策略该不该收紧。
展开完整文档(README 剩余 1 节)
DeepSeek Harness 网络安全红队工具
v2.3.2 · 让所有模型都能破甲,不同模型可换不同提示词
中文 · English
装一次,之后不用再点任何按钮:补丁在宿主启动时自己应用,界面是宿主设置里新增的一节,加主区一个演练台。
这一页只回答三件事:怎么装、装完在哪看、怎么退回去。要改这个仓库,读 AGENTS.md 与 文档索引。
这是什么
装在官方 DeepSeek Harness 桌面端上的插件,用于网络安全红队评测。
Harness 不只是把问题交给模型:它还会在运行时改提示词、审批门、沙箱和会话格式。只看「模型答不答」,会把宿主拦截误当成模型拒绝。这个插件把两层分开——补丁把宿主那侧的拦截挪开或改写成可继续,模型那侧的回答才反映模型本身。用于受控评测,也用来看默认策略该不该收紧。
三块界面:
| 位置 | 是什么 |
| 设置页里的 dsh-purge 一节 | 五个页签,见下表 |
| 主区演练台 | 点侧栏图标后占满主区:授权后看资产、技能与本机环境 |
| 侧栏图标 | 入口本身;未授权时先给授权窗,不给空壳 |
设置页的五个页签:
| 页签 | 内容 |
| 状态 | 结论句、补丁计数、运行环境、需要时的「重启宿主」 |
| 补丁 | 按层展开的每一条及其状态与原因 |
| 配置 | 更新、提示词注入、服务器名单、Hooks 拦截、危险操作(还原 / 卸载) |
| 技能 | 随包技能与本地技能,就地编辑 |
| 诊断 | 审计轨、安装健康、三条日志轨的落点与保留代数 |
补丁 66 条,另有 26 个永久保留的 id 空洞(共 92 个 id 守恒)。插件只动本机已装好的官方 @deepseek-ai 包与本机配置:它不是公网扫描器,也不是打别人站点的套件,仓库里没有木马、没有对外攻击载荷。
怎么装
dsh plugin --profile desktop add . # 在本仓库根目录执行
然后完全退出桌面端(含托盘),再打开。补丁在启动时自动应用。
给别的机器装,先打 tarball 再拷过去:
npm pack # 产出 dsh-purge-<版本>.tgz
dsh plugin --profile desktop add ./dsh-purge-<版本>.tgz
环境要求:Node.js ≥22.13、dsh 0.2.1-rc.2。npm 上没有这个包,不要 pnpm add dsh-purge;也不要用 dsh:// 或任何公网一键安装链接。
装完在哪看
1. 设置左栏多出 dsh-purge 一节,页头「已生效」,页脚「上次应用」不是「从未」。
2. 侧栏出现演练台图标。
3. 聊天里 /purge status 打出的 DSH_HOME 是你正在跑的那一份。
页头显示「需重载」或「部分跳过」时,那一节里会写清是哪一条、为什么。显示「部分跳过」不影响其余补丁生效。
常用命令
dsh-purge --status | --apply | --revert | --unseal | --uninstall | --diagnose | --edit
/purge status | apply | revert | uninstall | edit | help
/rules list | use <id> | create <id> | delete <id> | reset | help
/skills list | import <压缩包或文件夹> | create <id> [说明] | delete <id> | help /rewind
界面里没有「应用」按钮(2.0.0 起就没有):装完自动应用,要重来时用上面的命令。输入框旁的「回退一次 / 回退上一轮」走官方 session.fork({ atSeq }):撤回那一轮,新会话接上之前的上下文,旧会话归档,那句话回到输入框。
极简 / PTC 与标准不一致时,通常是 preset 里的拦截句没洗净:/purge revert → /purge apply → 完全退出宿主再打开 → 新开一轮对话。只换 preset 不重应用,旧进程里的补丁不会更新。
还原、卸载、更新
- 还原:dsh-purge --revert。每个目标文件在应用前备份为 <文件>.dshpurge.bak,还原用备份覆盖回去并删除备份;prompt-inject.md 是你的文件,还原时保留。
- 卸载:设置节 → 页脚 →「卸载」,或 /purge uninstall。会先还原已应用的补丁,再删注入文件、规则库与插件本身,然后重启宿主。
- 更新:换掉本机副本 → dsh-purge --revert → dsh-purge --apply → 完全退出宿主再打开。重复应用是幂等的。
在线更新默认关闭:设置页的「检测更新」显示「本地版:不检查更新」,不发出任何网络请求,代码里没有硬编码远端仓库。要启用得显式给 DSH_PURGE_UPDATE_REPO=owner/name 或 package.json 的 dsh.updateSource。
适配范围
只支持官方桌面端,只支持 dsh 0.2.1-rc.2(package.json 的 dshTarget)。插件启动时读宿主 @deepseek-ai/dsh 的版本并比对:主次版本不同即拒绝应用,同 minor 内允许 rc 序号向上漂移;版本不对时显示原因,不会乱改文件。
dsh web 命令行宿主面自 1.0.0 起不再维护,那个配置档不再更新——迁移到桌面端即可,数据留在原处。
找不到安装树时按这个顺序找:DSH_HOME / DSH_BASE → dsh 启动器旁的 .dsh → npm prefix -g / npm root -g → 嵌套的 @deepseek-ai/dsh/node_modules/@deepseek-ai → ~/.dsh。都找不到就提示设置 DSH_BASE,不改文件。
运行时文件在 $DSH_HOME:prompt-inject.md、rules/、skills/、net-scope-allow.txt、redteam/、audit/。
自己的服务器
中国大陆、香港、澳门的地址默认禁止,只有事先登记的那一台可以例外——在对话里说「这是我的服务器」不会放行,密钥和密码也不会。
登记在配置页签的服务器名单里,每行一台:203.0.113.10(一个 IP)、my-vps.example.com(主机名,保存时它的解析结果也会放行)、alice@my-vps.example.com(账号只用来认出这种写法,不能证明机器属于你)。保存后写入 $DSH_HOME/net-scope-allow.txt;密钥、密码、网段与通配符会在保存时丢掉。
手动安装
命令行装不上、或 dsh 不在 PATH 时用这个。只改正在用的那个宿主对应的配置档。
四步,逐条照做
1. 找到真正在用的 $DSH_HOME:目录名是 .dsh(偶见 dsh-home),里面有 profiles/,且 profiles/desktop/package.json 的 "name" 是 dsh-profile-desktop。本机常有两份 .dsh,要认你实际启动的那一份。
2. 把插件放到 $DSH_HOME/plugins/dsh-purge(目录名与包名都必须是 dsh-purge,复制整个目录,不要只拷几个 .js)。
3. 只改 $DSH_HOME/profiles/desktop/package.json 两处(先备份):dependencies 加 "dsh-purge": "file:../../plugins/dsh-purge";dsh.profile.bundles 末尾追加 "dsh-purge"。原有依赖与 bundle 一个都不要删,"dsh-purge" 不要写两次。
4. 在 $DSH_HOME/profiles/desktop 里 pnpm install,成功标志是出现 node_modules/dsh-purge/package.json。然后完全退出桌面端再打开。
交给 AI 助手(只安装)
安装 DeepSeek Harness 插件 dsh-purge,只装到官方桌面端的配置档。不要全盘搜索,不要读或改其它文件,也不要重启应用。
dsh 不在 PATH 就告诉用户后停止。当前目录已是本仓库时用 .。配置档不存在就告诉用户先启动一次桌面端。npm 上没有这个包,不要 pnpm add dsh-purge。
dsh plugin --profile desktop add .
命令结束后提醒用户:完全退出桌面端再打开,补丁会在启动时自动应用;打开宿主设置里的 dsh-purge 一节确认状态。然后停止。
第三方材料:lib/redteam、presets/redteam、skills/redteam 的原始版本来自 Jueze-2019/dsh-redteam-mode,按 MIT 许可保留版权声明,见 docs/redteam-upstream-LICENSE。仓库其余部分为 MIT。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
wufeng0105/dsh-purge-desktop
分离宿主拦截与模型拒绝,供红队受控评测
相关插件 · UI / 主题
破甲增强版JeffKeeping/dsh-purge-plus
dsh-purge 的非官方分支fork:适配 DeepSeek Harness 0.2.1-rc.2、破甲内核…
★ 387已汉化DeepSeek 客户端
71.9
无代码业务系统平台nocobase/nocobase
NocoBase 是什么
★ 24,804已汉化DSH
71.8
1Panel 服务器面板1Panel-dev/1Panel
全球 250 万+ 自托管用户共同喜爱。
★ 37,344已汉化DSH
71.5
终端编码代理esengine/DeepSeek-Reasonix
· 指南 · ACP · 扩展开发 · 规格 · 官方网站 · Discord · QQ
★ 36,045已汉化DSH
71.2
工作状态行动态ccch1mneyyy/working-activity
作者:chimney@ccch1mneyyy。社区项目,非 DeepSeek 官方项目。
★ 664已汉化DSH
71.2
多模型配置管家farion1231/cc-switch
跨平台桌面一体化助手,支持 Claude Code、Codex、OpenCode、DeepSeek Harness 等工具,唯一官网 ccswitch.io
★ 151,202已汉化DSH
71.1
这是你的仓库?认领条目