@kio_ai/aicli-switch 0.1.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/LICENSE +21 -0
- package/README.md +153 -0
- package/bin/aicli-switch.js +24 -0
- package/package.json +38 -0
- package/scripts/install.js +98 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 killaragorn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# aicli-switch
|
|
2
|
+
|
|
3
|
+
Switch between multiple Claude Code accounts without re-authenticating.
|
|
4
|
+
|
|
5
|
+
When one account hits its usage limit, just `aicli-switch another-account` — no need to `claude login` again.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
### npm (recommended)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g aicli-switch
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This downloads the pre-built binary for your platform automatically.
|
|
16
|
+
|
|
17
|
+
### Manual download
|
|
18
|
+
|
|
19
|
+
Download the binary for your OS from [Releases](https://github.com/killaragorn/aicli-switch/releases/latest):
|
|
20
|
+
|
|
21
|
+
| Platform | File |
|
|
22
|
+
|----------|------|
|
|
23
|
+
| Windows x64 | `aicli-switch-windows-amd64.exe` |
|
|
24
|
+
| macOS x64 | `aicli-switch-darwin-amd64` |
|
|
25
|
+
| macOS Apple Silicon | `aicli-switch-darwin-arm64` |
|
|
26
|
+
| Linux x64 | `aicli-switch-linux-amd64` |
|
|
27
|
+
| Linux ARM64 | `aicli-switch-linux-arm64` |
|
|
28
|
+
|
|
29
|
+
Move it to a directory in your PATH:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# macOS / Linux
|
|
33
|
+
chmod +x aicli-switch-*
|
|
34
|
+
mv aicli-switch-* /usr/local/bin/aicli-switch
|
|
35
|
+
|
|
36
|
+
# Windows — move to any directory in your PATH
|
|
37
|
+
move aicli-switch-windows-amd64.exe %USERPROFILE%\.local\bin\aicli-switch.exe
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Build from source
|
|
41
|
+
|
|
42
|
+
Requires Go 1.22+:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
git clone https://github.com/killaragorn/aicli-switch.git
|
|
46
|
+
cd aicli-switch
|
|
47
|
+
go build -o aicli-switch .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Step 1: You're logged into account A in Claude Code
|
|
54
|
+
# Save it as a profile
|
|
55
|
+
aicli-switch add work
|
|
56
|
+
|
|
57
|
+
# Step 2: Log into account B
|
|
58
|
+
claude login
|
|
59
|
+
|
|
60
|
+
# Step 3: Save account B
|
|
61
|
+
aicli-switch add personal
|
|
62
|
+
|
|
63
|
+
# Step 4: Now switch freely — no re-login needed
|
|
64
|
+
aicli-switch work # → switches to work account
|
|
65
|
+
aicli-switch personal # → switches to personal account
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Commands
|
|
69
|
+
|
|
70
|
+
| Command | Description |
|
|
71
|
+
|---------|-------------|
|
|
72
|
+
| `aicli-switch add <name>` | Save current Claude Code session as a named profile |
|
|
73
|
+
| `aicli-switch add <name> -t apikey` | Add an API Key profile (interactive) |
|
|
74
|
+
| `aicli-switch <name>` | Switch to a profile |
|
|
75
|
+
| `aicli-switch ls` | List all profiles with status |
|
|
76
|
+
| `aicli-switch status` | Show active profile details |
|
|
77
|
+
| `aicli-switch refresh [name]` | Manually refresh an OAuth token |
|
|
78
|
+
| `aicli-switch rm <name>` | Delete a profile |
|
|
79
|
+
| `aicli-switch version` | Show version |
|
|
80
|
+
|
|
81
|
+
## What It Looks Like
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
$ aicli-switch ls
|
|
85
|
+
NAME TYPE EMAIL STATUS EXPIRY
|
|
86
|
+
▶ work oauth user@company.com valid 6.9d
|
|
87
|
+
personal oauth me@gmail.com valid 4.2d
|
|
88
|
+
relay apikey - ready n/a
|
|
89
|
+
|
|
90
|
+
$ aicli-switch personal
|
|
91
|
+
Switched to profile "personal" (oauth)
|
|
92
|
+
Email: me@gmail.com
|
|
93
|
+
|
|
94
|
+
$ aicli-switch status
|
|
95
|
+
Active Profile: personal
|
|
96
|
+
Type: oauth
|
|
97
|
+
Email: me@gmail.com
|
|
98
|
+
Token: valid (expires in 4.2d)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## How It Works
|
|
102
|
+
|
|
103
|
+
### OAuth Profiles
|
|
104
|
+
|
|
105
|
+
1. **`add`** — copies your encrypted OAuth credentials (`~/.factory/auth.v2.*`) into `~/.cc-profiles/<name>/`
|
|
106
|
+
2. **`switch`** — checks if the token is expired → refreshes if needed → restores credentials to `~/.factory/`
|
|
107
|
+
3. **Token refresh** — calls Claude's OAuth endpoint with the saved refresh_token, no browser needed
|
|
108
|
+
|
|
109
|
+
### API Key Profiles
|
|
110
|
+
|
|
111
|
+
1. **`add -t apikey`** — prompts for API Key and Base URL, saves to profile
|
|
112
|
+
2. **`switch`** — updates `ANTHROPIC_API_KEY` and `ANTHROPIC_BASE_URL` in `~/.claude/settings.json`
|
|
113
|
+
|
|
114
|
+
### Storage Layout
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
~/.cc-profiles/
|
|
118
|
+
├── _active # Name of the currently active profile
|
|
119
|
+
├── work/
|
|
120
|
+
│ ├── auth.v2.file # AES-256-GCM encrypted OAuth tokens
|
|
121
|
+
│ ├── auth.v2.key # Encryption key
|
|
122
|
+
│ └── profile.json # Metadata (name, type, email, timestamps)
|
|
123
|
+
└── personal/
|
|
124
|
+
└── ...
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Security
|
|
128
|
+
|
|
129
|
+
- Credentials are **always encrypted** (AES-256-GCM), same as Claude Code itself
|
|
130
|
+
- Each profile has its own encryption key
|
|
131
|
+
- No plaintext tokens anywhere on disk
|
|
132
|
+
- The `_active` file only stores the profile name
|
|
133
|
+
|
|
134
|
+
## Update Detection
|
|
135
|
+
|
|
136
|
+
aicli-switch checks for new versions once per day (non-blocking). When an update is available:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
Update available: 0.1.0 → 0.2.0
|
|
140
|
+
Run: npm update -g aicli-switch
|
|
141
|
+
Or: https://github.com/killaragorn/aicli-switch/releases/tag/v0.2.0
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Roadmap
|
|
145
|
+
|
|
146
|
+
- [ ] OpenAI Codex CLI credential switching
|
|
147
|
+
- [ ] Gemini CLI credential switching
|
|
148
|
+
- [ ] Automatic failover on rate-limit
|
|
149
|
+
- [ ] Profile import/export
|
|
150
|
+
|
|
151
|
+
## License
|
|
152
|
+
|
|
153
|
+
MIT
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { execFileSync } = require("child_process");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
|
|
8
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
9
|
+
const binPath = path.join(__dirname, `aicli-switch${ext}`);
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(binPath)) {
|
|
12
|
+
console.error("aicli-switch binary not found. Try reinstalling:");
|
|
13
|
+
console.error(" npm install -g aicli-switch");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const result = execFileSync(binPath, process.argv.slice(2), {
|
|
19
|
+
stdio: "inherit",
|
|
20
|
+
windowsHide: true,
|
|
21
|
+
});
|
|
22
|
+
} catch (err) {
|
|
23
|
+
process.exit(err.status || 1);
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kio_ai/aicli-switch",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI tool for switching AI CLI tool credentials (Claude Code OAuth, API Keys)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude-code",
|
|
7
|
+
"oauth",
|
|
8
|
+
"account-switch",
|
|
9
|
+
"ai-cli",
|
|
10
|
+
"credential-manager"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "killaragorn",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/killaragorn/aicli-switch.git"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"aicli-switch": "bin/aicli-switch.js"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"postinstall": "node scripts/install.js"
|
|
23
|
+
},
|
|
24
|
+
"os": [
|
|
25
|
+
"win32",
|
|
26
|
+
"darwin",
|
|
27
|
+
"linux"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=16"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"bin/",
|
|
34
|
+
"scripts/",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const https = require("https");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const { execSync } = require("child_process");
|
|
8
|
+
|
|
9
|
+
const REPO = "killaragorn/aicli-switch";
|
|
10
|
+
const BIN_DIR = path.join(__dirname, "..", "bin");
|
|
11
|
+
const VERSION = require("../package.json").version;
|
|
12
|
+
|
|
13
|
+
const PLATFORM_MAP = {
|
|
14
|
+
win32: { os: "windows", arch: "amd64", ext: ".exe" },
|
|
15
|
+
darwin: { os: "darwin", arch: "amd64", ext: "" },
|
|
16
|
+
linux: { os: "linux", arch: "amd64", ext: "" },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const ARM64_OVERRIDE = {
|
|
20
|
+
darwin: { os: "darwin", arch: "arm64", ext: "" },
|
|
21
|
+
linux: { os: "linux", arch: "arm64", ext: "" },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function getPlatform() {
|
|
25
|
+
const platform = process.platform;
|
|
26
|
+
const arch = process.arch;
|
|
27
|
+
|
|
28
|
+
if (arch === "arm64" && ARM64_OVERRIDE[platform]) {
|
|
29
|
+
return ARM64_OVERRIDE[platform];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const info = PLATFORM_MAP[platform];
|
|
33
|
+
if (!info) {
|
|
34
|
+
console.error(`Unsupported platform: ${platform}/${arch}`);
|
|
35
|
+
console.error("Please build from source: go build -o aicli-switch .");
|
|
36
|
+
process.exit(0); // Don't fail npm install
|
|
37
|
+
}
|
|
38
|
+
return info;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function downloadFile(url, dest) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
function follow(u) {
|
|
44
|
+
https.get(u, { headers: { "User-Agent": "aicli-switch-npm" } }, (res) => {
|
|
45
|
+
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
46
|
+
follow(res.headers.location);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (res.statusCode !== 200) {
|
|
50
|
+
reject(new Error(`Download failed: HTTP ${res.statusCode}`));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const file = fs.createWriteStream(dest);
|
|
54
|
+
res.pipe(file);
|
|
55
|
+
file.on("finish", () => { file.close(); resolve(); });
|
|
56
|
+
file.on("error", reject);
|
|
57
|
+
}).on("error", reject);
|
|
58
|
+
}
|
|
59
|
+
follow(url);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function main() {
|
|
64
|
+
const { os: goos, arch, ext } = getPlatform();
|
|
65
|
+
const binName = `aicli-switch${ext}`;
|
|
66
|
+
const assetName = `aicli-switch-${goos}-${arch}${ext}`;
|
|
67
|
+
const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${assetName}`;
|
|
68
|
+
const dest = path.join(BIN_DIR, binName);
|
|
69
|
+
|
|
70
|
+
// Skip if binary already exists (e.g., local development)
|
|
71
|
+
if (fs.existsSync(dest)) {
|
|
72
|
+
console.log(`aicli-switch binary already exists at ${dest}`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
77
|
+
console.log(`Downloading aicli-switch v${VERSION} for ${goos}/${arch}...`);
|
|
78
|
+
console.log(` From: ${url}`);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
await downloadFile(url, dest);
|
|
82
|
+
|
|
83
|
+
// Make executable on Unix
|
|
84
|
+
if (process.platform !== "win32") {
|
|
85
|
+
fs.chmodSync(dest, 0o755);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log(`aicli-switch installed successfully!`);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error(`\nFailed to download pre-built binary: ${err.message}`);
|
|
91
|
+
console.error(`\nYou can build from source instead:`);
|
|
92
|
+
console.error(` git clone https://github.com/${REPO}.git`);
|
|
93
|
+
console.error(` cd aicli-switch && go build -o aicli-switch .`);
|
|
94
|
+
// Don't fail npm install - user can build manually
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
main();
|