@hasna/accounts 0.1.2 → 0.1.4
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 +37 -6
- package/dist/cli.js +101 -7
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +66 -4
- package/dist/lib/claude-auth.d.ts +3 -1
- package/dist/lib/claude-auth.d.ts.map +1 -1
- package/dist/lib/login.d.ts +12 -0
- package/dist/lib/login.d.ts.map +1 -0
- package/dist/lib/switch.d.ts +22 -0
- package/dist/lib/switch.d.ts.map +1 -0
- package/dist/lib/tools.d.ts.map +1 -1
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +17378 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -37,10 +37,8 @@ accounts add work --email work@company.com
|
|
|
37
37
|
accounts add personal --email me@gmail.com
|
|
38
38
|
|
|
39
39
|
# 3. Log in once per profile (isolated dir)
|
|
40
|
-
accounts login work # run /login inside Claude, then /exit
|
|
41
|
-
accounts
|
|
42
|
-
accounts login personal
|
|
43
|
-
accounts detect personal
|
|
40
|
+
accounts login work # run /login inside Claude, then /exit; accounts auto-applies it
|
|
41
|
+
accounts login personal # same: login, exit; it becomes the live/default account
|
|
44
42
|
|
|
45
43
|
# 4. Switch
|
|
46
44
|
accounts apply work --tool claude # Cursor / VS Code — live ~/.claude auth
|
|
@@ -51,8 +49,10 @@ accounts launch work --tool claude
|
|
|
51
49
|
eval "$(accounts env personal --tool claude)" # other terminal
|
|
52
50
|
```
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
After `accounts login <name> --tool claude`, `accounts` snapshots the auth Claude
|
|
53
|
+
wrote, updates the detected email, and applies that profile to live `~/.claude`
|
|
54
|
+
paths automatically. `accounts apply` still refuses profiles without auth so live
|
|
55
|
+
OAuth is not wiped.
|
|
56
56
|
|
|
57
57
|
## Three pointers (active, applied, isolated)
|
|
58
58
|
|
|
@@ -91,6 +91,7 @@ Implementation details: [docs/IMPLEMENT.md](docs/IMPLEMENT.md).
|
|
|
91
91
|
| `accounts login <name> --tool <tool>` | Launch the tool's login flow in an isolated profile dir. |
|
|
92
92
|
| `accounts apply <name> --tool claude` | Apply profile auth to live Claude paths (requires snapshot; Claude-only). |
|
|
93
93
|
| `accounts pick` | Interactive picker; default applies. `--env`, `--no-act`. |
|
|
94
|
+
| `accounts switch <name> --tool <tool>` | Switch profile and print a restart/resume command. Add `--resume`; add `--launch` to run it. |
|
|
94
95
|
| `accounts use <name> --tool <tool>` | Mark profile active; prints apply/env hints. |
|
|
95
96
|
| `accounts list` (`ls`) | List profiles (`●` active, `◉` applied, `●◉` both). |
|
|
96
97
|
| `accounts show <name> --tool <tool>` | Profile details including active/applied flags. |
|
|
@@ -108,6 +109,36 @@ Implementation details: [docs/IMPLEMENT.md](docs/IMPLEMENT.md).
|
|
|
108
109
|
|
|
109
110
|
See `accounts --help` for `set`, `rename`, `remove`, `tools`, etc.
|
|
110
111
|
|
|
112
|
+
## Agent / MCP Switching
|
|
113
|
+
|
|
114
|
+
`accounts` ships a stdio MCP server:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
accounts-mcp
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Add it to Claude/Codex/opencode/Cursor MCP config as a command server named
|
|
121
|
+
`accounts`. It exposes:
|
|
122
|
+
|
|
123
|
+
- `list_tools`
|
|
124
|
+
- `list_profiles`
|
|
125
|
+
- `current_profile`
|
|
126
|
+
- `switch_profile`
|
|
127
|
+
|
|
128
|
+
`switch_profile` applies Claude live auth when the target profile is Claude and
|
|
129
|
+
returns a restart handoff command. MCP servers cannot safely kill their parent
|
|
130
|
+
agent process, so the tool returns an instruction such as: exit this session and
|
|
131
|
+
run `CLAUDE_CONFIG_DIR=... claude --continue`.
|
|
132
|
+
|
|
133
|
+
Human equivalent:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
accounts switch account001 --tool claude --resume
|
|
137
|
+
accounts switch account001 --tool claude --resume --launch
|
|
138
|
+
accounts switch codex-work --tool codex --resume
|
|
139
|
+
accounts switch ops --tool opencode --resume
|
|
140
|
+
```
|
|
141
|
+
|
|
111
142
|
## Shell hook (optional)
|
|
112
143
|
|
|
113
144
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -6577,6 +6577,7 @@ var toolDefSchema = exports_external.object({
|
|
|
6577
6577
|
bin: exports_external.string().min(1),
|
|
6578
6578
|
loginArgs: exports_external.array(exports_external.string()).optional(),
|
|
6579
6579
|
loginHint: exports_external.string().optional(),
|
|
6580
|
+
resumeArgs: exports_external.array(exports_external.string()).optional(),
|
|
6580
6581
|
accountFile: exports_external.string().optional(),
|
|
6581
6582
|
emailPath: exports_external.array(exports_external.string()).optional()
|
|
6582
6583
|
});
|
|
@@ -6745,6 +6746,7 @@ var BUILTIN_TOOLS = [
|
|
|
6745
6746
|
defaultDir: join2(homedir2(), ".claude"),
|
|
6746
6747
|
bin: "claude",
|
|
6747
6748
|
loginHint: "run /login inside Claude, then /exit when done",
|
|
6749
|
+
resumeArgs: ["--continue"],
|
|
6748
6750
|
accountFile: ".claude.json",
|
|
6749
6751
|
emailPath: ["oauthAccount", "emailAddress"]
|
|
6750
6752
|
},
|
|
@@ -6755,7 +6757,8 @@ var BUILTIN_TOOLS = [
|
|
|
6755
6757
|
defaultDir: join2(homedir2(), ".codex"),
|
|
6756
6758
|
bin: "codex",
|
|
6757
6759
|
loginArgs: ["login"],
|
|
6758
|
-
loginHint: "complete the Codex login flow for this CODEX_HOME"
|
|
6760
|
+
loginHint: "complete the Codex login flow for this CODEX_HOME",
|
|
6761
|
+
resumeArgs: ["resume", "--last"]
|
|
6759
6762
|
},
|
|
6760
6763
|
{
|
|
6761
6764
|
id: "opencode",
|
|
@@ -6768,7 +6771,8 @@ var BUILTIN_TOOLS = [
|
|
|
6768
6771
|
defaultDir: join2(homedir2(), ".config", "opencode"),
|
|
6769
6772
|
bin: "opencode",
|
|
6770
6773
|
loginArgs: ["auth", "login"],
|
|
6771
|
-
loginHint: "complete opencode auth login for this isolated config/data root"
|
|
6774
|
+
loginHint: "complete opencode auth login for this isolated config/data root",
|
|
6775
|
+
resumeArgs: ["--continue"]
|
|
6772
6776
|
},
|
|
6773
6777
|
{
|
|
6774
6778
|
id: "cursor",
|
|
@@ -7248,8 +7252,8 @@ function snapshotLiveAuthToProfile(profileDir, _tool) {
|
|
|
7248
7252
|
writeJsonFile(profileKeychainSnapshot(profileDir), kc, profileDir);
|
|
7249
7253
|
}
|
|
7250
7254
|
}
|
|
7251
|
-
function ensureProfileAuthSnapshot(profileDir, tool) {
|
|
7252
|
-
if (hasAuthSnapshot(profileDir))
|
|
7255
|
+
function ensureProfileAuthSnapshot(profileDir, tool, opts = {}) {
|
|
7256
|
+
if (!opts.overwrite && hasAuthSnapshot(profileDir))
|
|
7253
7257
|
return;
|
|
7254
7258
|
const authDir = profileAuthDir(profileDir);
|
|
7255
7259
|
assertSafeWritePath(join6(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
|
|
@@ -7561,6 +7565,64 @@ function formatExportLines(env2) {
|
|
|
7561
7565
|
`);
|
|
7562
7566
|
}
|
|
7563
7567
|
|
|
7568
|
+
// src/lib/login.ts
|
|
7569
|
+
function finalizeLogin(name, toolId) {
|
|
7570
|
+
const profile = getProfile(name, toolId);
|
|
7571
|
+
const tool = getTool(profile.tool);
|
|
7572
|
+
if (tool.id === "claude") {
|
|
7573
|
+
ensureProfileAuthSnapshot(profile.dir, tool, { overwrite: true });
|
|
7574
|
+
redetectEmail(name, tool.id);
|
|
7575
|
+
return { profile: applyProfile(name, tool.id).profile, applied: true };
|
|
7576
|
+
}
|
|
7577
|
+
const updated = redetectEmail(name, tool.id);
|
|
7578
|
+
useProfile(name, tool.id);
|
|
7579
|
+
return { profile: updated, applied: false };
|
|
7580
|
+
}
|
|
7581
|
+
|
|
7582
|
+
// src/lib/switch.ts
|
|
7583
|
+
function shellQuote(value) {
|
|
7584
|
+
if (/^[A-Za-z0-9_./:=@+-]+$/.test(value))
|
|
7585
|
+
return value;
|
|
7586
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
7587
|
+
}
|
|
7588
|
+
function commandLine(env2, command) {
|
|
7589
|
+
return `${formatEnvAssignments(env2)} ${command.map(shellQuote).join(" ")}`.trim();
|
|
7590
|
+
}
|
|
7591
|
+
function commandFor(tool, opts) {
|
|
7592
|
+
return [tool.bin, ...opts.resume ? tool.resumeArgs ?? [] : [], ...opts.args ?? []];
|
|
7593
|
+
}
|
|
7594
|
+
function switchProfile(name, opts = {}) {
|
|
7595
|
+
const profile = getProfile(name, opts.tool);
|
|
7596
|
+
const tool = getTool(profile.tool);
|
|
7597
|
+
const mode = opts.mode ?? "auto";
|
|
7598
|
+
if (!["auto", "apply", "env", "active"].includes(mode)) {
|
|
7599
|
+
throw new AccountsError(`invalid switch mode "${mode}"`);
|
|
7600
|
+
}
|
|
7601
|
+
const env2 = profileEnv(profile, tool);
|
|
7602
|
+
let applied = false;
|
|
7603
|
+
if (mode === "apply" || mode === "auto" && tool.id === "claude") {
|
|
7604
|
+
applyProfile(name, tool.id);
|
|
7605
|
+
applied = true;
|
|
7606
|
+
} else {
|
|
7607
|
+
useProfile(name, tool.id);
|
|
7608
|
+
}
|
|
7609
|
+
const command = commandFor(tool, opts);
|
|
7610
|
+
const restartRequired = opts.resume === true || applied || mode === "env";
|
|
7611
|
+
const message = applied ? `${profile.name} is now the live/default ${tool.label} profile` : `${profile.name} is now the active ${tool.label} profile`;
|
|
7612
|
+
return {
|
|
7613
|
+
profile: getProfile(name, tool.id),
|
|
7614
|
+
tool,
|
|
7615
|
+
applied,
|
|
7616
|
+
active: true,
|
|
7617
|
+
env: env2,
|
|
7618
|
+
exports: formatExportLines(env2),
|
|
7619
|
+
command,
|
|
7620
|
+
commandLine: commandLine(env2, command),
|
|
7621
|
+
restartRequired,
|
|
7622
|
+
message
|
|
7623
|
+
};
|
|
7624
|
+
}
|
|
7625
|
+
|
|
7564
7626
|
// src/cli.ts
|
|
7565
7627
|
var program2 = new Command;
|
|
7566
7628
|
function die(message) {
|
|
@@ -7670,15 +7732,23 @@ program2.command("login").argument("<name>", "profile name").description("launch
|
|
|
7670
7732
|
console.log(source_default.dim(` config dir: ${profile.dir}`));
|
|
7671
7733
|
console.log(source_default.dim(` env: ${formatEnvAssignments(env2)}`));
|
|
7672
7734
|
console.log(source_default.yellow(` ${tool.loginHint ?? "complete the login flow, then exit when done"}`));
|
|
7673
|
-
|
|
7674
|
-
|
|
7735
|
+
if (tool.id === "claude") {
|
|
7736
|
+
console.log(source_default.dim(" After Claude exits, accounts will make this the live/default Claude account."));
|
|
7737
|
+
}
|
|
7675
7738
|
const res = spawnSync(tool.bin, loginArgs, {
|
|
7676
7739
|
stdio: "inherit",
|
|
7677
7740
|
env: { ...process.env, ...env2 }
|
|
7678
7741
|
});
|
|
7679
7742
|
if (res.error)
|
|
7680
7743
|
die(`failed to launch ${tool.bin}: ${res.error.message}`);
|
|
7681
|
-
|
|
7744
|
+
if ((res.status ?? 0) !== 0)
|
|
7745
|
+
process.exit(res.status ?? 1);
|
|
7746
|
+
const finalized = finalizeLogin(name, tool.id);
|
|
7747
|
+
if (finalized.applied) {
|
|
7748
|
+
console.log(source_default.green(`✓ ${source_default.bold(name)} is now the live/default ${tool.label} account`));
|
|
7749
|
+
} else {
|
|
7750
|
+
console.log(source_default.green(`✓ ${source_default.bold(name)} login finished and profile is active`));
|
|
7751
|
+
}
|
|
7682
7752
|
}));
|
|
7683
7753
|
program2.command("pick").description("interactively choose a profile (default: mark active and apply to live Claude paths)").option("-t, --tool <tool>", "filter by tool", DEFAULT_TOOL).option("--env", "print env export after selection instead of apply").option("--no-act", "only mark active (store current); do not apply or print env").action(action(async (opts) => {
|
|
7684
7754
|
const result = await pickProfile({ tool: opts.tool, mode: resolvePickMode(opts) });
|
|
@@ -7708,6 +7778,30 @@ program2.command("applied").argument("[tool]", "tool id (default: claude)").desc
|
|
|
7708
7778
|
die(`no applied profile for "${tool}". Run \`accounts apply <name>\` first.`);
|
|
7709
7779
|
console.log(p.name);
|
|
7710
7780
|
}));
|
|
7781
|
+
program2.command("switch").argument("<name>", "profile name").argument("[args...]", "extra args passed when printing/launching the tool").description("switch to a profile and print a restart/resume command; use --launch to run it").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").option("--mode <mode>", "switch mode: auto, apply, env, active", "auto").option("--resume", "include the tool's resume/continue args in the handoff command").option("--launch", "launch the tool after switching").option("--json", "output JSON").action(action((name, args, opts) => {
|
|
7782
|
+
const result = switchProfile(name, { tool: opts.tool, mode: opts.mode, resume: opts.resume, args });
|
|
7783
|
+
if (opts.json) {
|
|
7784
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7785
|
+
} else {
|
|
7786
|
+
console.log(source_default.green(`✓ ${result.message}`));
|
|
7787
|
+
if (result.applied)
|
|
7788
|
+
console.log(source_default.dim(" live/default auth updated"));
|
|
7789
|
+
console.log(source_default.dim(` restart command: ${result.commandLine}`));
|
|
7790
|
+
if (!opts.launch) {
|
|
7791
|
+
console.log(source_default.yellow(" Exit the current agent session, then run the restart command above."));
|
|
7792
|
+
}
|
|
7793
|
+
}
|
|
7794
|
+
if (opts.launch) {
|
|
7795
|
+
const [bin, ...launchArgs] = result.command;
|
|
7796
|
+
const res = spawnSync(bin, launchArgs, {
|
|
7797
|
+
stdio: "inherit",
|
|
7798
|
+
env: { ...process.env, ...result.env }
|
|
7799
|
+
});
|
|
7800
|
+
if (res.error)
|
|
7801
|
+
die(`failed to launch ${bin}: ${res.error.message}`);
|
|
7802
|
+
process.exit(res.status ?? 0);
|
|
7803
|
+
}
|
|
7804
|
+
}));
|
|
7711
7805
|
var hook = program2.command("hook").description("install a shell wrapper for claude");
|
|
7712
7806
|
hook.command("install").description(`write ${join10(accountsHome(), "claude-hook.sh")}`).action(action(() => {
|
|
7713
7807
|
const { path, created } = installHook();
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ export type { AddOptions, RemoveOptions, UpdateOptions } from "./lib/profiles.js
|
|
|
8
8
|
export { applyProfile, appliedProfile } from "./lib/apply.js";
|
|
9
9
|
export { importProfile, ensureProfileForLogin } from "./lib/import-profile.js";
|
|
10
10
|
export type { ImportOptions } from "./lib/import-profile.js";
|
|
11
|
+
export { finalizeLogin } from "./lib/login.js";
|
|
12
|
+
export type { FinalizeLoginResult } from "./lib/login.js";
|
|
13
|
+
export { switchProfile } from "./lib/switch.js";
|
|
14
|
+
export type { SwitchMode, SwitchOptions, SwitchResult } from "./lib/switch.js";
|
|
11
15
|
export { pickProfile } from "./lib/pick.js";
|
|
12
16
|
export type { PickOptions, PickResult } from "./lib/pick.js";
|
|
13
17
|
export { installHook, uninstallHook, hookPath, hookScript, shellSnippet } from "./lib/hook.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,aAAa,EACb,YAAY,EACZ,OAAO,EACP,SAAS,EACT,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,UAAU,EACV,cAAc,GACf,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC/E,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/F,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,4BAA4B,EAC5B,yBAAyB,EACzB,eAAe,EACf,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,aAAa,EACb,YAAY,EACZ,OAAO,EACP,SAAS,EACT,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,UAAU,EACV,cAAc,GACf,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC/E,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/F,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,4BAA4B,EAC5B,yBAAyB,EACzB,eAAe,EACf,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3998,6 +3998,7 @@ var toolDefSchema = exports_external.object({
|
|
|
3998
3998
|
bin: exports_external.string().min(1),
|
|
3999
3999
|
loginArgs: exports_external.array(exports_external.string()).optional(),
|
|
4000
4000
|
loginHint: exports_external.string().optional(),
|
|
4001
|
+
resumeArgs: exports_external.array(exports_external.string()).optional(),
|
|
4001
4002
|
accountFile: exports_external.string().optional(),
|
|
4002
4003
|
emailPath: exports_external.array(exports_external.string()).optional()
|
|
4003
4004
|
});
|
|
@@ -4162,6 +4163,7 @@ var BUILTIN_TOOLS = [
|
|
|
4162
4163
|
defaultDir: join2(homedir2(), ".claude"),
|
|
4163
4164
|
bin: "claude",
|
|
4164
4165
|
loginHint: "run /login inside Claude, then /exit when done",
|
|
4166
|
+
resumeArgs: ["--continue"],
|
|
4165
4167
|
accountFile: ".claude.json",
|
|
4166
4168
|
emailPath: ["oauthAccount", "emailAddress"]
|
|
4167
4169
|
},
|
|
@@ -4172,7 +4174,8 @@ var BUILTIN_TOOLS = [
|
|
|
4172
4174
|
defaultDir: join2(homedir2(), ".codex"),
|
|
4173
4175
|
bin: "codex",
|
|
4174
4176
|
loginArgs: ["login"],
|
|
4175
|
-
loginHint: "complete the Codex login flow for this CODEX_HOME"
|
|
4177
|
+
loginHint: "complete the Codex login flow for this CODEX_HOME",
|
|
4178
|
+
resumeArgs: ["resume", "--last"]
|
|
4176
4179
|
},
|
|
4177
4180
|
{
|
|
4178
4181
|
id: "opencode",
|
|
@@ -4185,7 +4188,8 @@ var BUILTIN_TOOLS = [
|
|
|
4185
4188
|
defaultDir: join2(homedir2(), ".config", "opencode"),
|
|
4186
4189
|
bin: "opencode",
|
|
4187
4190
|
loginArgs: ["auth", "login"],
|
|
4188
|
-
loginHint: "complete opencode auth login for this isolated config/data root"
|
|
4191
|
+
loginHint: "complete opencode auth login for this isolated config/data root",
|
|
4192
|
+
resumeArgs: ["--continue"]
|
|
4189
4193
|
},
|
|
4190
4194
|
{
|
|
4191
4195
|
id: "cursor",
|
|
@@ -4687,8 +4691,8 @@ function snapshotLiveAuthToProfile(profileDir, _tool) {
|
|
|
4687
4691
|
function snapshotClaudeAuthToProfile(profileDir, tool) {
|
|
4688
4692
|
snapshotLiveAuthToProfile(profileDir, tool);
|
|
4689
4693
|
}
|
|
4690
|
-
function ensureProfileAuthSnapshot(profileDir, tool) {
|
|
4691
|
-
if (hasAuthSnapshot(profileDir))
|
|
4694
|
+
function ensureProfileAuthSnapshot(profileDir, tool, opts = {}) {
|
|
4695
|
+
if (!opts.overwrite && hasAuthSnapshot(profileDir))
|
|
4692
4696
|
return;
|
|
4693
4697
|
const authDir = profileAuthDir(profileDir);
|
|
4694
4698
|
assertSafeWritePath(join6(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
|
|
@@ -4878,6 +4882,62 @@ function findProfileByName(name, toolId) {
|
|
|
4878
4882
|
throw err;
|
|
4879
4883
|
}
|
|
4880
4884
|
}
|
|
4885
|
+
// src/lib/login.ts
|
|
4886
|
+
function finalizeLogin(name, toolId) {
|
|
4887
|
+
const profile = getProfile(name, toolId);
|
|
4888
|
+
const tool = getTool(profile.tool);
|
|
4889
|
+
if (tool.id === "claude") {
|
|
4890
|
+
ensureProfileAuthSnapshot(profile.dir, tool, { overwrite: true });
|
|
4891
|
+
redetectEmail(name, tool.id);
|
|
4892
|
+
return { profile: applyProfile(name, tool.id).profile, applied: true };
|
|
4893
|
+
}
|
|
4894
|
+
const updated = redetectEmail(name, tool.id);
|
|
4895
|
+
useProfile(name, tool.id);
|
|
4896
|
+
return { profile: updated, applied: false };
|
|
4897
|
+
}
|
|
4898
|
+
// src/lib/switch.ts
|
|
4899
|
+
function shellQuote(value) {
|
|
4900
|
+
if (/^[A-Za-z0-9_./:=@+-]+$/.test(value))
|
|
4901
|
+
return value;
|
|
4902
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
4903
|
+
}
|
|
4904
|
+
function commandLine(env, command) {
|
|
4905
|
+
return `${formatEnvAssignments(env)} ${command.map(shellQuote).join(" ")}`.trim();
|
|
4906
|
+
}
|
|
4907
|
+
function commandFor(tool, opts) {
|
|
4908
|
+
return [tool.bin, ...opts.resume ? tool.resumeArgs ?? [] : [], ...opts.args ?? []];
|
|
4909
|
+
}
|
|
4910
|
+
function switchProfile(name, opts = {}) {
|
|
4911
|
+
const profile = getProfile(name, opts.tool);
|
|
4912
|
+
const tool = getTool(profile.tool);
|
|
4913
|
+
const mode = opts.mode ?? "auto";
|
|
4914
|
+
if (!["auto", "apply", "env", "active"].includes(mode)) {
|
|
4915
|
+
throw new AccountsError(`invalid switch mode "${mode}"`);
|
|
4916
|
+
}
|
|
4917
|
+
const env = profileEnv(profile, tool);
|
|
4918
|
+
let applied = false;
|
|
4919
|
+
if (mode === "apply" || mode === "auto" && tool.id === "claude") {
|
|
4920
|
+
applyProfile(name, tool.id);
|
|
4921
|
+
applied = true;
|
|
4922
|
+
} else {
|
|
4923
|
+
useProfile(name, tool.id);
|
|
4924
|
+
}
|
|
4925
|
+
const command = commandFor(tool, opts);
|
|
4926
|
+
const restartRequired = opts.resume === true || applied || mode === "env";
|
|
4927
|
+
const message = applied ? `${profile.name} is now the live/default ${tool.label} profile` : `${profile.name} is now the active ${tool.label} profile`;
|
|
4928
|
+
return {
|
|
4929
|
+
profile: getProfile(name, tool.id),
|
|
4930
|
+
tool,
|
|
4931
|
+
applied,
|
|
4932
|
+
active: true,
|
|
4933
|
+
env,
|
|
4934
|
+
exports: formatExportLines(env),
|
|
4935
|
+
command,
|
|
4936
|
+
commandLine: commandLine(env, command),
|
|
4937
|
+
restartRequired,
|
|
4938
|
+
message
|
|
4939
|
+
};
|
|
4940
|
+
}
|
|
4881
4941
|
// src/lib/pick.ts
|
|
4882
4942
|
import * as readline from "node:readline/promises";
|
|
4883
4943
|
import { stdin as input, stdout as output } from "node:process";
|
|
@@ -4977,6 +5037,7 @@ export {
|
|
|
4977
5037
|
updateProfile,
|
|
4978
5038
|
uninstallHook,
|
|
4979
5039
|
toolDefSchema,
|
|
5040
|
+
switchProfile,
|
|
4980
5041
|
storeSchema,
|
|
4981
5042
|
storePath,
|
|
4982
5043
|
snapshotLiveAuthToProfile,
|
|
@@ -5011,6 +5072,7 @@ export {
|
|
|
5011
5072
|
formatExportLines,
|
|
5012
5073
|
formatEnvAssignments,
|
|
5013
5074
|
findProfile,
|
|
5075
|
+
finalizeLogin,
|
|
5014
5076
|
expandPath,
|
|
5015
5077
|
ensureProfileForLogin,
|
|
5016
5078
|
ensureProfileAuthSnapshot,
|
|
@@ -4,7 +4,9 @@ export declare function snapshotLiveAuthToProfile(profileDir: string, _tool: Too
|
|
|
4
4
|
/** @deprecated Use snapshotLiveAuthToProfile */
|
|
5
5
|
export declare function snapshotClaudeAuthToProfile(profileDir: string, tool: ToolDef): void;
|
|
6
6
|
/** Build auth snapshots from files already present in the profile config dir. */
|
|
7
|
-
export declare function ensureProfileAuthSnapshot(profileDir: string, tool: ToolDef
|
|
7
|
+
export declare function ensureProfileAuthSnapshot(profileDir: string, tool: ToolDef, opts?: {
|
|
8
|
+
overwrite?: boolean;
|
|
9
|
+
}): void;
|
|
8
10
|
export declare function profileHasAuth(profileDir: string, tool: ToolDef): boolean;
|
|
9
11
|
/** Restore profile auth snapshots onto live Claude paths. */
|
|
10
12
|
export declare function restoreClaudeAuthFromProfile(profileDir: string, tool: ToolDef, profileName?: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-auth.d.ts","sourceRoot":"","sources":["../../src/lib/claude-auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AA2E3C,8FAA8F;AAC9F,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAmBlF;AAED,gDAAgD;AAChD,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAEnF;AAED,iFAAiF;AACjF,wBAAgB,yBAAyB,
|
|
1
|
+
{"version":3,"file":"claude-auth.d.ts","sourceRoot":"","sources":["../../src/lib/claude-auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AA2E3C,8FAA8F;AAC9F,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAmBlF;AAED,gDAAgD;AAChD,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAEnF;AAED,iFAAiF;AACjF,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,EACb,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,IAAI,CAeN;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAEzE;AAED,6DAA6D;AAC7D,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CAqDN;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAM3D"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Profile } from "../types.js";
|
|
2
|
+
export interface FinalizeLoginResult {
|
|
3
|
+
profile: Profile;
|
|
4
|
+
applied: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Finish an isolated login after the tool process exits successfully.
|
|
8
|
+
* Claude login becomes the live/default account; other tools are marked active
|
|
9
|
+
* and have metadata re-detected where possible.
|
|
10
|
+
*/
|
|
11
|
+
export declare function finalizeLogin(name: string, toolId?: string): FinalizeLoginResult;
|
|
12
|
+
//# sourceMappingURL=login.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/lib/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAM3C,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAahF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Profile, ToolDef } from "../types.js";
|
|
2
|
+
export type SwitchMode = "auto" | "apply" | "env" | "active";
|
|
3
|
+
export interface SwitchOptions {
|
|
4
|
+
tool?: string;
|
|
5
|
+
mode?: SwitchMode;
|
|
6
|
+
resume?: boolean;
|
|
7
|
+
args?: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface SwitchResult {
|
|
10
|
+
profile: Profile;
|
|
11
|
+
tool: ToolDef;
|
|
12
|
+
applied: boolean;
|
|
13
|
+
active: boolean;
|
|
14
|
+
env: Record<string, string>;
|
|
15
|
+
exports: string;
|
|
16
|
+
command: string[];
|
|
17
|
+
commandLine: string;
|
|
18
|
+
restartRequired: boolean;
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function switchProfile(name: string, opts?: SwitchOptions): SwitchResult;
|
|
22
|
+
//# sourceMappingURL=switch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/lib/switch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAOpD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAeD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,YAAY,CAmClF"}
|
package/dist/lib/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/lib/tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAgC,MAAM,aAAa,CAAC;AAGzE;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/lib/tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAgC,MAAM,aAAa,CAAC;AAGzE;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,OAAO,EA+DlC,CAAC;AAEF,eAAO,MAAM,YAAY,WAAW,CAAC;AAIrC,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,oFAAoF;AACpF,wBAAgB,SAAS,IAAI,OAAO,EAAE,CAMrC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAS3C;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAanD;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAWjD"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":""}
|