@hasna/accounts 0.1.11 → 0.1.13

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/index.js CHANGED
@@ -3999,6 +3999,7 @@ var toolDefSchema = exports_external.object({
3999
3999
  loginArgs: exports_external.array(exports_external.string()).optional(),
4000
4000
  loginHint: exports_external.string().optional(),
4001
4001
  resumeArgs: exports_external.array(exports_external.string()).optional(),
4002
+ permissionArgs: exports_external.record(exports_external.array(exports_external.string())).optional(),
4002
4003
  accountFile: exports_external.string().optional(),
4003
4004
  emailPath: exports_external.array(exports_external.string()).optional()
4004
4005
  });
@@ -4174,6 +4175,15 @@ var BUILTIN_TOOLS = [
4174
4175
  bin: "claude",
4175
4176
  loginHint: "run /login inside Claude, then /exit when done",
4176
4177
  resumeArgs: ["--continue"],
4178
+ permissionArgs: {
4179
+ dangerous: ["--dangerously-skip-permissions"],
4180
+ "allow-dangerous": ["--allow-dangerously-skip-permissions"],
4181
+ bypass: ["--permission-mode", "bypassPermissions"],
4182
+ auto: ["--permission-mode", "auto"],
4183
+ "accept-edits": ["--permission-mode", "acceptEdits"],
4184
+ "dont-ask": ["--permission-mode", "dontAsk"],
4185
+ plan: ["--permission-mode", "plan"]
4186
+ },
4177
4187
  accountFile: ".claude.json",
4178
4188
  emailPath: ["oauthAccount", "emailAddress"]
4179
4189
  },
@@ -4185,7 +4195,10 @@ var BUILTIN_TOOLS = [
4185
4195
  bin: "codex",
4186
4196
  loginArgs: ["login"],
4187
4197
  loginHint: "complete the Codex login flow for this CODEX_HOME",
4188
- resumeArgs: ["resume", "--last"]
4198
+ resumeArgs: ["resume", "--last"],
4199
+ permissionArgs: {
4200
+ dangerous: ["--dangerously-bypass-approvals-and-sandbox"]
4201
+ }
4189
4202
  },
4190
4203
  {
4191
4204
  id: "takumi",
@@ -4195,6 +4208,15 @@ var BUILTIN_TOOLS = [
4195
4208
  bin: "takumi",
4196
4209
  loginHint: "complete Takumi auth in this TAKUMI_CONFIG_DIR",
4197
4210
  resumeArgs: ["--continue"],
4211
+ permissionArgs: {
4212
+ dangerous: ["--dangerously-skip-permissions"],
4213
+ "allow-dangerous": ["--allow-dangerously-skip-permissions"],
4214
+ bypass: ["--permission-mode", "bypassPermissions"],
4215
+ auto: ["--permission-mode", "auto"],
4216
+ "accept-edits": ["--permission-mode", "acceptEdits"],
4217
+ "dont-ask": ["--permission-mode", "dontAsk"],
4218
+ plan: ["--permission-mode", "plan"]
4219
+ },
4198
4220
  accountFile: ".claude.json",
4199
4221
  emailPath: ["oauthAccount", "emailAddress"]
4200
4222
  },
@@ -4204,7 +4226,13 @@ var BUILTIN_TOOLS = [
4204
4226
  envVar: "GEMINI_CONFIG_DIR",
4205
4227
  defaultDir: join2(homedir2(), ".gemini"),
4206
4228
  bin: "gemini",
4207
- loginHint: "complete Gemini auth in this GEMINI_CONFIG_DIR"
4229
+ loginHint: "complete Gemini auth in this GEMINI_CONFIG_DIR",
4230
+ permissionArgs: {
4231
+ dangerous: ["--yolo"],
4232
+ yolo: ["--yolo"],
4233
+ "auto-edit": ["--approval-mode", "auto_edit"],
4234
+ plan: ["--approval-mode", "plan"]
4235
+ }
4208
4236
  },
4209
4237
  {
4210
4238
  id: "opencode",
@@ -4243,7 +4271,11 @@ var BUILTIN_TOOLS = [
4243
4271
  envVar: "HERMES_HOME",
4244
4272
  defaultDir: join2(homedir2(), ".hermes"),
4245
4273
  bin: "hermes",
4246
- loginHint: "complete Hermes auth in this HERMES_HOME"
4274
+ loginHint: "complete Hermes auth in this HERMES_HOME",
4275
+ permissionArgs: {
4276
+ dangerous: ["--yolo"],
4277
+ yolo: ["--yolo"]
4278
+ }
4247
4279
  },
4248
4280
  {
4249
4281
  id: "kimi",
@@ -4252,7 +4284,13 @@ var BUILTIN_TOOLS = [
4252
4284
  defaultDir: join2(homedir2(), ".kimi-code"),
4253
4285
  bin: "kimi",
4254
4286
  loginArgs: ["login"],
4255
- loginHint: "complete kimi login for this KIMI_CODE_HOME"
4287
+ loginHint: "complete kimi login for this KIMI_CODE_HOME",
4288
+ permissionArgs: {
4289
+ dangerous: ["--yolo"],
4290
+ yolo: ["--yolo"],
4291
+ auto: ["--auto"],
4292
+ plan: ["--plan"]
4293
+ }
4256
4294
  },
4257
4295
  {
4258
4296
  id: "grok",
@@ -4265,6 +4303,43 @@ var BUILTIN_TOOLS = [
4265
4303
  }
4266
4304
  ];
4267
4305
  var DEFAULT_TOOL = "claude";
4306
+ var PERMISSION_ALIASES = new Map([
4307
+ ["danger", "dangerous"],
4308
+ ["dangerously-skip-permissions", "dangerous"],
4309
+ ["skip-permissions", "dangerous"],
4310
+ ["skip", "dangerous"],
4311
+ ["bypasspermissions", "bypass"],
4312
+ ["bypass-permissions", "bypass"],
4313
+ ["acceptedits", "accept-edits"],
4314
+ ["accept-edit", "accept-edits"],
4315
+ ["autoedit", "auto-edit"],
4316
+ ["auto-edits", "auto-edit"],
4317
+ ["auto_edit", "auto-edit"],
4318
+ ["dontask", "dont-ask"],
4319
+ ["dont-ask-permissions", "dont-ask"]
4320
+ ]);
4321
+ function normalizePermissionPreset(value) {
4322
+ const normalized = value.trim().replace(/^--/, "").replaceAll("_", "-").toLowerCase();
4323
+ return PERMISSION_ALIASES.get(normalized) ?? normalized;
4324
+ }
4325
+ function permissionArgsFor(tool, permissions) {
4326
+ if (!permissions)
4327
+ return [];
4328
+ const preset = normalizePermissionPreset(permissions);
4329
+ if (preset === "default" || preset === "none" || preset === "off")
4330
+ return [];
4331
+ const args = tool.permissionArgs?.[preset];
4332
+ if (!args) {
4333
+ const supported = Object.keys(tool.permissionArgs ?? {}).sort();
4334
+ const suffix = supported.length > 0 ? ` Supported permissions: ${supported.join(", ")}.` : " No permission presets are configured.";
4335
+ throw new AccountsError(`tool "${tool.id}" does not support permissions "${permissions}".${suffix}`);
4336
+ }
4337
+ return args;
4338
+ }
4339
+ function mergeToolArgs(tool, args, opts = {}) {
4340
+ const permissionArgs = permissionArgsFor(tool, opts.permissions).filter((arg) => !args.includes(arg));
4341
+ return [...permissionArgs, ...args];
4342
+ }
4268
4343
  var BUILTIN_IDS = new Set(BUILTIN_TOOLS.map((t) => t.id));
4269
4344
  function isBuiltinTool(id) {
4270
4345
  return BUILTIN_IDS.has(id);
@@ -4317,256 +4392,13 @@ function removeCustomTool(id) {
4317
4392
  store.tools.splice(idx, 1);
4318
4393
  saveStore(store);
4319
4394
  }
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
4395
  // src/lib/claude-auth.ts
4564
- import { copyFileSync, existsSync as existsSync5, lstatSync as lstatSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync3, statSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
4565
- import { dirname as dirname4, join as join6 } from "node:path";
4396
+ import { copyFileSync, existsSync as existsSync3, lstatSync as lstatSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync2, statSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
4397
+ import { dirname as dirname3, join as join4 } from "node:path";
4566
4398
 
4567
4399
  // src/lib/claude-layout.ts
4568
- import { homedir as homedir4 } from "node:os";
4569
- import { dirname as dirname3, join as join5 } from "node:path";
4400
+ import { homedir as homedir3 } from "node:os";
4401
+ import { dirname as dirname2, join as join3 } from "node:path";
4570
4402
  var CLAUDE_KEYCHAIN_SERVICE = "Claude Code-credentials";
4571
4403
  var ACCOUNTS_AUTH_DIR = ".accounts-auth";
4572
4404
  var OAUTH_SNAPSHOT = "oauth-account.json";
@@ -4574,36 +4406,36 @@ var CREDENTIALS_SNAPSHOT = "credentials.json";
4574
4406
  var KEYCHAIN_SNAPSHOT = "keychain.json";
4575
4407
  function liveClaudeBase() {
4576
4408
  const testBase = process.env.ACCOUNTS_TEST_LIVE_DIR;
4577
- return testBase && testBase.trim() ? testBase : homedir4();
4409
+ return testBase && testBase.trim() ? testBase : homedir3();
4578
4410
  }
4579
4411
  function liveClaudePaths() {
4580
4412
  const base = liveClaudeBase();
4581
- const configDir = join5(base, ".claude");
4413
+ const configDir = join3(base, ".claude");
4582
4414
  return {
4583
4415
  configDir,
4584
- homeJson: join5(base, ".claude.json"),
4585
- credentialsFile: join5(configDir, ".credentials.json")
4416
+ homeJson: join3(base, ".claude.json"),
4417
+ credentialsFile: join3(configDir, ".credentials.json")
4586
4418
  };
4587
4419
  }
4588
4420
  function profileAccountJsonPaths(profileDir, tool) {
4589
4421
  if (!tool.accountFile)
4590
4422
  return [];
4591
- const paths = [join5(profileDir, tool.accountFile)];
4423
+ const paths = [join3(profileDir, tool.accountFile)];
4592
4424
  if (profileDir === tool.defaultDir)
4593
- paths.push(join5(dirname3(profileDir), tool.accountFile));
4425
+ paths.push(join3(dirname2(profileDir), tool.accountFile));
4594
4426
  return paths;
4595
4427
  }
4596
4428
  function profileAuthDir(profileDir) {
4597
- return join5(profileDir, ACCOUNTS_AUTH_DIR);
4429
+ return join3(profileDir, ACCOUNTS_AUTH_DIR);
4598
4430
  }
4599
4431
  function profileOAuthSnapshot(profileDir) {
4600
- return join5(profileAuthDir(profileDir), OAUTH_SNAPSHOT);
4432
+ return join3(profileAuthDir(profileDir), OAUTH_SNAPSHOT);
4601
4433
  }
4602
4434
  function profileCredentialsSnapshot(profileDir) {
4603
- return join5(profileAuthDir(profileDir), CREDENTIALS_SNAPSHOT);
4435
+ return join3(profileAuthDir(profileDir), CREDENTIALS_SNAPSHOT);
4604
4436
  }
4605
4437
  function profileKeychainSnapshot(profileDir) {
4606
- return join5(profileAuthDir(profileDir), KEYCHAIN_SNAPSHOT);
4438
+ return join3(profileAuthDir(profileDir), KEYCHAIN_SNAPSHOT);
4607
4439
  }
4608
4440
 
4609
4441
  // src/lib/keychain.ts
@@ -4667,24 +4499,38 @@ function writeClaudeKeychain(cred) {
4667
4499
  }
4668
4500
 
4669
4501
  // src/lib/claude-auth.ts
4502
+ var CLAUDE_API_AUTH_ENV_KEYS = [
4503
+ "ANTHROPIC_API_KEY",
4504
+ "ANTHROPIC_AUTH_TOKEN",
4505
+ "ANTHROPIC_BASE_URL",
4506
+ "CLAUDE_CODE_API_KEY_HELPER",
4507
+ "CLAUDE_CODE_API_KEY_HELPER_TTL_MS",
4508
+ "CLAUDE_CODE_USE_BEDROCK",
4509
+ "CLAUDE_CODE_USE_VERTEX"
4510
+ ];
4670
4511
  function readJsonFile(path) {
4671
- if (!existsSync5(path))
4512
+ if (!existsSync3(path))
4672
4513
  return;
4673
4514
  try {
4674
- return JSON.parse(readFileSync3(path, "utf8"));
4515
+ return JSON.parse(readFileSync2(path, "utf8"));
4675
4516
  } catch {
4676
4517
  return;
4677
4518
  }
4678
4519
  }
4679
4520
  function writeJsonFile(path, data, stayUnder) {
4680
4521
  assertSafeWritePath(path, stayUnder ? { mustStayUnder: stayUnder } : undefined);
4681
- mkdirSync4(dirname4(path), { recursive: true });
4522
+ mkdirSync3(dirname3(path), { recursive: true });
4682
4523
  writeFileSync2(path, JSON.stringify(data, null, 2) + `
4683
4524
  `, { mode: 384 });
4684
4525
  }
4685
4526
  function readOAuthFromPaths(paths) {
4686
4527
  return findOAuthSource(paths)?.oauth;
4687
4528
  }
4529
+ function readOAuthSnapshot(profileDir) {
4530
+ const snap = readJsonFile(profileOAuthSnapshot(profileDir));
4531
+ const oauth = snap?.oauthAccount;
4532
+ return oauth && typeof oauth === "object" ? oauth : undefined;
4533
+ }
4688
4534
  function findOAuthSource(paths) {
4689
4535
  for (const p of paths) {
4690
4536
  const data = readJsonFile(p);
@@ -4695,7 +4541,7 @@ function findOAuthSource(paths) {
4695
4541
  return;
4696
4542
  }
4697
4543
  function snapshotIsStale(sourcePath, snapshotPath) {
4698
- if (!existsSync5(snapshotPath))
4544
+ if (!existsSync3(snapshotPath))
4699
4545
  return true;
4700
4546
  try {
4701
4547
  return statSync(sourcePath).mtimeMs > statSync(snapshotPath).mtimeMs;
@@ -4726,6 +4572,46 @@ function mergeOAuthInto(paths, oauth, allowDelete, stayUnder) {
4726
4572
  }
4727
4573
  }
4728
4574
  }
4575
+ function sanitizeSettingsFile(configDir, stayUnder) {
4576
+ const settingsPath = join4(configDir, "settings.json");
4577
+ const settings = readJsonFile(settingsPath);
4578
+ if (!settings)
4579
+ return false;
4580
+ let changed = false;
4581
+ if ("apiKeyHelper" in settings) {
4582
+ delete settings.apiKeyHelper;
4583
+ changed = true;
4584
+ }
4585
+ const env = settings.env;
4586
+ if (env && typeof env === "object" && !Array.isArray(env)) {
4587
+ const envRecord = env;
4588
+ for (const key of CLAUDE_API_AUTH_ENV_KEYS) {
4589
+ if (key in envRecord) {
4590
+ delete envRecord[key];
4591
+ changed = true;
4592
+ }
4593
+ }
4594
+ }
4595
+ if (changed)
4596
+ writeJsonFile(settingsPath, settings, stayUnder);
4597
+ return changed;
4598
+ }
4599
+ function sanitizeClaudeProfileApiSettings(profileDir, tool) {
4600
+ if (tool.id !== "claude")
4601
+ return false;
4602
+ return sanitizeSettingsFile(profileDir, profileDir);
4603
+ }
4604
+ function sanitizeClaudeOAuthProfileSettings(profileDir, tool) {
4605
+ if (tool.id !== "claude")
4606
+ return false;
4607
+ if (!readOAuthSnapshot(profileDir) && !readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool))) {
4608
+ return false;
4609
+ }
4610
+ return sanitizeClaudeProfileApiSettings(profileDir, tool);
4611
+ }
4612
+ function sanitizeLiveClaudeOAuthSettings() {
4613
+ return sanitizeSettingsFile(liveClaudePaths().configDir, liveClaudeBase());
4614
+ }
4729
4615
  function liveOAuthEmail() {
4730
4616
  const live = liveClaudePaths();
4731
4617
  const oauth = readOAuthFromPaths([live.homeJson]);
@@ -4734,13 +4620,13 @@ function liveOAuthEmail() {
4734
4620
  }
4735
4621
  function snapshotLiveAuthToProfile(profileDir, _tool) {
4736
4622
  const authDir = profileAuthDir(profileDir);
4737
- assertSafeWritePath(join6(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
4738
- mkdirSync4(authDir, { recursive: true });
4623
+ assertSafeWritePath(join4(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
4624
+ mkdirSync3(authDir, { recursive: true });
4739
4625
  const live = liveClaudePaths();
4740
4626
  const oauth = readOAuthFromPaths([live.homeJson]);
4741
4627
  if (oauth)
4742
4628
  writeJsonFile(profileOAuthSnapshot(profileDir), { oauthAccount: oauth }, profileDir);
4743
- if (existsSync5(live.credentialsFile)) {
4629
+ if (existsSync3(live.credentialsFile)) {
4744
4630
  const dest = profileCredentialsSnapshot(profileDir);
4745
4631
  assertSafeWritePath(dest, { mustStayUnder: profileDir });
4746
4632
  copyFileSync(live.credentialsFile, dest);
@@ -4756,19 +4642,20 @@ function snapshotClaudeAuthToProfile(profileDir, tool) {
4756
4642
  }
4757
4643
  function ensureProfileAuthSnapshot(profileDir, tool, opts = {}) {
4758
4644
  const authDir = profileAuthDir(profileDir);
4759
- assertSafeWritePath(join6(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
4760
- mkdirSync4(authDir, { recursive: true });
4645
+ assertSafeWritePath(join4(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
4646
+ mkdirSync3(authDir, { recursive: true });
4761
4647
  const oauthSource = findOAuthSource(profileAccountJsonPaths(profileDir, tool));
4762
4648
  const oauthSnap = profileOAuthSnapshot(profileDir);
4763
4649
  if (oauthSource && (opts.overwrite || snapshotIsStale(oauthSource.path, oauthSnap))) {
4764
4650
  writeJsonFile(oauthSnap, { oauthAccount: oauthSource.oauth }, profileDir);
4765
4651
  }
4766
- const credFile = join6(profileDir, ".credentials.json");
4652
+ const credFile = join4(profileDir, ".credentials.json");
4767
4653
  const credSnap = profileCredentialsSnapshot(profileDir);
4768
- if (existsSync5(credFile) && (opts.overwrite || snapshotIsStale(credFile, credSnap))) {
4654
+ if (existsSync3(credFile) && (opts.overwrite || snapshotIsStale(credFile, credSnap))) {
4769
4655
  assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
4770
4656
  copyFileSync(credFile, credSnap);
4771
4657
  }
4658
+ sanitizeClaudeOAuthProfileSettings(profileDir, tool);
4772
4659
  }
4773
4660
  function profileHasAuth(profileDir, tool) {
4774
4661
  return hasAuthSnapshot(profileDir) || !!readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool));
@@ -4781,21 +4668,23 @@ function restoreClaudeAuthFromProfile(profileDir, tool, profileName) {
4781
4668
  ensureProfileAuthSnapshot(profileDir, tool);
4782
4669
  const live = liveClaudePaths();
4783
4670
  const liveRoot = liveClaudeBase();
4784
- mkdirSync4(live.configDir, { recursive: true });
4671
+ mkdirSync3(live.configDir, { recursive: true });
4785
4672
  const oauthSnap = readJsonFile(profileOAuthSnapshot(profileDir));
4786
4673
  const oauth = oauthSnap?.oauthAccount && typeof oauthSnap.oauthAccount === "object" ? oauthSnap.oauthAccount : readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool));
4787
4674
  if (!oauth) {
4788
4675
  throw new AccountsError("profile has no OAuth account data to apply");
4789
4676
  }
4677
+ sanitizeClaudeOAuthProfileSettings(profileDir, tool);
4678
+ sanitizeLiveClaudeOAuthSettings();
4790
4679
  assertSafeWritePath(live.homeJson, { mustStayUnder: liveRoot });
4791
4680
  mergeOAuthInto([live.homeJson], oauth, false, liveRoot);
4792
4681
  const credSnap = profileCredentialsSnapshot(profileDir);
4793
- if (existsSync5(credSnap)) {
4682
+ if (existsSync3(credSnap)) {
4794
4683
  assertSafeWritePath(live.credentialsFile, { mustStayUnder: liveRoot });
4795
4684
  assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
4796
4685
  copyFileSync(credSnap, live.credentialsFile);
4797
- writeFileSync2(live.credentialsFile, readFileSync3(live.credentialsFile), { mode: 384 });
4798
- } else if (existsSync5(live.credentialsFile)) {
4686
+ writeFileSync2(live.credentialsFile, readFileSync2(live.credentialsFile), { mode: 384 });
4687
+ } else if (existsSync3(live.credentialsFile)) {
4799
4688
  if (!lstatSync2(live.credentialsFile).isSymbolicLink())
4800
4689
  unlinkSync(live.credentialsFile);
4801
4690
  }
@@ -4817,9 +4706,257 @@ function restoreClaudeAuthFromProfile(profileDir, tool, profileName) {
4817
4706
  }
4818
4707
  }
4819
4708
  function hasAuthSnapshot(profileDir) {
4820
- return existsSync5(profileOAuthSnapshot(profileDir)) || existsSync5(profileCredentialsSnapshot(profileDir)) || existsSync5(profileKeychainSnapshot(profileDir));
4709
+ return existsSync3(profileOAuthSnapshot(profileDir)) || existsSync3(profileCredentialsSnapshot(profileDir)) || existsSync3(profileKeychainSnapshot(profileDir));
4821
4710
  }
4822
4711
 
4712
+ // src/lib/env.ts
4713
+ function renderTemplate(value, profile) {
4714
+ return value.replaceAll("{profileDir}", profile.dir).replaceAll("{profileName}", profile.name).replaceAll("{toolId}", profile.tool);
4715
+ }
4716
+ function profileEnv(profile, tool) {
4717
+ const env = {
4718
+ [tool.envVar]: profile.dir
4719
+ };
4720
+ for (const [name, value] of Object.entries(tool.extraEnv ?? {})) {
4721
+ env[name] = renderTemplate(value, profile);
4722
+ }
4723
+ if (tool.id === "claude") {
4724
+ sanitizeClaudeProfileApiSettings(profile.dir, tool);
4725
+ for (const key of CLAUDE_API_AUTH_ENV_KEYS)
4726
+ env[key] = "";
4727
+ }
4728
+ return env;
4729
+ }
4730
+ function formatEnvAssignments(env) {
4731
+ return Object.entries(env).map(([name, value]) => `${name}=${JSON.stringify(value)}`).join(" ");
4732
+ }
4733
+ function formatExportLines(env) {
4734
+ return Object.entries(env).map(([name, value]) => `export ${name}=${JSON.stringify(value)}`).join(`
4735
+ `);
4736
+ }
4737
+ // src/lib/detect.ts
4738
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
4739
+ import { dirname as dirname4, join as join5 } from "node:path";
4740
+ function detectEmail(dir, tool) {
4741
+ if (!tool.accountFile || !tool.emailPath)
4742
+ return;
4743
+ const candidates = [join5(dir, tool.accountFile)];
4744
+ if (dir === tool.defaultDir)
4745
+ candidates.push(join5(dirname4(dir), tool.accountFile));
4746
+ for (const file of candidates) {
4747
+ const email = readEmail(file, tool.emailPath);
4748
+ if (email)
4749
+ return email;
4750
+ }
4751
+ return;
4752
+ }
4753
+ function readEmail(file, path) {
4754
+ if (!existsSync4(file))
4755
+ return;
4756
+ let cursor;
4757
+ try {
4758
+ cursor = JSON.parse(readFileSync3(file, "utf8"));
4759
+ } catch {
4760
+ return;
4761
+ }
4762
+ for (const key of path) {
4763
+ if (cursor && typeof cursor === "object" && key in cursor) {
4764
+ cursor = cursor[key];
4765
+ } else {
4766
+ return;
4767
+ }
4768
+ }
4769
+ return typeof cursor === "string" && cursor.includes("@") ? cursor : undefined;
4770
+ }
4771
+ // src/lib/profiles.ts
4772
+ import { homedir as homedir4 } from "node:os";
4773
+ import { isAbsolute, join as join6, resolve as resolve2 } from "node:path";
4774
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, rmSync } from "node:fs";
4775
+ function nowIso() {
4776
+ return new Date().toISOString();
4777
+ }
4778
+ function expandPath(p) {
4779
+ let out = p;
4780
+ if (out === "~")
4781
+ out = homedir4();
4782
+ else if (out.startsWith("~/"))
4783
+ out = join6(homedir4(), out.slice(2));
4784
+ return isAbsolute(out) ? out : resolve2(process.cwd(), out);
4785
+ }
4786
+ function listProfiles(toolId) {
4787
+ const profiles = loadStore().profiles;
4788
+ const filtered = toolId ? profiles.filter((p) => p.tool === toolId) : profiles;
4789
+ return filtered.slice().sort((a, b) => a.tool.localeCompare(b.tool) || a.name.localeCompare(b.name));
4790
+ }
4791
+ function profileMatches(name, toolId) {
4792
+ return loadStore().profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
4793
+ }
4794
+ function findProfile(name, toolId) {
4795
+ const matches = profileMatches(name, toolId);
4796
+ return matches.length === 1 ? matches[0] : undefined;
4797
+ }
4798
+ function getProfile(name, toolId) {
4799
+ const matches = profileMatches(name, toolId);
4800
+ if (matches.length === 0) {
4801
+ const suffix = toolId ? ` for tool "${toolId}"` : "";
4802
+ throw new AccountsError(`no profile named "${name}"${suffix}. Run \`accounts list\` to see profiles.`);
4803
+ }
4804
+ if (matches.length > 1) {
4805
+ throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
4806
+ }
4807
+ const profile = matches[0];
4808
+ return profile;
4809
+ }
4810
+ function addProfile(opts) {
4811
+ const name = opts.name;
4812
+ const nameCheck = profileNameSchema.safeParse(name);
4813
+ if (!nameCheck.success)
4814
+ throw new AccountsError(nameCheck.error.issues[0]?.message ?? "invalid profile name");
4815
+ const toolId = opts.tool ?? DEFAULT_TOOL;
4816
+ const tool = getTool(toolId);
4817
+ const store = loadStore();
4818
+ if (store.profiles.some((p) => p.name === name && p.tool === toolId)) {
4819
+ throw new AccountsError(`a ${toolId} profile named "${name}" already exists`);
4820
+ }
4821
+ const dir = opts.dir ? expandPath(opts.dir) : join6(profilesDir(), toolId, name);
4822
+ if (store.profiles.some((p) => p.dir === dir)) {
4823
+ throw new AccountsError(`a profile already uses config dir ${dir}`);
4824
+ }
4825
+ mkdirSync4(dir, { recursive: true });
4826
+ const email = opts.email ?? detectEmail(dir, tool);
4827
+ const profile = {
4828
+ name,
4829
+ tool: toolId,
4830
+ ...email ? { email } : {},
4831
+ dir,
4832
+ ...opts.description ? { description: opts.description } : {},
4833
+ createdAt: nowIso()
4834
+ };
4835
+ store.profiles.push(profile);
4836
+ saveStore(store);
4837
+ return profile;
4838
+ }
4839
+ function removeProfile(name, opts = {}) {
4840
+ const options = typeof opts === "boolean" ? { purge: opts } : opts;
4841
+ const store = loadStore();
4842
+ const matches = store.profiles.map((profile2, idx2) => ({ profile: profile2, idx: idx2 })).filter(({ profile: profile2 }) => profile2.name === name && (!options.tool || profile2.tool === options.tool));
4843
+ if (matches.length === 0) {
4844
+ const suffix = options.tool ? ` for tool "${options.tool}"` : "";
4845
+ throw new AccountsError(`no profile named "${name}"${suffix}`);
4846
+ }
4847
+ if (matches.length > 1) {
4848
+ throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map(({ profile: profile2 }) => profile2.tool).join(", ")}); pass --tool`);
4849
+ }
4850
+ const idx = matches[0].idx;
4851
+ const profile = store.profiles[idx];
4852
+ store.profiles.splice(idx, 1);
4853
+ if (store.current[profile.tool] === name)
4854
+ delete store.current[profile.tool];
4855
+ if (store.applied[profile.tool] === name)
4856
+ delete store.applied[profile.tool];
4857
+ saveStore(store);
4858
+ let purged = false;
4859
+ let purgeNote;
4860
+ if (options.purge) {
4861
+ const managed = profile.dir.startsWith(profilesDir());
4862
+ const isDefault = profile.dir === getTool(profile.tool).defaultDir;
4863
+ if (managed && !isDefault && existsSync5(profile.dir)) {
4864
+ rmSync(profile.dir, { recursive: true, force: true });
4865
+ purged = true;
4866
+ } else {
4867
+ purgeNote = `refused to delete ${profile.dir} (not a managed profile dir); remove it manually if intended`;
4868
+ }
4869
+ }
4870
+ return { profile, purged, purgeNote };
4871
+ }
4872
+ function renameProfile(oldName, newName, toolId) {
4873
+ const nameCheck = profileNameSchema.safeParse(newName);
4874
+ if (!nameCheck.success)
4875
+ throw new AccountsError(nameCheck.error.issues[0]?.message ?? "invalid profile name");
4876
+ const store = loadStore();
4877
+ const matches = store.profiles.filter((p) => p.name === oldName && (!toolId || p.tool === toolId));
4878
+ if (matches.length === 0) {
4879
+ const suffix = toolId ? ` for tool "${toolId}"` : "";
4880
+ throw new AccountsError(`no profile named "${oldName}"${suffix}`);
4881
+ }
4882
+ if (matches.length > 1) {
4883
+ throw new AccountsError(`profile "${oldName}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
4884
+ }
4885
+ const profile = matches[0];
4886
+ if (store.profiles.some((p) => p.name === newName && p.tool === profile.tool)) {
4887
+ throw new AccountsError(`a ${profile.tool} profile named "${newName}" already exists`);
4888
+ }
4889
+ if (store.current[profile.tool] === oldName)
4890
+ store.current[profile.tool] = newName;
4891
+ if (store.applied[profile.tool] === oldName)
4892
+ store.applied[profile.tool] = newName;
4893
+ profile.name = newName;
4894
+ saveStore(store);
4895
+ return profile;
4896
+ }
4897
+ function updateProfile(name, opts) {
4898
+ const store = loadStore();
4899
+ const matches = store.profiles.filter((p) => p.name === name && (!opts.tool || p.tool === opts.tool));
4900
+ if (matches.length === 0) {
4901
+ const suffix = opts.tool ? ` for tool "${opts.tool}"` : "";
4902
+ throw new AccountsError(`no profile named "${name}"${suffix}`);
4903
+ }
4904
+ if (matches.length > 1) {
4905
+ throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
4906
+ }
4907
+ const profile = matches[0];
4908
+ if (opts.email !== undefined)
4909
+ profile.email = opts.email;
4910
+ if (opts.description !== undefined)
4911
+ profile.description = opts.description;
4912
+ if (opts.dir !== undefined) {
4913
+ const dir = expandPath(opts.dir);
4914
+ mkdirSync4(dir, { recursive: true });
4915
+ profile.dir = dir;
4916
+ }
4917
+ saveStore(store);
4918
+ return profile;
4919
+ }
4920
+ function redetectEmail(name, toolId) {
4921
+ const store = loadStore();
4922
+ const matches = store.profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
4923
+ if (matches.length === 0) {
4924
+ const suffix = toolId ? ` for tool "${toolId}"` : "";
4925
+ throw new AccountsError(`no profile named "${name}"${suffix}`);
4926
+ }
4927
+ if (matches.length > 1) {
4928
+ throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
4929
+ }
4930
+ const profile = matches[0];
4931
+ const email = detectEmail(profile.dir, getTool(profile.tool));
4932
+ if (email)
4933
+ profile.email = email;
4934
+ saveStore(store);
4935
+ return profile;
4936
+ }
4937
+ function useProfile(name, toolId) {
4938
+ const store = loadStore();
4939
+ const matches = store.profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
4940
+ if (matches.length === 0) {
4941
+ const suffix = toolId ? ` for tool "${toolId}"` : "";
4942
+ throw new AccountsError(`no profile named "${name}"${suffix}`);
4943
+ }
4944
+ if (matches.length > 1) {
4945
+ throw new AccountsError(`profile "${name}" exists for multiple tools (${matches.map((p) => p.tool).join(", ")}); pass --tool`);
4946
+ }
4947
+ const profile = matches[0];
4948
+ store.current[profile.tool] = name;
4949
+ profile.lastUsedAt = nowIso();
4950
+ saveStore(store);
4951
+ return { profile, toolId: profile.tool };
4952
+ }
4953
+ function currentProfile(toolId) {
4954
+ const store = loadStore();
4955
+ const name = store.current[toolId];
4956
+ if (!name)
4957
+ return;
4958
+ return store.profiles.find((p) => p.name === name);
4959
+ }
4823
4960
  // src/lib/apply-lock.ts
4824
4961
  import { closeSync, existsSync as existsSync6, mkdirSync as mkdirSync5, openSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
4825
4962
  import { join as join7 } from "node:path";
@@ -4970,7 +5107,8 @@ function commandLine(env, command) {
4970
5107
  return `${formatEnvAssignments(env)} ${command.map(shellQuote).join(" ")}`.trim();
4971
5108
  }
4972
5109
  function commandFor(tool, opts) {
4973
- return [tool.bin, ...opts.resume ? tool.resumeArgs ?? [] : [], ...opts.args ?? []];
5110
+ const args = [...opts.resume ? tool.resumeArgs ?? [] : [], ...opts.args ?? []];
5111
+ return [tool.bin, ...mergeToolArgs(tool, args, { permissions: opts.permissions })];
4974
5112
  }
4975
5113
  function switchProfile(name, opts = {}) {
4976
5114
  const profile = getProfile(name, opts.tool);
@@ -4999,6 +5137,7 @@ function switchProfile(name, opts = {}) {
4999
5137
  exports: formatExportLines(env),
5000
5138
  command,
5001
5139
  commandLine: commandLine(env, command),
5140
+ ...opts.permissions ? { permissions: normalizePermissionPreset(opts.permissions) } : {},
5002
5141
  restartRequired,
5003
5142
  message
5004
5143
  };
@@ -5323,7 +5462,8 @@ async function runSupervisedTool(initialProfile, tool, initialArgs = [], opts =
5323
5462
  tool: tool.id,
5324
5463
  mode: request.mode ?? "auto",
5325
5464
  resume: request.resume ?? true,
5326
- args: request.args ?? []
5465
+ args: request.args ?? [],
5466
+ permissions: request.permissions
5327
5467
  });
5328
5468
  log(`accounts supervisor: switching ${tool.id} to ${result.profile.name}`);
5329
5469
  setTimeout(() => void restartWith(result), 0);
@@ -5473,6 +5613,9 @@ export {
5473
5613
  shellSnippet,
5474
5614
  sendSupervisorRequest,
5475
5615
  saveStore,
5616
+ sanitizeLiveClaudeOAuthSettings,
5617
+ sanitizeClaudeProfileApiSettings,
5618
+ sanitizeClaudeOAuthProfileSettings,
5476
5619
  runSupervisedTool,
5477
5620
  restoreClaudeAuthFromProfile,
5478
5621
  resolveSupervisorLaunch,
@@ -5488,6 +5631,9 @@ export {
5488
5631
  profileHasAuth,
5489
5632
  profileEnv,
5490
5633
  pickProfile,
5634
+ permissionArgsFor,
5635
+ normalizePermissionPreset,
5636
+ mergeToolArgs,
5491
5637
  loadStore,
5492
5638
  listTools,
5493
5639
  listSupervisorStates,
@@ -5517,6 +5663,7 @@ export {
5517
5663
  addCustomTool,
5518
5664
  accountsHome,
5519
5665
  DEFAULT_TOOL,
5666
+ CLAUDE_API_AUTH_ENV_KEYS,
5520
5667
  BUILTIN_TOOLS,
5521
5668
  AccountsError
5522
5669
  };