WorkBuddy 工作空间管理(任务迁移 + 工作区重命名)
能力触发矩阵(用户需求 → 执行动作)
| 用户需求(自然语言) | 执行脚本 | 说明 |
|---|---|---|
| "把任务 XX 迁移/转移到 XX 空间" | migrate_task.py |
对话记录 + 产物迁移,先询问产物与目标位置 |
| "列出工作空间 XX 有哪些文件可迁移" | migrate_task.py --list-files |
列出源空间候选产物供用户选择 |
| "把工作空间 XX 重命名为 YY" | rename_workspace.py |
目录 + projects 镜像 + 数据库引用全量同步 |
| "把工作空间 XX 移动到 D 盘 / 其他路径" | rename_workspace.py |
跨盘移动(复制→校验→删源) |
| "工作空间 XX 改名会不会影响任务/数据?" | 读本 SKILL.md 解释 | 回答机制,不执行 |
> 说明:技能加载后由 AI 按本矩阵路由,无需用户记忆脚本命令;重命名/移动是高危操作,执行前必先 dry-run 预览并获用户确认。
触发场景
- 任务级迁移:用户想把某任务的对话记录/产物迁到另一个工作空间,或问"任务对话文件在哪""能不能直接复制到新任务"。
- 工作区重命名/移动:用户想给工作区文件夹改名(WorkBuddy 默认以日期命名,如
<日期>-<时间>格式)、或移动到另一个磁盘/路径。
关键机制(必须先理解,否则会失败)
- 任务对话文件:
~/.workbuddy/projects/<项目ID>/<会话UUID>.jsonl
- 项目 ID = 工作区路径转义:去盘符冒号、分隔符转-、盘符小写(C:\Users\<用户名>\Work\AI Chat→c-Users-<用户名>-Work-AI Chat)。
- jsonl 一行一事件:message / reasoning / function_call / function_call_result / file-history-snapshot / ai-title。 - 任务列表由
~/.workbuddy/workbuddy.db的 sessions 表驱动(按 cwd 分组显示在工作空间下)。只复制 jsonl 不注册 sessions 记录,重启后界面不显示!(踩坑点) workspaces表记录已知工作空间;edge-sync-mapping*.db仅云同步用,本地操作无需改。- jsonl 内
cwd字段为 JSON 转义后的文本(c:\\Users\\...),替换须匹配转义形式(脚本用json.dumps(path)[1:-1]生成)。 - 三阶段安全策略(两个能力通用):阶段1 复制 → 阶段2 校验(JSON 合法性 + 文件大小/sha256 + 替换完成度)→ 阶段3 删源(仅校验通过后)。默认"移动"语义删源,
--keep-source/不删源=复制语义。修改数据库前自动备份。
能力一:任务级迁移(migrate_task.py)
执行流程
- 前置确认(必须询问,禁止擅自假设):目标工作空间路径(界面左侧空间右键→打开文件夹可查磁盘路径);是否迁移产物(全部/指定/不迁移);产物放哪(新空间根目录 space / 任务文件夹 task)。
- 列出候选(供用户选择产物):
bash python migrate_task.py <源jsonl> <目标项目目录> <目标cwd> --list-files - 执行迁移:
bash python migrate_task.py <源jsonl> <目标项目目录> <目标cwd> <新标题> \ --files "产物A,产物B" --dest task --task-dir <任务文件夹名> \ [--copy-memory] [--verify|--no-verify] [--sha256] [--delete-source] [--dry-run] - 验证:目标项目目录 jsonl 文件名与 sessions 表 cwd 记录一一对应。
关键参数
--session-id <UUID>:断点续跑时传同一值,跳过已完成阶段(状态存<新UUID>.state.json)。--verify(默认开)/--no-verify:复制后校验;--sha256强校验。--delete-source:校验通过后删除源 jsonl(默认保留=副本语义)。--overwrite:产物目标已存在时强制覆盖;默认跳过已存在项(防误覆盖)。--copy-memory:复制源空间.workbuddy/memory/日志到目标空间。--files相对路径按源 cwd 解析;若 jsonl 无 cwd 字段,相对路径会报错引导改绝对路径。- 自动:新 UUID 生成、sessionId/cwd 替换、JSON 逐行校验、sessions 表 INSERT(复制源 user_id/model)、数据库备份、冲突检测(目标已存在同名 jsonl 则中止)。
能力二:工作区重命名/移动(rename_workspace.py)
执行流程
# 1) 先预览(必做)
python rename_workspace.py <旧路径> <新路径> --dry-run
# 2) 确认后执行(默认移动=校验后删源;--keep-source 则复制保留)
python rename_workspace.py <旧路径> <新路径> [--keep-source] [--sha256] [--dry-run]
三阶段做什么
| 阶段 | 内容 |
|---|---|
| 1 复制 | 工作区目录整体复制到新路径;projects 镜像目录(旧项目ID→新项目ID)复制,内部所有 jsonl 的 cwd 批量替换为新路径 |
| 2 校验 | 工作区文件数与大小比对(--sha256 抽样比对内容);镜像 jsonl 逐行 JSON 合法 + 无残留旧路径;数据库备份 |
| 3 删源 | 校验通过后删除旧工作区目录与旧镜像目录(--keep-source 保留) |
数据库同步
- sessions 表:
UPDATE cwd=新路径 WHERE cwd=旧路径(该工作区全部会话,含归档)。 - workspaces 表:存在则 UPDATE path,不存在则 INSERT(未注册路径仅移动目录并警告)。
- 断点恢复:状态存新镜像目录
.rename-state.json,重跑跳过已完成阶段(注意:状态文件写前确保目录存在)。
安全注意
- 高危操作:重命名/移动工作区会删除旧目录(默认移动语义)。执行前必须:
- 先 dry-run 预览;
- 确认旧路径确实是工作区(数据库有注册/有关联会话),无关联会话时脚本会警告;
- 校验失败时脚本中止且不删源。
- 项目 ID 碰撞检测:
path_to_project_id把路径中所有\、/、:替换为-,因此含连字符的路径(C:\a\b-c)与多级目录(C:\a\b\c)会映射到相同项目 ID。脚本已内置碰撞检测:新旧路径映射到同一 ID、或目标镜像已存在时拒绝执行,防止镜像目录/数据库被串写。 - 目标路径已存在 → 拒绝执行(不覆盖)。
- 跨盘移动(如 C→D)自动生效(copytree 跨盘安全);大目录建议
--sha256抽验。
执行后(两个能力通用,必做)
- 提示重启应用:所有迁移/重命名完成后,必须明确提醒用户:请完全退出 WorkBuddy 后重新打开(普通重启可能命中缓存),所作的更改才会生效。
- 保留源数据(副本语义):执行后默认保留原任务对话、原产物、原工作空间,不主动删除任何源文件。
- 验证后自行清理:提示用户重启后先检查新任务/新空间是否正常(新会话可打开、产物齐全、新空间出现在界面左侧),确认无误后由用户自行删除原任务/原空间(通过应用界面或手动删除目录均可)。AI 不代删,除非用户明确指示。
已踩坑与注意(通用性问题)
- jsonl 中 cwd 的存储规范(重要,实测):
- 盘符小写:
c:\Users\...(用户输入可能是C:\,必须以 jsonl 内实际值为准)。 - 中文/非 ASCII 路径以 Unicode 转义存储:中文路径会以
\uXXXX形式存储(原始字节中\u前缀会被转义为\\u)。 - 因此替换 cwd 时,先用
get_cwd_from_jsonl从镜像 jsonl 读取实际存储值作为匹配基准,新值用normalize_cwd_for_jsonl(小写盘符)生成;校验时精确匹配"cwd":"..."字段,不要整行包含匹配(对话内容里可能有旧路径,会误报)。 - 应用可能自行完成迁移:执行 rename 时若应用正在运行,它可能监听 projects 目录并自动完成复制/数据库同步,且默认保留源目录(复制语义)。脚本与应用的并发操作可能产生竞态,执行前先 dry-run,执行后务必核对数据库与镜像最终态。
- 应用运行时会监控 projects 目录并自动生成/清理临时副本(可能删除孤儿 jsonl),操作前备份、勿在同一目录反复复制。
- 对话内容里的历史路径(消息/推理/工具调用中的旧路径)不要替换——只替换
cwd字段。 - 源会话记录 id 被占用,不要 UPDATE 源记录 cwd,一律新建会话(migrate_task)或按路径批量 UPDATE(rename_workspace 只动 cwd 匹配行,安全)。
- 状态文件保存函数需
os.makedirs(dirname)防父目录缺失。 - 不同 WorkBuddy 版本存储可能不同(sessions.json vs workbuddy.db),执行前先探测数据库存在性。
- target_cwd 必须规范化:若直接使用用户传入的路径写入,会出现正斜杠/大写盘符(如
D:/Work/AI Chat),与现有会话(D:\Work\AI Chat)及 workspaces 表不一致,可能导致界面分组异常。修复方案:jsonl 内容用normalize_cwd_for_jsonl(小写盘符+反斜杠,与 rename_workspace.py 一致),sessions 表 INSERT 用normalize_cwd_for_db(反斜杠,与现有记录一致);产物复制路径仍用原始 target_cwd。执行迁移后务必核对三处一致:sessions.cwd / jsonl 内 cwd / workspaces.path。 - migrate_task.py 只注册 sessions,不注册 workspaces:迁移后必须手动向
workspaces表 INSERT 新空间路径(path, last_opened_at),否则界面左侧不显示新空间。此操作与脚本分开做,改库前先备份。 - bash 执行 Python 写路径字符串会被转义(Windows Git Bash 环境):在
bash -c "..."或 heredoc 中,Windows 路径的反斜杠会被 bash 转义成双斜杠写入数据库;-c双引号里\\也会被吞。对策:含 Windows 路径的 Python 代码一律写成 .py 脚本文件再执行,不要用 bash 内联传路径。 --files传目录时目标路径 = dest_base/task_dir/basename(rel):若产物在源 cwd 的子目录(如我的项目/),直接传--files 我的项目会在目标产生新空间\我的项目\我的项目两层嵌套。对策:传子目录列表--files "我的项目/00_方案,我的项目/01_数据,..." --task-dir "我的项目",目标结构即为新空间\我的项目\{子目录}。- 状态文件
.state.json是断点恢复机制的正常产物(jsonl_done/verify_done/db_done 均为 true 即完成),保留无碍,不必删除。
复用脚本(同目录)
migrate_task.py—— 任务级迁移(对话 + 产物 + memory)rename_workspace.py—— 工作区重命名/移动(目录 + 镜像 + 数据库)- 两者均内置:三阶段安全策略、dry-run、断点恢复、冲突检测、数据库自动备份、JSON 校验。