WorkBuddy 从 Windows 无损迁移到 Mac
这个技能解决什么
痛点:WorkBuddy 的历史任务、产物文件、文件树全部记录绝对路径。
从 Windows 拷到 macOS 后,目录结构根本不同(盘符 C:、反斜杠 \、
用户名目录差异),导致:
| 现象 | 真实原因 |
|---|---|
| 任务里的文档点不开 | 索引里的 uri 还是 file:///C:/Users/kixp/... |
| 任务列表/工作区列表空白 | 数据库 sessions.cwd / workspaces.path 全是 Windows 路径 |
| 文件树面板没内容 | file-tree-manifests 里的 path 找不到对应文件 |
| 历史会话点开是空的 | projects/ 目录名按 Windows cwd 命名,改了 cwd 就对不上 |
关键认知:这是 ENOENT(路径不存在),不是权限问题。
排查时先看日志里是 ENOENT 还是 EACCES——若是 ENOENT 且报错路径带
C:\Users\...,就是本技能要解决的问题,加权限没用。
路径分类:哪些必须改,哪些不用管
别把「历史对话里出现过 Windows 路径」当成「必须修」。真正影响使用的是
长期引用,过程路径改了没有任何收益,反而增加出错面积。
| 类别 | 典型位置 | 是否改写 | 理由 |
|---|---|---|---|
| 配置 / 定时任务 | workbuddy.db 的 automations.prompt、workspaces.path、sessions.cwd |
✅ 必改 | 每次运行/启动都会被解析,错了直接失败 |
| 文件调用地址 | storage(recentFiles/filePath)、artifact-index 的 uri、file-tree-manifests 的 path、media-index、unified-asset、assistant-display |
✅ 必改 | 点开产物、最近文件、文件树面板全靠它 |
| 会话结构 | projects/ 目录名 |
✅ 必改 | 目录名与 db 的 cwd 必须对得上,否则历史会话加载不出来 |
| 会话转录内容 | projects/**/*.jsonl 的正文、tasks/*.json 的 description |
❌ 默认跳过 | 只是历史对话原文,不会被再次当作路径解析(占残留总量绝大多数) |
| 审计/变更日志 | audit-log、changes-index、changes-detail、file-history |
❌ 默认跳过 | 同上,纯记录 |
| 代码快照 | artifact 里的 diff、脚本原文 | ❌ 一律不动 | 属于内容,改了反而破坏历史记录 |
对应参数:--scope=core(默认,按上表)/--scope=full(旧行为,连会话转录一起改)。
Windows 属性文件:.exe / .bat / .cmd / .ps1 / .dll / .msi 等在 Mac
上本来就无法运行,按策略去掉 Windows 后缀名即可(tool.exe → tool),
去掉后打不开属预期,无需进一步处理。用 winext 子命令,默认只列清单。
前置条件(必须严格按序)
① 在 Mac 上安装并启动一次 WorkBuddy → 生成 ~/.workbuddy 目录结构
② 完全退出 WorkBuddy → 释放索引与数据库的文件锁
③ 从 Windows 手工拷贝两个目录:
C:\Users\<你>\WorkBuddy → 拷贝到 Mac 的工作区目录
C:\Users\<你>\.workbuddy → 拷贝到 Mac 的 ~/.workbuddy(同名覆盖)
④ 运行本技能的脚本修复索引与数据库
⑤ 重新打开 WorkBuddy
为什么第①步不能省:WorkBuddy 首次启动会生成 workbuddy.db、
artifact-index/、projects/ 等目录结构。先启动再拷贝,才能保证
拷贝过来的文件覆盖到正确位置;反过来会出现"目录不存在、拷贝落空"。
为什么第②步不能省:运行中的 WorkBuddy 会缓存索引并持有数据库连接,
边跑边改会得到不一致的结果,甚至把改写覆盖回去。
执行清单
| # | 动作 | 命令 | 必检 |
|---|---|---|---|
| 1 | 诊断现状 | python3 scripts/wb_migrate.py doctor |
看是否有 Windows 路径残留 |
| 2 | 只读扫描 | python3 scripts/wb_migrate.py scan |
看影响面与缺失源文件归因 |
| 3 | 备份 | python3 scripts/wb_migrate.py backup |
确认备份路径已打印 |
| 4 | 试跑 | python3 scripts/wb_migrate.py migrate |
默认 dry-run,不写盘 |
| 5 | 正式执行 | python3 scripts/wb_migrate.py migrate --apply |
会自动备份;分阶段更稳,见下 |
| 6 | 校验 | python3 scripts/wb_migrate.py verify |
有悬空引用/混合路径时返回非 0 并列出 |
| 7 | Windows 属性文件 | python3 scripts/wb_migrate.py winext |
先看清单,再 --apply 去后缀 |
| 8 | 重启应用 | 完全退出后重新打开 WorkBuddy | 抽查 2-3 个旧任务 |
| 9 | 出问题回滚 | python3 scripts/wb_migrate.py restore --from <备份目录> |
回滚后需重启应用 |
分阶段执行(推荐,大数据量时更稳):
python3 scripts/wb_migrate.py migrate --apply --stage=projects # projects 目录 + JSONL(先做)
python3 scripts/wb_migrate.py migrate --apply --stage=index # 索引 + 文件树
python3 scripts/wb_migrate.py migrate --apply --stage=db # 数据库(最后做)
顺序很重要:projects 阶段要把 Windows 目录名改成 macOS 目录名,
需要知道「原始 Windows 路径」。db 阶段一旦先把 sessions.cwd 改掉,
原始信息就丢了。因此 --stage=all 会自动按
projects → index → db 执行。
即便如此,首次迁移时脚本也会把「原始 cwd 映射」写进
~/.workbuddy/.wbmigrate_state.json,任意顺序、任意次数重复执行都安全。
每阶段独立可重跑,中断后从下一阶段继续即可。
涉及删除的操作保护:清理悬空引用时,若单文件删除比例超过 50%
(--max-drop-ratio 可调),脚本会中止并报错,而不是删掉数据。
数据库里的会话/工作区清理同样受这条保护。
先跑 scan 核对影响面,确认无误后再用 --max-drop-ratio 0.9 放行。
文本目录始终处理:tasks / audit-log / changes-* / file-history
属于过程路径,默认(--scope=core)整段跳过;需要全文改写时显式传
--scope=full。这与早期版本「任何一次执行都一并改写」的行为不同——旧行为
会把十几万处历史对话原文也改一遍,收益为零。
用户怎么说(可直接复述)
我刚把 WorkBuddy 从 Windows 拷到 Mac,文件夹都拷过来了,
但历史任务里的文档点不开,能帮我修一下吗?
WorkBuddy 迁移到 Mac 后任务列表是空的,产物文件也不显示,
请帮我诊断并修复。
参数说明
--wb-dir PATH WorkBuddy 数据目录,默认 ~/.workbuddy
--win-user NAME Windows 用户名(自动探测失败时指定,如 kixp)
--ws-root PATH macOS 工作区根目录(自动探测失败时指定)
--map WIN=MAC 追加自定义映射,可重复指定
--stage STAGE projects / index / db / all,默认 all
--scope SCOPE core(默认,只改长期引用)/ full(连会话转录一起改)
--no-backup 跳过自动备份(不推荐,没有回滚点)
--max-drop-ratio N 涉及删除的比例上限,默认 0.5,超过则中止
--no-cleanup 只改路径、不删悬空条目(安全阀拦下时的替代方案)
winext 子命令参数:
--roots DIR... 扫描根目录,默认:数据目录 + 工作区根目录
--exts .exe ... 要去除的后缀,默认 exe/bat/cmd/ps1/dll/msi/com/scr/msu/lnk
--apply 真正重命名(默认只列清单)
自动探测规则:Windows 用户名从 workbuddy.db 的 sessions.cwd 提取;
macOS 工作区根目录在 ~/WorkBuddy、~/Documents/WorkBuddy、
~/Desktop/WorkBuddy 中选项目数最多的。
应避免的用法
| 不要这样 | 为什么 | 应该这样 |
|---|---|---|
| 用文本正则直接改 JSON 文件 | 路径里的 \ 会破坏 JSON 转义,文件直接损坏 |
必须 json.load → 递归改值 → json.dump |
用 uri[len("file:///"):] 取路径 |
丢掉前导斜杠,file:///Users/x 变成 Users/x,os.path.exists 全部 False → 有效文件被误删 |
用 urllib.parse.urlparse(uri).path |
| 不备份就直接改 | 误判时无法回滚,数据不可逆 | 先 backup,脚本也会自动备份 |
| 运行中改索引 | 应用缓存 + 文件锁,改写被覆盖 | 完全退出 WorkBuddy |
用 open(已有文件, "w") 写 .jsonl |
macOS 保护机制报 Operation not permitted |
写 .jsonl.bak 再 os.replace() 原子替换 |
在 ~/.workbuddy/projects/ 下新建 .jsonl |
安全层按扩展名检出 | 中转文件用非 .jsonl 后缀 |
对每个路径都 os.path.exists |
18MB 文件会卡死数分钟 | 结构化字段精确处理,散文用轻量前缀替换 |
只改 workbuddy.db 不改 projects/ 目录名 |
cwd 与目录名对不上,会话历史仍加载不出来 | 两者必须同步改 |
先跑 --stage=db 再跑 --stage=projects |
db 改写后原始 Windows 路径丢失,目录名反推会退回字符串猜测 | 用 --stage=all,它自动按 projects→index→db 排 |
手工改 projects/ 目录名 |
目录名里的 - 分不清是分隔符还是原字符(2026-05-12-task-1),会丢层级 |
用脚本,它从状态文件/db 的真实 cwd 反查 |
| 迁移后删掉状态文件 | 重复执行时无法恢复 Windows 用户名与原始 cwd 映射 | 保留 ~/.workbuddy/.wbmigrate_state.json |
忽略 verify 的非 0 退出码 |
悬空引用点开会失败 | 按提示处理,或用 --max-drop-ratio 显式放行 |
| 只替换前缀不换分隔符 | 会产出 /Users/vin/.workbuddy\plugins\cache\... 这种「Mac 前缀+反斜杠」混合路径,os.path.exists 全部 False(实测 storage 里 1774 条) |
整值路径必须走 normalize_mac_path(反斜杠统一转正斜杠) |
| 只认「盘符开头」的路径 | C:/Users/vin/...(盘符+Mac 结构)和 /Users/...\x(混合分隔符)都能穿透 WIN_PATH_RE |
单独扫混合形态(verify 第 6 项),apply() 里剥盘符 |
| 把历史对话里的路径当问题 | artifact 里的 diff、脚本原文(r"/Users/vin/Desktop\x")是内容不是引用,改了破坏历史 |
只处理路径型字段(PATH_FIELD_KEYS) |
常见问题速查
| 症状 | 原因 | 处理 |
|---|---|---|
| 改了但没生效 | WorkBuddy 没完全退出 | 完全退出(不是关窗口)后重开 |
PermissionError: Brokered file token |
沙箱检出了应用数据目录写入 | 在 WorkBuddy 终端里前台执行,或授权目录写入 |
Operation not permitted 写文件 |
macOS 保护机制 | 脚本已用原子写跳过;手动操作请改后缀中转 |
| 任务列表空了 | 清理过度,误删了有效条目 | 从备份恢复后用 verify 复查 |
| 文档仍打不开 | 源文件压根没拷过来 | 看 scan 的「缺失源文件归因」,把文件补到对应位置 |
verify 报 JSON 损坏 |
手改 JSON 时破坏转义 | restore --from <备份目录> 回滚,用脚本重做 |
| 迁移被「拒绝清理」拦下 | 删除比例超阈值,多半是路径映射有误 | 先 scan 核对;确认无误后 --max-drop-ratio 0.9 |
| 重复执行时报「无法探测 Windows 用户名」 | db 里已无 Windows 路径 | 脚本会自动从状态文件恢复;若状态文件丢失请手动加 --win-user |
| 迁移很慢 | 走了逐路径查文件系统的慢路径 | 用 --stage 分阶段,只处理必要的 |
verify 报「混合路径残留」 |
旧版工具只换前缀没换分隔符,或盘符+Mac 结构 | 跑 migrate --apply --stage=index,脚本会剥盘符/统一分隔符 |
能力边界
能做:
- 改写 artifact-index / file-tree-manifests / assistant-display 等索引里的路径
- 改写 workbuddy.db 的 workspaces.path / sessions.cwd / automations.prompt 等字段
- 改写 projects/**/*.jsonl 的 cwd 与工具参数里的路径(--scope=full)
- 重命名 projects/ 下按 Windows cwd 命名的目录
- 修复混合路径:盘符+Mac 结构(C:/Users/vin/...)、Mac 前缀+反斜杠(/Users/vin/a\b)
- 识别 Windows 属性文件并去掉 Windows 后缀名(winext)
- 清理指向已不存在文件的悬空 artifact 与文件树条目
不能做:
- 找回没拷过来的源文件(D 盘知识库、桌面文件等)——只能改路径,不能凭空造文件
- 把 .exe 变成可在 Mac 运行的程序 —— 去后缀只是让它不再像可执行文件
- 迁移 WorkBuddy 应用本体(.app 安装包)
- 迁移云端账号数据
- 恢复已被误删且没有备份的数据
失败兜底策略
- 任何阶段报错:先看
doctor的输出,确认数据目录路径是否正确 - 改坏了:用
python3 scripts/wb_migrate.py restore --from ~/.workbuddy-backup-<时间戳>/一键回滚
(回滚会同时清除迁移状态文件) - 不确定:先用
scan(只读)确认影响面,再决定是否--apply - 应用行为异常:先
verify,把输出贴给用户判断是否回滚
深入阅读索引
| 文档 | 内容 | 何时看 |
|---|---|---|
references/migration-guide.md |
完整操作手册、目录结构原理、映射表推导 | 需要理解原理或定制映射 |
references/pitfalls.md |
十个真实踩坑与根因(含本次事故复盘) | 遇到报错或想避免重犯 |
README.md |
方法论手册:为什么这样设计、完整案例 | 想深入理解或写自己的迁移脚本 |
目录结构
workbuddy-windows-to-mac/
├── SKILL.md 执行卡(本文件)
├── README.md 方法论手册(给人读)
├── scripts/
│ └── wb_migrate.py 迁移工具(doctor/scan/backup/migrate/restore/verify/winext)
├── tests/
│ ├── test_wb_migrate.py 单元测试(130 项)
│ └── verify_independent.py 独立验证器(端到端,51 项)
└── references/
├── migration-guide.md 完整操作手册与原理
└── pitfalls.md 踩坑实录