纪代插件远程管理器 NokorinNishikino/kidai-plugin-remote
DeepSeek Harness在 DSH 之外启停插件、隔离排障并回滚快照
30.2/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/18 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add NokorinNishikino/kidai-plugin-remote该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · market
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 52 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意未发布到 npm registry,仅可从源码安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包kidai-plugin-remote(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=20.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/7 10:40:43
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 206 处,展示前 108 条)
- 读取本地文件server.js:94
const parsed = JSON.parse(readFileSync(settingsPath(), "utf8")); - 写入本地文件server.js:112
mkdirSync(managerDataDir(), { recursive: true }); - 写入本地文件server.js:113
writeFileSync(settingsPath(), `${JSON.stringify(settings, null, 2)}\n`); - 写入本地文件server.js:166
mkdirSync(managerDataDir(), { recursive: true }); - 写入本地文件server.js:167
writeFileSync(launchReportPath(), `${JSON.stringify(report, null, 2)}\n`); - 读取本地文件server.js:175
return JSON.parse(readFileSync(launchReportPath(), "utf8")); - 写入本地文件server.js:186
mkdirSync(dir, { recursive: true }); - 写入本地文件server.js:187
writeFileSync(join(dir, "kidai-launch-notice.json"), `${JSON.stringify(notice, null, 2)}\n`); - 读取本地文件server.js:232
const marker = JSON.parse(readFileSync(isolationMarkerPath(home), "utf8")); - 读取本地文件server.js:292
if (!candidate.startsWith(publicRoot) || !existsSync(candidate) || !statSync(candidate).isFile()) { - 读取本地文件server.js:292
if (!candidate.startsWith(publicRoot) || !existsSync(candidate) || !statSync(candidate).isFile()) { - 读取本地文件server.js:297
const body = readFileSync(candidate); - 删除本地文件server.js:500
unlinkSync(launchReportPath()); - 删除本地文件server.js:638
unlinkSync(tmp); - 执行外部命令固定命令server.js:655
spawn("explorer.exe", [target], { detached: true, stdio: "ignore" }).unref(); - 执行外部命令来自配置/变量server.js:792
spawn(found, ["--app=" + url, "--window-size=1180,860"], { detached: true, stdio: "ignore" }).unref(); - 执行外部命令固定命令server.js:799
spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore", windowsHide: true }).unref(); - 读取本地文件lib/dsh-env.js:98
if (dir === "" || !existsSync(join(dir, DESKTOP_EXE_NAME))) return false; - 读取本地文件lib/dsh-env.js:100
existsSync(join(dir, "resources")) || - 读取本地文件lib/dsh-env.js:101
existsSync(join(dir, UNPACKED_REL)) || - 读取本地文件lib/dsh-env.js:102
existsSync(join(dir, DSH_CLI_BOOTSTRAP_REL)) - 执行外部命令固定命令lib/dsh-env.js:109
const output = execFileSync( - 读取本地文件lib/dsh-env.js:178
if (!existsSync(exe)) return undefined; - 读取本地文件lib/dsh-env.js:184
if (existsSync(bootstrap) || existsSync(join(install, "resources", "app.asar"))) { - 执行外部命令固定命令lib/dsh-env.js:497
const output = execFileSync( - 读取本地文件lib/profile.js:33
return JSON.parse(readFileSync(join(profileDir, "package.json"), "utf8").replace(/^ FEFF/, "")); - 读取本地文件lib/profile.js:54
if (existsSync(join(candidate, "package.json"))) return candidate; - 读取本地文件lib/profile.js:82
const parsed = JSON.parse(readFileSync(join(dir, "package.json"), "utf8").replace(/^ FEFF/, "")); - 读取本地文件lib/profile.js:118
if (asarPath === undefined || !existsSync(asarPath)) return undefined; - 读取本地文件lib/profile.js:153
return new Date(statSync(dir).birthtime).toISOString(); - 读取本地文件lib/conflicts.js:47
if (!existsSync(logsDir)) return []; - 读取本地文件lib/conflicts.js:48
const files = readdirSync(logsDir) - 读取本地文件lib/conflicts.js:50
.map((name) => ({ name, path: join(logsDir, name), mtime: statSync(join(logsDir, name)).mtimeMs })) - 读取本地文件lib/conflicts.js:54
const text = readFileSync(file.path, "utf8"); - 读取本地文件lib/conflicts.js:71
if (!existsSync(installRecoveryDir)) return findings; - 读取本地文件lib/conflicts.js:72
const entries = readdirSync(installRecoveryDir, { withFileTypes: true }); - 读取本地文件lib/patches.js:67
content = readFileSync(file, "utf8"); - 读取本地文件lib/patches.js:180
if (!existsSync(source)) return undefined; - 写入本地文件lib/patches.js:183
mkdirSync(targetDir, { recursive: true }); - 读取本地文件lib/patches.js:186
writeFileSync(target, readFileSync(source)); - 写入本地文件lib/patches.js:186
writeFileSync(target, readFileSync(source)); - 读取本地文件lib/patches.js:198
if (!existsSync(source)) return undefined; - 写入本地文件lib/patches.js:201
mkdirSync(targetDir, { recursive: true }); - 读取本地文件lib/patches.js:216
const entries = readdirSync(root, { withFileTypes: true }) - 读取本地文件lib/patches.js:219
.sort((a, b) => statSync(b).mtimeMs - statSync(a).mtimeMs); - 删除本地文件递归lib/patches.js:220
for (const old of entries.slice(keep)) rmSync(old, { recursive: true, force: true }); - 写入本地文件lib/patches.js:238
writeFileSync(String(path), readFileSync(snapshot)); - 写入本地文件lib/patches.js:286
writeFileSync(tmp, stringifyRows(doc)); - 写入本地文件lib/patches.js:287
renameSync(tmp, path); - 写入本地文件lib/launcher.js:47
mkdirSync(candidate, { recursive: true }); - 读取本地文件lib/launcher.js:67
if (envOverride && existsSync(envOverride)) { - 读取本地文件lib/launcher.js:80
if (env.desktopExe !== undefined && existsSync(env.desktopExe)) { - 执行外部命令来自配置/变量lib/launcher.js:93
const output = execFileSync(nodePath, ["--version"], { - 读取本地文件lib/launcher.js:116
return JSON.parse(readFileSync(runStatePath(), "utf8")); - 删除本地文件lib/launcher.js:126
rmSync(runStatePath(), { force: true }); - 写入本地文件lib/launcher.js:132
mkdirSync(managerDataDir(), { recursive: true }); - 写入本地文件lib/launcher.js:133
writeFileSync(runStatePath(), JSON.stringify(state, null, 2)); - 写入本地文件lib/launcher.js:154
mkdirSync(overlaysDir(), { recursive: true }); - 执行外部命令来自配置/变量lib/launcher.js:211
child = spawn(node.run, [...preArgs, ...command.args, ...args], { - 读取本地文件lib/launcher.js:341
const parsed = JSON.parse(readFileSync(statePath, "utf8")); - 读取本地文件lib/launcher.js:364
if (existsSync(env.crashEvidenceDir)) { - 读取本地文件lib/launcher.js:365
evidence.crashEvidence = readdirSync(env.crashEvidenceDir) - 写入本地文件lib/launcher.js:404
mkdirSync(join(pmPath, ".."), { recursive: true }); - 写入本地文件lib/launcher.js:405
writeFileSync(pmPath, JSON.stringify({ version: 1, profiles: others }, null, 2) + "\n"); - 删除本地文件lib/launcher.js:477
rmSync(markerPath, { force: true }); - 删除本地文件lib/launcher.js:502
rmSync(markerPath, { force: true }); - 执行外部命令来自配置/变量lib/launcher.js:539
const child = spawn(exe, [], { - 删除本地文件lib/launcher.js:764
rmSync(isolationMarkerPath(env.dshHome), { force: true }); - 执行外部命令固定命令lib/launcher.js:790
spawn("powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", script], { - 读取本地文件lib/plugin-mgmt.js:75
if (statSync(candidate).isFile()) return candidate; - 读取本地文件lib/plugin-mgmt.js:89
return statSync(candidate).isFile(); - 执行外部命令来自配置/变量lib/plugin-mgmt.js:129
child = spawn(command, args, { - 读取本地文件lib/plugin-mgmt.js:164
if (override && existsSync(override)) return { kind: "file", path: override, node: process.execPath }; - 读取本地文件lib/plugin-mgmt.js:168
if (packaged !== undefined && existsSync(packaged)) { - 读取本地文件lib/plugin-mgmt.js:223
if (!existsSync(manifestPath)) return; - 读取本地文件lib/plugin-mgmt.js:226
pkg = JSON.parse(readFileSync(manifestPath, "utf8")); - 删除本地文件递归lib/plugin-mgmt.js:331
rmSync(junctionPath, { recursive: true, force: true }); - 写入本地文件lib/plugin-mgmt.js:378
writeFileSync(path, `${JSON.stringify({ version: 1, profiles: others }, null, 2)}\n`); - 写入本地文件lib/plugin-mgmt.js:438
writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); - 删除本地文件递归lib/plugin-mgmt.js:532
rmSync(junctionPath, { recursive: true, force: true }); - 删除本地文件递归lib/plugin-mgmt.js:541
rmSync(target, { recursive: true, force: true }); - 写入本地文件lib/plugin-mgmt.js:626
writeFileSync(manifestPath, `${JSON.stringify(after, null, 2)}\n`); - 删除本地文件递归lib/plugin-mgmt.js:630
rmSync(join(profilesDir(env.dshHome), "node_modules", ...realName.split("/")), { recursive: true, force: true }); - 读取本地文件lib/snapshots.js:54
const parsed = JSON.parse(readFileSync(join(snapshotDir(home, id), "snapshot.json"), "utf8")); - 读取本地文件lib/snapshots.js:67
if (!existsSync(metaPath)) { - 读取本地文件lib/snapshots.js:71
const meta = JSON.parse(readFileSync(metaPath, "utf8")); - 写入本地文件lib/snapshots.js:75
writeFileSync(metaPath, `${JSON.stringify(meta, null, 2)}\n`); - 写入本地文件lib/snapshots.js:93
mkdirSync(dir, { recursive: true }); - 读取本地文件lib/snapshots.js:97
if (existsSync(manifestPath)) { - 写入本地文件lib/snapshots.js:98
copyFileSync(manifestPath, join(dir, "profile.package.json")); - 读取本地文件lib/snapshots.js:102
if (existsSync(homePatch)) { - 写入本地文件lib/snapshots.js:103
copyFileSync(homePatch, join(dir, "cordis.patch.yml.home")); - 读取本地文件lib/snapshots.js:107
if (existsSync(profilePatch)) { - 写入本地文件lib/snapshots.js:108
copyFileSync(profilePatch, join(dir, "cordis.patch.yml.profile")); - 写入本地文件lib/snapshots.js:113
copyFileSync(pm.path, join(dir, "plugin-management.json")); - 删除本地文件递归lib/snapshots.js:302
rmSync(target, { recursive: true, force: true }); - 读取本地文件lib/foreign-backups.js:43
if (existsSync(root)) { - 读取本地文件lib/foreign-backups.js:44
for (const entry of readdirSync(root, { withFileTypes: true })) { - 读取本地文件lib/foreign-backups.js:50
manifest = JSON.parse(readFileSync(manifestPath, "utf8")) ?? {}; - 读取本地文件lib/foreign-backups.js:57
createdAt = new Date(statSync(join(root, entry.name)).mtime).toISOString(); - 读取本地文件lib/foreign-backups.js:82
if (existsSync(root)) { - 读取本地文件lib/foreign-backups.js:83
for (const entry of readdirSync(root, { withFileTypes: true })) { - 写入本地文件lib/foreign-backups.js:168
copyFileSync(sourcePath, targetPath); - 发起网络请求public/app.js:116
const response = await fetch(path, options); - 写入剪贴板public/app.js:412
await navigator.clipboard.writeText(path); - 写入剪贴板public/app.js:747
navigator.clipboard?.writeText(text).then( - 发起网络请求public/app.js:1096
const response = await fetch(`/api/snapshots/import-zip?profile=${encodeURIComponent(state.profile)}&disableSuspected=${$("import-disable").checked ? - 发起网络请求public/app.js:1119
const response = await fetch(`/api/env-restore?profile=${encodeURIComponent(state.profile)}`, { method: "POST", body: file });
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 启停插件
- 隔离运行
- 回滚快照
KPR 纪代管理:DSH的外部管理器,启停插件、隔离运行、手动回滚、预检诊断、变砖救急!配合KSG(Kidai-snapshot-guard)使用,自动快照、备份回滚!
README
由 DeepSeek 最新模型翻译生成🛟 Kidai Plugin Remote · 纪代插件远程管理器
DSH 坏了也能用的插件管理器 —— 查看 · 启停 · 启动 · 隔离运行 · 快照 · 回滚
简体中文 · English
✨ 为什么用?
DeepSeek Harness(DSH)的插件生态越来越丰富,但启动失败往往来自插件本身:损坏的 bundle 列表、缺失的依赖、自引用 file:./node_modules/... 依赖……一旦 DSH 起不来,DSH 自己也救不了自己。Kidai Plugin Remote 就是为这种时刻准备的外部救援与日常管理工具——它在 DSH 之外运行,DSH 挂掉也能用。
- 🛟 先救援 —— 启动失败给出「退出码 + 日志 + 崩溃转储 + 冲突分析 + 修复提示」;一键回滚到最近良好快照,或隔离运行纯原生基线进行分析
- 📋 与纪代市场同源 —— 插件列表用与市场完全相同的方式组合(bundle 层 → profile 补丁 → home 补丁 → 桌面壳层),所见即 DSH 所载
- 🧊 隔离仅一次有效 —— 本次运行禁用全部第三方插件;退出自动恢复原配置,即使管理器被杀,内部守护也会在下次启动时恢复
- 💾 快照与回滚 —— 每次启动 / 配置变更保留一版待确认快照,下次成功运行转为「已验证」;离线回滚配置 + 第三方插件目录
展开完整文档(README 剩余 1 节)
🛟 Kidai Plugin Remote · 纪代插件远程管理器 DSH 坏了也能用的插件管理器 —— 查看 · 启停 · 启动 · 隔离运行 · 快照 · 回滚 简体中文 · English ✨ 为什么用? DeepSeek Harness(DSH)的插件生态越来越丰富,但启动失败往往来自插件本身:损坏的 bundle 列表、缺失的依赖、自引用 file:./node_modules/... 依赖……一旦 DSH 起不来,DSH 自己也救不了自己。Kidai Plugin Remote 就是为这种时刻准备的外部救援与日常管理工具——它在 DSH 之外运行,DSH 挂掉也能用。 - 🛟 先救援 —— 启动失败给出「退出码 + 日志 + 崩溃转储 + 冲突分析 + 修复提示」;一键回滚到最近良好快照,或隔离运行纯原生基线进行分析 - 📋 与纪代市场同源 —— 插件列表用与市场完全相同的方式组合(bundle 层 → profile 补丁 → home 补丁 → 桌面壳层),所见即 DSH 所载 - 🧊 隔离仅一次有效 —— 本次运行禁用全部第三方插件;退出自动恢复原配置,即使管理器被杀,内部守护也会在下次启动时恢复 - 💾 快照与回滚 —— 每次启动 / 配置变更保留一版待确认快照,下次成功运行转为「已验证」;离线回滚配置 + 第三方插件目录 - 🧩 插件管理 —— 孤儿扫描 / 装载 / 残留清理 / 卸载 + 入口校验(对齐市场 Hub 1.3.4) - 🎨 8 套主题 —— 暗色 / 浅色 / DS 蓝 / 灰绿 / 紫罗兰 / 青 / 珊瑚 / 玫瑰,服务器端记忆 - 🧲 四种启动方式 —— 正常 / 隔离 / 预检分析 / 失败报告;成功自动最小化 无需理解任何技术细节 —— 打开即用;开发者也能享受完整的组合诊断。 🚀 快速开始 方式 A — 零依赖桌面客户端(推荐分发) 使用配套仓库 kidai-plugin-remote-client 的 Kidai Plugin Remote Client.exe:下载解压、双击即用。不需要 Node、不需要浏览器。 方式 B — 经典启动 install.cmd # 一键安装:检查 Node、装入内部守护、创建桌面快捷方式启动 Kidai Plugin Remote.cmd # 直接启动(浏览器独立窗口) 源码直接跑: node server.js # 打开管理器 http://127.0.0.1:4877 node scripts/self-check.mjs # 只读自检(不启动 DSH、不改配置) 环境要求:本机 Node.js ≥ 20(不需要 DSH 本体)。 📖 使用指南 1. 启动管理器 —— 双击 启动 Kidai Plugin Remote.cmd(浏览器独立窗口),或用 Client 版 exe(原生窗口) 2. 查看插件 —— 「已安装插件」页:原生/第三方徽标、启停状态、版本、路径、安装时间;支持排序 / 筛选 / 宽窄视图 3. 启停插件 —— 行内开关切换:写入 $DSH_HOME/cordis.patch.yml(与市场同一套写入),重启 DSH 生效;DSH 运行中 HMR 即时生效 4. 启动 DSH —— 右侧「▶ 启动 DSH Desktop」;建议先「🔍 启动前预检分析」提前发现高危问题(未解析 bundle、补丁损坏、重复条目等) 5. 隔离运行 —— DSH 起不来时用「🧊 隔离运行」:本次启动禁用全部第三方插件,跑纯原生基线分析;退出自动恢复原配置 6. 快照与回滚 —— 每次启动/变更前自动留快照;出问题到「快照与回滚」页,选「已验证」快照一键回滚(配置 + 第三方插件目录),重启 DSH 即回到变更前 7. 故障报告 —— 启动失败自动弹出诊断报告:退出码、日志线索、冲突分析、每条附修复建议;也可「复制报告」保存 🔗 生态 | 仓库 | 职责 | 运行位置 | | kidai-plugin-remote(你在这里) | 查看 / 启停 / 启动 / 隔离 / 回滚 | DSH 之外(独立程序) | | kidai-plugin-remote-client | 同一管理器,原生窗口,零依赖 | DSH 之外(独立程序) | | kidai-snapshot-guard | 快照、待确认→已验证、隔离自动恢复 | DSH 内部(插件) | 三者共享同一个快照存储($DSH_HOME/.kidai-snapshots)与守护目录($DSH_HOME/guard/)——在任意一端给快照加备注,另一端都能看到。 📸 技术细节 - 读取 — $DSH_HOME → profile manifest dsh.profile.bundles → 双锚点解析(先 DSH 安装、后 profile)→ 按启动顺序应用补丁层(include 插件的精确算法, !!js 只解析不评估)→ 真实 loader 条目树。 - 写入 — 启停只写 home 级 cordis.patch.yml(与市场完全一致);隔离额外写桌面私有 plugin-management/state.json,退出或下次启动时自动还原。 - 启动 — spawn DSH Desktop.exe(自动发现或 DSH_DESKTOP_DIR);成功判定用桌面端自己的 health-commit;失败证据来自退出码、%APPDATA%\DSH Desktop\logs、 crash-evidence、profile-selection、plugin-install-recovery。 - CLI 校验 — dsh --dump-config 走桌面自带的 CLI 引导(resources\app.asar\lib\desktop-cli.js,用 ELECTRON_RUN_AS_NODE=1 以 DSH Desktop.exe --expose-internals 运行,零下载);仅当该引导缺失时才回退到系统 Node(≥ 22)跑 app.asar.unpacked 里的旧式 bin.js。 - Desktop 2.x 归档布局 — 安装识别只要求「可执行文件 + resources」,不再要求 app.asar.unpacked\package.json(2.x 不再提供);桌面自身的 cordis.patch.yml、以及归档内的核心 bundle(@deepseek-ai/dsh-base、@deepseek-ai/dsh-web-app …) 都由内置的 asar 读取器解析,因此不会再把「装在 app.asar 里」误报成依赖缺失。 - 运行态判定 — tasklist 被沙箱/权限拒绝时,改用单实例 lockfile 的独占占用探测(DSH Desktop 运行期间一直持有该文件;它的 mtime 只在启动时写一次,不能当新鲜度用)。 - 韧性 — 任何单个损坏的 bundle(manifest 损坏、目录缺失、补丁损坏)都会被跳过并报告,绝不致命:管理器、客户端、界面都能继续工作。 kidai-plugin-remote/ ├── server.js # HTTP + API(127.0.0.1:4877) ├── lib/ # dsh-env · patches · profile · inventory · conflicts · plugin-mgmt · snapshots · launcher ├── public/ # 单页 UI(无构建步骤)+ 8 套主题 ├── vendor/yaml/ # 内置 yaml 2.9.0(完全离线) ├── scripts/ # self-check · test-* · install-guard · install-shortcut · build-exe ├── install.cmd # 一键安装 ├── 启动 Kidai Plugin Remote.cmd └── build/ # exe 构建产物 📄 License MIT
预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
NokorinNishikino/kidai-plugin-remote
在 DSH 之外启停插件、隔离排障并回滚快照
相关插件 · 市场 / 管理
插件精选列表awesome-dsh-plugin/awesome-dsh-plugin
DeepSeek Harness(dsh)插件精选列表
★ 22,025未汉化DSH
73.6
新词雷达zhuyansen/new-term-radar
new-term-radar新词雷达
★ 2,049已汉化MCP
72.8
插件生态导航0xsline/awesome-deepseek-harness
安装 贡献指南 DeepSeek Docs 公开插件目录 Issues
★ 1,188已汉化DSH
72.6
技能注册中心iflytek/skillhub
企业级开源智能体技能注册中心——发布、发现并管理组织内可复用的技能包。
★ 5,358已汉化DSH
71.9
插件市场目录imsai-sh/awesome-deepseek-harness-plugins
面向 DeepSeek Harnessdsh生态的社区插件目录,共收录 13938 个插件含 PR 收录与…
★ 350已汉化DSH
71.8
插件精选清单Anil-matcha/awesome-dsh-plugin
DeepSeek Harnessdsh精选指南——DeepSeek…
★ 1,013已汉化DSH
71.7
这是你的仓库?认领条目