macOS 磁盘清理与 AI Agent 会话恢复记录

记录一次完整的 macOS 磁盘清理过程,以及迁移 Desktop 后恢复 Claude Code、OpenCode、Codex 等 AI Agent 对话的经验。
时间:2026-07-04 / 2026-07-05
系统:macOS(Apple Silicon)
用户目录:/Users/username


目录

  1. 前言
  2. 初始磁盘概况
  3. 第一阶段:游戏A 残留清理
  4. 第二阶段:Library 孤儿应用数据扫描
  5. 第三阶段:删除确认的应用残留
  6. 第四阶段:Claude-3p 目录分析
  7. 第五阶段:Docker 空间清理
  8. 第六阶段:Logic Pro 音色库迁移
  9. 第七阶段:Desktop 目录迁移到外置硬盘
  10. 第八阶段:AI Agent 会话恢复
  11. 遇到的问题与解决方案
  12. 释放空间总结
  13. 后续可清理项
  14. 常用命令速查

前言

电脑内置硬盘空间告急,发现很多应用卸载后数据没有自动清理,再加上 Docker、AI 模型缓存、微信聊天记录等,占用了大量空间。本次清理目标是:

  • 找出并删除已卸载应用的残留数据
  • 清理 Docker 镜像和构建缓存
  • 将大型数据(Logic Pro 音色库、Desktop)迁移到外置硬盘
  • 整理开发/AI 缓存
  • 修复 Desktop 迁移后 AI Agent(Claude Code、OpenCode、Codex)的会话恢复问题

初始磁盘概况

用户目录总计约 668 GB,主要分布:

位置初始大小
~/Desktop198 GB
~/Library133 GB
~/Music73 GB
~/Parallels49 GB
~/Downloads43 GB
~/.cache36 GB
~/Documents23 GB
~/Movies5.1 GB
~/.Trash78 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.app15.7 GB应用A
~/Library/Application Support/AppShellData11 GB应用C 内嵌浏览器壳
~/Library/Application Support/project-a1.3 GBproject-a 桌面版
~/Library/Containers/com.vendor.app2325 MB应用B 组件
~/Library/Application Support/com.vendor.app4220 MBAdobe 组件
~/Library/Containers/com.vendor.app5147 MB品牌A 跨屏互联
~/Library/Application Support/com.vendor.app675 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/

结果

项目大小
游戏A61 GB
应用A5.7 GB
AppShellData11 GB
project-a1.3 GB
合计79 GB

第四阶段:Claude-3p 目录分析

发现

~/Library/Application Support/Claude-3p 占用 12 GB,是 npx 版 Claude Code 的数据目录。

主要内容

子目录/文件大小说明
vm_bundles/claudevm.bundle12 GBClaude Code 虚拟机/隔离运行环境
claude-code-vm/x.x.xxx236 MBVM 运行时
claude-code/x.x.xxx212 MBCLI 运行时
Cache/Cache_Data94 MB应用缓存
IndexedDBLocal StorageCookies较小本地存储和登录状态

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 自带的声音资源库管理器:

  1. 打开 Logic Pro
  2. 菜单:Logic Pro > 声音资源库 > 打开声音资源库管理器
  3. 选择要迁移的内容,点击"重新定位..."
  4. 选择外置硬盘上的目标文件夹

注意事项

  • 外置硬盘建议格式化为 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 迁移后都可能遇到同样问题。通用恢复步骤:

  1. 找到 Agent 的数据目录:通常是 ~/.agent-name/~/.config/agent-name/~/.local/share/agent-name/
  2. 停止 Agent 所有进程
  3. 备份数据
  4. 替换配置文件和日志中的旧路径
  5. 检查 SQLite 数据库:用 grep -rl 或 SQL 查询找到包含旧路径的表和字段
  6. 重命名或合并 projects/sessions 缓存目录(如果 Agent 按路径编码目录名)
  7. 执行 VACUUM 清理 SQLite 二进制残留
  8. 重启 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_replpython3.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 -a42.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/uv4.0 GBuv cache clean
~/.rustup2.9 GB不开发 Rust 可删
~/.nuget2.2 GB不开发 .NET 可删
~/.bun1.5 GB不用 Bun 可删
~/.cargo1.3 GB不用 Rust 可删
~/.npm-global581 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_code136 GB,单个项目占用:

项目大小
project-g28 GB
project-h21 GB
project-i16 GB
project-j15 GB
project-b12 GB
project-a11 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

注意事项

  1. 移到废纸篓后记得清空,否则空间不会真正释放。
  2. 符号链接迁移 Desktop 后,外置硬盘必须保持挂载,否则桌面会显示为空。
  3. 清理 Docker 前确认没有需要保留的容器或镜像。
  4. 迁移 Logic Pro 音色库建议使用 APFS 格式的外置 SSD。
  5. 删除 ~/Desktop.bak,务必重启电脑并确认桌面功能完全正常。
  6. 开发服务器被杀掉后需要手动重启,包括 project-n、project-b、Docker 等。
  7. AI Agent 数据修改前务必备份,尤其是 SQLite 数据库和全局状态文件。
  8. Agent 会话恢复后建议测试 /resume,确认能加载历史对话再继续使用。

记录完毕。