🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

WorkBuddy 迁移 dingguangyi0/dsh-plugin-migration-workbuddy

DeepSeek Harness
dingguangyi053 天前有提交已提供中文文档扫描:含敏感能力

把 WorkBuddy 会话记忆与自动化任务安全导入 DSH

29.5/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/16 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

该插件未发布到 npm,按作者文档从 GitHub 源安装即可(静态检查只覆盖 npm 路径,不代表插件不可用)。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dingguangyi0/dsh-plugin-migration-workbuddy
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · chat
装得上吗
作者未把包发布到 npm,只能用源码安装
插件本身没问题,是分发方式不同
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 53 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-plugin-migration-workbuddy(未发布到 npm,仅可源码安装)
✓Node 引擎要求 ^22.19.0 || >=24.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/9/22 05:57:48

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 31 处,展示前 26 条)
  • 删除本地文件
    src/atomic-file.ts:72
    const remove = options.remove ?? ((path: string): void => rmSync(path, { force: true }))
  • 删除本地文件
    src/atomic-file.ts:130
    const remove = options.remove ?? ((path: string): Promise<void> => rm(path, { force: true }))
  • 读取本地文件
    src/automation.ts:151
    if (!existsSync(path)) return []
  • 发起网络请求
    src/client/api.ts:12
    const response = await fetch(path, { ...init, headers: { accept: 'application/json', ...(init?.body ? { 'content-type': 'application/json' } : {}) } }
  • 读取本地文件
    src/converter.ts:109
    const raw = await readFile(path, 'utf8')
  • 读取本地文件
    src/mcp.ts:90
    try { parsed = parseJsonc(await readFile(path, 'utf8')) } catch { return { drafts: [], skippedSecrets: ['invalid-json'] } }
  • 读取本地文件
    src/memory.ts:13
    const raw = await readFile(path, 'utf8')
  • 读取本地文件
    src/probe.ts:87
    handle = await opendir(directory)
  • 读取本地文件
    src/probe.ts:97
    info = await lstat(child)
  • 读取本地文件
    src/probe.ts:119
    bytes = (await stat(path)).size
  • 读取本地文件
    src/probe.ts:137
    const input = createInterface({ input: createReadStream(path, { encoding: 'utf8' }), crlfDelay: Infinity })
  • 读取本地文件
    src/probe.ts:163
    const info = await lstat(memoryRoot)
  • 读取本地文件
    src/probe.ts:178
    const info = await stat(path)
  • 写入本地文件
    src/service.ts:49
    await mkdir(join(path, '..'), { recursive: true, mode: 0o700 })
  • 写入本地文件
    src/service.ts:51
    await writeFile(temp, JSON.stringify(value, null, 2), { encoding: 'utf8', mode: 0o600 })
  • 读取本地文件
    src/service.ts:123
    const parsed = JSON.parse(await readFile(path, 'utf8')) as Partial<Manifest>
  • 读取本地文件
    src/service.ts:139
    if (!existsSync(root)) return []
  • 读取本地文件
    src/service.ts:152
    try { entries = await readdir(directory, { withFileTypes: true }) } catch { return }
  • 读取本地文件
    src/service.ts:260
    if (metadata?.mode !== 'session' && workspacePath !== undefined && !existsSync(workspacePath)) {
  • 写入本地文件
    src/service.ts:383
    if (selection.sessions) await mkdir(sessionWorkspacePath, { recursive: true, mode: 0o700 })
  • 读取本地文件
    src/service.ts:445
    if (this.workspaceRegistry && workspacePath && existsSync(workspacePath)) {
  • 写入本地文件
    src/service.ts:475
    await mkdir(join(this.memoryPath, '..'), { recursive: true, mode: 0o700 })
  • 写入本地文件
    src/service.ts:476
    await writeFile(this.memoryPath, manifest.memories.map(item => JSON.stringify(item)).join('\n') + (manifest.memories.length ? '\n' : ''), { encoding:
  • 读取本地文件
    src/service.ts:503
    if (workspacePath !== undefined && !existsSync(workspacePath)) {
  • 写入本地文件
    src/service.ts:555
    await mkdir(join(this.memoryPath, '..'), { recursive: true, mode: 0o700 })
  • 读取本地文件
    src/workbuddy-db.ts:77
    if (!existsSync(path)) return emptyCatalog()
扫描于 2026/11/4(0 天前) · 范围 全包扫描(包内未声明入口) · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-ui-renderer@deepseek-ai/dsh-client-ui-settings@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-llm@deepseek-ai/dsh-scope@deepseek-ai/dsh-session@deepseek-ai/dsh-session-persistence@deepseek-ai/dsh-workspace@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 迁移会话与记忆
  • 导入MCP草稿
  • 迁移自动化任务

把 WorkBuddy 的会话、记忆、MCP 草稿和自动化任务迁移到 DSH,先预览,源端只读

README

由 DeepSeek 最新模型翻译生成
dsh-plugin-migration-workbuddy 把 WorkBuddy 的会话、记忆、MCP 配置与自动化任务迁移进 DSH。 插件开箱可用,在设置页提供 扫描 → 预览 → 明确确认 → 导入 → 审计清单 的完整闭环;打开页面只做本机只读扫描,不会复制、移动或修改任何 WorkBuddy 数据。 安装 本包自带 cordis.patch.yml,并通过 dsh.bundle.patch 声明自己是 profile bundle:dsh plugin add 会把它同时装成依赖和 profile 层,不需要手写组合行。 推荐:从 Release 的 tarball 安装(一条命令,无需构建授权) dsh plugin --profile add \ https://github.com/dingguangyi0/dsh-plugin-migration-workbuddy/releases/download/v0.1.0/dsh-plugin-migration-workbuddy-0.1.0.tgz tgz 里已经是构建好的 lib/,装完即用:实测一条命令、约 3 秒、退出码 0,不需要任何 allowBuilds 授权,版本也被 URL 锁死。
展开完整文档(README 剩余 1 节)
dsh-plugin-migration-workbuddy

把 WorkBuddy 的会话、记忆、MCP 配置与自动化任务迁移进 DSH。

插件开箱可用,在设置页提供 扫描 → 预览 → 明确确认 → 导入 → 审计清单 的完整闭环;打开页面只做本机只读扫描,不会复制、移动或修改任何 WorkBuddy 数据。

安装

本包自带 cordis.patch.yml,并通过 dsh.bundle.patch 声明自己是 profile bundle:dsh plugin add 会把它同时装成依赖和 profile 层,不需要手写组合行。

推荐:从 Release 的 tarball 安装(一条命令,无需构建授权)

dsh plugin --profile add \
https://github.com/dingguangyi0/dsh-plugin-migration-workbuddy/releases/download/v0.1.0/dsh-plugin-migration-workbuddy-0.1.0.tgz

tgz 里已经是构建好的 lib/,装完即用:实测一条命令、约 3 秒、退出码 0,不需要任何 allowBuilds 授权,版本也被 URL 锁死。

从 GitHub 按 tag 安装(需要构建授权)

dsh plugin --profile add github:dingguangyi0/dsh-plugin-migration-workbuddy#v0.1.0

git 安装取的是源码而不是构建产物,所以本包提供 prepare 脚本,由 pnpm 在安装后自动从
src/ 构建出 lib/。pnpm ≥10 默认拒绝执行它:第一次 add 必定失败,并在错误里打印一条可直接复制的授权键。把 allowBuilds: 连同那条键写进该 profile 的 pnpm-workspace.yaml,再重跑同一条 add:

$DSH_HOME/profiles//pnpm-workspace.yaml
allowBuilds:
dsh-plugin-migration-workbuddy@https://codeload.github.com/dingguangyi0/dsh-plugin-migration-workbuddy/tar.gz/: true

实测两点坑:

- 必须用 pnpm 打印的那条完整键。只写包名 dsh-plugin-migration-workbuddy: true 不生效,还会继续报同一个错。
- 键里带解析出的 tarball 地址和 commit SHA,所以它顺带起了版本锁定的作用;如果哪次打印出来的键跟上一次不同(git 解析方式变了),用最新那条。

这条授权等于允许该包在安装时在你机器上执行代码(在任何沙箱之外)。只对你信任源码的包这么做,并固定到 tag 或 commit。

从本地检出安装

dsh plugin --profile add /绝对路径/dsh-plugin-migration-workbuddy

自己打 tarball / 发布到 registry

pnpm pack # 产出 dsh-plugin-migration-workbuddy-0.1.0.tgz(会自动跑 prepare,含 lib/)
dsh plugin --profile add ./dsh-plugin-migration-workbuddy-0.1.0.tgz

发布到 registry 之后(需先把 package.json 的 private 改为 false 并定许可证)
dsh plugin --profile add dsh-plugin-migration-workbuddy

关闭

在你自己的 $DSH_HOME/profiles//cordis.patch.yml 里按 id 覆盖即可:

- id: migration-workbuddy
disabled: true

装好后重启 DSH,设置页会出现「迁移与备份」。

配置

| 键 | 默认 | 说明 |
| enabled | true | 关闭后插件完全不扫描磁盘 |
| maxFileBytes | 10485760 | 单个源文件上限(1 KiB – 100 MiB) |
| maxFiles | 5000 | 单次扫描文件数上限 |
| toolMode | narrative | narrative 把工具调用/结果拍平为文本,导入历史不带工具协议、可无条件续聊;transcript 保留完整协议 |
| automationModelId | '' | 迁移的自动化规则写死的模型 id;空 = 用部署默认模型 |
| automationModelAllowlist | [] | 允许原样透传的模型 id;其余按 automationModelId 改写并记 automation-model-remapped |

源目录取 $WORKBUDDY_HOME,否则 ~/.workbuddy;目标取 $DSH_HOME,否则 ~/.dsh。

迁移内容

- 会话:JSONL 消息、推理、工具调用/结果转换为 DSH SessionEvent;按源文件 SHA-256 幂等,重复导入自动跳过,只有内容或元数据变化才替换。
工具调用同时写入模型可见的 assistant tool-call block 与审计事件;孤立调用/结果生成可继续对话的合成配对并记录降级原因;同一 callId 被源端重复写入时按 callId 去重(每 call 至多一个 tool-call block 与一条 tool/result),避免 Duplicate tool output。导入会话以 seed 前缀落盘(isSeeded + 精确 inheritedEventCount),运行时不会把导入历史重放为 live。
只读 workbuddy.db 的 sessions.is_playground 区分空间模式与会话模式:空间模式按记录里的权威 cwd 建立真实工作区;会话模式统一进入 $DSH_HOME/workspaces/session-mode(显示名 “会话模式”)。标题优先 custom_title/title 并写成合法的 session/title 事件,避免导入后退回首条消息当名字。
源端删除受尊重:sessions.deleted_at 非空的会话整体跳过,不再因为磁盘上还留着 .jsonl 而复活;工作区目录已不存在的会话同样跳过(已删除的工作区不重建),预览状态行显示「已排除 N 条」。
目录扫描本身不判断删除,判断来自 workbuddy.db。
- 按需导入:会话卡单击 = 快速全选/全不选可导入项,双击 = 进入精确选择。精确选择按「空间(工作区)× 会话」二级选择:左栏空间列表(组勾选、状态计数),右栏该空间会话明细(状态筛选、标题/路径搜索、逐条勾选、降级计数 tooltip);未分组会话仅可按条选择。
服务端 sessionKeys/workspaceIds 过滤在转换前执行,未知选择项计入审计 loss (unknown-selection-key),不影响其他导入。
- 记忆:解析 Markdown/JSON 候选,逐条去重后存入 $DSH_HOME/migration/memory/;不写 AGENTS.md,也不自动拼进全局 system prompt。
- MCP:只保留名称、URL、transport、command/args。token、cookie、API key、OAuth 与 credential 文件永不迁移,凭据需要在部署侧重新配置。
- 自动化任务:读 workbuddy.db 的 automations 表,RRULE 子集转 cron,支持按规则选择与 manifest 幂等;运行历史与运行时状态不迁移。模型改写见上表:源端模型词表(auto/fast-model/glm-/kimi- …)在别的部署上通常不存在,直接透传会让规则在运行时以「未知模型」失败。规则形状写契约要求的 target: { mode: 'new-session', workspaceId }。

自动化通道是可选的

规则落库通过部署注册的通道完成(服务名 automationImport;部分部署还会注册一个兼容通道名)。
没有通道也能用:预览照常列出自动化草稿,但标记为不可导入;显式导入时跳过并记 automation-channel-unavailable,不会让整批迁移失败。会话、记忆、MCP 不受影响。

安全边界

- 所有扫描只读;路由只接受 loopback + 同源 请求。
- 预览返回的路径经过 sanitizePathForPreview 脱敏,凭据类字段在解析阶段就被剔除。
- 附件、分支、原始 system prompt、旧版 SQLite 完整恢复尚未支持。DSH 没有通用物理删除接口,因此撤销语义是归档 + 清单审计。

开发

pnpm install
pnpm run build # tsdown(Host ESM + Client CJS) + tsc 声明
pnpm run typecheck
pnpm run test
pnpm run check # 三者串跑

产物在 lib/:Host 面 lib/index.js,Client 面 lib/client.js(window.__ModuleLoader__ 自注册,id = 包名)。

prepare 是安装时入口(pnpm 在 git 安装后自动调用),内容与 build 同一条链、只是不先清目录;它只用本包自己的 devDependencies,不依赖任何 monorepo 上下文,因此从 git 装也能构建成功。

说明

本包由一份早期的 WorkBuddy 迁移实现整理而来,并按独立插件重新命名与拆分:插件 id、设置项 id、文案与 CSS 前缀统一到本包自己的命名空间;路由为 /api/migration/workbuddy/*;目标 home 跟随 DSH 的 $DSH_HOME(默认 ~/.dsh);自动化规则落库从必需依赖改为可选通道(见上)。

许可证尚未确定(package.json 目前是 UNLICENSED + private: true);对外发布前需要先定许可证并把 private 改为 false。
预览分享卡片长什么样 ↓dingguangyi0/dsh-plugin-migration-workbuddy
分享 · DeepSeek Harness Hub
dingguangyi0/dsh-plugin-migration-workbuddy

把 WorkBuddy 会话记忆与自动化任务安全导入 DSH

这是你的仓库?认领条目

回到顶部