@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 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();