cchost 0.4.4 → 0.6.0
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 +112 -0
- package/README.md +114 -44
- package/bin/cc.js +6 -1
- package/lib/actions.js +290 -0
- package/lib/banner.js +3 -1
- package/lib/ccforward.js +77 -0
- package/lib/cli.js +363 -104
- package/lib/color.js +3 -1
- package/lib/copy.js +43 -41
- package/lib/doctor.js +211 -68
- package/lib/env.js +65 -9
- package/lib/profiles.js +47 -14
- package/lib/share.js +124 -6
- package/lib/spawn.js +2 -1
- package/lib/ui/login.html +117 -0
- package/lib/ui/page.html +1171 -0
- package/lib/ui/server.js +384 -0
- package/lib/ui/tokens.css +80 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,118 @@ 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.6.0] - 2026-11-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`cchost ui`: a local web view.** One page shows every profile, the state
|
|
13
|
+
of its 7 resources, its login and endpoint, the shared pool and doctor
|
|
14
|
+
results, and lets you add and remove profiles, share or unshare groups, copy
|
|
15
|
+
from `~/.claude/` and apply doctor fixes. Every change is previewed per
|
|
16
|
+
resource before it runs and reported step by step afterwards (Activity).
|
|
17
|
+
Zero dependencies; served on `127.0.0.1` with a Host-header check, strict
|
|
18
|
+
CSP, and no endpoint tokens ever sent to the page.
|
|
19
|
+
- **Web view sign-in, like rclone's web GUI.** `cchost ui` prints a username
|
|
20
|
+
and a per-run random password and opens a one-time sign-in link; the browser
|
|
21
|
+
gets an expiring HttpOnly session (`--session`, default 8h) and can sign
|
|
22
|
+
out. `--user` / `--pass` set your own credentials. Failed sign-ins are
|
|
23
|
+
rate-limited.
|
|
24
|
+
- **Fix doctor issues from the web view.** Per-issue Fix buttons with a
|
|
25
|
+
preview; fixes that need `--force` in the CLI ask for confirmation; manual
|
|
26
|
+
steps show a copyable command.
|
|
27
|
+
- **Web view polish.** Collapsible sidebar (remembered), share/private changes
|
|
28
|
+
can be reverted before applying by clicking the current side again, and
|
|
29
|
+
subtle motion (view and panel entrances, card hover, expanding Doctor
|
|
30
|
+
groups) that switches off under reduced motion.
|
|
31
|
+
|
|
32
|
+
- **`cchost add <profile> --private[=projects,tools,config]`** creates a
|
|
33
|
+
profile whose chosen resource groups (or all 7) start private and empty
|
|
34
|
+
instead of shared. Nothing from `~/.claude/` is copied in, unlike
|
|
35
|
+
`cchost unlink`. Works with `--custom`.
|
|
36
|
+
- **Private-by-choice record.** `add --private` and `cchost unlink` record
|
|
37
|
+
private resources in `<profile>/.cc-private.json`; `cchost link` removes
|
|
38
|
+
them. `cchost doctor` reports these as `private by choice` and `--fix` no
|
|
39
|
+
longer re-shares an empty or absent private resource. Profiles without the
|
|
40
|
+
file behave as before.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- **`cc` passes compiler calls to the real C compiler.** When the legacy `cc`
|
|
45
|
+
alias is run with anything other than a cchost command (`cc -c foo.c`,
|
|
46
|
+
`cc --version`, …), it runs the next `cc` on `PATH` that isn't cchost, so
|
|
47
|
+
`make`, `node-gyp`, and configure scripts work even when npm's bin directory
|
|
48
|
+
comes before `/usr/bin`. cchost commands (`cc use work`) and bare `cc` are
|
|
49
|
+
unchanged. Use `cchost --version` for cchost's own version.
|
|
50
|
+
|
|
51
|
+
### CI
|
|
52
|
+
|
|
53
|
+
- Releases now create the `vX.Y.Z` tag and GitHub Release (notes from this
|
|
54
|
+
changelog) right after the npm publish. Actions updated to v7.
|
|
55
|
+
|
|
56
|
+
## [0.5.0] - 2026-11-07
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- **`cchost` command.** The CLI now installs as both `cchost` (primary) and
|
|
61
|
+
`cc` (legacy alias). `cc` is the system C compiler on macOS and Linux, so
|
|
62
|
+
docs, help, and new scripts use `cchost`; the alias stays for backwards
|
|
63
|
+
compatibility.
|
|
64
|
+
- **Inherited-auth warning.** `cchost use` now warns when `ANTHROPIC_API_KEY`,
|
|
65
|
+
`ANTHROPIC_AUTH_TOKEN`, or `CLAUDE_CODE_OAUTH_TOKEN` is set in the shell for a
|
|
66
|
+
subscription profile, because those variables can silently override the
|
|
67
|
+
profile's login. It does not strip them.
|
|
68
|
+
- **Endpoint environment isolation.** Endpoint profiles now drop inherited
|
|
69
|
+
`ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN`, and
|
|
70
|
+
`ANTHROPIC_BASE_URL` values the profile does not set itself, with a short
|
|
71
|
+
notice listing what was removed.
|
|
72
|
+
- **macOS login visibility.** `cchost list` reports an inferred Keychain login
|
|
73
|
+
as `true` instead of `false`, exposes `credentialSource` in `--json`, and
|
|
74
|
+
`cchost doctor` explains that Keychain entries are namespaced by the profile's
|
|
75
|
+
exact `CLAUDE_CONFIG_DIR` path.
|
|
76
|
+
- **See what a profile shares.** `cchost list <profile>` prints each of the 7
|
|
77
|
+
resources as `shared`, `private`, `empty`, `missing`, or `foreign-link`;
|
|
78
|
+
`--json` adds a `resources` object.
|
|
79
|
+
- **`--dry-run`** on `cchost link`, `unlink`, and `copy` prints what would
|
|
80
|
+
change without touching the filesystem.
|
|
81
|
+
- **`cchost help sharing`**: a task-oriented guide to what is shared and how to
|
|
82
|
+
make a resource private, share it again, or copy into a profile.
|
|
83
|
+
|
|
84
|
+
### Changed
|
|
85
|
+
|
|
86
|
+
- All README examples, help text, and error hints now use `cchost`.
|
|
87
|
+
- `cchost doctor` no longer reports `/usr/bin/cc` or a real C compiler
|
|
88
|
+
(clang, gcc, ccache) as cchost; a `cc` entry counts only when it resolves to
|
|
89
|
+
cchost, and the two shims from one install still count as one entry.
|
|
90
|
+
- README now separates **credential** isolation from the default shared pool.
|
|
91
|
+
`projects/` (full session transcripts) and `settings.json` / `mcp.json`
|
|
92
|
+
(code-executing config) are shared across profiles by default, and are
|
|
93
|
+
documented as a privacy/security trade-off rather than as isolated state.
|
|
94
|
+
|
|
95
|
+
### Fixed
|
|
96
|
+
|
|
97
|
+
- `cchost link` reports a symlink that points outside `~/.claude/` as
|
|
98
|
+
`foreign-link` instead of claiming it is already linked.
|
|
99
|
+
- `cchost doctor --fix` prints and uses the post-fix results; `--json --fix`
|
|
100
|
+
is supported again and emits one post-fix JSON report (fix logs go to stderr).
|
|
101
|
+
- `cchost doctor` no longer warns that macOS subscription profiles may share
|
|
102
|
+
one Keychain login; it explains that entries are namespaced by the exact
|
|
103
|
+
profile path (renaming or moving a profile requires a new login), and stays
|
|
104
|
+
silent when no profile uses a Keychain login.
|
|
105
|
+
- `cchost help migrate` prints command-specific help.
|
|
106
|
+
- `.cc-env.json` is created user-only; optional non-string fields are ignored
|
|
107
|
+
instead of making the profile unusable.
|
|
108
|
+
- Help banner shows the version again, and `NO_COLOR` follows no-color.org
|
|
109
|
+
(a non-empty value disables color; `NO_COLOR=""` leaves it enabled).
|
|
110
|
+
|
|
111
|
+
### Known limitations
|
|
112
|
+
|
|
113
|
+
- **macOS Keychain entries are keyed by the exact profile path.** Claude Code
|
|
114
|
+
(verified with 2.1.319) stores each profile's OAuth token under a service
|
|
115
|
+
name derived from the `CLAUDE_CONFIG_DIR` string, so renaming, moving, or copying a profile — or
|
|
116
|
+
accessing it through a different path spelling or symlinked home — requires a
|
|
117
|
+
fresh login. `cchost list` infers the login from `.claude.json`; it does not
|
|
118
|
+
read the Keychain secret or verify that the token is still live.
|
|
119
|
+
|
|
8
120
|
## [0.4.4] - 2026-06-19
|
|
9
121
|
|
|
10
122
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# cchost
|
|
2
2
|
|
|
3
|
-
> **nvm, but for your Claude Code accounts.** Works on Windows, Linux, and macOS.
|
|
3
|
+
> **nvm, but for your Claude Code accounts.** Works on Windows, Linux, and macOS — see [Platform notes](#platform-notes) for macOS credential-storage caveats.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/cchost)
|
|
6
6
|
[](https://github.com/allenhack638/cchost/actions/workflows/ci.yml)
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
[](#install)
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<img src="https://raw.githubusercontent.com/allenhack638/cchost/master/docs/demo.png" alt="cchost CLI —
|
|
12
|
+
<img src="https://raw.githubusercontent.com/allenhack638/cchost/master/docs/demo.png" alt="cchost CLI — cchost list showing masked emails and shared resource counts" width="100%">
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
`cchost` is a multi-account profile manager for [Claude Code](https://code.claude.com).
|
|
16
16
|
|
|
17
|
-
- **Isolated
|
|
18
|
-
- **Shared
|
|
17
|
+
- **Isolated credentials** — each profile is a complete `CLAUDE_CONFIG_DIR` with its own login, endpoint, and credential files. Credentials are never copied between profiles (on macOS, see [Platform notes](#platform-notes) for Keychain caveats). Switch with `cchost use <name>`.
|
|
18
|
+
- **Shared tooling and history by default** — `skills/`, `agents/`, `commands/`, `projects/`, and the config files (`mcp.json`, `settings.json`, `CLAUDE.md`) link across all profiles. That includes session transcripts and code-executing config; see [Sharing model](#sharing-model) before using profiles for separated trust boundaries.
|
|
19
19
|
- **Custom endpoints** — route a profile through any Anthropic-compatible API (Moonshot, OpenRouter, self-hosted vLLM, corporate proxies) instead of Anthropic OAuth.
|
|
20
20
|
- **Zero runtime dependencies** — single Node CLI on your `PATH`. Identical behavior across PowerShell, cmd, bash, zsh, and fish.
|
|
21
21
|
|
|
@@ -27,32 +27,59 @@ npm install -g cchost
|
|
|
27
27
|
|
|
28
28
|
Requires Node.js 18+ and Claude Code 2.1.140+ (`npm install -g @anthropic-ai/claude-code`).
|
|
29
29
|
|
|
30
|
+
`cchost` is the primary command. The same binary is also installed as `cc` for
|
|
31
|
+
backwards compatibility. Because `cc` is also the C compiler on macOS and
|
|
32
|
+
Linux, `cc` only acts as cchost for cchost commands (`cc use work`, `cc list`,
|
|
33
|
+
…); anything else (`cc -c foo.c`, `cc --version`) is passed to the real
|
|
34
|
+
compiler further down `PATH`, so builds keep working. Prefer `cchost` in
|
|
35
|
+
scripts and daily use; `cchost --version` prints cchost's version.
|
|
36
|
+
|
|
30
37
|
## Quickstart
|
|
31
38
|
|
|
32
39
|
```bash
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
cchost add work # create a profile
|
|
41
|
+
cchost use work # launch Claude under it (prompts for login on first run)
|
|
42
|
+
cchost use work --resume # resume the last conversation
|
|
43
|
+
cchost list # see all profiles
|
|
44
|
+
cchost remove old-profile # delete a profile
|
|
45
|
+
cchost ui # see and change everything in your browser
|
|
38
46
|
```
|
|
39
47
|
|
|
48
|
+
## Web view
|
|
49
|
+
|
|
50
|
+
`cchost ui` opens a local page that shows every profile, what each one shares with `~/.claude/`, its login and endpoint, and the doctor results. You can add and remove profiles, switch a group between shared and private, copy from `~/.claude/` and apply doctor fixes from the page. Every change shows a per-resource preview first (the same result as `--dry-run`) and, once applied, lists each step it took; the Activity view keeps the history for the session.
|
|
51
|
+
|
|
52
|
+
Sign-in works like rclone's web GUI. `cchost ui` prints a username (`cchost`) and a random password that is new every run, then opens your browser with a one-time sign-in link (valid 2 minutes). The browser keeps an HttpOnly session cookie that lasts 8 hours (`--session=30m|8h|2d`) or until `cchost ui` stops; the sidebar's Sign out ends it early. Wrong passwords are rate-limited.
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
cchost ui running at http://127.0.0.1:52134/
|
|
56
|
+
|
|
57
|
+
Username: cchost
|
|
58
|
+
Password: k7Qp-3mZx-Wb9t-Lr2v
|
|
59
|
+
Sessions last 8h. The password is new every run.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The page runs on `127.0.0.1` only. Endpoint tokens are never sent to the page and emails are masked. `--port=N` picks a port, `--no-open` prints the one-time link instead of opening a browser, and `--user=NAME` / `--pass=PASSWORD` set your own credentials (a random password is safer: `--pass` ends up in shell history). Ctrl+C stops it.
|
|
63
|
+
|
|
64
|
+
In Doctor, every issue with an automatic fix has its own **Fix** button with a preview; fixes the CLI only applies with `--fix --force` (such as resetting a corrupt `.claude.json`) are marked **Fix…** and ask you to confirm. Issues that need a manual step show the command with a copy button.
|
|
65
|
+
|
|
40
66
|
## Commands
|
|
41
67
|
|
|
42
68
|
| Command | What it does |
|
|
43
69
|
| --- | --- |
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
54
|
-
|
|
55
|
-
|
|
70
|
+
| `cchost add <profile> [--private[=groups]]` | Create a subscription profile. Logs in via Anthropic OAuth on first `cchost use`. Auto-shares all 7 resources with `~/.claude/`, or starts the `--private` ones empty and unshared. |
|
|
71
|
+
| `cchost add <profile> --custom [...]` | Create or edit a custom-endpoint profile. Interactive wizard, or `--base-url=URL --token=TOKEN [--model=…]`. See [Custom endpoints](#custom-endpoints). |
|
|
72
|
+
| `cchost use <profile> [...args]` | Launch Claude under that profile. Extra args are forwarded to `claude`. |
|
|
73
|
+
| `cchost list [<profile>] [--json] [--reveal]` | List all profiles, or show one in detail including the state of each of its 7 resources. Emails and tokens are masked by default; `--reveal` prints them in full. |
|
|
74
|
+
| `cchost copy default <profile> [--force] [--dry-run]` | Seed an unlinked profile resource from `~/.claude/`. No-op for fully-shared profiles. |
|
|
75
|
+
| `cchost link <profile> [--projects\|--tools\|--config] [--dry-run]` | Link a profile's resources to `~/.claude/`. Defaults to all 7 when no flag is passed. |
|
|
76
|
+
| `cchost unlink <profile> [--projects\|--tools\|--config] [--dry-run]` | Break the link and make those resources private to the profile. Non-destructive. |
|
|
77
|
+
| `cchost remove <profile> [--force]` | Delete a profile. Requires typing the profile name. `--force` required when private resources exist. |
|
|
78
|
+
| `cchost ui [--port=N] [--no-open] [--session=8h]` | Open the local web view: see every profile and change sharing, profiles and doctor fixes with a preview first. See [Web view](#web-view). |
|
|
79
|
+
| `cchost doctor [--fix [--force]] [--json]` | Diagnose environment, storage, and platform issues. `--fix` applies safe auto-fixes; `--force` is required for destructive ones. |
|
|
80
|
+
| `cchost help [command]` | Print usage. `cchost help sharing` is a task guide to linking, unlinking, and copying. |
|
|
81
|
+
|
|
82
|
+
Sample `cchost list` output:
|
|
56
83
|
|
|
57
84
|
```
|
|
58
85
|
Profile LoggedIn Email Shared Endpoint
|
|
@@ -61,35 +88,44 @@ personal true p************.com 7/7 subscription
|
|
|
61
88
|
work true w************.com 7/7 subscription
|
|
62
89
|
```
|
|
63
90
|
|
|
64
|
-
The `Shared` column counts how many of the 7 shareable resources are linked into `~/.claude/`. `7/7` is the default; lower numbers mean one or more resources have been `
|
|
91
|
+
The `Shared` column counts how many of the 7 shareable resources are linked into `~/.claude/`. `7/7` is the default; lower numbers mean one or more resources have been `cchost unlink`ed and now hold private content.
|
|
65
92
|
|
|
66
93
|
## Sharing model
|
|
67
94
|
|
|
68
|
-
|
|
95
|
+
On Windows and Linux, anything that authenticates a profile stays per-profile and everything else is shared. On macOS, OAuth credentials live in the login Keychain rather than the profile directory — see [Platform notes](#platform-notes).
|
|
69
96
|
|
|
70
97
|
| Resource | Shared by default | Flag group |
|
|
71
98
|
| --- | :---: | --- |
|
|
72
99
|
| `projects/` | ✓ | `--projects` |
|
|
73
100
|
| `skills/`, `agents/`, `commands/` | ✓ | `--tools` |
|
|
74
101
|
| `mcp.json`, `settings.json`, `CLAUDE.md` | ✓ | `--config` |
|
|
75
|
-
| `.credentials.json`, `.claude.json`, `.cc-env.json` | never | — |
|
|
102
|
+
| `.credentials.json`, `.claude.json`, `.cc-env.json`, `.cc-private.json` | never | — |
|
|
76
103
|
| `sessions/`, `plugins/` | never | — |
|
|
77
104
|
|
|
78
|
-
Sharing uses POSIX symlinks on Linux/macOS and directory junctions on Windows (no admin or Developer Mode required). File resources fall back to a hard link on Windows when symlink creation would require elevation. Note that `mcp.json` and `settings.json` can execute arbitrary code through MCP servers and hooks — if a profile needs an isolated copy of either, run `
|
|
105
|
+
Sharing uses POSIX symlinks on Linux/macOS and directory junctions on Windows (no admin or Developer Mode required). File resources fall back to a hard link on Windows when symlink creation would require elevation. Note that `mcp.json` and `settings.json` can execute arbitrary code through MCP servers and hooks — if a profile needs an isolated copy of either, run `cchost unlink <profile> --config`.
|
|
106
|
+
|
|
107
|
+
> **Privacy note:** the defaults above are convenient, not isolated. `projects/`
|
|
108
|
+
> contains full conversation transcripts, and `settings.json` / `mcp.json` can
|
|
109
|
+
> execute hooks and MCP servers. For a work/personal split, unlink the resources
|
|
110
|
+
> that must not cross over before first use, or use a separate OS account.
|
|
111
|
+
|
|
112
|
+
To create a profile that starts private instead, use `cchost add <profile> --private` (all 7) or `--private=projects,tools,config` (just those groups). Private resources start empty — nothing from `~/.claude/` is copied in — and are recorded in `<profile>/.cc-private.json` so `cchost doctor --fix` never re-shares them.
|
|
113
|
+
|
|
114
|
+
To see exactly what a profile shares, run `cchost list <profile>` — it prints each resource as `shared`, `private`, `empty`, `missing`, or `foreign-link`. `cchost help sharing` walks through the common tasks.
|
|
79
115
|
|
|
80
|
-
To break sharing for a single profile:
|
|
116
|
+
To break sharing for a single profile (add `--dry-run` to any of these to preview first):
|
|
81
117
|
|
|
82
118
|
```bash
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
119
|
+
cchost unlink work --tools # private skills/agents/commands
|
|
120
|
+
cchost unlink work --projects # private projects/
|
|
121
|
+
cchost unlink work --config # private mcp.json/settings.json/CLAUDE.md
|
|
122
|
+
cchost unlink work # all 7 private
|
|
123
|
+
cchost link work --tools # re-share
|
|
88
124
|
```
|
|
89
125
|
|
|
90
|
-
`
|
|
126
|
+
`cchost unlink` is non-destructive — pool content is copied into the profile before the link is broken. `cchost link` refuses to overwrite existing private content; remove or relocate the private resource manually, then re-run.
|
|
91
127
|
|
|
92
|
-
Use `
|
|
128
|
+
Use `cchost copy default <profile>` to seed an unlinked resource from the current `~/.claude/`. For fully-shared profiles this is a no-op.
|
|
93
129
|
|
|
94
130
|
## Custom endpoints
|
|
95
131
|
|
|
@@ -97,43 +133,77 @@ A profile can route through any Anthropic-compatible API — Moonshot/Kimi, Open
|
|
|
97
133
|
|
|
98
134
|
> **Billing:** custom-endpoint profiles bill through the **third-party provider**, not your Anthropic subscription.
|
|
99
135
|
|
|
136
|
+
Inherited Anthropic auth/endpoint variables (`ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN`, `ANTHROPIC_BASE_URL`) are removed for endpoint profiles when the profile doesn't set them, so a shell-level key cannot override the endpoint.
|
|
137
|
+
|
|
100
138
|
```bash
|
|
101
|
-
|
|
139
|
+
cchost add kimi --custom --base-url=https://api.moonshot.ai/anthropic \
|
|
102
140
|
--token=sk-your-key \
|
|
103
141
|
--model=kimi-k2.5
|
|
104
|
-
|
|
142
|
+
cchost use kimi
|
|
105
143
|
```
|
|
106
144
|
|
|
107
|
-
Run `
|
|
145
|
+
Run `cchost add <profile> --custom` with no value flags for an interactive wizard — it prompts for every field and never echoes the token. Re-running on an existing custom-endpoint profile enters **edit mode**: the wizard prefills current values, and with flags only the flags you pass are changed.
|
|
108
146
|
|
|
109
147
|
```bash
|
|
110
|
-
|
|
111
|
-
|
|
148
|
+
cchost add kimi --custom --model=kimi-k3 # change just the model
|
|
149
|
+
cchost add kimi --custom --token=sk-rotated # rotate the API key
|
|
112
150
|
```
|
|
113
151
|
|
|
114
|
-
Subscription and custom-endpoint profiles are mutually exclusive: a profile is either one or the other for its entire lifetime. To switch, remove the profile with `
|
|
152
|
+
Subscription and custom-endpoint profiles are mutually exclusive: a profile is either one or the other for its entire lifetime. To switch, remove the profile with `cchost remove` and recreate it.
|
|
115
153
|
|
|
116
|
-
Inspect with `
|
|
154
|
+
Inspect with `cchost list <profile>` (token masked) or `cchost list <profile> --reveal` (full). The endpoint URL should not include `/v1` — Claude Code appends `/v1/messages` itself. Most providers serve a single model; `--model` applies to every tier (`opus`/`sonnet`/`haiku`/`subagent`), or override per-tier with `--opus=`, `--sonnet=`, etc.
|
|
117
155
|
|
|
118
|
-
On launch, `
|
|
156
|
+
On launch, `cchost use` prints a one-line endpoint banner to stderr:
|
|
119
157
|
|
|
120
158
|
```
|
|
121
159
|
[cchost] Profile 'kimi' → api.moonshot.ai (custom endpoint billing applies)
|
|
122
160
|
```
|
|
123
161
|
|
|
162
|
+
## Platform notes
|
|
163
|
+
|
|
164
|
+
### macOS
|
|
165
|
+
|
|
166
|
+
Claude Code stores OAuth credentials in the login **Keychain**, not in
|
|
167
|
+
`<profile>/.credentials.json`. Claude Code namespaces the Keychain entry by
|
|
168
|
+
the exact `CLAUDE_CONFIG_DIR` path (verified with Claude Code 2.1.319):
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
Claude Code-credentials-<first 8 hex of sha256(path)>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
So each profile gets its own Keychain entry. Two consequences:
|
|
175
|
+
|
|
176
|
+
- `cchost list` infers the login from `.claude.json`; it does not read the
|
|
177
|
+
Keychain secret. Treat `LoggedIn` as a login hint, not proof of a live token.
|
|
178
|
+
- The entry is keyed by the exact path string. Renaming, moving, or copying a
|
|
179
|
+
profile — or addressing it through a different path spelling or symlinked
|
|
180
|
+
home — changes the key and looks like a logout. Run `claude` under the new
|
|
181
|
+
path to log in again.
|
|
182
|
+
|
|
183
|
+
If you need guaranteed account separation on macOS, **custom-endpoint profiles**
|
|
184
|
+
(each has its own token in `.cc-env.json`) or separate macOS user accounts are
|
|
185
|
+
still the most explicit option.
|
|
186
|
+
|
|
187
|
+
### Windows and Linux
|
|
188
|
+
|
|
189
|
+
Credentials are file-based (`.credentials.json` in the profile directory), so
|
|
190
|
+
the `LoggedIn` column reflects the profile's own credential file.
|
|
191
|
+
|
|
124
192
|
## Security
|
|
125
193
|
|
|
126
|
-
`~/.claude-profiles/<profile>/` holds real OAuth credentials and API keys. Treat it like `~/.ssh`: don't commit it, don't share it, don't sync it to public cloud storage. The shipped `.gitignore` excludes profile directories. `
|
|
194
|
+
`~/.claude-profiles/<profile>/` holds real OAuth credentials and API keys. Treat it like `~/.ssh`: don't commit it, don't share it, don't sync it to public cloud storage. The shipped `.gitignore` excludes profile directories. `cchost copy` and `cchost link` never touch credential files (`.credentials.json`, `.claude.json`, `.cc-env.json`); each profile keeps its own auth state. On macOS, OAuth tokens are stored in the login Keychain instead — see [Platform notes](#platform-notes).
|
|
127
195
|
|
|
128
196
|
## Troubleshooting
|
|
129
197
|
|
|
130
|
-
Run `
|
|
198
|
+
Run `cchost doctor` first — it checks Node, Claude Code version, profile integrity, symlinks, and the shared pool.
|
|
131
199
|
|
|
132
200
|
**`Claude Code does not appear to be installed`** — install with `npm install -g @anthropic-ai/claude-code` and verify `claude --version` runs in a fresh terminal.
|
|
133
201
|
|
|
134
202
|
**`warning: Claude Code <version> is older than 2.1.140`** — earlier versions on Windows read `.claude.json` from `%USERPROFILE%` regardless of `CLAUDE_CONFIG_DIR`, breaking isolation. Run `claude update`.
|
|
135
203
|
|
|
136
|
-
**`
|
|
204
|
+
**`warning: ANTHROPIC_API_KEY ... may override the subscription login`** — a globally exported API key takes precedence over a profile's OAuth login. Unset it in that shell (`unset ANTHROPIC_API_KEY`, and the same for `ANTHROPIC_AUTH_TOKEN` / `CLAUDE_CODE_OAUTH_TOKEN`) or use a custom-endpoint profile.
|
|
205
|
+
|
|
206
|
+
**`Profile "<name>" does not exist`** — `cchost use` does not auto-create profiles. Run `cchost add <name>` first.
|
|
137
207
|
|
|
138
208
|
**Profile name rejected** — names must not contain path separators, whitespace, `..`, leading dots, or DOS reserved names (`CON`, `PRN`, `COM1`…). Use letters, digits, dashes, and underscores.
|
|
139
209
|
|
package/bin/cc.js
CHANGED
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const { run } = require('../lib/cli');
|
|
5
|
+
const { maybeForward } = require('../lib/ccforward');
|
|
5
6
|
|
|
6
7
|
(async () => {
|
|
7
8
|
try {
|
|
8
|
-
const
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
// Invoked as `cc` for a compile (`cc -c foo.c`)? Run the real compiler.
|
|
11
|
+
const forwarded = maybeForward(args);
|
|
12
|
+
if (forwarded !== null) process.exit(forwarded);
|
|
13
|
+
const code = await run(args);
|
|
9
14
|
process.exit(typeof code === 'number' ? code : 0);
|
|
10
15
|
} catch (err) {
|
|
11
16
|
const message = err && err.message ? err.message : String(err);
|