@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/README.md CHANGED
@@ -97,8 +97,8 @@ Implementation details: [docs/IMPLEMENT.md](docs/IMPLEMENT.md).
97
97
  | `accounts login <name> --tool <tool>` | Launch the tool's login flow in an isolated profile dir. |
98
98
  | `accounts apply <name> --tool claude` | Apply profile auth to live Claude paths (requires snapshot; Claude-only). |
99
99
  | `accounts pick` | Interactive picker; default applies. `--env`, `--no-act`. |
100
- | `accounts switch <name> --tool <tool>` | Switch profile and print a restart/resume command. Add `--resume`; add `--launch` to run it. |
101
- | `accounts switch <name> --tool <tool> --supervisor` | Ask a running `accounts run <tool>` supervisor to restart under that profile. |
100
+ | `accounts switch <name> --tool <tool>` | Switch profile and print a restart/resume command. Add `--resume`, `--launch`, or `--permissions <preset>`. |
101
+ | `accounts switch <name> --tool <tool> --supervisor` | Ask a running `accounts run <tool>` supervisor to restart under that profile. Supports `--permissions <preset>`. |
102
102
  | `accounts use <name> --tool <tool>` | Mark profile active; prints apply/env hints. |
103
103
  | `accounts list` (`ls`) | List profiles (`●` active, `◉` applied, `●◉` both). |
104
104
  | `accounts show <name> --tool <tool>` | Profile details including active/applied flags. |
@@ -106,8 +106,8 @@ Implementation details: [docs/IMPLEMENT.md](docs/IMPLEMENT.md).
106
106
  | `accounts active [tool]` | Print active profile name (scripting). |
107
107
  | `accounts applied [tool]` | Print applied profile name (scripting). |
108
108
  | `accounts env [name] --tool <tool>` | Print one or more `export ...` lines for the profile. |
109
- | `accounts launch <name> --tool <tool>` | Launch tool once with profile env. |
110
- | `accounts run <tool> [args...]` | Run a tool under the supervisor so MCP/CLI can switch and restart it. |
109
+ | `accounts launch <name> --tool <tool>` | Launch tool once with profile env. Supports `--permissions <preset>`. |
110
+ | `accounts run <tool> [args...]` | Run a tool under the supervisor so MCP/CLI can switch and restart it. Supports `--permissions <preset>`. |
111
111
  | `accounts supervisor status [tool]` | Show running supervisors. |
112
112
  | `accounts supervisor switch <name> --tool <tool>` | Switch a running supervisor to another profile. |
113
113
  | `accounts supervisor stop <tool>` | Stop a running supervisor and its child process. |
@@ -159,11 +159,18 @@ Human equivalent:
159
159
  ```bash
160
160
  accounts switch account001 --tool claude --resume
161
161
  accounts switch account001 --tool claude --resume --launch
162
+ accounts switch account001 --tool claude --resume --permissions dangerous
162
163
  accounts switch account001 --tool claude --supervisor
163
164
  accounts switch codex-work --tool codex --resume
164
165
  accounts switch ops --tool opencode --resume
165
166
  ```
166
167
 
168
+ `--permissions <preset>` maps a permission mode to the tool's own flags. For
169
+ example, `--permissions dangerous` launches Claude/Takumi with
170
+ `--dangerously-skip-permissions`, Codex with
171
+ `--dangerously-bypass-approvals-and-sandbox`, and Gemini/Hermes/Kimi with their
172
+ YOLO mode flags. Unsupported tools fail with a list of configured presets.
173
+
167
174
  ## Shell hook (optional)
168
175
 
169
176
  ```bash
@@ -233,6 +240,7 @@ For Grok Build, prefer `accounts launch` or `accounts shell`; exporting `HOME`
233
240
  globally is intentionally not recommended.
234
241
 
235
242
  Custom tools can join supervised resume switching with `accounts tools add ... --resume-arg <arg>`.
243
+ They can also define permission presets with `--permission-arg preset=--flag`.
236
244
 
237
245
  ## Library
238
246
 
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 = "/tmp/hasna-events-017-batch-1781608575/open-accounts/node_modules/@aws-sdk/core/dist-cjs/submodules/client";
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();
@@ -41977,6 +41977,7 @@ var toolDefSchema = exports_external.object({
41977
41977
  loginArgs: exports_external.array(exports_external.string()).optional(),
41978
41978
  loginHint: exports_external.string().optional(),
41979
41979
  resumeArgs: exports_external.array(exports_external.string()).optional(),
41980
+ permissionArgs: exports_external.record(exports_external.array(exports_external.string())).optional(),
41980
41981
  accountFile: exports_external.string().optional(),
41981
41982
  emailPath: exports_external.array(exports_external.string()).optional()
41982
41983
  });
@@ -42304,6 +42305,15 @@ var BUILTIN_TOOLS = [
42304
42305
  bin: "claude",
42305
42306
  loginHint: "run /login inside Claude, then /exit when done",
42306
42307
  resumeArgs: ["--continue"],
42308
+ permissionArgs: {
42309
+ dangerous: ["--dangerously-skip-permissions"],
42310
+ "allow-dangerous": ["--allow-dangerously-skip-permissions"],
42311
+ bypass: ["--permission-mode", "bypassPermissions"],
42312
+ auto: ["--permission-mode", "auto"],
42313
+ "accept-edits": ["--permission-mode", "acceptEdits"],
42314
+ "dont-ask": ["--permission-mode", "dontAsk"],
42315
+ plan: ["--permission-mode", "plan"]
42316
+ },
42307
42317
  accountFile: ".claude.json",
42308
42318
  emailPath: ["oauthAccount", "emailAddress"]
42309
42319
  },
@@ -42315,7 +42325,10 @@ var BUILTIN_TOOLS = [
42315
42325
  bin: "codex",
42316
42326
  loginArgs: ["login"],
42317
42327
  loginHint: "complete the Codex login flow for this CODEX_HOME",
42318
- resumeArgs: ["resume", "--last"]
42328
+ resumeArgs: ["resume", "--last"],
42329
+ permissionArgs: {
42330
+ dangerous: ["--dangerously-bypass-approvals-and-sandbox"]
42331
+ }
42319
42332
  },
42320
42333
  {
42321
42334
  id: "takumi",
@@ -42325,6 +42338,15 @@ var BUILTIN_TOOLS = [
42325
42338
  bin: "takumi",
42326
42339
  loginHint: "complete Takumi auth in this TAKUMI_CONFIG_DIR",
42327
42340
  resumeArgs: ["--continue"],
42341
+ permissionArgs: {
42342
+ dangerous: ["--dangerously-skip-permissions"],
42343
+ "allow-dangerous": ["--allow-dangerously-skip-permissions"],
42344
+ bypass: ["--permission-mode", "bypassPermissions"],
42345
+ auto: ["--permission-mode", "auto"],
42346
+ "accept-edits": ["--permission-mode", "acceptEdits"],
42347
+ "dont-ask": ["--permission-mode", "dontAsk"],
42348
+ plan: ["--permission-mode", "plan"]
42349
+ },
42328
42350
  accountFile: ".claude.json",
42329
42351
  emailPath: ["oauthAccount", "emailAddress"]
42330
42352
  },
@@ -42334,7 +42356,13 @@ var BUILTIN_TOOLS = [
42334
42356
  envVar: "GEMINI_CONFIG_DIR",
42335
42357
  defaultDir: join3(homedir3(), ".gemini"),
42336
42358
  bin: "gemini",
42337
- loginHint: "complete Gemini auth in this GEMINI_CONFIG_DIR"
42359
+ loginHint: "complete Gemini auth in this GEMINI_CONFIG_DIR",
42360
+ permissionArgs: {
42361
+ dangerous: ["--yolo"],
42362
+ yolo: ["--yolo"],
42363
+ "auto-edit": ["--approval-mode", "auto_edit"],
42364
+ plan: ["--approval-mode", "plan"]
42365
+ }
42338
42366
  },
42339
42367
  {
42340
42368
  id: "opencode",
@@ -42373,7 +42401,11 @@ var BUILTIN_TOOLS = [
42373
42401
  envVar: "HERMES_HOME",
42374
42402
  defaultDir: join3(homedir3(), ".hermes"),
42375
42403
  bin: "hermes",
42376
- loginHint: "complete Hermes auth in this HERMES_HOME"
42404
+ loginHint: "complete Hermes auth in this HERMES_HOME",
42405
+ permissionArgs: {
42406
+ dangerous: ["--yolo"],
42407
+ yolo: ["--yolo"]
42408
+ }
42377
42409
  },
42378
42410
  {
42379
42411
  id: "kimi",
@@ -42382,7 +42414,13 @@ var BUILTIN_TOOLS = [
42382
42414
  defaultDir: join3(homedir3(), ".kimi-code"),
42383
42415
  bin: "kimi",
42384
42416
  loginArgs: ["login"],
42385
- loginHint: "complete kimi login for this KIMI_CODE_HOME"
42417
+ loginHint: "complete kimi login for this KIMI_CODE_HOME",
42418
+ permissionArgs: {
42419
+ dangerous: ["--yolo"],
42420
+ yolo: ["--yolo"],
42421
+ auto: ["--auto"],
42422
+ plan: ["--plan"]
42423
+ }
42386
42424
  },
42387
42425
  {
42388
42426
  id: "grok",
@@ -42395,6 +42433,43 @@ var BUILTIN_TOOLS = [
42395
42433
  }
42396
42434
  ];
42397
42435
  var DEFAULT_TOOL = "claude";
42436
+ var PERMISSION_ALIASES = new Map([
42437
+ ["danger", "dangerous"],
42438
+ ["dangerously-skip-permissions", "dangerous"],
42439
+ ["skip-permissions", "dangerous"],
42440
+ ["skip", "dangerous"],
42441
+ ["bypasspermissions", "bypass"],
42442
+ ["bypass-permissions", "bypass"],
42443
+ ["acceptedits", "accept-edits"],
42444
+ ["accept-edit", "accept-edits"],
42445
+ ["autoedit", "auto-edit"],
42446
+ ["auto-edits", "auto-edit"],
42447
+ ["auto_edit", "auto-edit"],
42448
+ ["dontask", "dont-ask"],
42449
+ ["dont-ask-permissions", "dont-ask"]
42450
+ ]);
42451
+ function normalizePermissionPreset(value) {
42452
+ const normalized = value.trim().replace(/^--/, "").replaceAll("_", "-").toLowerCase();
42453
+ return PERMISSION_ALIASES.get(normalized) ?? normalized;
42454
+ }
42455
+ function permissionArgsFor(tool, permissions) {
42456
+ if (!permissions)
42457
+ return [];
42458
+ const preset = normalizePermissionPreset(permissions);
42459
+ if (preset === "default" || preset === "none" || preset === "off")
42460
+ return [];
42461
+ const args = tool.permissionArgs?.[preset];
42462
+ if (!args) {
42463
+ const supported = Object.keys(tool.permissionArgs ?? {}).sort();
42464
+ const suffix = supported.length > 0 ? ` Supported permissions: ${supported.join(", ")}.` : " No permission presets are configured.";
42465
+ throw new AccountsError(`tool "${tool.id}" does not support permissions "${permissions}".${suffix}`);
42466
+ }
42467
+ return args;
42468
+ }
42469
+ function mergeToolArgs(tool, args, opts = {}) {
42470
+ const permissionArgs = permissionArgsFor(tool, opts.permissions).filter((arg) => !args.includes(arg));
42471
+ return [...permissionArgs, ...args];
42472
+ }
42398
42473
  var BUILTIN_IDS = new Set(BUILTIN_TOOLS.map((t) => t.id));
42399
42474
  function isBuiltinTool(id) {
42400
42475
  return BUILTIN_IDS.has(id);
@@ -42778,6 +42853,15 @@ function writeClaudeKeychain(cred) {
42778
42853
  }
42779
42854
 
42780
42855
  // src/lib/claude-auth.ts
42856
+ var CLAUDE_API_AUTH_ENV_KEYS = [
42857
+ "ANTHROPIC_API_KEY",
42858
+ "ANTHROPIC_AUTH_TOKEN",
42859
+ "ANTHROPIC_BASE_URL",
42860
+ "CLAUDE_CODE_API_KEY_HELPER",
42861
+ "CLAUDE_CODE_API_KEY_HELPER_TTL_MS",
42862
+ "CLAUDE_CODE_USE_BEDROCK",
42863
+ "CLAUDE_CODE_USE_VERTEX"
42864
+ ];
42781
42865
  function readJsonFile(path) {
42782
42866
  if (!existsSync6(path))
42783
42867
  return;
@@ -42796,6 +42880,11 @@ function writeJsonFile(path, data, stayUnder) {
42796
42880
  function readOAuthFromPaths(paths) {
42797
42881
  return findOAuthSource(paths)?.oauth;
42798
42882
  }
42883
+ function readOAuthSnapshot(profileDir) {
42884
+ const snap = readJsonFile(profileOAuthSnapshot(profileDir));
42885
+ const oauth = snap?.oauthAccount;
42886
+ return oauth && typeof oauth === "object" ? oauth : undefined;
42887
+ }
42799
42888
  function findOAuthSource(paths) {
42800
42889
  for (const p of paths) {
42801
42890
  const data = readJsonFile(p);
@@ -42837,6 +42926,46 @@ function mergeOAuthInto(paths, oauth, allowDelete, stayUnder) {
42837
42926
  }
42838
42927
  }
42839
42928
  }
42929
+ function sanitizeSettingsFile(configDir, stayUnder) {
42930
+ const settingsPath = join7(configDir, "settings.json");
42931
+ const settings = readJsonFile(settingsPath);
42932
+ if (!settings)
42933
+ return false;
42934
+ let changed = false;
42935
+ if ("apiKeyHelper" in settings) {
42936
+ delete settings.apiKeyHelper;
42937
+ changed = true;
42938
+ }
42939
+ const env2 = settings.env;
42940
+ if (env2 && typeof env2 === "object" && !Array.isArray(env2)) {
42941
+ const envRecord = env2;
42942
+ for (const key of CLAUDE_API_AUTH_ENV_KEYS) {
42943
+ if (key in envRecord) {
42944
+ delete envRecord[key];
42945
+ changed = true;
42946
+ }
42947
+ }
42948
+ }
42949
+ if (changed)
42950
+ writeJsonFile(settingsPath, settings, stayUnder);
42951
+ return changed;
42952
+ }
42953
+ function sanitizeClaudeProfileApiSettings(profileDir, tool) {
42954
+ if (tool.id !== "claude")
42955
+ return false;
42956
+ return sanitizeSettingsFile(profileDir, profileDir);
42957
+ }
42958
+ function sanitizeClaudeOAuthProfileSettings(profileDir, tool) {
42959
+ if (tool.id !== "claude")
42960
+ return false;
42961
+ if (!readOAuthSnapshot(profileDir) && !readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool))) {
42962
+ return false;
42963
+ }
42964
+ return sanitizeClaudeProfileApiSettings(profileDir, tool);
42965
+ }
42966
+ function sanitizeLiveClaudeOAuthSettings() {
42967
+ return sanitizeSettingsFile(liveClaudePaths().configDir, liveClaudeBase());
42968
+ }
42840
42969
  function liveOAuthEmail() {
42841
42970
  const live = liveClaudePaths();
42842
42971
  const oauth = readOAuthFromPaths([live.homeJson]);
@@ -42877,6 +43006,7 @@ function ensureProfileAuthSnapshot(profileDir, tool, opts = {}) {
42877
43006
  assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
42878
43007
  copyFileSync(credFile, credSnap);
42879
43008
  }
43009
+ sanitizeClaudeOAuthProfileSettings(profileDir, tool);
42880
43010
  }
42881
43011
  function profileHasAuth(profileDir, tool) {
42882
43012
  return hasAuthSnapshot(profileDir) || !!readOAuthFromPaths(profileAccountJsonPaths(profileDir, tool));
@@ -42895,6 +43025,8 @@ function restoreClaudeAuthFromProfile(profileDir, tool, profileName) {
42895
43025
  if (!oauth) {
42896
43026
  throw new AccountsError("profile has no OAuth account data to apply");
42897
43027
  }
43028
+ sanitizeClaudeOAuthProfileSettings(profileDir, tool);
43029
+ sanitizeLiveClaudeOAuthSettings();
42898
43030
  assertSafeWritePath(live.homeJson, { mustStayUnder: liveRoot });
42899
43031
  mergeOAuthInto([live.homeJson], oauth, false, liveRoot);
42900
43032
  const credSnap = profileCredentialsSnapshot(profileDir);
@@ -43345,6 +43477,11 @@ function profileEnv(profile, tool) {
43345
43477
  for (const [name, value] of Object.entries(tool.extraEnv ?? {})) {
43346
43478
  env2[name] = renderTemplate(value, profile);
43347
43479
  }
43480
+ if (tool.id === "claude") {
43481
+ sanitizeClaudeProfileApiSettings(profile.dir, tool);
43482
+ for (const key of CLAUDE_API_AUTH_ENV_KEYS)
43483
+ env2[key] = "";
43484
+ }
43348
43485
  return env2;
43349
43486
  }
43350
43487
  function formatEnvAssignments(env2) {
@@ -43379,7 +43516,8 @@ function commandLine(env2, command) {
43379
43516
  return `${formatEnvAssignments(env2)} ${command.map(shellQuote).join(" ")}`.trim();
43380
43517
  }
43381
43518
  function commandFor(tool, opts) {
43382
- return [tool.bin, ...opts.resume ? tool.resumeArgs ?? [] : [], ...opts.args ?? []];
43519
+ const args = [...opts.resume ? tool.resumeArgs ?? [] : [], ...opts.args ?? []];
43520
+ return [tool.bin, ...mergeToolArgs(tool, args, { permissions: opts.permissions })];
43383
43521
  }
43384
43522
  function switchProfile(name, opts = {}) {
43385
43523
  const profile = getProfile(name, opts.tool);
@@ -43408,6 +43546,7 @@ function switchProfile(name, opts = {}) {
43408
43546
  exports: formatExportLines(env2),
43409
43547
  command,
43410
43548
  commandLine: commandLine(env2, command),
43549
+ ...opts.permissions ? { permissions: normalizePermissionPreset(opts.permissions) } : {},
43411
43550
  restartRequired,
43412
43551
  message
43413
43552
  };
@@ -43733,7 +43872,8 @@ async function runSupervisedTool(initialProfile, tool, initialArgs = [], opts =
43733
43872
  tool: tool.id,
43734
43873
  mode: request.mode ?? "auto",
43735
43874
  resume: request.resume ?? true,
43736
- args: request.args ?? []
43875
+ args: request.args ?? [],
43876
+ permissions: request.permissions
43737
43877
  });
43738
43878
  log(`accounts supervisor: switching ${tool.id} to ${result.profile.name}`);
43739
43879
  setTimeout(() => void restartWith(result), 0);
@@ -43825,6 +43965,20 @@ function printStorageSyncResult(result, json) {
43825
43965
  console.log(source_default.green(`pushed ${result.pushed}, pulled ${result.pulled}`));
43826
43966
  console.log(source_default.dim(`key: ${result.key}`));
43827
43967
  }
43968
+ function parsePermissionArgs(entries) {
43969
+ const permissionArgs = {};
43970
+ for (const entry of entries ?? []) {
43971
+ const idx = entry.indexOf("=");
43972
+ if (idx <= 0)
43973
+ die(`invalid --permission-arg ${entry}; expected PRESET=ARG`);
43974
+ const preset = normalizePermissionPreset(entry.slice(0, idx));
43975
+ const arg = entry.slice(idx + 1);
43976
+ if (!arg)
43977
+ die(`invalid --permission-arg ${entry}; expected PRESET=ARG`);
43978
+ (permissionArgs[preset] ??= []).push(arg);
43979
+ }
43980
+ return permissionArgs;
43981
+ }
43828
43982
  program2.name("accounts").description("Manage and switch between multiple Claude Code (and other AI tool) profiles/accounts.").version(getVersion());
43829
43983
  program2.command("add").argument("<name>", "profile name (lowercase, hyphenated)").description("create a new profile with an isolated config dir").option("-t, --tool <tool>", "tool the profile is for", DEFAULT_TOOL).option("-e, --email <email>", "account email (auto-detected when omitted)").option("-d, --dir <path>", "config dir to use (default: managed dir under ~/.hasna/accounts)").option("--description <text>", "free-text description").action(action((name, opts) => {
43830
43984
  const p = addProfile({ name, tool: opts.tool, email: opts.email, dir: opts.dir, description: opts.description });
@@ -43955,12 +44109,20 @@ program2.command("applied").argument("[tool]", "tool id (default: claude)").desc
43955
44109
  die(`no applied profile for "${tool}". Run \`accounts apply <name>\` first.`);
43956
44110
  console.log(p.name);
43957
44111
  }));
43958
- program2.command("switch").argument("<name>", "profile name").argument("[args...]", "extra args passed when printing/launching the tool").description("switch to a profile and print a restart/resume command; use --launch to run it").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").option("--mode <mode>", "switch mode: auto, apply, env, active", "auto").option("--resume", "include the tool's resume/continue args in the handoff command").option("--launch", "launch the tool after switching").option("--supervisor", "ask a running accounts supervisor to restart the tool").option("--json", "output JSON").action(action(async (name, args, opts) => {
44112
+ program2.command("switch").argument("<name>", "profile name").argument("[args...]", "extra args passed when printing/launching the tool").description("switch to a profile and print a restart/resume command; use --launch to run it").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").option("--mode <mode>", "switch mode: auto, apply, env, active", "auto").option("--resume", "include the tool's resume/continue args in the handoff command").option("--permissions <preset>", "tool-specific permission preset, e.g. dangerous").option("--launch", "launch the tool after switching").option("--supervisor", "ask a running accounts supervisor to restart the tool").option("--json", "output JSON").action(action(async (name, args, opts) => {
43959
44113
  if (opts.supervisor && opts.launch)
43960
44114
  die("--supervisor and --launch cannot be used together");
43961
44115
  if (opts.supervisor) {
43962
44116
  const profile = getProfile(name, opts.tool);
43963
- const response = await sendSupervisorRequest(profile.tool, { type: "switch_profile", name: profile.name, tool: profile.tool, mode: opts.mode, resume: opts.resume ?? true, args }, { allowMissing: true });
44117
+ const response = await sendSupervisorRequest(profile.tool, {
44118
+ type: "switch_profile",
44119
+ name: profile.name,
44120
+ tool: profile.tool,
44121
+ mode: opts.mode,
44122
+ resume: opts.resume ?? true,
44123
+ args,
44124
+ permissions: opts.permissions
44125
+ }, { allowMissing: true });
43964
44126
  if (!response) {
43965
44127
  die(`no running accounts supervisor for ${getTool(profile.tool).label}. Start one with \`accounts run ${profile.tool}\`.`);
43966
44128
  }
@@ -43976,7 +44138,13 @@ program2.command("switch").argument("<name>", "profile name").argument("[args...
43976
44138
  }
43977
44139
  return;
43978
44140
  }
43979
- const result = switchProfile(name, { tool: opts.tool, mode: opts.mode, resume: opts.resume, args });
44141
+ const result = switchProfile(name, {
44142
+ tool: opts.tool,
44143
+ mode: opts.mode,
44144
+ resume: opts.resume,
44145
+ args,
44146
+ permissions: opts.permissions
44147
+ });
43980
44148
  if (opts.json) {
43981
44149
  console.log(JSON.stringify(result, null, 2));
43982
44150
  } else {
@@ -44022,13 +44190,14 @@ program2.command("env").argument("[name]", "profile name (defaults to the active
44022
44190
  const tool = getTool(profile.tool);
44023
44191
  console.log(formatExportLines(profileEnv(profile, tool)));
44024
44192
  }));
44025
- program2.command("launch").argument("<name>", "profile name").argument("[args...]", "extra args passed to the tool binary").description("launch the tool's binary with the profile's config dir active").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").action(action((name, args, opts) => {
44193
+ program2.command("launch").argument("<name>", "profile name").argument("[args...]", "extra args passed to the tool binary").description("launch the tool's binary with the profile's config dir active").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").option("--permissions <preset>", "tool-specific permission preset, e.g. dangerous").action(action((name, args, opts) => {
44026
44194
  const profile = getProfile(name, opts.tool);
44027
44195
  const tool = getTool(profile.tool);
44028
44196
  const env2 = profileEnv(profile, tool);
44197
+ const launchArgs = mergeToolArgs(tool, args, { permissions: opts.permissions });
44029
44198
  useProfile(name, tool.id);
44030
- console.log(source_default.dim(`→ ${formatEnvAssignments(env2)} ${tool.bin} ${args.join(" ")}`));
44031
- const res = spawnSync2(tool.bin, args, {
44199
+ console.log(source_default.dim(`→ ${formatEnvAssignments(env2)} ${tool.bin} ${launchArgs.join(" ")}`));
44200
+ const res = spawnSync2(tool.bin, launchArgs, {
44032
44201
  stdio: "inherit",
44033
44202
  env: { ...process.env, ...env2 }
44034
44203
  });
@@ -44036,9 +44205,11 @@ program2.command("launch").argument("<name>", "profile name").argument("[args...
44036
44205
  die(`failed to launch ${tool.bin}: ${res.error.message}`);
44037
44206
  process.exit(res.status ?? 0);
44038
44207
  }));
44039
- program2.command("run").argument("<target>", "tool id to supervise (claude, codex, opencode...) or a profile name").argument("[args...]", "extra args passed to the tool binary").description("run a tool under the accounts supervisor so MCP can switch/restart it").option("-p, --profile <name>", "profile to run when target is a tool id").option("-t, --tool <tool>", "tool when target is a profile name").option("--resume", "start with the tool's resume/continue args").action(action(async (target, args, opts) => {
44208
+ program2.command("run").argument("<target>", "tool id to supervise (claude, codex, opencode...) or a profile name").argument("[args...]", "extra args passed to the tool binary").description("run a tool under the accounts supervisor so MCP can switch/restart it").option("-p, --profile <name>", "profile to run when target is a tool id").option("-t, --tool <tool>", "tool when target is a profile name").option("--resume", "start with the tool's resume/continue args").option("--permissions <preset>", "tool-specific permission preset, e.g. dangerous").action(action(async (target, args, opts) => {
44040
44209
  const plan = resolveSupervisorLaunch(target, { profile: opts.profile, tool: opts.tool });
44041
- const runArgs = [...opts.resume ? plan.tool.resumeArgs ?? [] : [], ...args];
44210
+ const runArgs = mergeToolArgs(plan.tool, [...opts.resume ? plan.tool.resumeArgs ?? [] : [], ...args], {
44211
+ permissions: opts.permissions
44212
+ });
44042
44213
  console.error(source_default.green(`✓ accounts supervisor running ${plan.tool.label} as ${source_default.bold(plan.profile.name)}`));
44043
44214
  console.error(source_default.dim(` control: accounts supervisor status ${plan.tool.id}`));
44044
44215
  console.error(source_default.dim(` switch: accounts switch <profile> --tool ${plan.tool.id} --supervisor`));
@@ -44071,9 +44242,17 @@ supervisor.command("status").argument("[tool]", "tool id").description("show run
44071
44242
  console.log(source_default.dim(` ${state2.command.join(" ")}`));
44072
44243
  }
44073
44244
  }));
44074
- supervisor.command("switch").argument("<name>", "profile name").argument("[args...]", "extra args passed after resume/continue args").description("switch a running supervisor to another profile").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").option("--mode <mode>", "switch mode: auto, apply, env, active", "auto").option("--no-resume", "restart without the tool's resume/continue args").option("--json", "output JSON").action(action(async (name, args, opts) => {
44245
+ supervisor.command("switch").argument("<name>", "profile name").argument("[args...]", "extra args passed after resume/continue args").description("switch a running supervisor to another profile").option("-t, --tool <tool>", "tool when the profile name exists for multiple tools").option("--mode <mode>", "switch mode: auto, apply, env, active", "auto").option("--no-resume", "restart without the tool's resume/continue args").option("--permissions <preset>", "tool-specific permission preset, e.g. dangerous").option("--json", "output JSON").action(action(async (name, args, opts) => {
44075
44246
  const profile = getProfile(name, opts.tool);
44076
- const response = await sendSupervisorRequest(profile.tool, { type: "switch_profile", name: profile.name, tool: profile.tool, mode: opts.mode, resume: opts.resume !== false, args }, { allowMissing: true });
44247
+ const response = await sendSupervisorRequest(profile.tool, {
44248
+ type: "switch_profile",
44249
+ name: profile.name,
44250
+ tool: profile.tool,
44251
+ mode: opts.mode,
44252
+ resume: opts.resume !== false,
44253
+ args,
44254
+ permissions: opts.permissions
44255
+ }, { allowMissing: true });
44077
44256
  if (!response)
44078
44257
  die(`no running accounts supervisor for ${getTool(profile.tool).label}`);
44079
44258
  if (!response.ok)
@@ -44209,10 +44388,12 @@ tools.command("list", { isDefault: true }).description("list supported tools (bu
44209
44388
  for (const t of all) {
44210
44389
  const tag = isBuiltinTool(t.id) ? source_default.dim("built-in") : source_default.magenta("custom");
44211
44390
  const envNames = [t.envVar, ...Object.keys(t.extraEnv ?? {})].join(", ");
44212
- console.log(`${source_default.cyan(t.id.padEnd(10))} ${t.label.padEnd(16)} ${source_default.dim(envNames)} → ${source_default.dim(t.defaultDir)} ${tag}`);
44391
+ const permissions = Object.keys(t.permissionArgs ?? {});
44392
+ const permissionsHint = permissions.length > 0 ? source_default.dim(` permissions: ${permissions.sort().join(",")}`) : "";
44393
+ console.log(`${source_default.cyan(t.id.padEnd(10))} ${t.label.padEnd(16)} ${source_default.dim(envNames)} → ${source_default.dim(t.defaultDir)} ${tag}${permissionsHint}`);
44213
44394
  }
44214
44395
  }));
44215
- tools.command("add").argument("<id>", "tool id, e.g. cursor").description("register a custom tool/app so profiles can target it").requiredOption("--label <label>", 'display name, e.g. "Cursor"').requiredOption("--env-var <VAR>", "env var that points the tool at its config dir").requiredOption("--bin <bin>", "binary to launch").option("--default-dir <path>", "default config dir (default: ~/.<id>)").option("--extra-env <VAR=VALUE...>", "additional env var templates; supports {profileDir}, {profileName}, {toolId}").option("--login-arg <arg...>", "arguments for `accounts login <profile> --tool <id>`").option("--resume-arg <arg...>", "arguments for supervised resume/restart, e.g. --continue").option("--account-file <file>", "file inside the config dir holding the email").option("--email-path <path>", "dot-path to the email inside that file (e.g. account.email)").action(action((id, opts) => {
44396
+ tools.command("add").argument("<id>", "tool id, e.g. cursor").description("register a custom tool/app so profiles can target it").requiredOption("--label <label>", 'display name, e.g. "Cursor"').requiredOption("--env-var <VAR>", "env var that points the tool at its config dir").requiredOption("--bin <bin>", "binary to launch").option("--default-dir <path>", "default config dir (default: ~/.<id>)").option("--extra-env <VAR=VALUE...>", "additional env var templates; supports {profileDir}, {profileName}, {toolId}").option("--login-arg <arg...>", "arguments for `accounts login <profile> --tool <id>`").option("--resume-arg <arg...>", "arguments for supervised resume/restart, e.g. --continue").option("--permission-arg <preset=arg...>", "tool permission preset args, e.g. dangerous=--yolo").option("--account-file <file>", "file inside the config dir holding the email").option("--email-path <path>", "dot-path to the email inside that file (e.g. account.email)").action(action((id, opts) => {
44216
44397
  const extraEnv = {};
44217
44398
  for (const entry of opts.extraEnv ?? []) {
44218
44399
  const idx = entry.indexOf("=");
@@ -44220,6 +44401,7 @@ tools.command("add").argument("<id>", "tool id, e.g. cursor").description("regis
44220
44401
  die(`invalid --extra-env ${entry}; expected VAR=VALUE`);
44221
44402
  extraEnv[entry.slice(0, idx)] = entry.slice(idx + 1);
44222
44403
  }
44404
+ const permissionArgs = parsePermissionArgs(opts.permissionArg);
44223
44405
  const def = {
44224
44406
  id,
44225
44407
  label: opts.label,
@@ -44229,6 +44411,7 @@ tools.command("add").argument("<id>", "tool id, e.g. cursor").description("regis
44229
44411
  ...Object.keys(extraEnv).length > 0 ? { extraEnv } : {},
44230
44412
  ...opts.loginArg ? { loginArgs: opts.loginArg } : {},
44231
44413
  ...opts.resumeArg ? { resumeArgs: opts.resumeArg } : {},
44414
+ ...Object.keys(permissionArgs).length > 0 ? { permissionArgs } : {},
44232
44415
  ...opts.accountFile ? { accountFile: opts.accountFile } : {},
44233
44416
  ...opts.emailPath ? { emailPath: opts.emailPath.split(".") } : {}
44234
44417
  };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export * from "./types.js";
2
2
  export { loadStore, saveStore, storePath, accountsHome, profilesDir } from "./storage.js";
3
- export { BUILTIN_TOOLS, DEFAULT_TOOL, getTool, listTools, isBuiltinTool, addCustomTool, removeCustomTool, } from "./lib/tools.js";
3
+ export { BUILTIN_TOOLS, DEFAULT_TOOL, getTool, listTools, isBuiltinTool, addCustomTool, removeCustomTool, mergeToolArgs, normalizePermissionPreset, permissionArgsFor, } from "./lib/tools.js";
4
4
  export { profileEnv, formatEnvAssignments, formatExportLines } from "./lib/env.js";
5
5
  export { detectEmail } from "./lib/detect.js";
6
6
  export { expandPath, listProfiles, findProfile, getProfile, addProfile, removeProfile, renameProfile, updateProfile, redetectEmail, useProfile, currentProfile, } from "./lib/profiles.js";
@@ -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";
@@ -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,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,aAAa,EACb,YAAY,EACZ,OAAO,EACP,SAAS,EACT,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,yBAAyB,EACzB,iBAAiB,GAClB,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"}