macOS 磁盘清理记录
macOS 磁盘清理与 AI Agent 会话恢复记录
记录一次完整的 macOS 磁盘清理过程,以及迁移 Desktop 后恢复 Claude Code、OpenCode、Codex 等 AI Agent 对话的经验。
时间:2026-07-04 / 2026-07-05
系统:macOS(Apple Silicon)
用户目录:/Users/username
目录
- 前言
- 初始磁盘概况
- 第一阶段:游戏A 残留清理
- 第二阶段:Library 孤儿应用数据扫描
- 第三阶段:删除确认的应用残留
- 第四阶段:Claude-3p 目录分析
- 第五阶段:Docker 空间清理
- 第六阶段:Logic Pro 音色库迁移
- 第七阶段:Desktop 目录迁移到外置硬盘
- 第八阶段:AI Agent 会话恢复
- 遇到的问题与解决方案
- 释放空间总结
- 后续可清理项
- 常用命令速查
前言
电脑内置硬盘空间告急,发现很多应用卸载后数据没有自动清理,再加上 Docker、AI 模型缓存、微信聊天记录等,占用了大量空间。本次清理目标是:
- 找出并删除已卸载应用的残留数据
- 清理 Docker 镜像和构建缓存
- 将大型数据(Logic Pro 音色库、Desktop)迁移到外置硬盘
- 整理开发/AI 缓存
- 修复 Desktop 迁移后 AI Agent(Claude Code、OpenCode、Codex)的会话恢复问题
初始磁盘概况
用户目录总计约 668 GB,主要分布:
| 位置 | 初始大小 |
|---|---|
~/Desktop | 198 GB |
~/Library | 133 GB |
~/Music | 73 GB |
~/Parallels | 49 GB |
~/Downloads | 43 GB |
~/.cache | 36 GB |
~/Documents | 23 GB |
~/Movies | 5.1 GB |
~/.Trash | 78 GB(后续产生) |
第一阶段:游戏A 残留清理
情况
卸载游戏A 后,游戏下载的资源仍残留在 Library 中,占用约 61 GB。
搜索命令
# 按名称搜索
mdfind -name "GameName"
mdfind -name "gamename"
mdfind "游戏A"
# 文件系统搜索
find ~ -maxdepth 5 \( -iname "*gamename*" -o -iname "*游戏A*" \) 2>/dev/null
发现
找到以下目录:
/Users/username/Library/Application Scripts/com.vendor.app3 (0 B)
/Users/username/Library/Containers/com.vendor.app3 (61 GB)
具体内容:
61G /Users/username/Library/Containers/com.vendor.app3/Data/Library/Client/Saved/Resources/3.4.0
11G /Users/username/Library/Containers/com.vendor.app3/Data/Library/Client/Saved/Resources/Video
清理命令
mkdir -p ~/.Trash
mv /Users/username/Library/Application\ Scripts/com.vendor.app3 ~/.Trash/
mv /Users/username/Library/Containers/com.vendor.app3 ~/.Trash/com.vendor.app3-Containers
采用移到废纸篓的方式,保留恢复余地。
第二阶段:Library 孤儿应用数据扫描
目标
扫描 ~/Library 中应用本体已不存在,但数据仍残留的 bundle-id 目录。
扫描脚本
#!/bin/bash
# 收集已安装应用的 bundle ID
installed_bundles=$(mktemp)
mdfind 'kMDItemContentType == "com.apple.application-bundle"' 2>/dev/null | while read app; do
[ -f "$app/Contents/Info.plist" ] || continue
id=$(defaults read "$app/Contents/Info.plist" CFBundleIdentifier 2>/dev/null)
[ -n "$id" ] && echo "$id"
done | sort -u > "$installed_bundles"
# 扫描常见 Library 位置
locations=(
"$HOME/Library/Application Support"
"$HOME/Library/Containers"
"$HOME/Library/Caches"
"$HOME/Library/Application Scripts"
"$HOME/Library/Logs"
"$HOME/Library/WebKit"
"$HOME/Library/Saved Application State"
"$HOME/Library/Preferences"
"$HOME/Library/HTTPStorages"
"$HOME/Library/Group Containers"
)
results=$(mktemp)
for loc in "${locations[@]}"; do
[ -d "$loc" ] || continue
find "$loc" -maxdepth 1 -mindepth 1 \( -type d -o -type f -name "*.plist" \) -print0 2>/dev/null | \
while IFS= read -r -d '' item; do
name=$(basename "$item")
base="${name%.plist}"
if echo "$base" | grep -Eq '^[A-Za-z][A-Za-z0-9_-]*(\.[A-Za-z][A-Za-z0-9_-]*)+$'; then
# 排除苹果系统组件
echo "$base" | grep -Eq '^com\.apple\.' && continue
if ! grep -Fxq "$base" "$installed_bundles"; then
size=$(du -sh "$item" 2>/dev/null | cut -f1)
printf "%s\t%s\n" "$size" "$item" >> "$results"
fi
fi
done
done
sort -hr "$results"
rm "$installed_bundles" "$results"
扫描结果(较大的几项)
| 路径 | 大小 | 说明 |
|---|---|---|
~/Library/Containers/com.vendor.app1 | 5.7 GB | 应用A |
~/Library/Application Support/AppShellData | 11 GB | 应用C 内嵌浏览器壳 |
~/Library/Application Support/project-a | 1.3 GB | project-a 桌面版 |
~/Library/Containers/com.vendor.app2 | 325 MB | 应用B 组件 |
~/Library/Application Support/com.vendor.app4 | 220 MB | Adobe 组件 |
~/Library/Containers/com.vendor.app5 | 147 MB | 品牌A 跨屏互联 |
~/Library/Application Support/com.vendor.app6 | 75 MB | 应用C 字体辅助 |
第三阶段:删除确认的应用残留
操作
将以下目录移到废纸篓:
mv /Users/username/Library/Containers/com.vendor.app1 ~/.Trash/
mv /Users/username/Library/Application\ Support/AppShellData ~/.Trash/
mv /Users/username/Library/Application\ Support/project-a ~/.Trash/
结果
| 项目 | 大小 |
|---|---|
| 游戏A | 61 GB |
| 应用A | 5.7 GB |
| AppShellData | 11 GB |
| project-a | 1.3 GB |
| 合计 | 79 GB |
第四阶段:Claude-3p 目录分析
发现
~/Library/Application Support/Claude-3p 占用 12 GB,是 npx 版 Claude Code 的数据目录。
主要内容
| 子目录/文件 | 大小 | 说明 |
|---|---|---|
vm_bundles/claudevm.bundle | 12 GB | Claude Code 虚拟机/隔离运行环境 |
claude-code-vm/x.x.xxx | 236 MB | VM 运行时 |
claude-code/x.x.xxx | 212 MB | CLI 运行时 |
Cache/Cache_Data | 94 MB | 应用缓存 |
IndexedDB、Local Storage、Cookies 等 | 较小 | 本地存储和登录状态 |
npx 版 Claude Code 数据分布
# 核心配置和历史
~/.claude (1.0 GB)
~/.claude.json (配置文件)
# VM + 缓存
~/Library/Application Support/Claude-3p (12 GB)
# npx 缓存
~/.npm/_npx (1.7 GB)
决定
因为正在使用 npx 版 Claude Code,删除 Claude-3p 后下次运行会重新下载 VM bundle,所以决定暂时保留,不处理。
第五阶段:Docker 空间清理
初始情况
Docker 占用约 46 GB,主要是容器镜像和 Build Cache。
docker system df
输出:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 9 12.3GB 4.623GB (37%)
Containers 9 9 2.753MB 0B (0%)
Local Volumes 7 0 587.7kB 587.7kB (100%)
Build Cache 856 0 38.55GB 12.77GB
清理命令
docker system prune -a
结果
实际回收了 42.51 GB 空间,超出预期。
第六阶段:Logic Pro 音色库迁移
情况
~/Music/Logic Pro Library.bundle 占用约 72 GB,考虑迁移到外置硬盘。
外置硬盘信息
df -h /Volumes/ExternalDrive
diskutil info /Volumes/ExternalDrive
结果:APFS 格式,3.7 TB 容量,2.0 TB 可用。
迁移方法
通过 Logic Pro 自带的声音资源库管理器:
- 打开 Logic Pro
- 菜单:Logic Pro > 声音资源库 > 打开声音资源库管理器
- 选择要迁移的内容,点击"重新定位..."
- 选择外置硬盘上的目标文件夹
注意事项
- 外置硬盘建议格式化为 APFS
- 建议使用 SSD,否则加载音色会有延迟
- 迁移完成后原
~/Music/Logic Pro Library.bundle会被释放 - 后续下载/更新内容包会自动写入外置硬盘
第七阶段:Desktop 目录迁移到外置硬盘
目标
将 ~/Desktop(198 GB)迁移到 /Volumes/ExternalDrive/Desktop,但保持 ~/Desktop 路径有效。
方案
使用符号链接(Symbolic Link):
- 实际文件存储在
/Volumes/ExternalDrive/Desktop ~/Desktop作为符号链接指向外置硬盘位置
完整操作流程
1. 检查外置硬盘格式和空间
df -h /Volumes/ExternalDrive
diskutil info /Volumes/ExternalDrive
2. 检查 iCloud 桌面同步状态
defaults read com.apple.finder FXICloudDriveDesktop
返回 0 表示未开启,不会冲突。
3. 复制数据
mkdir -p /Volumes/ExternalDrive/Desktop
rsync -avh --progress /Users/username/Desktop/ /Volumes/ExternalDrive/Desktop/
4. 验证复制完整性
du -sh /Users/username/Desktop
du -sh /Volumes/ExternalDrive/Desktop
# 检查差异
rsync -avn --delete /Users/username/Desktop/ /Volumes/ExternalDrive/Desktop/
5. 处理权限问题
两个 .msc 文件属于 root,普通用户无法读取:
sudo chown -R username:staff /Users/username/Desktop/ai_code/project-m
然后重新 rsync:
rsync -avh --progress /Users/username/Desktop/ /Volumes/ExternalDrive/Desktop/
6. 停止占用 Desktop 的进程
迁移前需要停止占用 Desktop 的进程:
# Docker
osascript -e 'quit app "Docker"'
killall -9 Docker "Docker Desktop" com.docker.backend com.docker.build
# 开发服务器
killall -9 codebase- node_repl python3.1
# 如果还有残留,按 PID 杀掉
lsof +D /Users/username/Desktop | awk 'NR>1 {print $2}' | sort -u | xargs kill -9
7. 移除 Desktop 的删除保护 ACL
如果 mv 报 Permission denied,检查 ACL:
ls -leO@ /Users/username/Desktop
发现 group:everyone deny delete,需要移除:
chmod -N /Users/username/Desktop
8. 创建符号链接
mv /Users/username/Desktop /Users/username/Desktop.bak
ln -s /Volumes/ExternalDrive/Desktop /Users/username/Desktop
9. 验证并重启 Finder
ls -la /Users/username/Desktop
readlink /Users/username/Desktop
killall Finder
结果
/Users/username/Desktop -> /Volumes/ExternalDrive/Desktop
迁移成功,原 Desktop 保留为 ~/Desktop.bak,确认稳定后可删除。
第八阶段:AI Agent 会话恢复
问题现象
Desktop 迁移到符号链接后,Claude Code、OpenCode、Codex 等 AI Agent 无法通过 /resume 或类似命令恢复之前的对话。
根本原因
这些 AI Agent 按绝对路径字符串识别项目和绑定会话:
- 迁移前项目路径:
/Users/username/Desktop/ai_code/project-x - 迁移后实际路径:
/Volumes/ExternalDrive/Desktop/ai_code/project-x
虽然符号链接让 ~/Desktop 仍然可访问,但 Agent 内部解析到的是真实外置硬盘路径。路径字符串变化后,Agent 就认为这是一个新项目,无法匹配历史会话。
8.1 Claude Code(npx 版)恢复
数据位置
~/.claude # 核心配置、历史、projects
~/.claude.json # 主配置文件
~/Library/Application Support/Claude-3p # VM bundle + 缓存
修复步骤
1. 停止 Claude Code 进程
killall -9 claude claude.exe python3.1
2. 备份配置文件
cp ~/.claude.json ~/.claude.json.backup.$(date +%s)
cp ~/.claude/history.jsonl ~/.claude/history.jsonl.backup.$(date +%s)
3. 替换配置文件中的路径
sed -i '' 's|/Users/username/Desktop/|/Volumes/ExternalDrive/Desktop/|g' ~/.claude.json
sed -i '' 's|/Users/username/Desktop/|/Volumes/ExternalDrive/Desktop/|g' ~/.claude/history.jsonl
4. 重命名 projects 目录
Claude Code 的 projects 缓存目录命名规则是把路径中的 / 替换为 -:
# 示例:把 Desktop 相关的旧路径文件夹全部重命名
find ~/.claude/projects -maxdepth 1 -type d -name "*-Users-username-Desktop-*" | while read dir; do
newdir=$(echo "$dir" | sed 's/-Users-username-Desktop-/-Volumes-ExternalDrive-Desktop-/')
if [ ! -e "$newdir" ]; then
mv "$dir" "$newdir"
fi
done
如果有冲突(新旧目录都已存在),保留包含历史数据的大目录,删除新生成的空目录:
# 示例:处理 project-x 冲突
mv ~/.claude/projects/-Volumes-ExternalDrive-Desktop-ai-code-project-x \
~/.claude/projects/-Volumes-ExternalDrive-Desktop-ai-code-project-x.new
mv ~/.claude/projects/-Users-username-Desktop-ai-code-project-x \
~/.claude/projects/-Volumes-ExternalDrive-Desktop-ai-code-project-x
rm -rf ~/.claude/projects/-Volumes-ExternalDrive-Desktop-ai-code-project-x.new
5. 测试恢复
cd /Volumes/ExternalDrive/Desktop/ai_code/project-x
npx claude-code
# 进入后尝试
/resume
8.2 OpenCode 恢复
数据位置
~/.config/opencode/opencode.json
~/.local/state/opencode/prompt-history.jsonl
~/.local/share/opencode/opencode.db # SQLite 主数据库
~/.local/share/opencode/opencode.db-wal # WAL 文件
~/.local/share/opencode/storage/ # 会话、消息、part 等 JSON
~/.local/share/opencode/snapshot/ # 项目 snapshot
~/.local/share/opencode/log/ # 日志
修复步骤
1. 停止 OpenCode
killall -9 opencode "OpenCode" "OpenCode Helper"
2. 备份
cp ~/.local/share/opencode/opencode.db ~/.local/share/opencode/opencode.db.backup.$(date +%s)
cp ~/.local/state/opencode/prompt-history.jsonl ~/.local/state/opencode/prompt-history.jsonl.backup.$(date +%s)
3. 合并 WAL 并替换数据库路径
sqlite3 ~/.local/share/opencode/opencode.db "PRAGMA wal_checkpoint(TRUNCATE);"
sqlite3 ~/.local/share/opencode/opencode.db << 'SQL'
UPDATE project SET worktree = REPLACE(worktree, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE worktree LIKE '%/Users/username/Desktop/%';
UPDATE project SET worktree = REPLACE(worktree, 'Users/username/Desktop/', 'Volumes/ExternalDrive/Desktop/') WHERE worktree LIKE '%Users/username/Desktop/%';
UPDATE session SET directory = REPLACE(directory, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE directory LIKE '%/Users/username/Desktop/%';
UPDATE session SET directory = REPLACE(directory, 'Users/username/Desktop/', 'Volumes/ExternalDrive/Desktop/') WHERE directory LIKE '%Users/username/Desktop/%';
UPDATE session SET path = REPLACE(path, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE path LIKE '%/Users/username/Desktop/%';
UPDATE session SET path = REPLACE(path, 'Users/username/Desktop/', 'Volumes/ExternalDrive/Desktop/') WHERE path LIKE '%Users/username/Desktop/%';
UPDATE workspace SET directory = REPLACE(directory, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE directory LIKE '%/Users/username/Desktop/%';
UPDATE workspace SET directory = REPLACE(directory, 'Users/username/Desktop/', 'Volumes/ExternalDrive/Desktop/') WHERE directory LIKE '%Users/username/Desktop/%';
UPDATE workspace SET extra = REPLACE(extra, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE extra LIKE '%/Users/username/Desktop/%';
UPDATE workspace SET extra = REPLACE(extra, 'Users/username/Desktop/', 'Volumes/ExternalDrive/Desktop/') WHERE extra LIKE '%Users/username/Desktop/%';
UPDATE message SET data = REPLACE(data, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE data LIKE '%/Users/username/Desktop/%';
UPDATE message SET data = REPLACE(data, 'Users/username/Desktop/', 'Volumes/ExternalDrive/Desktop/') WHERE data LIKE '%Users/username/Desktop/%';
UPDATE session_input SET prompt = REPLACE(prompt, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE prompt LIKE '%/Users/username/Desktop/%';
UPDATE session_input SET prompt = REPLACE(prompt, 'Users/username/Desktop/', 'Volumes/ExternalDrive/Desktop/') WHERE prompt LIKE '%Users/username/Desktop/%';
UPDATE part SET data = REPLACE(data, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE data LIKE '%/Users/username/Desktop/%';
UPDATE part SET data = REPLACE(data, 'Users/username/Desktop/', 'Volumes/ExternalDrive/Desktop/') WHERE data LIKE '%Users/username/Desktop/%';
UPDATE event SET data = REPLACE(data, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE data LIKE '%/Users/username/Desktop/%';
UPDATE event SET data = REPLACE(data, 'Users/username/Desktop/', 'Volumes/ExternalDrive/Desktop/') WHERE data LIKE '%Users/username/Desktop/%';
SQL
4. 处理 project_directory 表的 UNIQUE 冲突
如果 project_directory 表中同时存在旧路径和新路径,直接 UPDATE 会违反主键约束。需要先删除旧路径记录:
sqlite3 ~/.local/share/opencode/opencode.db "DELETE FROM project_directory WHERE directory LIKE '/Users/username/Desktop/%' OR directory LIKE 'Users/username/Desktop/%';"
5. 替换文本文件路径
chmod -R +w ~/.local/state/opencode ~/.local/share/opencode ~/.cache/opencode ~/.config/opencode
find ~/.local/state/opencode ~/.local/share/opencode ~/.cache/opencode ~/.config/opencode \
-type f ! -name "*.backup.*" \
\( -name "*.json" -o -name "*.jsonl" -o -name "*.log" -o -name "*.txt" \
-o -name "*.config" -o -name "alternates" -o -name "*.db-wal" \) \
-exec sed -i '' 's|/Users/username/Desktop/|/Volumes/ExternalDrive/Desktop/|g' {} +
6. 清理二进制残留
即使 SQL 查询无旧路径,SQLite 二进制文件中可能仍有残留字符串。执行 VACUUM 清理:
sqlite3 ~/.local/share/opencode/opencode.db "VACUUM;"
7. 测试恢复
cd /Volumes/ExternalDrive/Desktop/ai_code/project-x
opencode
# 尝试恢复对话
8.3 Codex 恢复
数据位置
~/.codex/.codex-global-state.json
~/.codex/session_index.jsonl
~/.codex/logs_2.sqlite
~/.codex/sqlite/logs_2.sqlite
~/.codex/sqlite/state_5.sqlite
~/.codex/state_5.sqlite
~/.codex/goals_1.sqlite
~/.codex/ambient-suggestions/
~/.codex/archived_sessions/
修复步骤
1. 停止 Codex.app
osascript -e 'quit app "Codex"'
killall -9 Codex "bare-modifier-monitor" "browser_crashpad_handler"
2. 备份
cp -R ~/.codex ~/.codex.backup.$(date +%s)
3. 替换文本文件路径
find ~/.codex -type f \
\( -name "*.json" -o -name "*.jsonl" -o -name "*.toml" -o -name "*.yaml" \
-o -name "*.yml" -o -name "*.log" -o -name "*.txt" -o -name "*.md" \) \
! -path "*/backups_state/*" ! -name "*.bak*" \
-exec sed -i '' 's|/Users/username/Desktop/|/Volumes/ExternalDrive/Desktop/|g' {} +
4. 替换 SQLite 数据库路径
# logs_2.sqlite
sqlite3 ~/.codex/logs_2.sqlite "UPDATE logs SET feedback_log_body = REPLACE(feedback_log_body, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE feedback_log_body LIKE '%/Users/username/Desktop/%';"
sqlite3 ~/.codex/sqlite/logs_2.sqlite "UPDATE logs SET feedback_log_body = REPLACE(feedback_log_body, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE feedback_log_body LIKE '%/Users/username/Desktop/%';"
# state_5.sqlite
sqlite3 ~/.codex/state_5.sqlite "UPDATE threads SET cwd = REPLACE(cwd, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE cwd LIKE '%/Users/username/Desktop/%';"
sqlite3 ~/.codex/state_5.sqlite "UPDATE threads SET title = REPLACE(title, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE title LIKE '%/Users/username/Desktop/%';"
sqlite3 ~/.codex/state_5.sqlite "UPDATE threads SET sandbox_policy = REPLACE(sandbox_policy, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE sandbox_policy LIKE '%/Users/username/Desktop/%';"
sqlite3 ~/.codex/state_5.sqlite "UPDATE threads SET first_user_message = REPLACE(first_user_message, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE first_user_message LIKE '%/Users/username/Desktop/%';"
sqlite3 ~/.codex/state_5.sqlite "UPDATE threads SET preview = REPLACE(preview, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE preview LIKE '%/Users/username/Desktop/%';"
# 对 ~/.codex/sqlite/state_5.sqlite 执行同样的更新
sqlite3 ~/.codex/sqlite/state_5.sqlite "UPDATE threads SET cwd = REPLACE(cwd, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE cwd LIKE '%/Users/username/Desktop/%';"
sqlite3 ~/.codex/sqlite/state_5.sqlite "UPDATE threads SET title = REPLACE(title, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE title LIKE '%/Users/username/Desktop/%';"
sqlite3 ~/.codex/sqlite/state_5.sqlite "UPDATE threads SET sandbox_policy = REPLACE(sandbox_policy, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE sandbox_policy LIKE '%/Users/username/Desktop/%';"
sqlite3 ~/.codex/sqlite/state_5.sqlite "UPDATE threads SET first_user_message = REPLACE(first_user_message, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE first_user_message LIKE '%/Users/username/Desktop/%';"
sqlite3 ~/.codex/sqlite/state_5.sqlite "UPDATE threads SET preview = REPLACE(preview, '/Users/username/Desktop/', '/Volumes/ExternalDrive/Desktop/') WHERE preview LIKE '%/Users/username/Desktop/%';"
5. 清理二进制残留
for db in ~/.codex/logs_2.sqlite ~/.codex/sqlite/logs_2.sqlite ~/.codex/sqlite/codex-dev.db ~/.codex/sqlite/state_5.sqlite ~/.codex/state_5.sqlite ~/.codex/goals_1.sqlite; do
[ -f "$db" ] && sqlite3 "$db" "VACUUM;"
done
6. 测试恢复
打开 Codex.app,或进入项目目录启动 Codex CLI,查看历史会话是否恢复。
8.4 通用恢复思路
任何按绝对路径管理项目的 AI Agent,在 Desktop 迁移后都可能遇到同样问题。通用恢复步骤:
- 找到 Agent 的数据目录:通常是
~/.agent-name/、~/.config/agent-name/、~/.local/share/agent-name/ - 停止 Agent 所有进程
- 备份数据
- 替换配置文件和日志中的旧路径
- 检查 SQLite 数据库:用
grep -rl或 SQL 查询找到包含旧路径的表和字段 - 重命名或合并 projects/sessions 缓存目录(如果 Agent 按路径编码目录名)
- 执行 VACUUM 清理 SQLite 二进制残留
- 重启 Agent 测试
遇到的问题与解决方案
问题 1:rsync 遇到 root 权限文件
现象:
rsync error: /Users/username/Desktop/ai_code/project-m/.../.msc: Permission denied
解决:
sudo chown -R username:staff /Users/username/Desktop/ai_code/project-m
问题 2:Docker 占用 Desktop 目录
现象: mv 无法重命名 Desktop。
解决: 停止 Docker Desktop 和相关容器。
osascript -e 'quit app "Docker"'
killall -9 Docker "Docker Desktop" com.docker.backend com.docker.build
问题 3:开发服务器占用 Desktop
现象: 停止 Docker 后仍有 node_repl、python3.1 等进程占用 Desktop。
解决: 杀掉相关进程。
killall -9 codebase- node_repl python3.1
# 或按 PID 强制终止
lsof +D /Users/username/Desktop | awk 'NR>1 {print $2}' | sort -u | xargs kill -9
问题 4:Desktop 目录有 ACL 删除保护
现象: mv: rename /Users/username/Desktop to /Users/username/Desktop.bak: Permission denied
检查:
ls -leO@ /Users/username/Desktop
# 输出:0: group:everyone deny delete
解决:
chmod -N /Users/username/Desktop
问题 5:AI Agent 无法恢复对话
现象: Desktop 迁移后 Claude Code / OpenCode / Codex 无法 /resume。
原因: Agent 按绝对路径字符串识别项目,路径从 /Users/username/Desktop/... 变为 /Volumes/ExternalDrive/Desktop/...。
解决: 见 第八阶段:AI Agent 会话恢复。
释放空间总结
| 操作 | 释放/迁移空间 |
|---|---|
| 游戏A 残留 → 废纸篓 | 61 GB |
| 应用A → 废纸篓 | 5.7 GB |
| AppShellData → 废纸篓 | 11 GB |
| project-a → 废纸篓 | 1.3 GB |
Docker system prune -a | 42.5 GB |
| Desktop 迁移到外置硬盘 | 198 GB |
| 合计 | 约 319 GB |
其中废纸篓和 Desktop 迁移释放的是内置硬盘空间;Desktop 数据本身仍在外置硬盘上保留。
后续可清理项
1. 清倒废纸篓
rm -rf ~/.Trash/*
可释放约 78 GB。
2. 微信聊天记录
微信占用 41 GB,其中聊天记录约 39 GB。可在微信设置 → 通用设置 → 存储空间中清理。
3. HuggingFace / ModelScope 模型缓存
# HuggingFace
~/.cache/huggingface (24 GB)
# ModelScope
~/.cache/modelscope (4.7 GB)
可用 huggingface-cli delete-cache 删除不用的模型。
4. 开发工具缓存
| 路径 | 大小 | 清理命令 |
|---|---|---|
~/.cache/uv | 4.0 GB | uv cache clean |
~/.rustup | 2.9 GB | 不开发 Rust 可删 |
~/.nuget | 2.2 GB | 不开发 .NET 可删 |
~/.bun | 1.5 GB | 不用 Bun 可删 |
~/.cargo | 1.3 GB | 不用 Rust 可删 |
~/.npm-global | 581 MB | 检查全局 npm 包 |
5. Codex / Hermes / Superpowers 缓存
~/.codex (2.6 GB) # 可清理 sessions、archived_sessions、generated_images
~/.hermes (3.1 GB) # Hermes agent 数据
~/.config/superpowers (5.9 GB) # project-a 工作树
6. 不用的 ai_code 项目
~/Desktop/ai_code 共 136 GB,单个项目占用:
| 项目 | 大小 |
|---|---|
| project-g | 28 GB |
| project-h | 21 GB |
| project-i | 16 GB |
| project-j | 15 GB |
| project-b | 12 GB |
| project-a | 11 GB |
7. Parallels 虚拟机
~/Parallels/MyVM.pvm (49 GB)
如不用 Windows 可删除。
8. Downloads 安装包
~/Downloads/installer.zip (7.4 GB)
~/Downloads/installer.dmg (7.5 GB)
安装完成后可删除。
常用命令速查
# 查看目录大小
du -sh /path/to/dir
# 查看当前目录下所有子目录大小
du -sh * | sort -hr
# 查找大文件
find ~ -type f -size +100M -exec ls -lh {} + | sort -k5 -hr
# 查找占用目录的进程
lsof +D /path/to/dir
# 查看 ACL
ls -leO@ /path/to/file
# 移除所有 ACL
chmod -N /path/to/file
# 创建符号链接
ln -s /path/to/target /path/to/link
# Docker 清理
docker system prune -a
# 查看 Docker 空间使用
docker system df
# SQLite WAL checkpoint
sqlite3 db.sqlite "PRAGMA wal_checkpoint(TRUNCATE);"
# SQLite VACUUM
sqlite3 db.sqlite "VACUUM;"
# 清倒废纸篓
rm -rf ~/.Trash/*
# 查看磁盘使用
df -h /
# 查看外置硬盘信息
diskutil info /Volumes/ExternalDrive
注意事项
- 移到废纸篓后记得清空,否则空间不会真正释放。
- 符号链接迁移 Desktop 后,外置硬盘必须保持挂载,否则桌面会显示为空。
- 清理 Docker 前确认没有需要保留的容器或镜像。
- 迁移 Logic Pro 音色库建议使用 APFS 格式的外置 SSD。
- 删除
~/Desktop.bak前,务必重启电脑并确认桌面功能完全正常。 - 开发服务器被杀掉后需要手动重启,包括 project-n、project-b、Docker 等。
- AI Agent 数据修改前务必备份,尤其是 SQLite 数据库和全局状态文件。
- Agent 会话恢复后建议测试
/resume,确认能加载历史对话再继续使用。
记录完毕。