在 Windows 上免装 Node 直接运行 DSH 内核
30.3/100
综合分
5
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/27 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查未通过:仓库 package.json 标记 private,未发布到 npm,需从源码安装。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add chermye/dsh-desktop该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:需留意
是什么
dsh 原生插件 · security
装得上吗
实装验证未通过(dep_tree_unresolvable),装前请到仓库确认最近更新与 issue
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 67 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
⚠︎ 实装验证未通过(dep_tree_unresolvable · 2026/9/27) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装仓库 package.json 标记 private,未发布到 npm,需从源码安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-desktop @ 0.2.0
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖要求 ^0.1.1-rc.2 · 最新 0.2.1-rc.2 兼容
✓入口文件main/exports/bin 已声明
源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/20 04:29:50
🔴 安全扫描发现高危能力自动 · 静态分析源码
v2.7.0🔴 扫描:高危尚无人工评估
静态扫描发现安装期即执行代码,或命令参数由运行时变量拼接(参数来源无法静态判定,从严处理)。
安装时即执行脚本命令参数由运行时变量拼接读写/删除本地文件发起外部网络请求
查看扫描证据(共 94 处,展示前 94 条)
- 读取本地文件scripts/patch-picker-worker.mjs:61
const source = readFileSync(target, "utf8"); - 写入本地文件scripts/patch-picker-worker.mjs:85
writeFileSync(target, patched); - 读取本地文件scripts/patch-storage-json.mjs:251
const source = readFileSync(target, "utf8"); - 写入本地文件scripts/patch-storage-json.mjs:278
writeFileSync(target, patched); - 发起网络请求packages/carrier/lib/index.js:65
sharedFetch = conn !== void 0 ? conn.createSharedFetchHandler("/api", { fetch: (req) => apiFetch.fetch(req) }) : apiFetch; - 读取本地文件packages/carrier/lib/index.js:117
await send({ t: "bundle:ok", rid: frame.rid, source: readFileSync(path, "utf8") }); - 发起网络请求packages/carrier/lib/index.js:158
const resp = await apiFetch.fetch(new Request(`${LOOPBACK_BASE}/api/session.export?sessionId=${encodeURIComponent(sessionId)}`, { method: "GET" })); - 发起网络请求packages/carrier/lib/index.js:177
const resp = await sharedFetch.fetch(new Request(`${LOOPBACK_BASE}/api/respond`, { - 发起网络请求packages/carrier/lib/index.js:186
const resp = await sharedFetch.fetch(new Request(`${LOOPBACK_BASE}/api/${method}`, { - 读取本地文件scripts/build-installer.mjs:35
if (existsSync(sourceZip)) { - 读取本地文件scripts/build-installer.mjs:43
if (!existsSync(targetZip)) { - 写入本地文件scripts/build-installer.mjs:44
mkdirSync(targetDir, { recursive: true }); - 写入本地文件scripts/build-installer.mjs:45
copyFileSync(sourceZip, targetZip); - 执行外部命令来自配置/变量scripts/build-installer.mjs:50
const child = spawn(process.execPath, [cli, ...process.argv.slice(2)], { - 写入本地文件scripts/copy-static.mjs:25
mkdirSync(join(dist, "preload"), { recursive: true }); - 写入本地文件scripts/copy-static.mjs:26
mkdirSync(join(dist, "transport"), { recursive: true }); - 写入本地文件scripts/copy-static.mjs:27
mkdirSync(join(dist, "assets"), { recursive: true }); - 写入本地文件scripts/copy-static.mjs:29
copyFileSync(join(root, "src", "preload", "preload.cjs"), join(dist, "preload", "preload.cjs")); - 写入本地文件scripts/copy-static.mjs:30
copyFileSync(join(root, "src", "transport", "transport.js"), join(dist, "transport", "transport.js")); - 删除本地文件scripts/copy-static.mjs:36
rmSync(join(dist, "assets", "icon.png"), { force: true }); - 删除本地文件scripts/copy-static.mjs:37
rmSync(join(dist, "assets", "tray.png"), { force: true }); - 读取本地文件scripts/copy-static.mjs:39
const officialSvg = readFileSync(require.resolve("@deepseek-ai/dsh-web-frontend/dist/favicon.svg"), "utf8"); - 读取本地文件scripts/copy-static.mjs:62
const pngBytes = readFileSync(join(dist, "assets", "icon-light.png")); - 写入本地文件scripts/copy-static.mjs:76
writeFileSync(join(dist, "assets", "icon.ico"), Buffer.concat([icondir, entry, pngBytes])); - 执行外部命令来自配置/变量scripts/e2e-recovery.mjs:42
const child = spawn(exeToRun, [...baseArgs, `--remote-debugging-port=${PORT}`], { - 发起网络请求scripts/e2e-recovery.mjs:60
const resp = await fetch(`http://127.0.0.1:${PORT}/json/list`); - 执行外部命令固定命令scripts/e2e-recovery.mjs:136
const killer = spawn("taskkill", ["/PID", String(child.pid), "/T", "/F"], { stdio: "ignore" }); - 删除本地文件递归scripts/e2e-recovery.mjs:192
rmSync(home, { recursive: true, force: true }); - 删除本地文件递归scripts/e2e-recovery.mjs:193
rmSync(userData, { recursive: true, force: true }); - 执行外部命令来自配置/变量scripts/e2e-smoke.mjs:36
const child = spawn(exeToRun, args, { - 发起网络请求scripts/e2e-smoke.mjs:58
const resp = await fetch(`http://127.0.0.1:${PORT}/json/list`); - 写入本地文件scripts/e2e-smoke.mjs:283
writeFileSync(shotPath, Buffer.from(shot.data, "base64")); - 执行外部命令固定命令scripts/e2e-smoke.mjs:300
const killer = spawn("taskkill", ["/PID", String(child.pid), "/T", "/F"], { stdio: "ignore" }); - 删除本地文件递归scripts/e2e-smoke.mjs:310
if (home !== null) rmSync(home, { recursive: true, force: true }); - 删除本地文件递归scripts/e2e-smoke.mjs:311
rmSync(userData, { recursive: true, force: true }); - 读取本地文件scripts/repair-session-logs.mjs:30
if (!existsSync(root)) { - 读取本地文件scripts/repair-session-logs.mjs:36
if (!existsSync(corePath)) { - 执行外部命令来自配置/变量scripts/repro-kernel-spawn.mjs:9
const child = spawn(exe, [bin, "--profile", "desktop"], { - 写入本地文件scripts/repro-real-home.mjs:16
writeFileSync(stderrPath, ""); - 写入本地文件scripts/repro-real-home.mjs:17
writeFileSync(stdoutPath, ""); - 写入本地文件scripts/repro-real-home.mjs:18
const stderrLine = (line) => appendFileSync(stderrPath, `[stderr] ${line}\n`); - 写入本地文件scripts/repro-real-home.mjs:21
appendFileSync(stdoutPath, line + "\n"); - 执行外部命令来自配置/变量scripts/repro-real-home.mjs:28
const child = spawn(exe, [bin, "--profile", "desktop"], { - 写入本地文件scripts/repro-real-home.mjs:50
child.stdout.on("data", (chunk) => appendFileSync(stdoutPath, `[stdout] ${chunk.toString("hex")}`)); - 读取本地文件scripts/scan-all-session-logs.mjs:12
for (const entry of readdirSync(dir, { withFileTypes: true })) { - 读取本地文件scripts/scan-all-session-logs.mjs:47
const raw = readFileSync(file); - 读取本地文件scripts/scan-all-session-logs.mjs:79
const kb = (statSync(file).size / 1024).toFixed(0); - 写入本地文件scripts/setup-profile.mjs:32
mkdirSync(profileDir, { recursive: true }); - 读取本地文件scripts/setup-profile.mjs:35
if (!existsSync(manifestPath)) { - 写入本地文件scripts/setup-profile.mjs:36
writeFileSync(manifestPath, JSON.stringify({ dsh: { profile: { bundles: DESKTOP_BUNDLES } } }, null, 2) + "\n"); - 写入本地文件scripts/setup-profile.mjs:41
mkdirSync(fallbackDir, { recursive: true }); - 写入本地文件scripts/setup-profile.mjs:43
mkdirSync(dirname(link), { recursive: true }); - 读取本地文件scripts/setup-profile.mjs:45
if (!existsSync(link)) { - 执行外部命令来自配置/变量scripts/smoke-carrier.mjs:23
const child = spawn(process.execPath, [dshBin, "--profile", "desktop"], { - 删除本地文件递归scripts/smoke-carrier.mjs:190
rmSync(home, { recursive: true, force: true }); - 读取本地文件scripts/verify-repair.mjs:30
const raw = readFileSync(path); - 读取本地文件src/main/app-protocol.ts:106
const html = readFileSync(join(distDir, "index.html"), "utf8"); - 读取本地文件src/main/app-protocol.ts:125
return new Response(readFileSync(options.transportPath, "utf8"), { - 读取本地文件src/main/app-protocol.ts:147
const body = readFileSync(filePath); - 发起网络请求src/main/carrier-client.ts:66
const frame = (await this.request({ t: "rpc", method, payload }, timeoutMs)) as { result: { ok: boolean; value?: unknown; error?: unknown } }; - 发起网络请求src/main/carrier-client.ts:72
const frame = (await this.request({ t: "manifest" })) as { manifest: unknown }; - 发起网络请求src/main/carrier-client.ts:78
const frame = (await this.request({ t: "bundle", id })) as { source: string }; - 发起网络请求src/main/carrier-client.ts:85
const frame = (await this.request({ t: "ping", seq }, timeoutMs)) as { t: string; seq: number }; - 读取本地文件src/main/config.ts:20
const raw = JSON.parse(readFileSync(configPath(), "utf8")) as Partial<AppConfig>; - 写入本地文件src/main/config.ts:29
mkdirSync(app.getPath("userData"), { recursive: true }); - 写入本地文件src/main/config.ts:30
writeFileSync(configPath(), JSON.stringify(next, null, 2) + "\n"); - 写入本地文件src/main/log.ts:14
mkdirSync(dirname(logPath), { recursive: true }); - 写入本地文件src/main/log.ts:16
if (statSync(logPath).size > MAIN_LOG_MAX_BYTES) renameSync(logPath, `${logPath}.old`); - 读取本地文件src/main/log.ts:16
if (statSync(logPath).size > MAIN_LOG_MAX_BYTES) renameSync(logPath, `${logPath}.old`); - 写入本地文件src/main/log.ts:20
return createWriteStream(logPath, { flags: "a" }); - 读取本地文件src/main/profiles.ts:34
if (!existsSync(manifestPath)) { - 写入本地文件src/main/profiles.ts:35
mkdirSync(profileDir, { recursive: true }); - 写入本地文件src/main/profiles.ts:36
writeFileSync(manifestPath, JSON.stringify({ dsh: { profile: { bundles: DESKTOP_BUNDLES } } }, null, 2) + "\n"); - 写入本地文件src/main/profiles.ts:45
mkdirSync(fallbackDir, { recursive: true }); - 写入本地文件src/main/profiles.ts:48
mkdirSync(dirname(link), { recursive: true }); - 读取本地文件src/main/profiles.ts:50
if (!existsSync(link)) return false; - 删除本地文件src/main/profiles.ts:59
rmdirSync(link); - 删除本地文件src/main/profiles.ts:61
rmSync(link, { force: true }); - 读取本地文件src/main/profiles.ts:75
const manifest = JSON.parse(readFileSync(join(profileDir, "package.json"), "utf8")) as { - 读取本地文件src/main/profiles.ts:88
if (!existsSync(profilesDir)) return []; - 读取本地文件src/main/profiles.ts:89
const names = readdirSync(profilesDir, { withFileTypes: true }) - 写入本地文件src/main/server-manager.ts:141
mkdirSync(dirname(path), { recursive: true }); - 写入本地文件src/main/server-manager.ts:143
if (statSync(path).size > KERNEL_LOG_MAX_BYTES) renameSync(path, `${path}.old`); - 读取本地文件src/main/server-manager.ts:143
if (statSync(path).size > KERNEL_LOG_MAX_BYTES) renameSync(path, `${path}.old`); - 写入本地文件src/main/server-manager.ts:147
this.kernelLog = createWriteStream(path, { flags: "a" }); - 执行外部命令表达式求值src/main/server-manager.ts:163
private spawn(): Promise<void> { - 执行外部命令来自配置/变量src/main/server-manager.ts:168
const child = spawn(process.execPath, [dshBin, "--profile", this.profile], { - 读取本地文件src/main/session-repair.ts:120
const raw = readFileSync(path); - 读取本地文件src/main/session-repair.ts:270
const mtimeMs = statSync(path).mtimeMs; - 写入本地文件src/main/session-repair.ts:335
copyFileSync(path, backupPath); - 写入本地文件src/main/session-repair.ts:337
writeFileSync(tmpPath, serializeArtifact(path, scan.header, rows)); - 写入本地文件src/main/session-repair.ts:339
renameSync(tmpPath, path); - 删除本地文件src/main/session-repair.ts:341
rmSync(tmpPath, { force: true }); - 读取本地文件src/main/session-repair.ts:361
entries = readdirSync(dir, { withFileTypes: true });
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis-plugin-group@deepseek-ai/dsh@deepseek-ai/dsh-anonymous-user-id@deepseek-ai/dsh-atomic-write@deepseek-ai/dsh-authorization@deepseek-ai/dsh-bash-local@deepseek-ai/dsh-client-modules@deepseek-ai/dsh-code-runtime@deepseek-ai/dsh-compaction@deepseek-ai/dsh-fs@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-invariants给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 免装Node运行内核
README
由 DeepSeek 最新模型翻译生成dsh-desktop
Windows 桌面客户端,用于 DeepSeek Harness (DSH)。
- UI 复用官方 Web UI,零修改
- 完全自包含:捆绑 dsh 内核,用 Electron 自带的 Node(ELECTRON_RUN_AS_NODE=1)运行,不要求系统安装 Node/dsh
- 零端口:内核不监听任何地址(连 127.0.0.1 都没有),传输全部走私有 stdio 管道(帧协议),攻击面归零
- 菜单栏与托盘跟随「通用设置 → 语言」实时切换(中英双语)
- 托盘常驻、单实例、关闭到托盘、多 profile 切换
架构与协议详见 docs/design.md。
展开完整文档(README 剩余 1 节)
dsh-desktop Windows 桌面客户端,用于 DeepSeek Harness (DSH)。 - UI 复用官方 Web UI,零修改 - 完全自包含:捆绑 dsh 内核,用 Electron 自带的 Node(ELECTRON_RUN_AS_NODE=1)运行,不要求系统安装 Node/dsh - 零端口:内核不监听任何地址(连 127.0.0.1 都没有),传输全部走私有 stdio 管道(帧协议),攻击面归零 - 菜单栏与托盘跟随「通用设置 → 语言」实时切换(中英双语) - 托盘常驻、单实例、关闭到托盘、多 profile 切换 架构与协议详见 docs/design.md。 快速开始 npm install # 安装依赖(含 Electron 二进制;国内网络可在 .npmrc 配置镜像) npm run build # 编译主进程 + 复制静态资源 + 生成图标 npm start # 启动桌面应用 npm run smoke:carrier # 无 Electron 的内核冒烟测试(先跑它验证环境) npm run smoke:recovery # 内核崩溃/重启恢复能力 E2E("kernel not running" 回归) 首次启动会在 $DSH_HOME/profiles/(默认 ~/.dsh/profiles/)创建 desktop profile,并与你的 dsh CLI 共享会话、配置和凭据。 打包安装器 完整教程(含验证清单、踩坑记录、发版流程)见 docs/package/packaging-guide.md。 npm run pack # 免安装版:release/win-unpacked/(构建后可直接运行验证) npm run dist # NSIS 安装器:release/DSH-Desktop-Setup-.exe - 安装器为按用户安装(无需管理员),可选安装目录,带桌面/开始菜单快捷方式。 - 构建脚本 scripts/build-installer.mjs 已内置国内镜像(electron + electron-builder 二进制),无需手动设置环境变量。 - 注意:dsh 的一批运行时包在 npm 锁文件中被标记为 peer 依赖,electron-builder 的依赖收集器会跳过它们;因此这些包被显式声明为本应用的直接依赖(见 package.json 里 @deepseek-ai/dsh- 直依赖)。升级 dsh 版本后如遇内核启动报 Cannot find package,比对 node_modules/@deepseek-ai 与打包产物的包清单补齐。此外 sharp 是内核插件 @deepseek-ai/dsh-attachment-local 的硬依赖,build.files 不得排除它(详见 docs/package/packaging-guide.md 坑 5)。 - 应用未签名,首次运行安装器时 Windows SmartScreen 可能提示「更多信息 → 仍要运行」。 目录结构 src/ main/ Electron 主进程(TS) preload/preload.cjs 页面桥(contextBridge) transport/transport.js __DSH_TRANSPORT__ 注入脚本(官方传输缝隙) packages/carrier/ 内核侧插件 bundle(stdio carrier + 空壳 webServer) scripts/ 构建 / 冒烟 / profile 设置脚本 docs/design.md 设计规格 注意事项 - 依赖 pin 住 @deepseek-ai/dsh 版本;升级后先跑 npm run smoke:carrier 回归。 - 传输契约(上游缝 API)集中在 packages/carrier/lib 和 src/transport/transport.js 两处。 - 会话日志是单写者格式:桌面端与 dsh CLI 共享同一 $DSH_HOME 的会话日志,两个 dsh 进程同时打开同一会话并发送消息会互相覆写 seq,造成该会话日志损坏(corrupt session log: seq gap)。同一会话避免同时在 CLI 与桌面端操作;应用每次启动会自动扫描并修复损坏的会话日志(改写前留 .bak- 备份)。 - 手动修复/体检入口: node scripts/repair-session-logs.mjs # dry-run:只检测 node scripts/repair-session-logs.mjs --apply # 修复(自动备份,跳过 2 分钟内活跃写入的文件) node scripts/scan-all-session-logs.mjs "$env:USERPROFILE\.dsh\sessions" # 全量连续性体检
预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
chermye/dsh-desktop
在 Windows 上免装 Node 直接运行 DSH 内核
相关插件 · 安全 / 权限
智能体逆向工程morluto/rea
用智能体逆向工程任何东西,从应用行为到原生二进制。
★ 415,267已汉化DSH
73.3
智能体集群框架ruvnet/ruflo
面向 Claude Code 与 Codex 的智能体元基座meta-harness。
★ 80,414已汉化MCP
71.9
WorkBuddy 模型接入corrinehu/dsh-workbuddy-connect
2026 年 10 月 20 日起,WorkBuddy…
★ 1,604已汉化DSH
71.7
破甲一键通z91772524-ai/pojia-next
十五个 AI…
★ 967已汉化DSH
71.6
AI 代理虚拟终端strukto-ai/mirage
Mirage 是给 AI 智能体用的虚拟终端:一层 shell,统管数据、命令行和运行时。Unix…
★ 3,756已汉化DSH
70.8
Agent 操作层agentic-os-org/ANOLISA
ANOLISA(Agentic Nexus Operating Layer & Interface System Architecture)|智能体操作系统,带运行时、安全、可观测性,以及 Tokenless 响应压缩,降低 token 用量与成本。
★ 649已汉化DSH
70.7