@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 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 --tool claude # Cursor / VS Code — live ~/.claude auth
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 --tool claude
50
- eval "$(accounts env personal --tool claude)" # other terminal
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 --tool claude
53
+ accounts use work
54
54
  accounts run claude --resume
55
- accounts switch personal --tool claude --supervisor # from another terminal
55
+ accounts switch personal --supervisor # from another terminal
56
56
  ```
57
57
 
58
- After `accounts login <name> --tool claude`, `accounts` snapshots the auth Claude
59
- wrote, updates the detected email, and applies that profile to live `~/.claude`
60
- paths automatically. `accounts apply` still refuses profiles without auth so live
61
- OAuth is not wiped.
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> --tool <tool>` | Launch the tool's login flow in an isolated profile dir. |
98
- | `accounts apply <name> --tool claude` | Apply profile auth to live Claude paths (requires snapshot; Claude-only). |
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> --tool <tool>` | Switch profile and print a restart/resume command. Add `--resume`, `--launch`, or `--permissions <preset>`. |
101
- | `accounts switch <name> --tool <tool> --supervisor` | Ask a running `accounts run <tool>` supervisor to restart under that profile. Supports `--permissions <preset>`. |
102
- | `accounts use <name> --tool <tool>` | Mark profile active; prints apply/env hints. |
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] --tool <tool>` | Print one or more `export ...` lines for the profile. |
109
- | `accounts launch <name> --tool <tool>` | Launch tool once with profile env. Supports `--permissions <preset>`. |
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> --tool <tool>` | Switch a running supervisor to another profile. |
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> --tool <tool>` | Subshell with profile env. |
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 --tool claude
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 --tool claude --resume
161
- accounts switch account001 --tool claude --resume --launch
162
- accounts switch account001 --tool claude --resume --permissions dangerous
163
- accounts switch account001 --tool claude --supervisor
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.message}`);
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 = DEFAULT_TOOL) {
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} --tool ${p.tool} (sets ${tool.envVar} and runs ${tool.bin})`));
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} --tool ${p.tool} OR accounts apply ${p.name} --tool ${p.tool}`));
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", DEFAULT_TOOL).action(action((name, opts) => {
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.message}`);
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 = DEFAULT_TOOL) {
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,SAAe;;;;;;;;EAIxE"}
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"}
@@ -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;AAgBD,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAqBlE"}
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.message}`);
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.13" }, { capabilities: { tools: {} } });
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.13",
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",