@hasna/accounts 0.1.10 → 0.1.12
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/dist/cli.js +64 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +339 -273
- package/dist/lib/claude-auth.d.ts +4 -0
- package/dist/lib/claude-auth.d.ts.map +1 -1
- package/dist/lib/env.d.ts.map +1 -1
- package/dist/mcp.js +63 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -992,7 +992,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
992
992
|
this._exitCallback = (err) => {
|
|
993
993
|
if (err.code !== "commander.executeSubCommandAsync") {
|
|
994
994
|
throw err;
|
|
995
|
-
}
|
|
995
|
+
} else {}
|
|
996
996
|
};
|
|
997
997
|
}
|
|
998
998
|
return this;
|
|
@@ -12259,7 +12259,7 @@ var require_es5 = __commonJS((exports, module) => {
|
|
|
12259
12259
|
|
|
12260
12260
|
// node_modules/@aws-sdk/core/dist-cjs/submodules/client/index.js
|
|
12261
12261
|
var require_client2 = __commonJS((exports) => {
|
|
12262
|
-
var __dirname = "/
|
|
12262
|
+
var __dirname = "/home/hasna/workspace/hasna/opensource/open-accounts/node_modules/@aws-sdk/core/dist-cjs/submodules/client";
|
|
12263
12263
|
var retry = require_retry();
|
|
12264
12264
|
var protocols = require_protocols();
|
|
12265
12265
|
var lambdaInvokeStore = require_invoke_store();
|
|
@@ -42778,6 +42778,15 @@ function writeClaudeKeychain(cred) {
|
|
|
42778
42778
|
}
|
|
42779
42779
|
|
|
42780
42780
|
// src/lib/claude-auth.ts
|
|
42781
|
+
var CLAUDE_API_AUTH_ENV_KEYS = [
|
|
42782
|
+
"ANTHROPIC_API_KEY",
|
|
42783
|
+
"ANTHROPIC_AUTH_TOKEN",
|
|
42784
|
+
"ANTHROPIC_BASE_URL",
|
|
42785
|
+
"CLAUDE_CODE_API_KEY_HELPER",
|
|
42786
|
+
"CLAUDE_CODE_API_KEY_HELPER_TTL_MS",
|
|
42787
|
+
"CLAUDE_CODE_USE_BEDROCK",
|
|
42788
|
+
"CLAUDE_CODE_USE_VERTEX"
|
|
42789
|
+
];
|
|
42781
42790
|
function readJsonFile(path) {
|
|
42782
42791
|
if (!existsSync6(path))
|
|
42783
42792
|
return;
|
|
@@ -42796,6 +42805,11 @@ function writeJsonFile(path, data, stayUnder) {
|
|
|
42796
42805
|
function readOAuthFromPaths(paths) {
|
|
42797
42806
|
return findOAuthSource(paths)?.oauth;
|
|
42798
42807
|
}
|
|
42808
|
+
function readOAuthSnapshot(profileDir) {
|
|
42809
|
+
const snap = readJsonFile(profileOAuthSnapshot(profileDir));
|
|
42810
|
+
const oauth = snap?.oauthAccount;
|
|
42811
|
+
return oauth && typeof oauth === "object" ? oauth : undefined;
|
|
42812
|
+
}
|
|
42799
42813
|
function findOAuthSource(paths) {
|
|
42800
42814
|
for (const p of paths) {
|
|
42801
42815
|
const data = readJsonFile(p);
|
|
@@ -42837,6 +42851,46 @@ function mergeOAuthInto(paths, oauth, allowDelete, stayUnder) {
|
|
|
42837
42851
|
}
|
|
42838
42852
|
}
|
|
42839
42853
|
}
|
|
42854
|
+
function sanitizeSettingsFile(configDir, stayUnder) {
|
|
42855
|
+
const settingsPath = join7(configDir, "settings.json");
|
|
42856
|
+
const settings = readJsonFile(settingsPath);
|
|
42857
|
+
if (!settings)
|
|
42858
|
+
return false;
|
|
42859
|
+
let changed = false;
|
|
42860
|
+
if ("apiKeyHelper" in settings) {
|
|
42861
|
+
delete settings.apiKeyHelper;
|
|
42862
|
+
changed = true;
|
|
42863
|
+
}
|
|
42864
|
+
const env2 = settings.env;
|
|
42865
|
+
if (env2 && typeof env2 === "object" && !Array.isArray(env2)) {
|
|
42866
|
+
const envRecord = env2;
|
|
42867
|
+
for (const key of CLAUDE_API_AUTH_ENV_KEYS) {
|
|
42868
|
+
if (key in envRecord) {
|
|
42869
|
+
delete envRecord[key];
|
|
42870
|
+
changed = true;
|
|
42871
|
+
}
|
|
42872
|
+
}
|
|
42873
|
+
}
|
|
42874
|
+
if (changed)
|
|
42875
|
+
writeJsonFile(settingsPath, settings, stayUnder);
|
|
42876
|
+
return changed;
|
|
42877
|
+
}
|
|
42878
|
+
function sanitizeClaudeProfileApiSettings(profileDir, tool) {
|
|
42879
|
+
if (tool.id !== "claude")
|
|
42880
|
+
return false;
|
|
42881
|
+
return sanitizeSettingsFile(profileDir, profileDir);
|
|
42882
|
+
}
|
|
42883
|
+
function sanitizeClaudeOAuthProfileSettings(profileDir, tool) {
|
|
42884
|
+
if (tool.id !== "claude")
|
|
42885
|
+
return false;
|
|
42886
|
+
if (!readOAuthSnapshot(profileDir) && !readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool))) {
|
|
42887
|
+
return false;
|
|
42888
|
+
}
|
|
42889
|
+
return sanitizeClaudeProfileApiSettings(profileDir, tool);
|
|
42890
|
+
}
|
|
42891
|
+
function sanitizeLiveClaudeOAuthSettings() {
|
|
42892
|
+
return sanitizeSettingsFile(liveClaudePaths().configDir, liveClaudeBase());
|
|
42893
|
+
}
|
|
42840
42894
|
function liveOAuthEmail() {
|
|
42841
42895
|
const live = liveClaudePaths();
|
|
42842
42896
|
const oauth = readOAuthFromPaths([live.homeJson]);
|
|
@@ -42877,6 +42931,7 @@ function ensureProfileAuthSnapshot(profileDir, tool, opts = {}) {
|
|
|
42877
42931
|
assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
|
|
42878
42932
|
copyFileSync(credFile, credSnap);
|
|
42879
42933
|
}
|
|
42934
|
+
sanitizeClaudeOAuthProfileSettings(profileDir, tool);
|
|
42880
42935
|
}
|
|
42881
42936
|
function profileHasAuth(profileDir, tool) {
|
|
42882
42937
|
return hasAuthSnapshot(profileDir) || !!readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool));
|
|
@@ -42895,6 +42950,8 @@ function restoreClaudeAuthFromProfile(profileDir, tool, profileName) {
|
|
|
42895
42950
|
if (!oauth) {
|
|
42896
42951
|
throw new AccountsError("profile has no OAuth account data to apply");
|
|
42897
42952
|
}
|
|
42953
|
+
sanitizeClaudeOAuthProfileSettings(profileDir, tool);
|
|
42954
|
+
sanitizeLiveClaudeOAuthSettings();
|
|
42898
42955
|
assertSafeWritePath(live.homeJson, { mustStayUnder: liveRoot });
|
|
42899
42956
|
mergeOAuthInto([live.homeJson], oauth, false, liveRoot);
|
|
42900
42957
|
const credSnap = profileCredentialsSnapshot(profileDir);
|
|
@@ -43345,6 +43402,11 @@ function profileEnv(profile, tool) {
|
|
|
43345
43402
|
for (const [name, value] of Object.entries(tool.extraEnv ?? {})) {
|
|
43346
43403
|
env2[name] = renderTemplate(value, profile);
|
|
43347
43404
|
}
|
|
43405
|
+
if (tool.id === "claude") {
|
|
43406
|
+
sanitizeClaudeProfileApiSettings(profile.dir, tool);
|
|
43407
|
+
for (const key of CLAUDE_API_AUTH_ENV_KEYS)
|
|
43408
|
+
env2[key] = "";
|
|
43409
|
+
}
|
|
43348
43410
|
return env2;
|
|
43349
43411
|
}
|
|
43350
43412
|
function formatEnvAssignments(env2) {
|
package/dist/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type { RunSupervisorOptions, SupervisorClientOptions, SupervisorLaunchPla
|
|
|
17
17
|
export { pickProfile } from "./lib/pick.js";
|
|
18
18
|
export type { PickOptions, PickResult } from "./lib/pick.js";
|
|
19
19
|
export { installHook, uninstallHook, hookPath, hookScript, shellSnippet } from "./lib/hook.js";
|
|
20
|
-
export { snapshotClaudeAuthToProfile, snapshotLiveAuthToProfile, restoreClaudeAuthFromProfile, ensureProfileAuthSnapshot, hasAuthSnapshot, profileHasAuth, } from "./lib/claude-auth.js";
|
|
20
|
+
export { snapshotClaudeAuthToProfile, snapshotLiveAuthToProfile, restoreClaudeAuthFromProfile, ensureProfileAuthSnapshot, hasAuthSnapshot, profileHasAuth, sanitizeClaudeProfileApiSettings, sanitizeClaudeOAuthProfileSettings, sanitizeLiveClaudeOAuthSettings, CLAUDE_API_AUTH_ENV_KEYS, } from "./lib/claude-auth.js";
|
|
21
21
|
export { withApplyLock } from "./lib/apply-lock.js";
|
|
22
22
|
export { isSafeProfileName } from "./lib/hook.js";
|
|
23
23
|
export { readClaudeKeychain, keychainSupported } from "./lib/keychain.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,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,EACL,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,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,
|
|
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,EACL,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,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,EACd,gCAAgC,EAChC,kCAAkC,EAClC,+BAA+B,EAC/B,wBAAwB,GACzB,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
|
@@ -4317,256 +4317,13 @@ function removeCustomTool(id) {
|
|
|
4317
4317
|
store.tools.splice(idx, 1);
|
|
4318
4318
|
saveStore(store);
|
|
4319
4319
|
}
|
|
4320
|
-
// src/lib/env.ts
|
|
4321
|
-
function renderTemplate(value, profile) {
|
|
4322
|
-
return value.replaceAll("{profileDir}", profile.dir).replaceAll("{profileName}", profile.name).replaceAll("{toolId}", profile.tool);
|
|
4323
|
-
}
|
|
4324
|
-
function profileEnv(profile, tool) {
|
|
4325
|
-
const env = {
|
|
4326
|
-
[tool.envVar]: profile.dir
|
|
4327
|
-
};
|
|
4328
|
-
for (const [name, value] of Object.entries(tool.extraEnv ?? {})) {
|
|
4329
|
-
env[name] = renderTemplate(value, profile);
|
|
4330
|
-
}
|
|
4331
|
-
return env;
|
|
4332
|
-
}
|
|
4333
|
-
function formatEnvAssignments(env) {
|
|
4334
|
-
return Object.entries(env).map(([name, value]) => `${name}=${JSON.stringify(value)}`).join(" ");
|
|
4335
|
-
}
|
|
4336
|
-
function formatExportLines(env) {
|
|
4337
|
-
return Object.entries(env).map(([name, value]) => `export ${name}=${JSON.stringify(value)}`).join(`
|
|
4338
|
-
`);
|
|
4339
|
-
}
|
|
4340
|
-
// src/lib/detect.ts
|
|
4341
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
|
|
4342
|
-
import { dirname as dirname2, join as join3 } from "node:path";
|
|
4343
|
-
function detectEmail(dir, tool) {
|
|
4344
|
-
if (!tool.accountFile || !tool.emailPath)
|
|
4345
|
-
return;
|
|
4346
|
-
const candidates = [join3(dir, tool.accountFile)];
|
|
4347
|
-
if (dir === tool.defaultDir)
|
|
4348
|
-
candidates.push(join3(dirname2(dir), tool.accountFile));
|
|
4349
|
-
for (const file of candidates) {
|
|
4350
|
-
const email = readEmail(file, tool.emailPath);
|
|
4351
|
-
if (email)
|
|
4352
|
-
return email;
|
|
4353
|
-
}
|
|
4354
|
-
return;
|
|
4355
|
-
}
|
|
4356
|
-
function readEmail(file, path) {
|
|
4357
|
-
if (!existsSync3(file))
|
|
4358
|
-
return;
|
|
4359
|
-
let cursor;
|
|
4360
|
-
try {
|
|
4361
|
-
cursor = JSON.parse(readFileSync2(file, "utf8"));
|
|
4362
|
-
} catch {
|
|
4363
|
-
return;
|
|
4364
|
-
}
|
|
4365
|
-
for (const key of path) {
|
|
4366
|
-
if (cursor && typeof cursor === "object" && key in cursor) {
|
|
4367
|
-
cursor = cursor[key];
|
|
4368
|
-
} else {
|
|
4369
|
-
return;
|
|
4370
|
-
}
|
|
4371
|
-
}
|
|
4372
|
-
return typeof cursor === "string" && cursor.includes("@") ? cursor : undefined;
|
|
4373
|
-
}
|
|
4374
|
-
// src/lib/profiles.ts
|
|
4375
|
-
import { homedir as homedir3 } from "node:os";
|
|
4376
|
-
import { isAbsolute, join as join4, resolve as resolve2 } from "node:path";
|
|
4377
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3, rmSync } from "node:fs";
|
|
4378
|
-
function nowIso() {
|
|
4379
|
-
return new Date().toISOString();
|
|
4380
|
-
}
|
|
4381
|
-
function expandPath(p) {
|
|
4382
|
-
let out = p;
|
|
4383
|
-
if (out === "~")
|
|
4384
|
-
out = homedir3();
|
|
4385
|
-
else if (out.startsWith("~/"))
|
|
4386
|
-
out = join4(homedir3(), out.slice(2));
|
|
4387
|
-
return isAbsolute(out) ? out : resolve2(process.cwd(), out);
|
|
4388
|
-
}
|
|
4389
|
-
function listProfiles(toolId) {
|
|
4390
|
-
const profiles = loadStore().profiles;
|
|
4391
|
-
const filtered = toolId ? profiles.filter((p) => p.tool === toolId) : profiles;
|
|
4392
|
-
return filtered.slice().sort((a, b) => a.tool.localeCompare(b.tool) || a.name.localeCompare(b.name));
|
|
4393
|
-
}
|
|
4394
|
-
function profileMatches(name, toolId) {
|
|
4395
|
-
return loadStore().profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
|
|
4396
|
-
}
|
|
4397
|
-
function findProfile(name, toolId) {
|
|
4398
|
-
const matches = profileMatches(name, toolId);
|
|
4399
|
-
return matches.length === 1 ? matches[0] : undefined;
|
|
4400
|
-
}
|
|
4401
|
-
function getProfile(name, toolId) {
|
|
4402
|
-
const matches = profileMatches(name, toolId);
|
|
4403
|
-
if (matches.length === 0) {
|
|
4404
|
-
const suffix = toolId ? ` for tool "${toolId}"` : "";
|
|
4405
|
-
throw new AccountsError(`no profile named "${name}"${suffix}. Run \`accounts list\` to see profiles.`);
|
|
4406
|
-
}
|
|
4407
|
-
if (matches.length > 1) {
|
|
4408
|
-
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4409
|
-
}
|
|
4410
|
-
const profile = matches[0];
|
|
4411
|
-
return profile;
|
|
4412
|
-
}
|
|
4413
|
-
function addProfile(opts) {
|
|
4414
|
-
const name = opts.name;
|
|
4415
|
-
const nameCheck = profileNameSchema.safeParse(name);
|
|
4416
|
-
if (!nameCheck.success)
|
|
4417
|
-
throw new AccountsError(nameCheck.error.issues[0]?.message ?? "invalid profile name");
|
|
4418
|
-
const toolId = opts.tool ?? DEFAULT_TOOL;
|
|
4419
|
-
const tool = getTool(toolId);
|
|
4420
|
-
const store = loadStore();
|
|
4421
|
-
if (store.profiles.some((p) => p.name === name && p.tool === toolId)) {
|
|
4422
|
-
throw new AccountsError(`a ${toolId} profile named "${name}" already exists`);
|
|
4423
|
-
}
|
|
4424
|
-
const dir = opts.dir ? expandPath(opts.dir) : join4(profilesDir(), toolId, name);
|
|
4425
|
-
if (store.profiles.some((p) => p.dir === dir)) {
|
|
4426
|
-
throw new AccountsError(`a profile already uses config dir ${dir}`);
|
|
4427
|
-
}
|
|
4428
|
-
mkdirSync3(dir, { recursive: true });
|
|
4429
|
-
const email = opts.email ?? detectEmail(dir, tool);
|
|
4430
|
-
const profile = {
|
|
4431
|
-
name,
|
|
4432
|
-
tool: toolId,
|
|
4433
|
-
...email ? { email } : {},
|
|
4434
|
-
dir,
|
|
4435
|
-
...opts.description ? { description: opts.description } : {},
|
|
4436
|
-
createdAt: nowIso()
|
|
4437
|
-
};
|
|
4438
|
-
store.profiles.push(profile);
|
|
4439
|
-
saveStore(store);
|
|
4440
|
-
return profile;
|
|
4441
|
-
}
|
|
4442
|
-
function removeProfile(name, opts = {}) {
|
|
4443
|
-
const options = typeof opts === "boolean" ? { purge: opts } : opts;
|
|
4444
|
-
const store = loadStore();
|
|
4445
|
-
const matches = store.profiles.map((profile2, idx2) => ({ profile: profile2, idx: idx2 })).filter(({ profile: profile2 }) => profile2.name === name && (!options.tool || profile2.tool === options.tool));
|
|
4446
|
-
if (matches.length === 0) {
|
|
4447
|
-
const suffix = options.tool ? ` for tool "${options.tool}"` : "";
|
|
4448
|
-
throw new AccountsError(`no profile named "${name}"${suffix}`);
|
|
4449
|
-
}
|
|
4450
|
-
if (matches.length > 1) {
|
|
4451
|
-
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map(({ profile: profile2 }) => profile2.tool).join(", ")}); pass --tool`);
|
|
4452
|
-
}
|
|
4453
|
-
const idx = matches[0].idx;
|
|
4454
|
-
const profile = store.profiles[idx];
|
|
4455
|
-
store.profiles.splice(idx, 1);
|
|
4456
|
-
if (store.current[profile.tool] === name)
|
|
4457
|
-
delete store.current[profile.tool];
|
|
4458
|
-
if (store.applied[profile.tool] === name)
|
|
4459
|
-
delete store.applied[profile.tool];
|
|
4460
|
-
saveStore(store);
|
|
4461
|
-
let purged = false;
|
|
4462
|
-
let purgeNote;
|
|
4463
|
-
if (options.purge) {
|
|
4464
|
-
const managed = profile.dir.startsWith(profilesDir());
|
|
4465
|
-
const isDefault = profile.dir === getTool(profile.tool).defaultDir;
|
|
4466
|
-
if (managed && !isDefault && existsSync4(profile.dir)) {
|
|
4467
|
-
rmSync(profile.dir, { recursive: true, force: true });
|
|
4468
|
-
purged = true;
|
|
4469
|
-
} else {
|
|
4470
|
-
purgeNote = `refused to delete ${profile.dir} (not a managed profile dir); remove it manually if intended`;
|
|
4471
|
-
}
|
|
4472
|
-
}
|
|
4473
|
-
return { profile, purged, purgeNote };
|
|
4474
|
-
}
|
|
4475
|
-
function renameProfile(oldName, newName, toolId) {
|
|
4476
|
-
const nameCheck = profileNameSchema.safeParse(newName);
|
|
4477
|
-
if (!nameCheck.success)
|
|
4478
|
-
throw new AccountsError(nameCheck.error.issues[0]?.message ?? "invalid profile name");
|
|
4479
|
-
const store = loadStore();
|
|
4480
|
-
const matches = store.profiles.filter((p) => p.name === oldName && (!toolId || p.tool === toolId));
|
|
4481
|
-
if (matches.length === 0) {
|
|
4482
|
-
const suffix = toolId ? ` for tool "${toolId}"` : "";
|
|
4483
|
-
throw new AccountsError(`no profile named "${oldName}"${suffix}`);
|
|
4484
|
-
}
|
|
4485
|
-
if (matches.length > 1) {
|
|
4486
|
-
throw new AccountsError(`profile "${oldName}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4487
|
-
}
|
|
4488
|
-
const profile = matches[0];
|
|
4489
|
-
if (store.profiles.some((p) => p.name === newName && p.tool === profile.tool)) {
|
|
4490
|
-
throw new AccountsError(`a ${profile.tool} profile named "${newName}" already exists`);
|
|
4491
|
-
}
|
|
4492
|
-
if (store.current[profile.tool] === oldName)
|
|
4493
|
-
store.current[profile.tool] = newName;
|
|
4494
|
-
if (store.applied[profile.tool] === oldName)
|
|
4495
|
-
store.applied[profile.tool] = newName;
|
|
4496
|
-
profile.name = newName;
|
|
4497
|
-
saveStore(store);
|
|
4498
|
-
return profile;
|
|
4499
|
-
}
|
|
4500
|
-
function updateProfile(name, opts) {
|
|
4501
|
-
const store = loadStore();
|
|
4502
|
-
const matches = store.profiles.filter((p) => p.name === name && (!opts.tool || p.tool === opts.tool));
|
|
4503
|
-
if (matches.length === 0) {
|
|
4504
|
-
const suffix = opts.tool ? ` for tool "${opts.tool}"` : "";
|
|
4505
|
-
throw new AccountsError(`no profile named "${name}"${suffix}`);
|
|
4506
|
-
}
|
|
4507
|
-
if (matches.length > 1) {
|
|
4508
|
-
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4509
|
-
}
|
|
4510
|
-
const profile = matches[0];
|
|
4511
|
-
if (opts.email !== undefined)
|
|
4512
|
-
profile.email = opts.email;
|
|
4513
|
-
if (opts.description !== undefined)
|
|
4514
|
-
profile.description = opts.description;
|
|
4515
|
-
if (opts.dir !== undefined) {
|
|
4516
|
-
const dir = expandPath(opts.dir);
|
|
4517
|
-
mkdirSync3(dir, { recursive: true });
|
|
4518
|
-
profile.dir = dir;
|
|
4519
|
-
}
|
|
4520
|
-
saveStore(store);
|
|
4521
|
-
return profile;
|
|
4522
|
-
}
|
|
4523
|
-
function redetectEmail(name, toolId) {
|
|
4524
|
-
const store = loadStore();
|
|
4525
|
-
const matches = store.profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
|
|
4526
|
-
if (matches.length === 0) {
|
|
4527
|
-
const suffix = toolId ? ` for tool "${toolId}"` : "";
|
|
4528
|
-
throw new AccountsError(`no profile named "${name}"${suffix}`);
|
|
4529
|
-
}
|
|
4530
|
-
if (matches.length > 1) {
|
|
4531
|
-
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4532
|
-
}
|
|
4533
|
-
const profile = matches[0];
|
|
4534
|
-
const email = detectEmail(profile.dir, getTool(profile.tool));
|
|
4535
|
-
if (email)
|
|
4536
|
-
profile.email = email;
|
|
4537
|
-
saveStore(store);
|
|
4538
|
-
return profile;
|
|
4539
|
-
}
|
|
4540
|
-
function useProfile(name, toolId) {
|
|
4541
|
-
const store = loadStore();
|
|
4542
|
-
const matches = store.profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
|
|
4543
|
-
if (matches.length === 0) {
|
|
4544
|
-
const suffix = toolId ? ` for tool "${toolId}"` : "";
|
|
4545
|
-
throw new AccountsError(`no profile named "${name}"${suffix}`);
|
|
4546
|
-
}
|
|
4547
|
-
if (matches.length > 1) {
|
|
4548
|
-
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4549
|
-
}
|
|
4550
|
-
const profile = matches[0];
|
|
4551
|
-
store.current[profile.tool] = name;
|
|
4552
|
-
profile.lastUsedAt = nowIso();
|
|
4553
|
-
saveStore(store);
|
|
4554
|
-
return { profile, toolId: profile.tool };
|
|
4555
|
-
}
|
|
4556
|
-
function currentProfile(toolId) {
|
|
4557
|
-
const store = loadStore();
|
|
4558
|
-
const name = store.current[toolId];
|
|
4559
|
-
if (!name)
|
|
4560
|
-
return;
|
|
4561
|
-
return store.profiles.find((p) => p.name === name);
|
|
4562
|
-
}
|
|
4563
4320
|
// src/lib/claude-auth.ts
|
|
4564
|
-
import { copyFileSync, existsSync as
|
|
4565
|
-
import { dirname as
|
|
4321
|
+
import { copyFileSync, existsSync as existsSync3, lstatSync as lstatSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync2, statSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4322
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
4566
4323
|
|
|
4567
4324
|
// src/lib/claude-layout.ts
|
|
4568
|
-
import { homedir as
|
|
4569
|
-
import { dirname as
|
|
4325
|
+
import { homedir as homedir3 } from "node:os";
|
|
4326
|
+
import { dirname as dirname2, join as join3 } from "node:path";
|
|
4570
4327
|
var CLAUDE_KEYCHAIN_SERVICE = "Claude Code-credentials";
|
|
4571
4328
|
var ACCOUNTS_AUTH_DIR = ".accounts-auth";
|
|
4572
4329
|
var OAUTH_SNAPSHOT = "oauth-account.json";
|
|
@@ -4574,36 +4331,36 @@ var CREDENTIALS_SNAPSHOT = "credentials.json";
|
|
|
4574
4331
|
var KEYCHAIN_SNAPSHOT = "keychain.json";
|
|
4575
4332
|
function liveClaudeBase() {
|
|
4576
4333
|
const testBase = process.env.ACCOUNTS_TEST_LIVE_DIR;
|
|
4577
|
-
return testBase && testBase.trim() ? testBase :
|
|
4334
|
+
return testBase && testBase.trim() ? testBase : homedir3();
|
|
4578
4335
|
}
|
|
4579
4336
|
function liveClaudePaths() {
|
|
4580
4337
|
const base = liveClaudeBase();
|
|
4581
|
-
const configDir =
|
|
4338
|
+
const configDir = join3(base, ".claude");
|
|
4582
4339
|
return {
|
|
4583
4340
|
configDir,
|
|
4584
|
-
homeJson:
|
|
4585
|
-
credentialsFile:
|
|
4341
|
+
homeJson: join3(base, ".claude.json"),
|
|
4342
|
+
credentialsFile: join3(configDir, ".credentials.json")
|
|
4586
4343
|
};
|
|
4587
4344
|
}
|
|
4588
4345
|
function profileAccountJsonPaths(profileDir, tool) {
|
|
4589
4346
|
if (!tool.accountFile)
|
|
4590
4347
|
return [];
|
|
4591
|
-
const paths = [
|
|
4348
|
+
const paths = [join3(profileDir, tool.accountFile)];
|
|
4592
4349
|
if (profileDir === tool.defaultDir)
|
|
4593
|
-
paths.push(
|
|
4350
|
+
paths.push(join3(dirname2(profileDir), tool.accountFile));
|
|
4594
4351
|
return paths;
|
|
4595
4352
|
}
|
|
4596
4353
|
function profileAuthDir(profileDir) {
|
|
4597
|
-
return
|
|
4354
|
+
return join3(profileDir, ACCOUNTS_AUTH_DIR);
|
|
4598
4355
|
}
|
|
4599
4356
|
function profileOAuthSnapshot(profileDir) {
|
|
4600
|
-
return
|
|
4357
|
+
return join3(profileAuthDir(profileDir), OAUTH_SNAPSHOT);
|
|
4601
4358
|
}
|
|
4602
4359
|
function profileCredentialsSnapshot(profileDir) {
|
|
4603
|
-
return
|
|
4360
|
+
return join3(profileAuthDir(profileDir), CREDENTIALS_SNAPSHOT);
|
|
4604
4361
|
}
|
|
4605
4362
|
function profileKeychainSnapshot(profileDir) {
|
|
4606
|
-
return
|
|
4363
|
+
return join3(profileAuthDir(profileDir), KEYCHAIN_SNAPSHOT);
|
|
4607
4364
|
}
|
|
4608
4365
|
|
|
4609
4366
|
// src/lib/keychain.ts
|
|
@@ -4667,24 +4424,38 @@ function writeClaudeKeychain(cred) {
|
|
|
4667
4424
|
}
|
|
4668
4425
|
|
|
4669
4426
|
// src/lib/claude-auth.ts
|
|
4427
|
+
var CLAUDE_API_AUTH_ENV_KEYS = [
|
|
4428
|
+
"ANTHROPIC_API_KEY",
|
|
4429
|
+
"ANTHROPIC_AUTH_TOKEN",
|
|
4430
|
+
"ANTHROPIC_BASE_URL",
|
|
4431
|
+
"CLAUDE_CODE_API_KEY_HELPER",
|
|
4432
|
+
"CLAUDE_CODE_API_KEY_HELPER_TTL_MS",
|
|
4433
|
+
"CLAUDE_CODE_USE_BEDROCK",
|
|
4434
|
+
"CLAUDE_CODE_USE_VERTEX"
|
|
4435
|
+
];
|
|
4670
4436
|
function readJsonFile(path) {
|
|
4671
|
-
if (!
|
|
4437
|
+
if (!existsSync3(path))
|
|
4672
4438
|
return;
|
|
4673
4439
|
try {
|
|
4674
|
-
return JSON.parse(
|
|
4440
|
+
return JSON.parse(readFileSync2(path, "utf8"));
|
|
4675
4441
|
} catch {
|
|
4676
4442
|
return;
|
|
4677
4443
|
}
|
|
4678
4444
|
}
|
|
4679
4445
|
function writeJsonFile(path, data, stayUnder) {
|
|
4680
4446
|
assertSafeWritePath(path, stayUnder ? { mustStayUnder: stayUnder } : undefined);
|
|
4681
|
-
|
|
4447
|
+
mkdirSync3(dirname3(path), { recursive: true });
|
|
4682
4448
|
writeFileSync2(path, JSON.stringify(data, null, 2) + `
|
|
4683
4449
|
`, { mode: 384 });
|
|
4684
4450
|
}
|
|
4685
4451
|
function readOAuthFromPaths(paths) {
|
|
4686
4452
|
return findOAuthSource(paths)?.oauth;
|
|
4687
4453
|
}
|
|
4454
|
+
function readOAuthSnapshot(profileDir) {
|
|
4455
|
+
const snap = readJsonFile(profileOAuthSnapshot(profileDir));
|
|
4456
|
+
const oauth = snap?.oauthAccount;
|
|
4457
|
+
return oauth && typeof oauth === "object" ? oauth : undefined;
|
|
4458
|
+
}
|
|
4688
4459
|
function findOAuthSource(paths) {
|
|
4689
4460
|
for (const p of paths) {
|
|
4690
4461
|
const data = readJsonFile(p);
|
|
@@ -4695,7 +4466,7 @@ function findOAuthSource(paths) {
|
|
|
4695
4466
|
return;
|
|
4696
4467
|
}
|
|
4697
4468
|
function snapshotIsStale(sourcePath, snapshotPath) {
|
|
4698
|
-
if (!
|
|
4469
|
+
if (!existsSync3(snapshotPath))
|
|
4699
4470
|
return true;
|
|
4700
4471
|
try {
|
|
4701
4472
|
return statSync(sourcePath).mtimeMs > statSync(snapshotPath).mtimeMs;
|
|
@@ -4726,6 +4497,46 @@ function mergeOAuthInto(paths, oauth, allowDelete, stayUnder) {
|
|
|
4726
4497
|
}
|
|
4727
4498
|
}
|
|
4728
4499
|
}
|
|
4500
|
+
function sanitizeSettingsFile(configDir, stayUnder) {
|
|
4501
|
+
const settingsPath = join4(configDir, "settings.json");
|
|
4502
|
+
const settings = readJsonFile(settingsPath);
|
|
4503
|
+
if (!settings)
|
|
4504
|
+
return false;
|
|
4505
|
+
let changed = false;
|
|
4506
|
+
if ("apiKeyHelper" in settings) {
|
|
4507
|
+
delete settings.apiKeyHelper;
|
|
4508
|
+
changed = true;
|
|
4509
|
+
}
|
|
4510
|
+
const env = settings.env;
|
|
4511
|
+
if (env && typeof env === "object" && !Array.isArray(env)) {
|
|
4512
|
+
const envRecord = env;
|
|
4513
|
+
for (const key of CLAUDE_API_AUTH_ENV_KEYS) {
|
|
4514
|
+
if (key in envRecord) {
|
|
4515
|
+
delete envRecord[key];
|
|
4516
|
+
changed = true;
|
|
4517
|
+
}
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4520
|
+
if (changed)
|
|
4521
|
+
writeJsonFile(settingsPath, settings, stayUnder);
|
|
4522
|
+
return changed;
|
|
4523
|
+
}
|
|
4524
|
+
function sanitizeClaudeProfileApiSettings(profileDir, tool) {
|
|
4525
|
+
if (tool.id !== "claude")
|
|
4526
|
+
return false;
|
|
4527
|
+
return sanitizeSettingsFile(profileDir, profileDir);
|
|
4528
|
+
}
|
|
4529
|
+
function sanitizeClaudeOAuthProfileSettings(profileDir, tool) {
|
|
4530
|
+
if (tool.id !== "claude")
|
|
4531
|
+
return false;
|
|
4532
|
+
if (!readOAuthSnapshot(profileDir) && !readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool))) {
|
|
4533
|
+
return false;
|
|
4534
|
+
}
|
|
4535
|
+
return sanitizeClaudeProfileApiSettings(profileDir, tool);
|
|
4536
|
+
}
|
|
4537
|
+
function sanitizeLiveClaudeOAuthSettings() {
|
|
4538
|
+
return sanitizeSettingsFile(liveClaudePaths().configDir, liveClaudeBase());
|
|
4539
|
+
}
|
|
4729
4540
|
function liveOAuthEmail() {
|
|
4730
4541
|
const live = liveClaudePaths();
|
|
4731
4542
|
const oauth = readOAuthFromPaths([live.homeJson]);
|
|
@@ -4734,13 +4545,13 @@ function liveOAuthEmail() {
|
|
|
4734
4545
|
}
|
|
4735
4546
|
function snapshotLiveAuthToProfile(profileDir, _tool) {
|
|
4736
4547
|
const authDir = profileAuthDir(profileDir);
|
|
4737
|
-
assertSafeWritePath(
|
|
4738
|
-
|
|
4548
|
+
assertSafeWritePath(join4(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
|
|
4549
|
+
mkdirSync3(authDir, { recursive: true });
|
|
4739
4550
|
const live = liveClaudePaths();
|
|
4740
4551
|
const oauth = readOAuthFromPaths([live.homeJson]);
|
|
4741
4552
|
if (oauth)
|
|
4742
4553
|
writeJsonFile(profileOAuthSnapshot(profileDir), { oauthAccount: oauth }, profileDir);
|
|
4743
|
-
if (
|
|
4554
|
+
if (existsSync3(live.credentialsFile)) {
|
|
4744
4555
|
const dest = profileCredentialsSnapshot(profileDir);
|
|
4745
4556
|
assertSafeWritePath(dest, { mustStayUnder: profileDir });
|
|
4746
4557
|
copyFileSync(live.credentialsFile, dest);
|
|
@@ -4756,19 +4567,20 @@ function snapshotClaudeAuthToProfile(profileDir, tool) {
|
|
|
4756
4567
|
}
|
|
4757
4568
|
function ensureProfileAuthSnapshot(profileDir, tool, opts = {}) {
|
|
4758
4569
|
const authDir = profileAuthDir(profileDir);
|
|
4759
|
-
assertSafeWritePath(
|
|
4760
|
-
|
|
4570
|
+
assertSafeWritePath(join4(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
|
|
4571
|
+
mkdirSync3(authDir, { recursive: true });
|
|
4761
4572
|
const oauthSource = findOAuthSource(profileAccountJsonPaths(profileDir, tool));
|
|
4762
4573
|
const oauthSnap = profileOAuthSnapshot(profileDir);
|
|
4763
4574
|
if (oauthSource && (opts.overwrite || snapshotIsStale(oauthSource.path, oauthSnap))) {
|
|
4764
4575
|
writeJsonFile(oauthSnap, { oauthAccount: oauthSource.oauth }, profileDir);
|
|
4765
4576
|
}
|
|
4766
|
-
const credFile =
|
|
4577
|
+
const credFile = join4(profileDir, ".credentials.json");
|
|
4767
4578
|
const credSnap = profileCredentialsSnapshot(profileDir);
|
|
4768
|
-
if (
|
|
4579
|
+
if (existsSync3(credFile) && (opts.overwrite || snapshotIsStale(credFile, credSnap))) {
|
|
4769
4580
|
assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
|
|
4770
4581
|
copyFileSync(credFile, credSnap);
|
|
4771
4582
|
}
|
|
4583
|
+
sanitizeClaudeOAuthProfileSettings(profileDir, tool);
|
|
4772
4584
|
}
|
|
4773
4585
|
function profileHasAuth(profileDir, tool) {
|
|
4774
4586
|
return hasAuthSnapshot(profileDir) || !!readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool));
|
|
@@ -4781,21 +4593,23 @@ function restoreClaudeAuthFromProfile(profileDir, tool, profileName) {
|
|
|
4781
4593
|
ensureProfileAuthSnapshot(profileDir, tool);
|
|
4782
4594
|
const live = liveClaudePaths();
|
|
4783
4595
|
const liveRoot = liveClaudeBase();
|
|
4784
|
-
|
|
4596
|
+
mkdirSync3(live.configDir, { recursive: true });
|
|
4785
4597
|
const oauthSnap = readJsonFile(profileOAuthSnapshot(profileDir));
|
|
4786
4598
|
const oauth = oauthSnap?.oauthAccount && typeof oauthSnap.oauthAccount === "object" ? oauthSnap.oauthAccount : readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool));
|
|
4787
4599
|
if (!oauth) {
|
|
4788
4600
|
throw new AccountsError("profile has no OAuth account data to apply");
|
|
4789
4601
|
}
|
|
4602
|
+
sanitizeClaudeOAuthProfileSettings(profileDir, tool);
|
|
4603
|
+
sanitizeLiveClaudeOAuthSettings();
|
|
4790
4604
|
assertSafeWritePath(live.homeJson, { mustStayUnder: liveRoot });
|
|
4791
4605
|
mergeOAuthInto([live.homeJson], oauth, false, liveRoot);
|
|
4792
4606
|
const credSnap = profileCredentialsSnapshot(profileDir);
|
|
4793
|
-
if (
|
|
4607
|
+
if (existsSync3(credSnap)) {
|
|
4794
4608
|
assertSafeWritePath(live.credentialsFile, { mustStayUnder: liveRoot });
|
|
4795
4609
|
assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
|
|
4796
4610
|
copyFileSync(credSnap, live.credentialsFile);
|
|
4797
|
-
writeFileSync2(live.credentialsFile,
|
|
4798
|
-
} else if (
|
|
4611
|
+
writeFileSync2(live.credentialsFile, readFileSync2(live.credentialsFile), { mode: 384 });
|
|
4612
|
+
} else if (existsSync3(live.credentialsFile)) {
|
|
4799
4613
|
if (!lstatSync2(live.credentialsFile).isSymbolicLink())
|
|
4800
4614
|
unlinkSync(live.credentialsFile);
|
|
4801
4615
|
}
|
|
@@ -4817,9 +4631,257 @@ function restoreClaudeAuthFromProfile(profileDir, tool, profileName) {
|
|
|
4817
4631
|
}
|
|
4818
4632
|
}
|
|
4819
4633
|
function hasAuthSnapshot(profileDir) {
|
|
4820
|
-
return
|
|
4634
|
+
return existsSync3(profileOAuthSnapshot(profileDir)) || existsSync3(profileCredentialsSnapshot(profileDir)) || existsSync3(profileKeychainSnapshot(profileDir));
|
|
4821
4635
|
}
|
|
4822
4636
|
|
|
4637
|
+
// src/lib/env.ts
|
|
4638
|
+
function renderTemplate(value, profile) {
|
|
4639
|
+
return value.replaceAll("{profileDir}", profile.dir).replaceAll("{profileName}", profile.name).replaceAll("{toolId}", profile.tool);
|
|
4640
|
+
}
|
|
4641
|
+
function profileEnv(profile, tool) {
|
|
4642
|
+
const env = {
|
|
4643
|
+
[tool.envVar]: profile.dir
|
|
4644
|
+
};
|
|
4645
|
+
for (const [name, value] of Object.entries(tool.extraEnv ?? {})) {
|
|
4646
|
+
env[name] = renderTemplate(value, profile);
|
|
4647
|
+
}
|
|
4648
|
+
if (tool.id === "claude") {
|
|
4649
|
+
sanitizeClaudeProfileApiSettings(profile.dir, tool);
|
|
4650
|
+
for (const key of CLAUDE_API_AUTH_ENV_KEYS)
|
|
4651
|
+
env[key] = "";
|
|
4652
|
+
}
|
|
4653
|
+
return env;
|
|
4654
|
+
}
|
|
4655
|
+
function formatEnvAssignments(env) {
|
|
4656
|
+
return Object.entries(env).map(([name, value]) => `${name}=${JSON.stringify(value)}`).join(" ");
|
|
4657
|
+
}
|
|
4658
|
+
function formatExportLines(env) {
|
|
4659
|
+
return Object.entries(env).map(([name, value]) => `export ${name}=${JSON.stringify(value)}`).join(`
|
|
4660
|
+
`);
|
|
4661
|
+
}
|
|
4662
|
+
// src/lib/detect.ts
|
|
4663
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
|
|
4664
|
+
import { dirname as dirname4, join as join5 } from "node:path";
|
|
4665
|
+
function detectEmail(dir, tool) {
|
|
4666
|
+
if (!tool.accountFile || !tool.emailPath)
|
|
4667
|
+
return;
|
|
4668
|
+
const candidates = [join5(dir, tool.accountFile)];
|
|
4669
|
+
if (dir === tool.defaultDir)
|
|
4670
|
+
candidates.push(join5(dirname4(dir), tool.accountFile));
|
|
4671
|
+
for (const file of candidates) {
|
|
4672
|
+
const email = readEmail(file, tool.emailPath);
|
|
4673
|
+
if (email)
|
|
4674
|
+
return email;
|
|
4675
|
+
}
|
|
4676
|
+
return;
|
|
4677
|
+
}
|
|
4678
|
+
function readEmail(file, path) {
|
|
4679
|
+
if (!existsSync4(file))
|
|
4680
|
+
return;
|
|
4681
|
+
let cursor;
|
|
4682
|
+
try {
|
|
4683
|
+
cursor = JSON.parse(readFileSync3(file, "utf8"));
|
|
4684
|
+
} catch {
|
|
4685
|
+
return;
|
|
4686
|
+
}
|
|
4687
|
+
for (const key of path) {
|
|
4688
|
+
if (cursor && typeof cursor === "object" && key in cursor) {
|
|
4689
|
+
cursor = cursor[key];
|
|
4690
|
+
} else {
|
|
4691
|
+
return;
|
|
4692
|
+
}
|
|
4693
|
+
}
|
|
4694
|
+
return typeof cursor === "string" && cursor.includes("@") ? cursor : undefined;
|
|
4695
|
+
}
|
|
4696
|
+
// src/lib/profiles.ts
|
|
4697
|
+
import { homedir as homedir4 } from "node:os";
|
|
4698
|
+
import { isAbsolute, join as join6, resolve as resolve2 } from "node:path";
|
|
4699
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, rmSync } from "node:fs";
|
|
4700
|
+
function nowIso() {
|
|
4701
|
+
return new Date().toISOString();
|
|
4702
|
+
}
|
|
4703
|
+
function expandPath(p) {
|
|
4704
|
+
let out = p;
|
|
4705
|
+
if (out === "~")
|
|
4706
|
+
out = homedir4();
|
|
4707
|
+
else if (out.startsWith("~/"))
|
|
4708
|
+
out = join6(homedir4(), out.slice(2));
|
|
4709
|
+
return isAbsolute(out) ? out : resolve2(process.cwd(), out);
|
|
4710
|
+
}
|
|
4711
|
+
function listProfiles(toolId) {
|
|
4712
|
+
const profiles = loadStore().profiles;
|
|
4713
|
+
const filtered = toolId ? profiles.filter((p) => p.tool === toolId) : profiles;
|
|
4714
|
+
return filtered.slice().sort((a, b) => a.tool.localeCompare(b.tool) || a.name.localeCompare(b.name));
|
|
4715
|
+
}
|
|
4716
|
+
function profileMatches(name, toolId) {
|
|
4717
|
+
return loadStore().profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
|
|
4718
|
+
}
|
|
4719
|
+
function findProfile(name, toolId) {
|
|
4720
|
+
const matches = profileMatches(name, toolId);
|
|
4721
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
4722
|
+
}
|
|
4723
|
+
function getProfile(name, toolId) {
|
|
4724
|
+
const matches = profileMatches(name, toolId);
|
|
4725
|
+
if (matches.length === 0) {
|
|
4726
|
+
const suffix = toolId ? ` for tool "${toolId}"` : "";
|
|
4727
|
+
throw new AccountsError(`no profile named "${name}"${suffix}. Run \`accounts list\` to see profiles.`);
|
|
4728
|
+
}
|
|
4729
|
+
if (matches.length > 1) {
|
|
4730
|
+
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4731
|
+
}
|
|
4732
|
+
const profile = matches[0];
|
|
4733
|
+
return profile;
|
|
4734
|
+
}
|
|
4735
|
+
function addProfile(opts) {
|
|
4736
|
+
const name = opts.name;
|
|
4737
|
+
const nameCheck = profileNameSchema.safeParse(name);
|
|
4738
|
+
if (!nameCheck.success)
|
|
4739
|
+
throw new AccountsError(nameCheck.error.issues[0]?.message ?? "invalid profile name");
|
|
4740
|
+
const toolId = opts.tool ?? DEFAULT_TOOL;
|
|
4741
|
+
const tool = getTool(toolId);
|
|
4742
|
+
const store = loadStore();
|
|
4743
|
+
if (store.profiles.some((p) => p.name === name && p.tool === toolId)) {
|
|
4744
|
+
throw new AccountsError(`a ${toolId} profile named "${name}" already exists`);
|
|
4745
|
+
}
|
|
4746
|
+
const dir = opts.dir ? expandPath(opts.dir) : join6(profilesDir(), toolId, name);
|
|
4747
|
+
if (store.profiles.some((p) => p.dir === dir)) {
|
|
4748
|
+
throw new AccountsError(`a profile already uses config dir ${dir}`);
|
|
4749
|
+
}
|
|
4750
|
+
mkdirSync4(dir, { recursive: true });
|
|
4751
|
+
const email = opts.email ?? detectEmail(dir, tool);
|
|
4752
|
+
const profile = {
|
|
4753
|
+
name,
|
|
4754
|
+
tool: toolId,
|
|
4755
|
+
...email ? { email } : {},
|
|
4756
|
+
dir,
|
|
4757
|
+
...opts.description ? { description: opts.description } : {},
|
|
4758
|
+
createdAt: nowIso()
|
|
4759
|
+
};
|
|
4760
|
+
store.profiles.push(profile);
|
|
4761
|
+
saveStore(store);
|
|
4762
|
+
return profile;
|
|
4763
|
+
}
|
|
4764
|
+
function removeProfile(name, opts = {}) {
|
|
4765
|
+
const options = typeof opts === "boolean" ? { purge: opts } : opts;
|
|
4766
|
+
const store = loadStore();
|
|
4767
|
+
const matches = store.profiles.map((profile2, idx2) => ({ profile: profile2, idx: idx2 })).filter(({ profile: profile2 }) => profile2.name === name && (!options.tool || profile2.tool === options.tool));
|
|
4768
|
+
if (matches.length === 0) {
|
|
4769
|
+
const suffix = options.tool ? ` for tool "${options.tool}"` : "";
|
|
4770
|
+
throw new AccountsError(`no profile named "${name}"${suffix}`);
|
|
4771
|
+
}
|
|
4772
|
+
if (matches.length > 1) {
|
|
4773
|
+
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map(({ profile: profile2 }) => profile2.tool).join(", ")}); pass --tool`);
|
|
4774
|
+
}
|
|
4775
|
+
const idx = matches[0].idx;
|
|
4776
|
+
const profile = store.profiles[idx];
|
|
4777
|
+
store.profiles.splice(idx, 1);
|
|
4778
|
+
if (store.current[profile.tool] === name)
|
|
4779
|
+
delete store.current[profile.tool];
|
|
4780
|
+
if (store.applied[profile.tool] === name)
|
|
4781
|
+
delete store.applied[profile.tool];
|
|
4782
|
+
saveStore(store);
|
|
4783
|
+
let purged = false;
|
|
4784
|
+
let purgeNote;
|
|
4785
|
+
if (options.purge) {
|
|
4786
|
+
const managed = profile.dir.startsWith(profilesDir());
|
|
4787
|
+
const isDefault = profile.dir === getTool(profile.tool).defaultDir;
|
|
4788
|
+
if (managed && !isDefault && existsSync5(profile.dir)) {
|
|
4789
|
+
rmSync(profile.dir, { recursive: true, force: true });
|
|
4790
|
+
purged = true;
|
|
4791
|
+
} else {
|
|
4792
|
+
purgeNote = `refused to delete ${profile.dir} (not a managed profile dir); remove it manually if intended`;
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4795
|
+
return { profile, purged, purgeNote };
|
|
4796
|
+
}
|
|
4797
|
+
function renameProfile(oldName, newName, toolId) {
|
|
4798
|
+
const nameCheck = profileNameSchema.safeParse(newName);
|
|
4799
|
+
if (!nameCheck.success)
|
|
4800
|
+
throw new AccountsError(nameCheck.error.issues[0]?.message ?? "invalid profile name");
|
|
4801
|
+
const store = loadStore();
|
|
4802
|
+
const matches = store.profiles.filter((p) => p.name === oldName && (!toolId || p.tool === toolId));
|
|
4803
|
+
if (matches.length === 0) {
|
|
4804
|
+
const suffix = toolId ? ` for tool "${toolId}"` : "";
|
|
4805
|
+
throw new AccountsError(`no profile named "${oldName}"${suffix}`);
|
|
4806
|
+
}
|
|
4807
|
+
if (matches.length > 1) {
|
|
4808
|
+
throw new AccountsError(`profile "${oldName}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4809
|
+
}
|
|
4810
|
+
const profile = matches[0];
|
|
4811
|
+
if (store.profiles.some((p) => p.name === newName && p.tool === profile.tool)) {
|
|
4812
|
+
throw new AccountsError(`a ${profile.tool} profile named "${newName}" already exists`);
|
|
4813
|
+
}
|
|
4814
|
+
if (store.current[profile.tool] === oldName)
|
|
4815
|
+
store.current[profile.tool] = newName;
|
|
4816
|
+
if (store.applied[profile.tool] === oldName)
|
|
4817
|
+
store.applied[profile.tool] = newName;
|
|
4818
|
+
profile.name = newName;
|
|
4819
|
+
saveStore(store);
|
|
4820
|
+
return profile;
|
|
4821
|
+
}
|
|
4822
|
+
function updateProfile(name, opts) {
|
|
4823
|
+
const store = loadStore();
|
|
4824
|
+
const matches = store.profiles.filter((p) => p.name === name && (!opts.tool || p.tool === opts.tool));
|
|
4825
|
+
if (matches.length === 0) {
|
|
4826
|
+
const suffix = opts.tool ? ` for tool "${opts.tool}"` : "";
|
|
4827
|
+
throw new AccountsError(`no profile named "${name}"${suffix}`);
|
|
4828
|
+
}
|
|
4829
|
+
if (matches.length > 1) {
|
|
4830
|
+
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4831
|
+
}
|
|
4832
|
+
const profile = matches[0];
|
|
4833
|
+
if (opts.email !== undefined)
|
|
4834
|
+
profile.email = opts.email;
|
|
4835
|
+
if (opts.description !== undefined)
|
|
4836
|
+
profile.description = opts.description;
|
|
4837
|
+
if (opts.dir !== undefined) {
|
|
4838
|
+
const dir = expandPath(opts.dir);
|
|
4839
|
+
mkdirSync4(dir, { recursive: true });
|
|
4840
|
+
profile.dir = dir;
|
|
4841
|
+
}
|
|
4842
|
+
saveStore(store);
|
|
4843
|
+
return profile;
|
|
4844
|
+
}
|
|
4845
|
+
function redetectEmail(name, toolId) {
|
|
4846
|
+
const store = loadStore();
|
|
4847
|
+
const matches = store.profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
|
|
4848
|
+
if (matches.length === 0) {
|
|
4849
|
+
const suffix = toolId ? ` for tool "${toolId}"` : "";
|
|
4850
|
+
throw new AccountsError(`no profile named "${name}"${suffix}`);
|
|
4851
|
+
}
|
|
4852
|
+
if (matches.length > 1) {
|
|
4853
|
+
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4854
|
+
}
|
|
4855
|
+
const profile = matches[0];
|
|
4856
|
+
const email = detectEmail(profile.dir, getTool(profile.tool));
|
|
4857
|
+
if (email)
|
|
4858
|
+
profile.email = email;
|
|
4859
|
+
saveStore(store);
|
|
4860
|
+
return profile;
|
|
4861
|
+
}
|
|
4862
|
+
function useProfile(name, toolId) {
|
|
4863
|
+
const store = loadStore();
|
|
4864
|
+
const matches = store.profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
|
|
4865
|
+
if (matches.length === 0) {
|
|
4866
|
+
const suffix = toolId ? ` for tool "${toolId}"` : "";
|
|
4867
|
+
throw new AccountsError(`no profile named "${name}"${suffix}`);
|
|
4868
|
+
}
|
|
4869
|
+
if (matches.length > 1) {
|
|
4870
|
+
throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
|
|
4871
|
+
}
|
|
4872
|
+
const profile = matches[0];
|
|
4873
|
+
store.current[profile.tool] = name;
|
|
4874
|
+
profile.lastUsedAt = nowIso();
|
|
4875
|
+
saveStore(store);
|
|
4876
|
+
return { profile, toolId: profile.tool };
|
|
4877
|
+
}
|
|
4878
|
+
function currentProfile(toolId) {
|
|
4879
|
+
const store = loadStore();
|
|
4880
|
+
const name = store.current[toolId];
|
|
4881
|
+
if (!name)
|
|
4882
|
+
return;
|
|
4883
|
+
return store.profiles.find((p) => p.name === name);
|
|
4884
|
+
}
|
|
4823
4885
|
// src/lib/apply-lock.ts
|
|
4824
4886
|
import { closeSync, existsSync as existsSync6, mkdirSync as mkdirSync5, openSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
4825
4887
|
import { join as join7 } from "node:path";
|
|
@@ -5473,6 +5535,9 @@ export {
|
|
|
5473
5535
|
shellSnippet,
|
|
5474
5536
|
sendSupervisorRequest,
|
|
5475
5537
|
saveStore,
|
|
5538
|
+
sanitizeLiveClaudeOAuthSettings,
|
|
5539
|
+
sanitizeClaudeProfileApiSettings,
|
|
5540
|
+
sanitizeClaudeOAuthProfileSettings,
|
|
5476
5541
|
runSupervisedTool,
|
|
5477
5542
|
restoreClaudeAuthFromProfile,
|
|
5478
5543
|
resolveSupervisorLaunch,
|
|
@@ -5517,6 +5582,7 @@ export {
|
|
|
5517
5582
|
addCustomTool,
|
|
5518
5583
|
accountsHome,
|
|
5519
5584
|
DEFAULT_TOOL,
|
|
5585
|
+
CLAUDE_API_AUTH_ENV_KEYS,
|
|
5520
5586
|
BUILTIN_TOOLS,
|
|
5521
5587
|
AccountsError
|
|
5522
5588
|
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { ToolDef } from "../types.js";
|
|
2
|
+
export declare const CLAUDE_API_AUTH_ENV_KEYS: readonly ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_BASE_URL", "CLAUDE_CODE_API_KEY_HELPER", "CLAUDE_CODE_API_KEY_HELPER_TTL_MS", "CLAUDE_CODE_USE_BEDROCK", "CLAUDE_CODE_USE_VERTEX"];
|
|
3
|
+
export declare function sanitizeClaudeProfileApiSettings(profileDir: string, tool: ToolDef): boolean;
|
|
4
|
+
export declare function sanitizeClaudeOAuthProfileSettings(profileDir: string, tool: ToolDef): boolean;
|
|
5
|
+
export declare function sanitizeLiveClaudeOAuthSettings(): boolean;
|
|
2
6
|
/** Email address of the account currently authenticated on the live Claude paths. */
|
|
3
7
|
export declare function liveOAuthEmail(): string | undefined;
|
|
4
8
|
/** Snapshot live Claude auth into a profile directory (used when switching away on apply). */
|
|
@@ -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;
|
|
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;AAuB3C,eAAO,MAAM,wBAAwB,sMAQ3B,CAAC;AAoGX,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAG3F;AAED,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAM7F;AAED,wBAAgB,+BAA+B,IAAI,OAAO,CAEzD;AAED,qFAAqF;AACrF,wBAAgB,cAAc,IAAI,MAAM,GAAG,SAAS,CAKnD;AAED,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;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,EACb,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,IAAI,CAmBN;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,CAwDN;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAM3D"}
|
package/dist/lib/env.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAOpD,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYlF;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAIxE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAIrE"}
|
package/dist/mcp.js
CHANGED
|
@@ -17072,6 +17072,15 @@ function writeClaudeKeychain(cred) {
|
|
|
17072
17072
|
}
|
|
17073
17073
|
|
|
17074
17074
|
// src/lib/claude-auth.ts
|
|
17075
|
+
var CLAUDE_API_AUTH_ENV_KEYS = [
|
|
17076
|
+
"ANTHROPIC_API_KEY",
|
|
17077
|
+
"ANTHROPIC_AUTH_TOKEN",
|
|
17078
|
+
"ANTHROPIC_BASE_URL",
|
|
17079
|
+
"CLAUDE_CODE_API_KEY_HELPER",
|
|
17080
|
+
"CLAUDE_CODE_API_KEY_HELPER_TTL_MS",
|
|
17081
|
+
"CLAUDE_CODE_USE_BEDROCK",
|
|
17082
|
+
"CLAUDE_CODE_USE_VERTEX"
|
|
17083
|
+
];
|
|
17075
17084
|
function readJsonFile(path) {
|
|
17076
17085
|
if (!existsSync3(path))
|
|
17077
17086
|
return;
|
|
@@ -17090,6 +17099,11 @@ function writeJsonFile(path, data, stayUnder) {
|
|
|
17090
17099
|
function readOAuthFromPaths(paths) {
|
|
17091
17100
|
return findOAuthSource(paths)?.oauth;
|
|
17092
17101
|
}
|
|
17102
|
+
function readOAuthSnapshot(profileDir) {
|
|
17103
|
+
const snap = readJsonFile(profileOAuthSnapshot(profileDir));
|
|
17104
|
+
const oauth = snap?.oauthAccount;
|
|
17105
|
+
return oauth && typeof oauth === "object" ? oauth : undefined;
|
|
17106
|
+
}
|
|
17093
17107
|
function findOAuthSource(paths) {
|
|
17094
17108
|
for (const p of paths) {
|
|
17095
17109
|
const data = readJsonFile(p);
|
|
@@ -17131,6 +17145,46 @@ function mergeOAuthInto(paths, oauth, allowDelete, stayUnder) {
|
|
|
17131
17145
|
}
|
|
17132
17146
|
}
|
|
17133
17147
|
}
|
|
17148
|
+
function sanitizeSettingsFile(configDir, stayUnder) {
|
|
17149
|
+
const settingsPath = join4(configDir, "settings.json");
|
|
17150
|
+
const settings = readJsonFile(settingsPath);
|
|
17151
|
+
if (!settings)
|
|
17152
|
+
return false;
|
|
17153
|
+
let changed = false;
|
|
17154
|
+
if ("apiKeyHelper" in settings) {
|
|
17155
|
+
delete settings.apiKeyHelper;
|
|
17156
|
+
changed = true;
|
|
17157
|
+
}
|
|
17158
|
+
const env = settings.env;
|
|
17159
|
+
if (env && typeof env === "object" && !Array.isArray(env)) {
|
|
17160
|
+
const envRecord = env;
|
|
17161
|
+
for (const key of CLAUDE_API_AUTH_ENV_KEYS) {
|
|
17162
|
+
if (key in envRecord) {
|
|
17163
|
+
delete envRecord[key];
|
|
17164
|
+
changed = true;
|
|
17165
|
+
}
|
|
17166
|
+
}
|
|
17167
|
+
}
|
|
17168
|
+
if (changed)
|
|
17169
|
+
writeJsonFile(settingsPath, settings, stayUnder);
|
|
17170
|
+
return changed;
|
|
17171
|
+
}
|
|
17172
|
+
function sanitizeClaudeProfileApiSettings(profileDir, tool) {
|
|
17173
|
+
if (tool.id !== "claude")
|
|
17174
|
+
return false;
|
|
17175
|
+
return sanitizeSettingsFile(profileDir, profileDir);
|
|
17176
|
+
}
|
|
17177
|
+
function sanitizeClaudeOAuthProfileSettings(profileDir, tool) {
|
|
17178
|
+
if (tool.id !== "claude")
|
|
17179
|
+
return false;
|
|
17180
|
+
if (!readOAuthSnapshot(profileDir) && !readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool))) {
|
|
17181
|
+
return false;
|
|
17182
|
+
}
|
|
17183
|
+
return sanitizeClaudeProfileApiSettings(profileDir, tool);
|
|
17184
|
+
}
|
|
17185
|
+
function sanitizeLiveClaudeOAuthSettings() {
|
|
17186
|
+
return sanitizeSettingsFile(liveClaudePaths().configDir, liveClaudeBase());
|
|
17187
|
+
}
|
|
17134
17188
|
function liveOAuthEmail() {
|
|
17135
17189
|
const live = liveClaudePaths();
|
|
17136
17190
|
const oauth = readOAuthFromPaths([live.homeJson]);
|
|
@@ -17171,6 +17225,7 @@ function ensureProfileAuthSnapshot(profileDir, tool, opts = {}) {
|
|
|
17171
17225
|
assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
|
|
17172
17226
|
copyFileSync(credFile, credSnap);
|
|
17173
17227
|
}
|
|
17228
|
+
sanitizeClaudeOAuthProfileSettings(profileDir, tool);
|
|
17174
17229
|
}
|
|
17175
17230
|
function profileHasAuth(profileDir, tool) {
|
|
17176
17231
|
return hasAuthSnapshot(profileDir) || !!readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool));
|
|
@@ -17189,6 +17244,8 @@ function restoreClaudeAuthFromProfile(profileDir, tool, profileName) {
|
|
|
17189
17244
|
if (!oauth) {
|
|
17190
17245
|
throw new AccountsError("profile has no OAuth account data to apply");
|
|
17191
17246
|
}
|
|
17247
|
+
sanitizeClaudeOAuthProfileSettings(profileDir, tool);
|
|
17248
|
+
sanitizeLiveClaudeOAuthSettings();
|
|
17192
17249
|
assertSafeWritePath(live.homeJson, { mustStayUnder: liveRoot });
|
|
17193
17250
|
mergeOAuthInto([live.homeJson], oauth, false, liveRoot);
|
|
17194
17251
|
const credSnap = profileCredentialsSnapshot(profileDir);
|
|
@@ -17306,6 +17363,11 @@ function profileEnv(profile, tool) {
|
|
|
17306
17363
|
for (const [name, value] of Object.entries(tool.extraEnv ?? {})) {
|
|
17307
17364
|
env[name] = renderTemplate(value, profile);
|
|
17308
17365
|
}
|
|
17366
|
+
if (tool.id === "claude") {
|
|
17367
|
+
sanitizeClaudeProfileApiSettings(profile.dir, tool);
|
|
17368
|
+
for (const key of CLAUDE_API_AUTH_ENV_KEYS)
|
|
17369
|
+
env[key] = "";
|
|
17370
|
+
}
|
|
17309
17371
|
return env;
|
|
17310
17372
|
}
|
|
17311
17373
|
function formatEnvAssignments(env) {
|
|
@@ -17464,7 +17526,7 @@ function ok(data) {
|
|
|
17464
17526
|
function fail(message) {
|
|
17465
17527
|
return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
|
|
17466
17528
|
}
|
|
17467
|
-
var server = new Server({ name: "accounts", version: "0.1.
|
|
17529
|
+
var server = new Server({ name: "accounts", version: "0.1.12" }, { capabilities: { tools: {} } });
|
|
17468
17530
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
17469
17531
|
tools: [
|
|
17470
17532
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/accounts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
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",
|