@hasna/accounts 0.1.13 → 0.1.15
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/README.md +23 -23
- package/dist/cli.js +22 -6
- package/dist/index.js +19 -3
- package/dist/lib/import-profile.d.ts.map +1 -1
- package/dist/lib/keychain.d.ts +1 -0
- package/dist/lib/keychain.d.ts.map +1 -1
- package/dist/mcp.js +18 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,23 +42,23 @@ accounts login work # run /login inside Claude, then /exit; accounts auto
|
|
|
42
42
|
accounts login personal # same: login, exit; it becomes the live/default account
|
|
43
43
|
|
|
44
44
|
# 4. Switch
|
|
45
|
-
accounts apply work
|
|
45
|
+
accounts apply work # Cursor / VS Code — live ~/.claude auth
|
|
46
46
|
accounts apply personal
|
|
47
47
|
|
|
48
48
|
# Or terminal-only (parallel sessions OK):
|
|
49
|
-
accounts launch work
|
|
50
|
-
eval "$(accounts env personal
|
|
49
|
+
accounts launch work
|
|
50
|
+
eval "$(accounts env personal)" # other terminal
|
|
51
51
|
|
|
52
52
|
# Or supervised: lets MCP switch/restart this Claude process automatically
|
|
53
|
-
accounts use work
|
|
53
|
+
accounts use work
|
|
54
54
|
accounts run claude --resume
|
|
55
|
-
accounts switch personal --
|
|
55
|
+
accounts switch personal --supervisor # from another terminal
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
After `accounts login <name
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
After `accounts login <name>`, `accounts` snapshots the auth Claude wrote,
|
|
59
|
+
updates the detected email, and applies that profile to live `~/.claude` paths
|
|
60
|
+
automatically. `accounts apply` still refuses profiles without auth so live OAuth
|
|
61
|
+
is not wiped.
|
|
62
62
|
|
|
63
63
|
## Three pointers (active, applied, isolated)
|
|
64
64
|
|
|
@@ -94,24 +94,24 @@ Implementation details: [docs/IMPLEMENT.md](docs/IMPLEMENT.md).
|
|
|
94
94
|
|---------|-------------|
|
|
95
95
|
| `accounts add <name>` | Create a profile. `--tool`, `--email`, `--dir`, `--description`. |
|
|
96
96
|
| `accounts import [name]` | Import existing config dir (default `~/.claude`). `--copy` for managed copy. |
|
|
97
|
-
| `accounts login <name
|
|
98
|
-
| `accounts apply <name
|
|
97
|
+
| `accounts login <name>` | Launch the profile's tool login flow in an isolated profile dir. Use `--tool` only for new or ambiguous profiles. |
|
|
98
|
+
| `accounts apply <name>` | Apply profile auth to live Claude paths (requires snapshot; Claude-only). |
|
|
99
99
|
| `accounts pick` | Interactive picker; default applies. `--env`, `--no-act`. |
|
|
100
|
-
| `accounts switch <name
|
|
101
|
-
| `accounts switch <name> --
|
|
102
|
-
| `accounts use <name
|
|
100
|
+
| `accounts switch <name>` | Switch profile and print a restart/resume command. Add `--resume`, `--launch`, or `--permissions <preset>`. Use `--tool` only when ambiguous. |
|
|
101
|
+
| `accounts switch <name> --supervisor` | Ask a running `accounts run <tool>` supervisor to restart under that profile. Supports `--permissions <preset>`. |
|
|
102
|
+
| `accounts use <name>` | Mark profile active; prints apply/env hints. |
|
|
103
103
|
| `accounts list` (`ls`) | List profiles (`●` active, `◉` applied, `●◉` both). |
|
|
104
104
|
| `accounts show <name> --tool <tool>` | Profile details including active/applied flags. |
|
|
105
105
|
| `accounts current` | Active profile per tool (with applied hint). |
|
|
106
106
|
| `accounts active [tool]` | Print active profile name (scripting). |
|
|
107
107
|
| `accounts applied [tool]` | Print applied profile name (scripting). |
|
|
108
|
-
| `accounts env [name]
|
|
109
|
-
| `accounts launch <name
|
|
108
|
+
| `accounts env [name]` | Print one or more `export ...` lines for the profile. Use `--tool` only when ambiguous or when no name is passed. |
|
|
109
|
+
| `accounts launch <name>` | Launch tool once with profile env. Supports `--permissions <preset>`. |
|
|
110
110
|
| `accounts run <tool> [args...]` | Run a tool under the supervisor so MCP/CLI can switch and restart it. Supports `--permissions <preset>`. |
|
|
111
111
|
| `accounts supervisor status [tool]` | Show running supervisors. |
|
|
112
|
-
| `accounts supervisor switch <name
|
|
112
|
+
| `accounts supervisor switch <name>` | Switch a running supervisor to another profile. Use `--tool` only when ambiguous. |
|
|
113
113
|
| `accounts supervisor stop <tool>` | Stop a running supervisor and its child process. |
|
|
114
|
-
| `accounts shell <name
|
|
114
|
+
| `accounts shell <name>` | Subshell with profile env. |
|
|
115
115
|
| `accounts hook install` | Install `claude()` wrapper — see [docs/hook.md](docs/hook.md). |
|
|
116
116
|
| `accounts hook uninstall` | Remove hook script. |
|
|
117
117
|
| `accounts hook path` | Print hook script path. |
|
|
@@ -140,7 +140,7 @@ Add it to Claude/Codex/opencode/Cursor MCP config as a command server named
|
|
|
140
140
|
For automatic agent restarts, start the agent through `accounts run`:
|
|
141
141
|
|
|
142
142
|
```bash
|
|
143
|
-
accounts use account001
|
|
143
|
+
accounts use account001
|
|
144
144
|
accounts run claude --resume
|
|
145
145
|
```
|
|
146
146
|
|
|
@@ -157,10 +157,10 @@ handoff behavior and returns a command such as:
|
|
|
157
157
|
Human equivalent:
|
|
158
158
|
|
|
159
159
|
```bash
|
|
160
|
-
accounts switch account001 --
|
|
161
|
-
accounts switch account001 --
|
|
162
|
-
accounts switch account001 --
|
|
163
|
-
accounts switch account001 --
|
|
160
|
+
accounts switch account001 --resume
|
|
161
|
+
accounts switch account001 --resume --launch
|
|
162
|
+
accounts switch account001 --resume --permissions dangerous
|
|
163
|
+
accounts switch account001 --supervisor
|
|
164
164
|
accounts switch codex-work --tool codex --resume
|
|
165
165
|
accounts switch ops --tool opencode --resume
|
|
166
166
|
```
|
package/dist/cli.js
CHANGED
|
@@ -42835,6 +42835,22 @@ function readKeychainAccount() {
|
|
|
42835
42835
|
return;
|
|
42836
42836
|
}
|
|
42837
42837
|
}
|
|
42838
|
+
function bufferText(value) {
|
|
42839
|
+
if (typeof value === "string")
|
|
42840
|
+
return value;
|
|
42841
|
+
if (value instanceof Uint8Array)
|
|
42842
|
+
return new TextDecoder().decode(value);
|
|
42843
|
+
return;
|
|
42844
|
+
}
|
|
42845
|
+
function keychainWriteFailureMessage(err) {
|
|
42846
|
+
const record = err && typeof err === "object" ? err : {};
|
|
42847
|
+
const stderr = bufferText(record.stderr);
|
|
42848
|
+
const stdout = bufferText(record.stdout);
|
|
42849
|
+
const detail = (stderr || stdout || "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).at(-1);
|
|
42850
|
+
if (detail)
|
|
42851
|
+
return detail;
|
|
42852
|
+
return typeof record.status === "number" ? `security exited with status ${record.status}` : "security command failed";
|
|
42853
|
+
}
|
|
42838
42854
|
function writeClaudeKeychain(cred) {
|
|
42839
42855
|
if (!keychainSupported()) {
|
|
42840
42856
|
throw new AccountsError("macOS keychain is only available on darwin");
|
|
@@ -42848,7 +42864,7 @@ function writeClaudeKeychain(cred) {
|
|
|
42848
42864
|
stdio: ["ignore", "pipe", "pipe"]
|
|
42849
42865
|
});
|
|
42850
42866
|
} catch (err) {
|
|
42851
|
-
throw new AccountsError(`keychain write failed: ${err
|
|
42867
|
+
throw new AccountsError(`keychain write failed: ${keychainWriteFailureMessage(err)}`);
|
|
42852
42868
|
}
|
|
42853
42869
|
}
|
|
42854
42870
|
|
|
@@ -43351,11 +43367,11 @@ function importProfile(opts) {
|
|
|
43351
43367
|
ensureProfileAuthSnapshot(profile.dir, tool);
|
|
43352
43368
|
return profile;
|
|
43353
43369
|
}
|
|
43354
|
-
function ensureProfileForLogin(name, toolId
|
|
43370
|
+
function ensureProfileForLogin(name, toolId) {
|
|
43355
43371
|
const existing = findProfileByName(name, toolId);
|
|
43356
43372
|
if (existing)
|
|
43357
43373
|
return existing;
|
|
43358
|
-
return addProfile({ name, tool: toolId, description: "created for login" });
|
|
43374
|
+
return addProfile({ name, tool: toolId ?? DEFAULT_TOOL, description: "created for login" });
|
|
43359
43375
|
}
|
|
43360
43376
|
function findProfileByName(name, toolId) {
|
|
43361
43377
|
try {
|
|
@@ -43986,7 +44002,7 @@ program2.command("add").argument("<name>", "profile name (lowercase, hyphenated)
|
|
|
43986
44002
|
console.log(` config dir: ${p.dir}`);
|
|
43987
44003
|
console.log(` email: ${p.email ?? source_default.dim("(none — set with `accounts set " + p.name + " --email ...`)")}`);
|
|
43988
44004
|
const tool = getTool(p.tool);
|
|
43989
|
-
console.log(source_default.dim(` launch it: accounts launch ${p.name}
|
|
44005
|
+
console.log(source_default.dim(` launch it: accounts launch ${p.name} (sets ${tool.envVar} and runs ${tool.bin})`));
|
|
43990
44006
|
}));
|
|
43991
44007
|
program2.command("list").alias("ls").description("list all profiles").option("-t, --tool <tool>", "filter by tool").option("--json", "output JSON").action(action((opts) => {
|
|
43992
44008
|
const profiles = listProfiles(opts.tool);
|
|
@@ -44051,9 +44067,9 @@ program2.command("import").argument("[name]", "profile name (default: main)").de
|
|
|
44051
44067
|
console.log(source_default.green(`✓ imported profile ${source_default.bold(p.name)}`));
|
|
44052
44068
|
console.log(` config dir: ${p.dir}`);
|
|
44053
44069
|
console.log(` email: ${p.email ?? source_default.dim("(none)")}`);
|
|
44054
|
-
console.log(source_default.dim(` next: accounts login ${p.name}
|
|
44070
|
+
console.log(source_default.dim(` next: accounts login ${p.name} OR accounts apply ${p.name}`));
|
|
44055
44071
|
}));
|
|
44056
|
-
program2.command("login").argument("<name>", "profile name").description("launch the tool's login flow inside an isolated profile dir").option("-t, --tool <tool>", "tool"
|
|
44072
|
+
program2.command("login").argument("<name>", "profile name").description("launch the tool's login flow inside an isolated profile dir").option("-t, --tool <tool>", "tool when creating a missing profile or when the profile name is ambiguous").action(action((name, opts) => {
|
|
44057
44073
|
const profile = ensureProfileForLogin(name, opts.tool);
|
|
44058
44074
|
const tool = getTool(profile.tool);
|
|
44059
44075
|
const env2 = profileEnv(profile, tool);
|
package/dist/index.js
CHANGED
|
@@ -4481,6 +4481,22 @@ function readKeychainAccount() {
|
|
|
4481
4481
|
return;
|
|
4482
4482
|
}
|
|
4483
4483
|
}
|
|
4484
|
+
function bufferText(value) {
|
|
4485
|
+
if (typeof value === "string")
|
|
4486
|
+
return value;
|
|
4487
|
+
if (value instanceof Uint8Array)
|
|
4488
|
+
return new TextDecoder().decode(value);
|
|
4489
|
+
return;
|
|
4490
|
+
}
|
|
4491
|
+
function keychainWriteFailureMessage(err) {
|
|
4492
|
+
const record = err && typeof err === "object" ? err : {};
|
|
4493
|
+
const stderr = bufferText(record.stderr);
|
|
4494
|
+
const stdout = bufferText(record.stdout);
|
|
4495
|
+
const detail = (stderr || stdout || "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).at(-1);
|
|
4496
|
+
if (detail)
|
|
4497
|
+
return detail;
|
|
4498
|
+
return typeof record.status === "number" ? `security exited with status ${record.status}` : "security command failed";
|
|
4499
|
+
}
|
|
4484
4500
|
function writeClaudeKeychain(cred) {
|
|
4485
4501
|
if (!keychainSupported()) {
|
|
4486
4502
|
throw new AccountsError("macOS keychain is only available on darwin");
|
|
@@ -4494,7 +4510,7 @@ function writeClaudeKeychain(cred) {
|
|
|
4494
4510
|
stdio: ["ignore", "pipe", "pipe"]
|
|
4495
4511
|
});
|
|
4496
4512
|
} catch (err) {
|
|
4497
|
-
throw new AccountsError(`keychain write failed: ${err
|
|
4513
|
+
throw new AccountsError(`keychain write failed: ${keychainWriteFailureMessage(err)}`);
|
|
4498
4514
|
}
|
|
4499
4515
|
}
|
|
4500
4516
|
|
|
@@ -5069,11 +5085,11 @@ function importProfile(opts) {
|
|
|
5069
5085
|
ensureProfileAuthSnapshot(profile.dir, tool);
|
|
5070
5086
|
return profile;
|
|
5071
5087
|
}
|
|
5072
|
-
function ensureProfileForLogin(name, toolId
|
|
5088
|
+
function ensureProfileForLogin(name, toolId) {
|
|
5073
5089
|
const existing = findProfileByName(name, toolId);
|
|
5074
5090
|
if (existing)
|
|
5075
5091
|
return existing;
|
|
5076
|
-
return addProfile({ name, tool: toolId, description: "created for login" });
|
|
5092
|
+
return addProfile({ name, tool: toolId ?? DEFAULT_TOOL, description: "created for login" });
|
|
5077
5093
|
}
|
|
5078
5094
|
function findProfileByName(name, toolId) {
|
|
5079
5095
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-profile.d.ts","sourceRoot":"","sources":["../../src/lib/import-profile.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa;;;;;;;;EAqChD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"import-profile.d.ts","sourceRoot":"","sources":["../../src/lib/import-profile.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa;;;;;;;;EAqChD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;;;;;;;;EAIlE"}
|
package/dist/lib/keychain.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface KeychainCredential {
|
|
|
8
8
|
export declare function assertAllowedKeychainCredential(cred: KeychainCredential): void;
|
|
9
9
|
/** Read Claude Code OAuth payload from macOS login keychain. */
|
|
10
10
|
export declare function readClaudeKeychain(): KeychainCredential | undefined;
|
|
11
|
+
export declare function keychainWriteFailureMessage(err: unknown): string;
|
|
11
12
|
/** Write Claude Code credentials into the login keychain (replaces existing entry). */
|
|
12
13
|
export declare function writeClaudeKeychain(cred: KeychainCredential): void;
|
|
13
14
|
//# sourceMappingURL=keychain.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keychain.d.ts","sourceRoot":"","sources":["../../src/lib/keychain.ts"],"names":[],"mappings":"AAKA,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,yFAAyF;AACzF,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAU9E;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,IAAI,kBAAkB,GAAG,SAAS,CAgBnE;
|
|
1
|
+
{"version":3,"file":"keychain.d.ts","sourceRoot":"","sources":["../../src/lib/keychain.ts"],"names":[],"mappings":"AAKA,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,yFAAyF;AACzF,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAU9E;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,IAAI,kBAAkB,GAAG,SAAS,CAgBnE;AAsBD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAWhE;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAqBlE"}
|
package/dist/mcp.js
CHANGED
|
@@ -17129,6 +17129,22 @@ function readKeychainAccount() {
|
|
|
17129
17129
|
return;
|
|
17130
17130
|
}
|
|
17131
17131
|
}
|
|
17132
|
+
function bufferText(value) {
|
|
17133
|
+
if (typeof value === "string")
|
|
17134
|
+
return value;
|
|
17135
|
+
if (value instanceof Uint8Array)
|
|
17136
|
+
return new TextDecoder().decode(value);
|
|
17137
|
+
return;
|
|
17138
|
+
}
|
|
17139
|
+
function keychainWriteFailureMessage(err) {
|
|
17140
|
+
const record3 = err && typeof err === "object" ? err : {};
|
|
17141
|
+
const stderr = bufferText(record3.stderr);
|
|
17142
|
+
const stdout = bufferText(record3.stdout);
|
|
17143
|
+
const detail = (stderr || stdout || "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).at(-1);
|
|
17144
|
+
if (detail)
|
|
17145
|
+
return detail;
|
|
17146
|
+
return typeof record3.status === "number" ? `security exited with status ${record3.status}` : "security command failed";
|
|
17147
|
+
}
|
|
17132
17148
|
function writeClaudeKeychain(cred) {
|
|
17133
17149
|
if (!keychainSupported()) {
|
|
17134
17150
|
throw new AccountsError("macOS keychain is only available on darwin");
|
|
@@ -17142,7 +17158,7 @@ function writeClaudeKeychain(cred) {
|
|
|
17142
17158
|
stdio: ["ignore", "pipe", "pipe"]
|
|
17143
17159
|
});
|
|
17144
17160
|
} catch (err) {
|
|
17145
|
-
throw new AccountsError(`keychain write failed: ${err
|
|
17161
|
+
throw new AccountsError(`keychain write failed: ${keychainWriteFailureMessage(err)}`);
|
|
17146
17162
|
}
|
|
17147
17163
|
}
|
|
17148
17164
|
|
|
@@ -17603,7 +17619,7 @@ function ok(data) {
|
|
|
17603
17619
|
function fail(message) {
|
|
17604
17620
|
return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
|
|
17605
17621
|
}
|
|
17606
|
-
var server = new Server({ name: "accounts", version: "0.1.
|
|
17622
|
+
var server = new Server({ name: "accounts", version: "0.1.15" }, { capabilities: { tools: {} } });
|
|
17607
17623
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
17608
17624
|
tools: [
|
|
17609
17625
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/accounts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "Manage and switch between multiple Claude Code (and other AI coding tool) profiles/accounts locally — isolated config dirs, per-account email, one-command switching.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|