cchost 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -0
- package/README.md +123 -63
- package/lib/banner.js +29 -0
- package/lib/cli.js +545 -207
- package/lib/copy.js +242 -0
- package/lib/doctor.js +154 -22
- package/lib/env.js +40 -45
- package/lib/profiles.js +10 -0
- package/lib/share.js +343 -57
- package/package.json +1 -1
- package/lib/migrate.js +0 -145
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,152 @@ All notable changes to `cchost` are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [0.4.1] - 2026-06-04
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Shared resources expanded from 4 to 7.** Profiles now also auto-link
|
|
13
|
+
`mcp.json`, `settings.json`, and `CLAUDE.md` into `~/.claude/`, in addition
|
|
14
|
+
to the four directories (`projects/`, `skills/`, `agents/`, `commands/`).
|
|
15
|
+
MCP servers, user settings, and user-level memory are now visible to every
|
|
16
|
+
profile by default — the trust boundary becomes clean: only the three
|
|
17
|
+
credential files (`.credentials.json`, `.claude.json`, `.cc-env.json`) stay
|
|
18
|
+
per-profile.
|
|
19
|
+
- **`cc copy` replaces `cc migrate`.** Same direction (`default → <profile>`),
|
|
20
|
+
same `--force` flag — the verb just matches what the command actually does.
|
|
21
|
+
`cc migrate` still works as a deprecation alias and forwards to `cc copy`
|
|
22
|
+
with a one-line warning; it will be removed in a future version.
|
|
23
|
+
- **`cc link` / `cc unlink` accept `--config`** to target the three single
|
|
24
|
+
files. The three groups now: `--projects`, `--tools`, `--config`. No flag
|
|
25
|
+
still means all 7.
|
|
26
|
+
- **`cc unlink` is non-destructive.** Materializes the current pool content
|
|
27
|
+
into a private directory or file as part of breaking the link, so the
|
|
28
|
+
profile's view of that resource is preserved. Same-name collisions in the
|
|
29
|
+
profile (if any) are kept untouched.
|
|
30
|
+
- **`cc link` refuses to overwrite private content.** If a profile's resource
|
|
31
|
+
already has non-empty private content, `cc link` reports it as `refused`
|
|
32
|
+
and leaves it alone (other resources still link). Move or remove the
|
|
33
|
+
content manually, then re-run.
|
|
34
|
+
- **`cc remove` requires `--force` when private (unlinked) content exists.**
|
|
35
|
+
Symlinked resources are still removed silently (the shared pool is
|
|
36
|
+
untouched); private content prompts the user to acknowledge that its
|
|
37
|
+
content is unique and will be lost.
|
|
38
|
+
- **`cc list` uses a single `--reveal` flag.** Drops `--reveal-email`;
|
|
39
|
+
`--reveal` now shows both the API token (where applicable) and the full
|
|
40
|
+
email. Email mask format also changed for stronger redaction:
|
|
41
|
+
`allen@cyber.co.in` → `a*************.in` (first char + TLD only; the
|
|
42
|
+
domain is no longer visible).
|
|
43
|
+
- **`cc list` "Shared" column is `N/7`.**
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- `cc doctor` now backfills missing resource symlinks on existing profiles
|
|
48
|
+
(e.g. v0.4.0 profiles that pre-date `mcp.json` / `settings.json` /
|
|
49
|
+
`CLAUDE.md` sharing). Safe auto-fix when the resource is missing or empty;
|
|
50
|
+
warning-only with manual guidance when private content exists.
|
|
51
|
+
- Windows file symlink fallback: when `fs.symlinkSync(..., 'file')` fails
|
|
52
|
+
with EPERM/UNKNOWN (Developer Mode not enabled), `cc link` falls back to a
|
|
53
|
+
hard link so editing-in-place still propagates between profiles. The
|
|
54
|
+
fallback is noted in the link command output.
|
|
55
|
+
|
|
56
|
+
### Help
|
|
57
|
+
|
|
58
|
+
- Per-command help (`cc help <cmd>`) now spells out the 7 resources, the
|
|
59
|
+
three flag groups, and what stays per-profile.
|
|
60
|
+
|
|
61
|
+
## [0.4.0] - 2026-06-04
|
|
62
|
+
|
|
63
|
+
### Changed (breaking)
|
|
64
|
+
|
|
65
|
+
- **`~/.claude/` is now the shared pool.** Every profile's `projects/`,
|
|
66
|
+
`skills/`, `agents/`, `commands/` symlink directly into Claude Code's own
|
|
67
|
+
default config dir. There is no longer a parallel `~/.claude-shared/` pool:
|
|
68
|
+
the two locations are unified. A profile is now a credential set + a
|
|
69
|
+
symlinked view onto the shared pool.
|
|
70
|
+
- **`cc add` auto-links all four artifact dirs.** New profiles ship with the
|
|
71
|
+
symlinks in place, so a skill, agent, or command installed under any profile
|
|
72
|
+
is immediately visible to every other profile. Bare `claude` (without
|
|
73
|
+
`cc use`) sees the same set too — there is no profile-vs-bare split.
|
|
74
|
+
- **`cc link <profile>` and `cc unlink <profile>` accept `--tools` and
|
|
75
|
+
`--projects` flags** to target a subset:
|
|
76
|
+
- `--tools` → `skills/`, `agents/`, `commands/`
|
|
77
|
+
- `--projects` → `projects/`
|
|
78
|
+
- No flag → all four (current default behavior)
|
|
79
|
+
- **`cc list` "Shared" column expects `4/4`** as the steady state for v0.4
|
|
80
|
+
profiles. `0/4`, `3/4`, etc. show profiles whose tool or project sharing has
|
|
81
|
+
been turned off via `cc unlink --tools` / `--projects`.
|
|
82
|
+
|
|
83
|
+
### Removed
|
|
84
|
+
|
|
85
|
+
- **`cc migrate default shared` and `cc migrate shared <profile>`.** The shared
|
|
86
|
+
pool was the destination of the first and the source of the second; with the
|
|
87
|
+
pool unified into `~/.claude/`, both directions are no-ops. Use
|
|
88
|
+
`cc link <profile>` / `cc unlink <profile>` to control sharing.
|
|
89
|
+
|
|
90
|
+
### Migration from 0.3.x
|
|
91
|
+
|
|
92
|
+
The v0.3 pool at `~/.claude-shared/` is folded into `~/.claude/` automatically
|
|
93
|
+
on the next `cc add` or `cc doctor --fix`. The migration:
|
|
94
|
+
|
|
95
|
+
- Moves every entry in `~/.claude-shared/{projects,skills,agents,commands}/`
|
|
96
|
+
into the matching `~/.claude/<sub>/`, renaming on collision (existing
|
|
97
|
+
`~/.claude/` content is never overwritten — duplicates get an `__legacy`
|
|
98
|
+
suffix).
|
|
99
|
+
- Re-points any existing profile symlink that targets `~/.claude-shared/<sub>/`
|
|
100
|
+
to `~/.claude/<sub>/`.
|
|
101
|
+
- Removes `~/.claude-shared/` once empty.
|
|
102
|
+
|
|
103
|
+
Idempotent and non-destructive — re-running is a no-op once the legacy dir is
|
|
104
|
+
gone. `cc doctor` surfaces an explicit warning while the legacy dir still
|
|
105
|
+
exists, with a `--fix` action that runs the migration.
|
|
106
|
+
|
|
107
|
+
## [0.3.2] - 2026-06-04
|
|
108
|
+
|
|
109
|
+
### Changed
|
|
110
|
+
|
|
111
|
+
- **`cc list` masks account emails by default.** Emails are shown as
|
|
112
|
+
`i***@example.com` in both the table view and the per-profile detail view,
|
|
113
|
+
including the `--json` output. Pass `--reveal-email` to print them in full.
|
|
114
|
+
The list is now safe to paste in screenshots or issue reports.
|
|
115
|
+
- `--reveal-email` is rejected together with `--json` — same precedent as
|
|
116
|
+
`--reveal`. Scripts that need the real address can read `.claude.json`
|
|
117
|
+
directly.
|
|
118
|
+
- Token masking is unchanged: `--reveal` still works on `cc list <profile>`
|
|
119
|
+
and `--reveal-email` does not affect it.
|
|
120
|
+
|
|
121
|
+
## [0.3.1] - 2026-05-19
|
|
122
|
+
|
|
123
|
+
### Changed
|
|
124
|
+
|
|
125
|
+
- **Custom API endpoints are now configured through `cc add`, not `cc env`.**
|
|
126
|
+
The standalone `cc env` command (shipped in 0.3.0) is removed; endpoint
|
|
127
|
+
configuration is folded into the profile-creation command:
|
|
128
|
+
- `cc add <profile> --custom` — create a custom-endpoint profile via an
|
|
129
|
+
interactive wizard; the token is never echoed.
|
|
130
|
+
- `cc add <profile> --custom --base-url=URL --token=TOKEN [--model/--opus/--sonnet/--haiku/--subagent=NAME]`
|
|
131
|
+
— non-interactive create.
|
|
132
|
+
- Re-running `cc add <profile> --custom` on an existing endpoint profile
|
|
133
|
+
edits it in place (wizard prefills current values; with flags, only the
|
|
134
|
+
flags you pass are changed).
|
|
135
|
+
- `cc add --custom` is atomic — cancelling the wizard leaves no profile
|
|
136
|
+
behind.
|
|
137
|
+
- **Endpoint inspection moved to `cc list`.** `cc env show` is replaced by
|
|
138
|
+
`cc list <profile>` — a per-profile detail view. `cc list <profile> --reveal`
|
|
139
|
+
unmasks the API token; `cc list <profile> --json` emits it as an object
|
|
140
|
+
(token always masked in JSON).
|
|
141
|
+
|
|
142
|
+
### Removed
|
|
143
|
+
|
|
144
|
+
- `cc env` and `cc env show` — superseded by `cc add --custom` and
|
|
145
|
+
`cc list <profile>`.
|
|
146
|
+
|
|
147
|
+
### Notes
|
|
148
|
+
|
|
149
|
+
- A profile is still born subscription or endpoint and stays that way:
|
|
150
|
+
`cc add --custom` refuses a profile that already has Anthropic OAuth
|
|
151
|
+
credentials. `.cc-env.json` is still never migrated and never linked, and is
|
|
152
|
+
still written with user-only file permissions.
|
|
153
|
+
|
|
8
154
|
## [0.3.0] - 2026-05-19
|
|
9
155
|
|
|
10
156
|
### Added
|
|
@@ -71,6 +217,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
71
217
|
per-process state and must stay per-profile.
|
|
72
218
|
- Cross-platform claim narrowed to the verified scope (Windows and Linux).
|
|
73
219
|
|
|
220
|
+
[0.3.1]: https://github.com/allenhack638/cchost/releases/tag/v0.3.1
|
|
74
221
|
[0.3.0]: https://github.com/allenhack638/cchost/releases/tag/v0.3.0
|
|
75
222
|
[0.2.1]: https://github.com/allenhack638/cchost/releases/tag/v0.2.1
|
|
76
223
|
[0.2.0]: https://github.com/allenhack638/cchost/releases/tag/v0.2.0
|
package/README.md
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
# cchost
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Run multiple isolated Claude Code accounts on one machine — switch between them with a single `cc` command.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/cchost)
|
|
6
|
+
[](https://github.com/allenhack638/cchost/actions/workflows/ci.yml)
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
[](https://nodejs.org)
|
|
9
|
+
|
|
10
|
+
<!-- Demo: record a ~15s clip of `cc add` → `cc use` → `cc list`, save it as
|
|
11
|
+
docs/demo.gif, and uncomment the line below. -->
|
|
12
|
+
<!--  -->
|
|
13
|
+
|
|
14
|
+
Claude Code keeps one account's login, history, and settings in a single config directory. To use a second account you normally have to log out and back in, which loses your place. cchost gives each account its own directory so you can keep several side by side and pick one when you launch.
|
|
15
|
+
|
|
16
|
+
Each profile is a complete, isolated `CLAUDE_CONFIG_DIR`: credentials, session history, project state, plugins, and settings. Create one with `cc add <name>`, launch under it with `cc use <name>`. Nothing is shared between profiles unless you ask for it.
|
|
17
|
+
|
|
18
|
+
`cc` is a plain Node CLI on your PATH, so it works the same from PowerShell, cmd, bash, zsh, or fish. No shell scripts, no rc-file edits. Tested on Windows, Linux, and macOS in CI.
|
|
6
19
|
|
|
7
20
|
## Install
|
|
8
21
|
|
|
@@ -16,15 +29,14 @@ Requires Node.js 18+ and Claude Code 2.1.140+ already installed. Get Claude Code
|
|
|
16
29
|
|
|
17
30
|
| Command | What it does |
|
|
18
31
|
| --- | --- |
|
|
19
|
-
| `cc add <profile>` | Create a profile
|
|
32
|
+
| `cc add <profile>` | Create a subscription profile (logs in with Anthropic OAuth on first use). Auto-symlinks artifact dirs into `~/.claude/`. |
|
|
33
|
+
| `cc add <profile> --custom [...]` | Create — or, if it already exists, edit — a profile routed through a custom API endpoint. Opens a wizard, or takes `--base-url=URL --token=TOKEN [--model=…]`. See [Custom endpoints](#custom-endpoints-kimi-openrouter-etc). |
|
|
20
34
|
| `cc use <profile> [...args]` | Launch Claude under that profile. Profile must already exist. Args after the name are forwarded verbatim to `claude`. |
|
|
21
|
-
| `cc list [--json]` |
|
|
22
|
-
| `cc
|
|
23
|
-
| `cc
|
|
24
|
-
| `cc
|
|
25
|
-
| `cc
|
|
26
|
-
| `cc unlink <profile>` | Restore a profile to its own private artifact dirs (copies shared content back). |
|
|
27
|
-
| `cc remove <profile>` | Delete a profile. Requires typing the profile name to confirm. |
|
|
35
|
+
| `cc list [<profile>] [--json] [--reveal]` | List every profile (login state, email, shared count N/7, endpoint), or show one profile in detail. Emails and tokens are masked by default; `--reveal` shows both in full. |
|
|
36
|
+
| `cc copy default <profile> [--force]` | Copy `~/.claude/` resources into a profile. Meaningful only when one or more resources have been unlinked via `cc unlink`; otherwise every resource resolves to the same on-disk path and is skipped. Skip-on-collision by default; `--force` overwrites. `cc migrate` is a deprecated alias. |
|
|
37
|
+
| `cc link <profile> [<profile>...] [--projects\|--tools\|--config]` | (Re-)link a profile's resources to `~/.claude/`. No flag = all 7. Refuses to overwrite private content. |
|
|
38
|
+
| `cc unlink <profile> [--projects\|--tools\|--config]` | Break the links and copy current `~/.claude/` content into the profile as private resources. Non-destructive. |
|
|
39
|
+
| `cc remove <profile> [--force]` | Delete a profile. Requires typing the profile name to confirm. `--force` is required when private (unlinked) resources exist. |
|
|
28
40
|
| `cc doctor [--fix [--force]] [--json]` | Diagnose environment, storage, and platform issues. |
|
|
29
41
|
| `cc help [command]` | Print usage (top-level, or for a single command). |
|
|
30
42
|
|
|
@@ -42,93 +54,141 @@ cc remove old-profile
|
|
|
42
54
|
`cc list` output:
|
|
43
55
|
|
|
44
56
|
```
|
|
45
|
-
Profile LoggedIn Email
|
|
46
|
-
kimi false -
|
|
47
|
-
personal true
|
|
48
|
-
scratch false -
|
|
49
|
-
work true
|
|
57
|
+
Profile LoggedIn Email Shared Endpoint
|
|
58
|
+
kimi false - 7/7 api.moonshot.ai
|
|
59
|
+
personal true p************.com 7/7 subscription
|
|
60
|
+
scratch false - 7/7 subscription
|
|
61
|
+
work true w************.com 7/7 subscription
|
|
50
62
|
```
|
|
51
63
|
|
|
52
|
-
|
|
64
|
+
`7/7` is the steady state since v0.4.1 — every profile auto-shares 4 dirs (`projects`, `skills`, `agents`, `commands`) **and** 3 files (`mcp.json`, `settings.json`, `CLAUDE.md`) with `~/.claude/`. A lower number means one or more resources were unlinked via `cc unlink <profile> --projects|--tools|--config`.
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
| --- | :---: | :---: | --- |
|
|
56
|
-
| `projects/` | ✓ | ✓ | Resumable conversation transcripts |
|
|
57
|
-
| `skills/` | ✓ | ✓ | Custom slash-command scripts |
|
|
58
|
-
| `agents/` | ✓ | ✓ | Custom agent definitions |
|
|
59
|
-
| `commands/` | ✓ | ✓ | Custom command configs |
|
|
60
|
-
| `mcp.json` | ✓ (default→profile only) | — | Per-profile MCP server config; may carry auth tokens |
|
|
61
|
-
| `settings.json` | ✓ (default→profile only) | — | Per-profile UI/feature settings |
|
|
62
|
-
| `CLAUDE.md` | ✓ (default→profile only) | — | Per-profile project instructions |
|
|
63
|
-
| `sessions/` | — | — | Transient per-process state; sharing would corrupt bookkeeping |
|
|
64
|
-
| `plugins/` | — | — | Carries auth tokens; deferred to a future opt-in flag |
|
|
65
|
-
| `.credentials.json` | — | — | Never touched — each profile keeps its own auth |
|
|
66
|
-
| `.claude.json` | — | — | Never touched — re-synced from server on every launch |
|
|
67
|
-
| `.cc-env.json` | — | — | Per-profile custom-endpoint config; holds an API key. Never migrated, never linked. |
|
|
66
|
+
Emails are masked by default so the list is safe to paste in screenshots and issue reports. Pass `--reveal` to show them in full (same flag also reveals the API token on custom-endpoint profiles).
|
|
68
67
|
|
|
69
|
-
|
|
68
|
+
The **Shared** column is a count: how many of the 7 shareable resources symlink into `~/.claude/`.
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
- `7/7` — the default since v0.4.1. All four artifact dirs *and* the three
|
|
71
|
+
config files point at the shared pool; a tool, server, or hook configured
|
|
72
|
+
under any profile is immediately visible to every other profile.
|
|
73
|
+
- `6/7`, `5/7`, … — one or more resources were `cc unlink`ed and now hold
|
|
74
|
+
private content.
|
|
75
|
+
- `0/7` — fully isolated; the profile keeps its own copy of everything.
|
|
76
|
+
- `4/7` — typical of a profile created on v0.4.0 before the file resources
|
|
77
|
+
were added. Run `cc doctor --fix` to backfill them.
|
|
72
78
|
|
|
73
|
-
|
|
79
|
+
### What's shared, what's per-profile
|
|
74
80
|
|
|
75
|
-
|
|
76
|
-
cc migrate default work # copy ~/.claude/* → ~/.claude-profiles/work/
|
|
77
|
-
cc migrate default shared # copy ~/.claude/projects,skills,agents,commands → ~/.claude-shared/
|
|
78
|
-
cc migrate shared personal # copy ~/.claude-shared/* → ~/.claude-profiles/personal/
|
|
79
|
-
cc migrate default work --force # same as first, overwriting anything that already exists
|
|
80
|
-
```
|
|
81
|
+
Since v0.4.1, **`~/.claude/` is the shared pool**, and **all 7 resources** auto-link into it on `cc add`. The trust boundary is simple: anything that authenticates this profile's identity stays per-profile; everything else is global.
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
| Resource | Location | Shared? | Flag group |
|
|
84
|
+
| --- | --- | :---: | --- |
|
|
85
|
+
| `projects/` | `~/.claude/projects/` | ✓ (symlink) | `--projects` |
|
|
86
|
+
| `skills/` | `~/.claude/skills/` | ✓ (symlink) | `--tools` |
|
|
87
|
+
| `agents/` | `~/.claude/agents/` | ✓ (symlink) | `--tools` |
|
|
88
|
+
| `commands/` | `~/.claude/commands/` | ✓ (symlink) | `--tools` |
|
|
89
|
+
| `mcp.json` | `~/.claude/mcp.json` | ✓ (file symlink / hard link) | `--config` |
|
|
90
|
+
| `settings.json` | `~/.claude/settings.json` | ✓ (file symlink / hard link) | `--config` |
|
|
91
|
+
| `CLAUDE.md` | `~/.claude/CLAUDE.md` | ✓ (file symlink / hard link) | `--config` |
|
|
92
|
+
| `sessions/` | per-profile | — | (never shared) |
|
|
93
|
+
| `plugins/` | per-profile | — | (never shared) |
|
|
94
|
+
| `.credentials.json` | per-profile | — | Anthropic OAuth token. Never touched. |
|
|
95
|
+
| `.claude.json` | per-profile | — | Account identity (re-synced on every launch). |
|
|
96
|
+
| `.cc-env.json` | per-profile | — | Custom-endpoint API key. Never copied, never linked. |
|
|
83
97
|
|
|
84
|
-
|
|
98
|
+
`mcp.json` carries MCP server tokens and `settings.json` carries hooks that can run arbitrary commands. Sharing them means every profile sees the same set — if you need per-profile separation for one of them, `cc unlink <profile> --config` breaks the link and makes that profile's copies private.
|
|
85
99
|
|
|
86
|
-
###
|
|
100
|
+
### Seeding a private profile from `~/.claude/`
|
|
87
101
|
|
|
88
|
-
If
|
|
102
|
+
If a profile has unlinked resources (`cc unlink <p>`) and you want to seed them from the current `~/.claude/`:
|
|
89
103
|
|
|
90
104
|
```bash
|
|
91
|
-
cc
|
|
92
|
-
cc
|
|
105
|
+
cc copy default work # copies anything unlinked from ~/.claude/ → work
|
|
106
|
+
cc copy default work --force # same, overwriting if already present
|
|
93
107
|
```
|
|
94
108
|
|
|
95
|
-
|
|
109
|
+
For a fresh `cc add` profile this is a no-op — every resource already resolves to `~/.claude/` via its symlink, so there's nothing to copy. `cc copy` becomes meaningful only after `cc unlink`. (`cc migrate` is a deprecated alias for `cc copy` and still works.)
|
|
110
|
+
|
|
111
|
+
### Opting out of sharing for a profile
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
cc unlink work --tools # private skills/agents/commands for "work" only
|
|
115
|
+
cc unlink work --projects # private projects/ for "work" only
|
|
116
|
+
cc unlink work --config # private mcp.json/settings.json/CLAUDE.md
|
|
117
|
+
cc unlink work # private everything (all 7 unlinked)
|
|
118
|
+
cc link work --tools # re-share just the tools
|
|
119
|
+
cc link work --config # re-share just the config files
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`cc unlink` is non-destructive — current pool content is copied into the profile as a private dir or file before the link is broken, so your view of the resource is preserved. `cc link` refuses to overwrite existing private content; move or remove it manually and re-run.
|
|
123
|
+
|
|
124
|
+
Credential files (`.credentials.json`, `.claude.json`, `.cc-env.json`) are never touched: each profile keeps its own auth state.
|
|
96
125
|
|
|
97
|
-
|
|
126
|
+
### How sharing works under the hood
|
|
98
127
|
|
|
99
|
-
|
|
128
|
+
Every profile created by `cc add` ships with 7 links pointing at `~/.claude/<resource>`:
|
|
100
129
|
|
|
101
|
-
|
|
130
|
+
- Directories use Windows junctions (no admin / Developer Mode required) or POSIX symlinks.
|
|
131
|
+
- Files (`mcp.json`, `settings.json`, `CLAUDE.md`) use file symlinks where possible. On Windows without Developer Mode, file symlinks require elevation — `cc link` falls back to a **hard link** there, which works without admin and behaves identically for edit-in-place flows.
|
|
102
132
|
|
|
103
|
-
`
|
|
133
|
+
`sessions/` and `plugins/` are **never** linked. `sessions/` holds transient per-process registry state (PID, status, timestamps) and sharing it would corrupt Claude's running-process bookkeeping. `plugins/` carries auth tokens.
|
|
134
|
+
|
|
135
|
+
If two profiles open the same project at the same time, both will write to the same conversation files in `~/.claude/projects/<cwd>/` (last write wins). Either avoid that or run `cc unlink <profile> --projects` on one of them.
|
|
136
|
+
|
|
137
|
+
`cc remove` is safe with fully-shared profiles — it deletes only the symlinks, leaving `~/.claude/` untouched. If a profile has *private* (unlinked) resources, `cc remove` requires `--force` because that content is unique to the profile and will be lost.
|
|
104
138
|
|
|
105
139
|
## Custom endpoints (Kimi, OpenRouter, etc.)
|
|
106
140
|
|
|
107
|
-
A profile can route through any Anthropic-compatible API endpoint instead of Anthropic's subscription OAuth — Moonshot/Kimi, OpenRouter, Requesty, a self-hosted vLLM, or a corporate proxy.
|
|
141
|
+
A profile can route through any Anthropic-compatible API endpoint instead of Anthropic's subscription OAuth — Moonshot/Kimi, OpenRouter, Requesty, a self-hosted vLLM, or a corporate proxy. You declare this when you create the profile, with `cc add <profile> --custom`.
|
|
108
142
|
|
|
109
|
-
> **Billing:**
|
|
143
|
+
> **Billing:** a custom-endpoint profile bills through the **third-party provider**, using the API key you supply — **not** your Anthropic subscription. You are responsible for that provider's usage charges. A subscription profile is unaffected.
|
|
110
144
|
|
|
111
|
-
|
|
145
|
+
A custom-endpoint profile and a subscription profile are mutually exclusive: a profile is born one or the other and stays that way. `cc add --custom` refuses to run on a profile that already has Anthropic OAuth credentials — create custom-endpoint profiles fresh.
|
|
112
146
|
|
|
113
147
|
### Worked example — Moonshot / Kimi
|
|
114
148
|
|
|
115
149
|
```bash
|
|
116
|
-
cc add kimi
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
--model=kimi-k2.5
|
|
150
|
+
cc add kimi --custom --base-url=https://api.moonshot.ai/anthropic \
|
|
151
|
+
--token=sk-your-moonshot-key \
|
|
152
|
+
--model=kimi-k2.5
|
|
120
153
|
cc use kimi
|
|
121
154
|
```
|
|
122
155
|
|
|
123
156
|
Moonshot's endpoint URL ends in `/anthropic` — Claude Code appends `/v1/messages` itself, so do **not** add `/v1`. Most third-party providers serve a single model name; pass it as `--model` and it is applied to every tier (opus/sonnet/haiku/subagent). To override a tier, pass `--opus=`, `--sonnet=`, `--haiku=`, or `--subagent=`.
|
|
124
157
|
|
|
125
|
-
Run `cc
|
|
158
|
+
Run `cc add <profile> --custom` with no value flags for an interactive wizard instead — it prompts for every field and never echoes the token. `cc add --custom` is atomic: if you cancel the wizard, no profile is left behind.
|
|
159
|
+
|
|
160
|
+
### Editing a custom-endpoint profile
|
|
161
|
+
|
|
162
|
+
Re-run `cc add <profile> --custom` on a profile that already has a custom endpoint and it switches to **edit mode**: the wizard prefills current values, and with flags only the flags you pass are changed.
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
cc add kimi --custom --model=kimi-k3 # change just the model
|
|
166
|
+
cc add kimi --custom --token=sk-rotated # rotate the API key
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Inspect a config with `cc list <profile>` — the API token is masked:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
Profile: kimi
|
|
173
|
+
Directory: /home/you/.claude-profiles/kimi
|
|
174
|
+
LoggedIn: false
|
|
175
|
+
Email: -
|
|
176
|
+
Shared: 7/7
|
|
177
|
+
Endpoint: api.moonshot.ai
|
|
178
|
+
Base URL: https://api.moonshot.ai/anthropic
|
|
179
|
+
Token: sk-you...key9 (32 chars)
|
|
180
|
+
Model: kimi-k2.5
|
|
181
|
+
Opus: kimi-k2.5
|
|
182
|
+
Sonnet: kimi-k2.5
|
|
183
|
+
Haiku: kimi-k2.5
|
|
184
|
+
Subagent: kimi-k2.5
|
|
185
|
+
```
|
|
126
186
|
|
|
127
|
-
|
|
187
|
+
`cc list <profile> --reveal` prints the full API key and the full email — do not paste that output anywhere.
|
|
128
188
|
|
|
129
|
-
There is no
|
|
189
|
+
There is no way to convert a custom-endpoint profile back to a subscription profile. To stop using an endpoint, `cc remove` the profile and recreate it.
|
|
130
190
|
|
|
131
|
-
When you launch
|
|
191
|
+
When you launch a custom-endpoint profile, `cc use` prints a one-line reminder to stderr:
|
|
132
192
|
|
|
133
193
|
```
|
|
134
194
|
[cchost] Profile 'kimi' → api.moonshot.ai (custom endpoint billing applies)
|
|
@@ -149,9 +209,9 @@ The env var is set on the child process only — that's all `claude` needs.
|
|
|
149
209
|
|
|
150
210
|
## Sensitive data
|
|
151
211
|
|
|
152
|
-
`~/.claude-profiles/<profile>/` holds real OAuth credentials. Treat it like SSH keys: don't commit it, don't share it, don't sync it to public cloud storage. The `.gitignore` shipped with this project excludes profile directories from anywhere they might land. `cc
|
|
212
|
+
`~/.claude-profiles/<profile>/` holds real OAuth credentials. Treat it like SSH keys: don't commit it, don't share it, don't sync it to public cloud storage. The `.gitignore` shipped with this project excludes profile directories from anywhere they might land. `cc copy` and `cc link` never touch `.credentials.json` or `.claude.json`.
|
|
153
213
|
|
|
154
|
-
`.cc-env.json` (custom-endpoint config) contains a third-party **API key** — treat it exactly like `.credentials.json`. It is written with user-only file permissions, and `cc
|
|
214
|
+
`.cc-env.json` (custom-endpoint config) contains a third-party **API key** — treat it exactly like `.credentials.json`. It is written with user-only file permissions, and `cc copy`/`cc link` never copy or link it across profiles. `cc list <profile>` masks the token; only `cc list <profile> --reveal` prints it in full.
|
|
155
215
|
|
|
156
216
|
## Troubleshooting
|
|
157
217
|
|
package/lib/banner.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ASCII banner shown on `cc`, `cc help`, `cc --help`, and the unknown-command
|
|
4
|
+
// fallback. Generated once with figlet's "ANSI Shadow" font and frozen as a
|
|
5
|
+
// literal so the runtime has no dependency on figlet. Plain ASCII / no color —
|
|
6
|
+
// works in any terminal, including ones with NO_COLOR or no TTY.
|
|
7
|
+
|
|
8
|
+
const BANNER =
|
|
9
|
+
'\n' +
|
|
10
|
+
' ██████╗ ██████╗██╗ ██╗ ██████╗ ███████╗████████╗\n' +
|
|
11
|
+
'██╔════╝██╔════╝██║ ██║██╔═══██╗██╔════╝╚══██╔══╝\n' +
|
|
12
|
+
'██║ ██║ ███████║██║ ██║███████╗ ██║ \n' +
|
|
13
|
+
'██║ ██║ ██╔══██║██║ ██║╚════██║ ██║ \n' +
|
|
14
|
+
'╚██████╗╚██████╗██║ ██║╚██████╔╝███████║ ██║ \n' +
|
|
15
|
+
' ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ \n';
|
|
16
|
+
|
|
17
|
+
function renderBanner() {
|
|
18
|
+
let version = '';
|
|
19
|
+
try {
|
|
20
|
+
version = require('../package.json').version;
|
|
21
|
+
} catch {
|
|
22
|
+
// package.json missing — banner still renders without a version.
|
|
23
|
+
}
|
|
24
|
+
const tagline = 'Multi-profile launcher for Claude Code';
|
|
25
|
+
const versionLine = version ? `v${version} — ${tagline}` : tagline;
|
|
26
|
+
return BANNER + ' ' + versionLine + '\n\n';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { renderBanner, BANNER };
|