搬迁 WorkBuddy 工作区文件夹(保留旧对话)v2
✨ 功能清单(这个技能能做什么)
- 文件夹搬迁:把项目/工作区文件夹从任意位置搬到新位置(换盘、移入云盘同步目录、调整目录层级),旧对话全部保留、照常打开
- 文件夹改名:不移动位置、仅重命名文件夹(如
项目旧名→项目新名),同样保证旧对话可用 - 批量处理:一次处理几十个文件夹(清单文件每行
旧路径|新路径),自动逐个修复 - 修复权威数据库:自动更新
workbuddy.db(SQLite)里的工作区路径workspaces.path和会话路径sessions.cwd——这是旧对话能打开的关键 - 修复全部缓存:对话记录(projects jsonl)、会话元数据(sessions json)、界面会话列表(app/sessions.json)、产物索引(artifact-index)全层修复
- 兼容所有路径写法:盘符大小写、单/双反斜杠、正斜杠全部自动识别,同风格替换不破坏数据格式
- 自动备份可回滚:改动前自动备份到
~/.workbuddy/_pathfix_backup_<日期>/,出问题随时恢复 - 数据安全校验:所有改动文件自动做 JSON/JSONL 合法性校验,非法即提示且不破坏原文件
- 归档目录自动整理:
projects/下的对话归档目录随新路径自动改名/合并 - 故障排查支持:内置"旧对话打不开"的排查思路与全盘残留扫描方法
背景原理(必须理解,4 层数据)
WorkBuddy 的对话/工作区数据不存放在项目文件夹内部,而是按"项目路径"归档在用户数据目录 ~/.workbuddy/,共 4 层:
| 层级 | 位置 | 内容 | 是否权威 |
|---|---|---|---|
| 1 | projects/<路径编码>/*.jsonl |
对话内容记录 | 缓存 |
| 2 | sessions/*.json |
会话元数据(cwd 字段) | 缓存 |
| 3 | app/sessions.json + artifact-index/*.json |
界面层会话列表/产物索引 | 缓存 |
| 4 | workbuddy.db(SQLite) |
会话/工作区权威索引(sessions.cwd、workspaces.path) |
权威 |
关键经验:
- workbuddy.db 是权威源。只修 jsonl/json 缓存没用——WorkBuddy 重启时会用 db 里的数据重建缓存,旧路径会"复发"。
- 路径编码规则:盘符小写、去冒号、反斜杠变横线。例:D:\360安全云盘同步版\临时桌面\workbuddy测试 → d-360安全云盘同步版-临时桌面-workbuddy测试。
- db 里的路径是小写盘符 + 单反斜杠(如 d:\...),jsonl/json 里可能是大小写盘符 × 单/双反斜杠 × 正斜杠的任意组合。
快速使用
单个文件夹
python move_workspace.py --old "旧路径" --new "新路径"
批量(很多个文件夹)
先建一个清单文件(UTF-8 编码,每行 旧路径|新路径,# 开头为注释):
# 批量迁移清单
D:\360安全云盘同步版\临时桌面\workbuddy测试|D:\360安全云盘同步版\workbuddy测试
D:\旧位置\项目A|D:\新位置\项目A
C:\项目B|D:\项目B
然后运行:
python move_workspace.py --batch "清单文件.txt"
注意:
- 文件夹本身要先移动到新位置(脚本只修 WorkBuddy 的记录,不搬文件夹)
- 执行后必须重启 WorkBuddy,界面才会从数据库读取新路径
- 脚本自带备份(~/.workbuddy/_pathfix_backup_<日期>/),出错可回滚
脚本做了什么
对每一组 (旧路径, 新路径):
1. 移动归档:projects/<旧编码> → projects/<新编码>(新编码已存在则合并,文件名冲突跳过并备份)
2. 修数据库:workbuddy.db 的 sessions.cwd、workspaces.path 等全部文本字段(先备份 db)
3. 修缓存:全盘扫描 projects jsonl / sessions json / app/sessions.json / artifact-index,替换旧路径引用
4. 同风格替换:每个旧路径变体(大小写盘符 × 单/双反斜杠 × 正斜杠)配同风格的替换值,保持 JSON 转义形式不被破坏
5. 校验:所有改动文件的 JSON/JSONL 合法性
运行环境:C:/Users/Administrator/.workbuddy/binaries/python/versions/3.13.12/python.exe(受管运行时)
注意事项
- 零删除原则(用户明确要求):脚本全程不删除任何数据——用户项目文件夹脚本从不动;WorkBuddy 内部旧归档也是移入备份区(
~/.workbuddy/_pathfix_backup_<日期>/projects_old/)而非删除。清理旧数据必须用户明确确认,且通过回收站方式(可恢复)。不要用单独的_trash_src.py之类的脚本自动删旧文件夹 - 必须修 workbuddy.db,否则重启后旧路径"复发"(本次实战教训:前 3 轮只修缓存全部被 db 重建覆盖)
- 必须重启 WorkBuddy 才生效(UI 从 db 读取)
- 若旧项目是"把文件夹从 A 移到 B",且 B 目录里已放好文件夹 → 直接跑脚本即可;不要用"目录联接(junction)"技巧替代(云盘同步目录内建 junction 有同步风险;C 盘工作区 junction 也可能被应用替换)
- Windows + Git Bash 的坑:heredoc / echo 管道把含反斜杠路径的 Python 代码传给 python.exe 时,反斜杠会被自动转成
/;命令行参数--old "D:\路径"在 Git Bash 里同样会被转成D:/路径。已修复:脚本在 process_one 内做参数归一化(/→\),直接传路径即可;若仍有极端情况,可参考路径硬编码进.py文件的做法(scripts/_run_move_once.py已移出技能目录,归档在C:\Users\Administrator\old_scripts\) - fix_db 的坑:
workbuddy.db中workspaces.last_opened_at等字段是整型,遍历全字段做old in val会TypeError: argument of type 'int' is not iterable。已修复:仅对isinstance(val, str)的字段做替换 - validate 的坑:脚本会顺带修复
.md/.html等备份文件,validate 阶段只应校验.json/.jsonl,否则这些文件会被误报"JSON 校验失败"(实际数据无损)。已修复 - junction 检测的坑:
os.path.isjunction()在本环境可能误报 False,判断目录是否为联接要用 ctypes 调GetFileAttributesW(attr & 0x400) - 删除目录建议用回收站:PowerShell
Add-Type会被安全策略拦截,用 ctypes 调shell32.SHFileOperationW(FO_DELETE | FOF_ALLOWUNDO)。注意pFrom必须以双 null 结尾('D:\\xxx\x00\x00',写成 .py 文件),否则返回错误码 2/124 不生效 - 源目录删除失败(共享冲突/句柄占用):若 360 云盘同步或 WorkBuddy 文件监听占用源目录句柄,回收站删除会失败(错误码 32),但内容往往已删空。此时
os.listdir为空即视为完成,残留空壳目录等重启 WorkBuddy 后手动删除即可,不影响搬迁结果
故障排查(旧对话打不开)
按顺序检查(均可用脚本内置功能处理):
1. workbuddy.db 的 sessions.cwd / workspaces.path 是否还有旧路径(SQL 查询或直接重跑脚本)
2. app/sessions.json(界面会话列表)是否还有旧路径
3. artifact-index/*.json(产物索引)是否还有旧路径
4. projects/<编码>/*.jsonl 对话内容是否还有旧路径(对话文字里出现旧路径字样不影响打开,无需处理)
5. 全盘 grep 旧路径的关键目录名 定位所有残留:grep -rl -a "旧目录名" ~/.workbuddy/(排除 logs/binaries/blobs/plugins)
6. 都清干净后重启 WorkBuddy
脚本参考
完整脚本见 scripts/move_workspace.py(本技能内,支持 --old/--new 单组与 --batch 批量)。