功能
复制现有配置
本页由英文机器翻译而来,欢迎指正。 在 GitHub 上编辑此页
如果你在使用 ccam 之前就用过 Claude Code,你的配置都在 ~/.claude 和 ~/.claude.json 中。ccam migrate 会把它们复制到一个共享组中,让通过该组共享这些项的每个账号一开始就拥有你现有的配置。源文件夹只会被读取,直接运行 claude 也会像以前一样工作。在第一次 ccam add 之后运行一次,之后每当有账号开始共享 MCP 服务器时再运行一次。
用法
ccam migrate # ~/.claude into group default, checklist on a terminal
ccam --dry-run migrate # show the plan, copy nothing
ccam migrate --settings --mcp # only these items, no checklist
ccam migrate --history --yes # conversation history only, no questions
ccam migrate ~/.claude-work --group work在终端中,如果不带项目选项也不带 --yes,ccam 会先显示一个清单:
Copy into group default
From /home/me/.claude
? Choose what to copy (Space to toggle)
› [x] MCP servers
[x] settings.json
[x] global CLAUDE.md
[x] agents, commands, skills
[ ] conversation history
Enter show the plan · Esc cancelSpace(或 x)切换光标所在的项,方向键或 j/k 移动光标,Enter 显示计划,Esc、q 或 Ctrl+C 会打印 Cancelled.。源中没有内容的项会标记为 not found。如果你取消勾选所有项,ccam 会打印 Nothing selected. 并停止。
然后 ccam 打印计划,并在复制之前征求确认:
$ ccam migrate --yes
Copy from /home/me/.claude into group default (/home/me/.local/share/ccam/groups/default):
mcp ~/.claude.json new: fs, linear
sign-ins linear → personal; skipped: work (not logged in yet)
settings settings.json new: 61 B
memory CLAUDE.md new: 11 B
extensions agents/ add 1 file the group lacks (6 B)
skills/ add 1 file the group lacks (13 B)
not found, skipped: commands/, plugins/, output-styles/, rules/
Conversation history (projects/, history.jsonl) is not included; add --history to copy it.
✓ Copied into group default: 2 MCP servers, settings.json, CLAUDE.md, agents/, skills/, MCP sign-ins for personal
MCP sign-ins were not copied to: work (not logged in yet). Sign in to those servers there with /mcp.
Accounts that share these through group default:
mcp personal, work
settings personal, work
memory personal, work
extensions personal, work组只会到达通过它共享某一项的账号,因此摘要会按项列出这些账号。对于尚未共享的账号,ccam 会打印开启共享的 ccam share <name> --<item> on 命令。
选项
| 选项 | 作用 | 默认值 |
|---|---|---|
[folder] |
要从中复制的 Claude Code 文件夹 | ~/.claude |
--settings |
复制 settings.json |
关闭 |
--memory |
复制全局 CLAUDE.md |
关闭 |
--extensions |
复制 agents/、commands/、skills/、plugins/、output-styles/、rules/ |
关闭 |
--mcp |
复制用户 MCP 服务器(.claude.json 中的 mcpServers) |
关闭 |
--history |
复制对话历史(projects/、history.jsonl) |
关闭 |
-g、--group string |
要复制到的共享组 | default |
-y、--yes |
不询问直接复制;发生冲突时保留组中的副本 | 关闭 |
--dry-run(全局) |
打印计划,并在任何询问或复制之前停止 | 关闭 |
不带项目选项时,在终端中由清单决定。不在终端中或带有 --yes 时,ccam 复制除对话历史以外的所有内容。默认不包括对话历史,因为 projects/ 可能很大。
--group on 表示 default。--group off 和 --group local 会被拒绝,并显示 --group takes a group name, not "off"。ccam migrate 支持 --dry-run,试运行时清单依然会出现,方便你预览所选内容。
工作原理
internal/cli/migrate.go 选定项目,然后 migrate.Build 读取源和组并返回一个计划。在你确认之后、执行 Plan.Apply 之前,不会写入任何内容。
- 找到源。
checkSource会拒绝不存在的路径、不是文件夹的路径,以及不包含任何已知 Claude Code 条目的文件夹。migrate.ClaudeJSON找到属于该文件夹的.claude.json:在文件夹内;或者对于内部没有该文件的~/.claude,则是它旁边的~/.claude.json。未设置CLAUDE_CONFIG_DIR时,Claude Code 就把它放在那里。 - 把项目映射到路径。 每个路径都来自
share.Layout,也就是ccam share使用的同一份允许列表。MCP 服务器通过mcp.LocalServers从.claude.json中读出,它使用profile.TopLevelValue扫描器,而不是解析整个文件。 - 只复制,不移动。 文件通过
fsutil.AtomicWrite或fsutil.CopyFile写入~/.local/share/ccam/groups/<group>/;MCP 服务器写入组的mcp.json。
每一项都把一个源路径映射到一个组路径:
两行历史记录是虚线,因为只有加上 --history 才会复制它们。.credentials.json 和 .claude.json 列在 share.Never 中,永远不会进入组:如果它们出现在布局中,Build 会返回内部错误,遍历文件夹时也会按名称跳过它们。
buildEntry 为每个路径确定一个状态,计划中的每一行描述的就是这个状态:
- Missing:源中没有,或者应为文件夹的位置是一个文件。每项列出一次,显示为
not found, skipped。 - Linked:源路径已经解析到组中的副本,例如当源是 ccam 的账号文件夹时。
- Same:组中已有完全相同的内容。
- New:组中没有,因此整体复制。
- Merge:两边都有的文件夹。
copyMissing只添加组中没有的文件;内容不同的文件保持组中的版本,计划中显示group copies kept。对于plugins/,注册表installed_plugins.json和known_marketplaces.json会被合并,插件的绝对路径会被改写为指向组的文件夹。 - Conflict:两边都有但内容不同的文件。你可以逐个文件选择:
keep group、use mine,对于.json文件还有merge JSON(深度合并,值冲突时组中的值优先),对于history.jsonl还有merge by line。定义不同的 MCP 服务器也属于冲突,可选keep group或use mine。列出的第一个选项是按 Enter 时的默认值;--yes总是保留组中的副本。
清单本身是 tui.MigratePicker,基于 ccam add 使用的 checklist 组件构建;migrate.Found 通过 lstat 调用和 MCP 服务器列表标记不存在的项。
MCP 登录
通过 OAuth 登录的 MCP 服务器把令牌保存在登录文件 .credentials.json 的 mcpOAuth 下,而不是服务器列表中。Claude Code 用 <name>| 加上由服务器的 type、url 和 headers 计算出的 sha256 哈希的前 16 个字符作为每个条目的键。这个键与文件夹无关,因此只要服务器定义完全相同,复制过去的条目在其他账号中也能使用。所以 internal/migrate/logins.go 中的 buildLogins 只复制那些最终在组中采用源定义的服务器的条目:新增的、本来就相同的,或者在冲突中你选择了 use mine 的。当你复制扩展且源中有 plugins/ 时,插件服务器的登录(以 plugin: 开头的键)也会一起复制。
这些条目写入每个接收账号自己的 .credentials.json,通过 fsutil.AtomicWrite 以 0600 权限写入。它们永远不会进入组。只有通过目标组共享 mcp(对于插件服务器则是 extensions)的账号才会接收它们,并且只添加账号中没有的键:账号已有的条目(可能更新)会被保留。计划中的 sign-ins 一行列出服务器、接收账号和被跳过的账号。出现以下情况时,ccam 会跳过该账号,并列出其名称和原因:
- 用
ccam import原地注册的账号,因为直接运行的claude可能正在使用它的登录文件; - 正在运行的账号,因为 Claude Code 会改写它的登录文件(写入前会再检查一次,报告为
started meanwhile); - 尚未登录的账号;
- 把登录保存在 macOS 钥匙串中的账号,ccam 不会写入钥匙串。
请在被跳过的账号中用 /mcp 登录这些服务器。之后才开始共享 MCP 服务器的账号,会在你再次运行 ccam migrate 时获得这些登录;摘要会用 Then run `ccam migrate` again to give them the MCP sign-ins too. 提示这一点。
安全性与边界情况
- 源只会被读取。其中的任何文件都不会被移动、链接或修改,源的登录也从不会被写入,包括在可能从钥匙串读取登录的 macOS 上。
- 在组中的文件被替换之前(无论是因为
use mine、合并,还是现有mcp.json中加入了新的 MCP 服务器),组中的副本会保存在<group>/.ccam-backup/<time>/中。每次运行的文件夹名都是唯一的,因此同一秒内的两次运行不会覆盖彼此的备份。摘要会打印这个路径。 - 使用
--yes时,每个冲突都保留组中的副本,ccam 会告诉你如何改为自己选择:不带--yes运行同一命令。 - 如果没有任何需要更改的内容,ccam 会打印
Nothing to copy.;如果每个冲突都保留组中的副本,则打印Nothing to copy: the group keeps its own copies. - 如果复制中途失败,ccam 会停止并显示
The source folder was not changed. Group files replaced so far are saved in,后面跟着备份文件夹。 - 源不存在时,会以
no Claude Code folder at <path>. Give the folder to copy from: ccam migrate <folder>结束。