@hasna/accounts 0.1.14 → 0.1.16

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
@@ -4000,6 +4000,7 @@ var toolDefSchema = exports_external.object({
4000
4000
  loginHint: exports_external.string().optional(),
4001
4001
  resumeArgs: exports_external.array(exports_external.string()).optional(),
4002
4002
  permissionArgs: exports_external.record(exports_external.array(exports_external.string())).optional(),
4003
+ launchArgs: exports_external.array(exports_external.string()).optional(),
4003
4004
  accountFile: exports_external.string().optional(),
4004
4005
  emailPath: exports_external.array(exports_external.string()).optional()
4005
4006
  });
@@ -4171,6 +4172,9 @@ var BUILTIN_TOOLS = [
4171
4172
  id: "claude",
4172
4173
  label: "Claude Code",
4173
4174
  envVar: "CLAUDE_CONFIG_DIR",
4175
+ extraEnv: {
4176
+ TELEGRAM_STATE_DIR: "{profileDir}/channels/telegram"
4177
+ },
4174
4178
  defaultDir: join2(homedir2(), ".claude"),
4175
4179
  bin: "claude",
4176
4180
  loginHint: "run /login inside Claude, then /exit when done",
@@ -4187,6 +4191,16 @@ var BUILTIN_TOOLS = [
4187
4191
  accountFile: ".claude.json",
4188
4192
  emailPath: ["oauthAccount", "emailAddress"]
4189
4193
  },
4194
+ {
4195
+ id: "codex-app",
4196
+ label: "Codex App",
4197
+ envVar: "CODEX_HOME",
4198
+ defaultDir: join2(homedir2(), ".codex"),
4199
+ bin: "/Applications/Codex.app/Contents/MacOS/Codex",
4200
+ loginHint: "sign in inside Codex.app, then quit the app when the profile is ready",
4201
+ launchArgs: ["--user-data-dir={profileDir}/electron-user-data"],
4202
+ accountFile: "auth.json"
4203
+ },
4190
4204
  {
4191
4205
  id: "codex",
4192
4206
  label: "Codex CLI",
@@ -4336,9 +4350,17 @@ function permissionArgsFor(tool, permissions) {
4336
4350
  }
4337
4351
  return args;
4338
4352
  }
4353
+ function renderToolArg(value, profile) {
4354
+ return value.replaceAll("{profileDir}", profile.dir).replaceAll("{profileName}", profile.name).replaceAll("{toolId}", profile.tool);
4355
+ }
4356
+ function launchArgsFor(tool, profile) {
4357
+ const args = tool.launchArgs ?? [];
4358
+ return profile ? args.map((arg) => renderToolArg(arg, profile)) : args;
4359
+ }
4339
4360
  function mergeToolArgs(tool, args, opts = {}) {
4361
+ const launchArgs = launchArgsFor(tool, opts.profile).filter((arg) => !args.includes(arg));
4340
4362
  const permissionArgs = permissionArgsFor(tool, opts.permissions).filter((arg) => !args.includes(arg));
4341
- return [...permissionArgs, ...args];
4363
+ return [...permissionArgs, ...launchArgs, ...args];
4342
4364
  }
4343
4365
  var BUILTIN_IDS = new Set(BUILTIN_TOOLS.map((t) => t.id));
4344
4366
  function isBuiltinTool(id) {
@@ -4725,6 +4747,42 @@ function hasAuthSnapshot(profileDir) {
4725
4747
  return existsSync3(profileOAuthSnapshot(profileDir)) || existsSync3(profileCredentialsSnapshot(profileDir)) || existsSync3(profileKeychainSnapshot(profileDir));
4726
4748
  }
4727
4749
 
4750
+ // src/lib/codex-app.ts
4751
+ import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
4752
+ import { join as join5 } from "node:path";
4753
+ var FILE_CREDENTIALS_LINE = 'cli_auth_credentials_store = "file"';
4754
+ function insertRootConfigLine(config, line) {
4755
+ if (config.trim() === "")
4756
+ return `${line}
4757
+ `;
4758
+ const lines = config.split(/\r?\n/);
4759
+ const tableIndex = lines.findIndex((entry) => /^\s*\[[^\]]+\]\s*(?:#.*)?$/.test(entry));
4760
+ if (tableIndex === -1)
4761
+ return `${config.trimEnd()}
4762
+
4763
+ ${line}
4764
+ `;
4765
+ const before = lines.slice(0, tableIndex).join(`
4766
+ `).trimEnd();
4767
+ const after = lines.slice(tableIndex).join(`
4768
+ `).trimStart();
4769
+ return `${before}${before ? `
4770
+
4771
+ ` : ""}${line}
4772
+
4773
+ ${after}${after.endsWith(`
4774
+ `) ? "" : `
4775
+ `}`;
4776
+ }
4777
+ function ensureCodexAppProfileConfig(profileDir) {
4778
+ mkdirSync4(profileDir, { recursive: true });
4779
+ const configPath = join5(profileDir, "config.toml");
4780
+ const current = existsSync4(configPath) ? readFileSync3(configPath, "utf8") : "";
4781
+ if (/^\s*cli_auth_credentials_store\s*=/.test(current))
4782
+ return;
4783
+ writeFileSync3(configPath, insertRootConfigLine(current, FILE_CREDENTIALS_LINE), { mode: 384 });
4784
+ }
4785
+
4728
4786
  // src/lib/env.ts
4729
4787
  function renderTemplate(value, profile) {
4730
4788
  return value.replaceAll("{profileDir}", profile.dir).replaceAll("{profileName}", profile.name).replaceAll("{toolId}", profile.tool);
@@ -4741,6 +4799,8 @@ function profileEnv(profile, tool) {
4741
4799
  for (const key of CLAUDE_API_AUTH_ENV_KEYS)
4742
4800
  env[key] = "";
4743
4801
  }
4802
+ if (tool.id === "codex-app")
4803
+ ensureCodexAppProfileConfig(profile.dir);
4744
4804
  return env;
4745
4805
  }
4746
4806
  function formatEnvAssignments(env) {
@@ -4751,14 +4811,14 @@ function formatExportLines(env) {
4751
4811
  `);
4752
4812
  }
4753
4813
  // src/lib/detect.ts
4754
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
4755
- import { dirname as dirname4, join as join5 } from "node:path";
4814
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
4815
+ import { dirname as dirname4, join as join6 } from "node:path";
4756
4816
  function detectEmail(dir, tool) {
4757
4817
  if (!tool.accountFile || !tool.emailPath)
4758
4818
  return;
4759
- const candidates = [join5(dir, tool.accountFile)];
4819
+ const candidates = [join6(dir, tool.accountFile)];
4760
4820
  if (dir === tool.defaultDir)
4761
- candidates.push(join5(dirname4(dir), tool.accountFile));
4821
+ candidates.push(join6(dirname4(dir), tool.accountFile));
4762
4822
  for (const file of candidates) {
4763
4823
  const email = readEmail(file, tool.emailPath);
4764
4824
  if (email)
@@ -4767,11 +4827,11 @@ function detectEmail(dir, tool) {
4767
4827
  return;
4768
4828
  }
4769
4829
  function readEmail(file, path) {
4770
- if (!existsSync4(file))
4830
+ if (!existsSync5(file))
4771
4831
  return;
4772
4832
  let cursor;
4773
4833
  try {
4774
- cursor = JSON.parse(readFileSync3(file, "utf8"));
4834
+ cursor = JSON.parse(readFileSync4(file, "utf8"));
4775
4835
  } catch {
4776
4836
  return;
4777
4837
  }
@@ -4786,8 +4846,8 @@ function readEmail(file, path) {
4786
4846
  }
4787
4847
  // src/lib/profiles.ts
4788
4848
  import { homedir as homedir4 } from "node:os";
4789
- import { isAbsolute, join as join6, resolve as resolve2 } from "node:path";
4790
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, rmSync } from "node:fs";
4849
+ import { isAbsolute, join as join7, resolve as resolve2 } from "node:path";
4850
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, rmSync } from "node:fs";
4791
4851
  function nowIso() {
4792
4852
  return new Date().toISOString();
4793
4853
  }
@@ -4796,7 +4856,7 @@ function expandPath(p) {
4796
4856
  if (out === "~")
4797
4857
  out = homedir4();
4798
4858
  else if (out.startsWith("~/"))
4799
- out = join6(homedir4(), out.slice(2));
4859
+ out = join7(homedir4(), out.slice(2));
4800
4860
  return isAbsolute(out) ? out : resolve2(process.cwd(), out);
4801
4861
  }
4802
4862
  function listProfiles(toolId) {
@@ -4834,11 +4894,11 @@ function addProfile(opts) {
4834
4894
  if (store.profiles.some((p) => p.name === name && p.tool === toolId)) {
4835
4895
  throw new AccountsError(`a ${toolId} profile named "${name}" already exists`);
4836
4896
  }
4837
- const dir = opts.dir ? expandPath(opts.dir) : join6(profilesDir(), toolId, name);
4897
+ const dir = opts.dir ? expandPath(opts.dir) : join7(profilesDir(), toolId, name);
4838
4898
  if (store.profiles.some((p) => p.dir === dir)) {
4839
4899
  throw new AccountsError(`a profile already uses config dir ${dir}`);
4840
4900
  }
4841
- mkdirSync4(dir, { recursive: true });
4901
+ mkdirSync5(dir, { recursive: true });
4842
4902
  const email = opts.email ?? detectEmail(dir, tool);
4843
4903
  const profile = {
4844
4904
  name,
@@ -4876,7 +4936,7 @@ function removeProfile(name, opts = {}) {
4876
4936
  if (options.purge) {
4877
4937
  const managed = profile.dir.startsWith(profilesDir());
4878
4938
  const isDefault = profile.dir === getTool(profile.tool).defaultDir;
4879
- if (managed && !isDefault && existsSync5(profile.dir)) {
4939
+ if (managed && !isDefault && existsSync6(profile.dir)) {
4880
4940
  rmSync(profile.dir, { recursive: true, force: true });
4881
4941
  purged = true;
4882
4942
  } else {
@@ -4927,7 +4987,7 @@ function updateProfile(name, opts) {
4927
4987
  profile.description = opts.description;
4928
4988
  if (opts.dir !== undefined) {
4929
4989
  const dir = expandPath(opts.dir);
4930
- mkdirSync4(dir, { recursive: true });
4990
+ mkdirSync5(dir, { recursive: true });
4931
4991
  profile.dir = dir;
4932
4992
  }
4933
4993
  saveStore(store);
@@ -4974,19 +5034,19 @@ function currentProfile(toolId) {
4974
5034
  return store.profiles.find((p) => p.name === name);
4975
5035
  }
4976
5036
  // src/lib/apply-lock.ts
4977
- import { closeSync, existsSync as existsSync6, mkdirSync as mkdirSync5, openSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
4978
- import { join as join7 } from "node:path";
5037
+ import { closeSync, existsSync as existsSync7, mkdirSync as mkdirSync6, openSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
5038
+ import { join as join8 } from "node:path";
4979
5039
  function lockPath() {
4980
- return join7(accountsHome(), ".apply.lock");
5040
+ return join8(accountsHome(), ".apply.lock");
4981
5041
  }
4982
5042
  function withApplyLock(fn) {
4983
5043
  const home = accountsHome();
4984
- mkdirSync5(home, { recursive: true });
5044
+ mkdirSync6(home, { recursive: true });
4985
5045
  const path = lockPath();
4986
5046
  let fd;
4987
5047
  try {
4988
5048
  fd = openSync(path, "wx", 384);
4989
- writeFileSync3(fd, `${process.pid}
5049
+ writeFileSync4(fd, `${process.pid}
4990
5050
  `, { encoding: "utf8", mode: 384 });
4991
5051
  return fn();
4992
5052
  } catch (err) {
@@ -5002,7 +5062,7 @@ function withApplyLock(fn) {
5002
5062
  if (fd !== undefined) {
5003
5063
  closeSync(fd);
5004
5064
  try {
5005
- if (existsSync6(path))
5065
+ if (existsSync7(path))
5006
5066
  unlinkSync2(path);
5007
5067
  } catch {}
5008
5068
  }
@@ -5046,19 +5106,19 @@ function applyProfileUnlocked(name, toolId) {
5046
5106
  return { profile, ...previous && previous !== name ? { previous } : {} };
5047
5107
  }
5048
5108
  // src/lib/import-profile.ts
5049
- import { cpSync, existsSync as existsSync7 } from "node:fs";
5050
- import { join as join8 } from "node:path";
5109
+ import { cpSync, existsSync as existsSync8 } from "node:fs";
5110
+ import { join as join9 } from "node:path";
5051
5111
  function importProfile(opts) {
5052
5112
  const toolId = opts.tool ?? DEFAULT_TOOL;
5053
5113
  const tool = getTool(toolId);
5054
5114
  const name = opts.name ?? "main";
5055
5115
  const sourceDir = opts.dir ? expandPath(opts.dir) : tool.defaultDir;
5056
- if (!existsSync7(sourceDir)) {
5116
+ if (!existsSync8(sourceDir)) {
5057
5117
  throw new AccountsError(`config dir does not exist: ${sourceDir}`);
5058
5118
  }
5059
5119
  if (opts.copy) {
5060
- const targetDir = join8(profilesDir(), toolId, name);
5061
- if (existsSync7(targetDir)) {
5120
+ const targetDir = join9(profilesDir(), toolId, name);
5121
+ if (existsSync8(targetDir)) {
5062
5122
  throw new AccountsError(`managed copy target already exists: ${targetDir}`);
5063
5123
  }
5064
5124
  cpSync(sourceDir, targetDir, { recursive: true });
@@ -5085,11 +5145,11 @@ function importProfile(opts) {
5085
5145
  ensureProfileAuthSnapshot(profile.dir, tool);
5086
5146
  return profile;
5087
5147
  }
5088
- function ensureProfileForLogin(name, toolId = DEFAULT_TOOL) {
5148
+ function ensureProfileForLogin(name, toolId) {
5089
5149
  const existing = findProfileByName(name, toolId);
5090
5150
  if (existing)
5091
5151
  return existing;
5092
- return addProfile({ name, tool: toolId, description: "created for login" });
5152
+ return addProfile({ name, tool: toolId ?? DEFAULT_TOOL, description: "created for login" });
5093
5153
  }
5094
5154
  function findProfileByName(name, toolId) {
5095
5155
  try {
@@ -5122,9 +5182,9 @@ function shellQuote(value) {
5122
5182
  function commandLine(env, command) {
5123
5183
  return `${formatEnvAssignments(env)} ${command.map(shellQuote).join(" ")}`.trim();
5124
5184
  }
5125
- function commandFor(tool, opts) {
5185
+ function commandFor(profile, tool, opts) {
5126
5186
  const args = [...opts.resume ? tool.resumeArgs ?? [] : [], ...opts.args ?? []];
5127
- return [tool.bin, ...mergeToolArgs(tool, args, { permissions: opts.permissions })];
5187
+ return [tool.bin, ...mergeToolArgs(tool, args, { permissions: opts.permissions, profile })];
5128
5188
  }
5129
5189
  function switchProfile(name, opts = {}) {
5130
5190
  const profile = getProfile(name, opts.tool);
@@ -5141,7 +5201,7 @@ function switchProfile(name, opts = {}) {
5141
5201
  } else {
5142
5202
  useProfile(name, tool.id);
5143
5203
  }
5144
- const command = commandFor(tool, opts);
5204
+ const command = commandFor(profile, tool, opts);
5145
5205
  const restartRequired = opts.resume === true || applied || mode === "env";
5146
5206
  const message = applied ? `${profile.name} is now the live/default ${tool.label} profile` : `${profile.name} is now the active ${tool.label} profile`;
5147
5207
  return {
@@ -5161,22 +5221,22 @@ function switchProfile(name, opts = {}) {
5161
5221
  // src/lib/supervisor.ts
5162
5222
  import { spawn } from "node:child_process";
5163
5223
  import { createHash } from "node:crypto";
5164
- import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync4, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
5224
+ import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync5, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
5165
5225
  import { createConnection, createServer } from "node:net";
5166
- import { basename, join as join9 } from "node:path";
5226
+ import { basename, join as join10 } from "node:path";
5167
5227
  var STATE_SUFFIX = ".json";
5168
5228
  function supervisorDir() {
5169
- return join9(accountsHome(), "supervisors");
5229
+ return join10(accountsHome(), "supervisors");
5170
5230
  }
5171
5231
  function supervisorStatePath(toolId) {
5172
- return join9(supervisorDir(), `${toolId}${STATE_SUFFIX}`);
5232
+ return join10(supervisorDir(), `${toolId}${STATE_SUFFIX}`);
5173
5233
  }
5174
5234
  function supervisorSocketPath(toolId) {
5175
5235
  if (process.platform === "win32") {
5176
5236
  const hash = createHash("sha1").update(accountsHome()).digest("hex").slice(0, 12);
5177
5237
  return `\\\\.\\pipe\\hasna-accounts-${hash}-${toolId}`;
5178
5238
  }
5179
- return join9(supervisorDir(), `${toolId}.sock`);
5239
+ return join10(supervisorDir(), `${toolId}.sock`);
5180
5240
  }
5181
5241
  function nowIso2() {
5182
5242
  return new Date().toISOString();
@@ -5190,23 +5250,23 @@ function parseState(raw) {
5190
5250
  }
5191
5251
  function readSupervisorState(toolId) {
5192
5252
  const path = supervisorStatePath(toolId);
5193
- if (!existsSync8(path))
5253
+ if (!existsSync9(path))
5194
5254
  return;
5195
5255
  try {
5196
- return parseState(readFileSync4(path, "utf8"));
5256
+ return parseState(readFileSync5(path, "utf8"));
5197
5257
  } catch {
5198
5258
  return;
5199
5259
  }
5200
5260
  }
5201
5261
  function listSupervisorStates() {
5202
5262
  const dir = supervisorDir();
5203
- if (!existsSync8(dir))
5263
+ if (!existsSync9(dir))
5204
5264
  return [];
5205
5265
  return readdirSync(dir).filter((name) => name.endsWith(STATE_SUFFIX)).map((name) => basename(name, STATE_SUFFIX)).map((toolId) => readSupervisorState(toolId)).filter((state) => state !== undefined);
5206
5266
  }
5207
5267
  function writeSupervisorState(state) {
5208
- mkdirSync6(supervisorDir(), { recursive: true });
5209
- writeFileSync4(supervisorStatePath(state.tool), JSON.stringify(state, null, 2) + `
5268
+ mkdirSync7(supervisorDir(), { recursive: true });
5269
+ writeFileSync5(supervisorStatePath(state.tool), JSON.stringify(state, null, 2) + `
5210
5270
  `, { mode: 384 });
5211
5271
  }
5212
5272
  function removeSupervisorFiles(toolId) {
@@ -5347,7 +5407,7 @@ async function runSupervisedTool(initialProfile, tool, initialArgs = [], opts =
5347
5407
  throw new AccountsError(`an accounts supervisor for ${tool.label} is already running (pid ${existing.pid})`);
5348
5408
  }
5349
5409
  removeSupervisorFiles(tool.id);
5350
- mkdirSync6(supervisorDir(), { recursive: true });
5410
+ mkdirSync7(supervisorDir(), { recursive: true });
5351
5411
  const startedAt = nowIso2();
5352
5412
  const restartDelayMs = opts.restartDelayMs ?? 350;
5353
5413
  const log = opts.log ?? (() => {
@@ -5552,8 +5612,8 @@ async function pickProfile(opts = {}) {
5552
5612
  return { profile, mode };
5553
5613
  }
5554
5614
  // src/lib/hook.ts
5555
- import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
5556
- import { join as join10 } from "node:path";
5615
+ import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
5616
+ import { join as join11 } from "node:path";
5557
5617
  var HOOK_FILE = "claude-hook.sh";
5558
5618
  var MARKER = "# accounts-claude-hook";
5559
5619
  var NAME_PATTERN = "^[a-z0-9][a-z0-9-]*$";
@@ -5561,7 +5621,7 @@ function shellQuotePath(path) {
5561
5621
  return `'${path.replace(/'/g, `'\\''`)}'`;
5562
5622
  }
5563
5623
  function hookPath() {
5564
- return join10(accountsHome(), HOOK_FILE);
5624
+ return join11(accountsHome(), HOOK_FILE);
5565
5625
  }
5566
5626
  function hookScript() {
5567
5627
  const quotedHook = shellQuotePath(hookPath());
@@ -5591,16 +5651,16 @@ claude() {
5591
5651
  }
5592
5652
  function installHook() {
5593
5653
  const path = hookPath();
5594
- mkdirSync7(accountsHome(), { recursive: true });
5595
- const created = !existsSync9(path);
5596
- writeFileSync5(path, hookScript(), { mode: 493 });
5654
+ mkdirSync8(accountsHome(), { recursive: true });
5655
+ const created = !existsSync10(path);
5656
+ writeFileSync6(path, hookScript(), { mode: 493 });
5597
5657
  return { path, created };
5598
5658
  }
5599
5659
  function uninstallHook() {
5600
5660
  const path = hookPath();
5601
- if (!existsSync9(path))
5661
+ if (!existsSync10(path))
5602
5662
  return false;
5603
- const content = readFileSync5(path, "utf8");
5663
+ const content = readFileSync6(path, "utf8");
5604
5664
  if (!content.includes(MARKER))
5605
5665
  return false;
5606
5666
  unlinkSync3(path);
@@ -5654,6 +5714,7 @@ export {
5654
5714
  listTools,
5655
5715
  listSupervisorStates,
5656
5716
  listProfiles,
5717
+ launchArgsFor,
5657
5718
  keychainSupported,
5658
5719
  isSafeProfileName,
5659
5720
  isBuiltinTool,
@@ -0,0 +1,2 @@
1
+ export declare function ensureCodexAppProfileConfig(profileDir: string): void;
2
+ //# sourceMappingURL=codex-app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-app.d.ts","sourceRoot":"","sources":["../../src/lib/codex-app.ts"],"names":[],"mappings":"AAgBA,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAMpE"}
@@ -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;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"}
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;AAQpD,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAalF;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"}
@@ -1 +1 @@
1
- {"version":3,"file":"import-profile.d.ts","sourceRoot":"","sources":["../../src/lib/import-profile.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa;;;;;;;;EAqChD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAe;;;;;;;;EAIxE"}
1
+ {"version":3,"file":"import-profile.d.ts","sourceRoot":"","sources":["../../src/lib/import-profile.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa;;;;;;;;EAqChD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;;;;;;;;EAIlE"}
@@ -1,4 +1,4 @@
1
- import { type ToolDef } from "../types.js";
1
+ import { type Profile, type ToolDef } from "../types.js";
2
2
  /**
3
3
  * Built-in tools. Users can register more at runtime with `accounts tools add`,
4
4
  * which persists them in the store — so the CLI scales to any app that reads a
@@ -8,9 +8,11 @@ export declare const BUILTIN_TOOLS: ToolDef[];
8
8
  export declare const DEFAULT_TOOL = "claude";
9
9
  export interface ToolArgOptions {
10
10
  permissions?: string;
11
+ profile?: Profile;
11
12
  }
12
13
  export declare function normalizePermissionPreset(value: string): string;
13
14
  export declare function permissionArgsFor(tool: ToolDef, permissions?: string): string[];
15
+ export declare function launchArgsFor(tool: ToolDef, profile?: Profile): string[];
14
16
  export declare function mergeToolArgs(tool: ToolDef, args: string[], opts?: ToolArgOptions): string[];
15
17
  export declare function isBuiltinTool(id: string): boolean;
16
18
  /** All tools: built-ins plus any user-registered ones (custom wins on id clash). */
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/lib/tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAgC,MAAM,aAAa,CAAC;AAGzE;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,OAAO,EAuIlC,CAAC;AAEF,eAAO,MAAM,YAAY,WAAW,CAAC;AAErC,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkBD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAW/E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,cAAmB,GAAG,MAAM,EAAE,CAGhG;AAID,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,oFAAoF;AACpF,wBAAgB,SAAS,IAAI,OAAO,EAAE,CAMrC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAS3C;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAanD;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAWjD"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/lib/tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAgC,MAAM,aAAa,CAAC;AAGvF;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,OAAO,EAoJlC,CAAC;AAEF,eAAO,MAAM,YAAY,WAAW,CAAC;AAErC,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAkBD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAW/E;AASD,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAGxE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,cAAmB,GAAG,MAAM,EAAE,CAIhG;AAID,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,oFAAoF;AACpF,wBAAgB,SAAS,IAAI,OAAO,EAAE,CAMrC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAS3C;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAanD;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAWjD"}
package/dist/mcp.js CHANGED
@@ -16635,6 +16635,7 @@ var toolDefSchema = exports_external.object({
16635
16635
  loginHint: exports_external.string().optional(),
16636
16636
  resumeArgs: exports_external.array(exports_external.string()).optional(),
16637
16637
  permissionArgs: exports_external.record(exports_external.array(exports_external.string())).optional(),
16638
+ launchArgs: exports_external.array(exports_external.string()).optional(),
16638
16639
  accountFile: exports_external.string().optional(),
16639
16640
  emailPath: exports_external.array(exports_external.string()).optional()
16640
16641
  });
@@ -16805,6 +16806,9 @@ var BUILTIN_TOOLS = [
16805
16806
  id: "claude",
16806
16807
  label: "Claude Code",
16807
16808
  envVar: "CLAUDE_CONFIG_DIR",
16809
+ extraEnv: {
16810
+ TELEGRAM_STATE_DIR: "{profileDir}/channels/telegram"
16811
+ },
16808
16812
  defaultDir: join2(homedir2(), ".claude"),
16809
16813
  bin: "claude",
16810
16814
  loginHint: "run /login inside Claude, then /exit when done",
@@ -16821,6 +16825,16 @@ var BUILTIN_TOOLS = [
16821
16825
  accountFile: ".claude.json",
16822
16826
  emailPath: ["oauthAccount", "emailAddress"]
16823
16827
  },
16828
+ {
16829
+ id: "codex-app",
16830
+ label: "Codex App",
16831
+ envVar: "CODEX_HOME",
16832
+ defaultDir: join2(homedir2(), ".codex"),
16833
+ bin: "/Applications/Codex.app/Contents/MacOS/Codex",
16834
+ loginHint: "sign in inside Codex.app, then quit the app when the profile is ready",
16835
+ launchArgs: ["--user-data-dir={profileDir}/electron-user-data"],
16836
+ accountFile: "auth.json"
16837
+ },
16824
16838
  {
16825
16839
  id: "codex",
16826
16840
  label: "Codex CLI",
@@ -16969,9 +16983,17 @@ function permissionArgsFor(tool, permissions) {
16969
16983
  }
16970
16984
  return args;
16971
16985
  }
16986
+ function renderToolArg(value, profile) {
16987
+ return value.replaceAll("{profileDir}", profile.dir).replaceAll("{profileName}", profile.name).replaceAll("{toolId}", profile.tool);
16988
+ }
16989
+ function launchArgsFor(tool, profile) {
16990
+ const args = tool.launchArgs ?? [];
16991
+ return profile ? args.map((arg) => renderToolArg(arg, profile)) : args;
16992
+ }
16972
16993
  function mergeToolArgs(tool, args, opts = {}) {
16994
+ const launchArgs = launchArgsFor(tool, opts.profile).filter((arg) => !args.includes(arg));
16973
16995
  const permissionArgs = permissionArgsFor(tool, opts.permissions).filter((arg) => !args.includes(arg));
16974
- return [...permissionArgs, ...args];
16996
+ return [...permissionArgs, ...launchArgs, ...args];
16975
16997
  }
16976
16998
  var BUILTIN_IDS = new Set(BUILTIN_TOOLS.map((t) => t.id));
16977
16999
  function listTools() {
@@ -17443,6 +17465,42 @@ function applyProfileUnlocked(name, toolId) {
17443
17465
  return { profile, ...previous && previous !== name ? { previous } : {} };
17444
17466
  }
17445
17467
 
17468
+ // src/lib/codex-app.ts
17469
+ import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
17470
+ import { join as join6 } from "node:path";
17471
+ var FILE_CREDENTIALS_LINE = 'cli_auth_credentials_store = "file"';
17472
+ function insertRootConfigLine(config2, line) {
17473
+ if (config2.trim() === "")
17474
+ return `${line}
17475
+ `;
17476
+ const lines = config2.split(/\r?\n/);
17477
+ const tableIndex = lines.findIndex((entry) => /^\s*\[[^\]]+\]\s*(?:#.*)?$/.test(entry));
17478
+ if (tableIndex === -1)
17479
+ return `${config2.trimEnd()}
17480
+
17481
+ ${line}
17482
+ `;
17483
+ const before = lines.slice(0, tableIndex).join(`
17484
+ `).trimEnd();
17485
+ const after = lines.slice(tableIndex).join(`
17486
+ `).trimStart();
17487
+ return `${before}${before ? `
17488
+
17489
+ ` : ""}${line}
17490
+
17491
+ ${after}${after.endsWith(`
17492
+ `) ? "" : `
17493
+ `}`;
17494
+ }
17495
+ function ensureCodexAppProfileConfig(profileDir) {
17496
+ mkdirSync5(profileDir, { recursive: true });
17497
+ const configPath = join6(profileDir, "config.toml");
17498
+ const current = existsSync5(configPath) ? readFileSync3(configPath, "utf8") : "";
17499
+ if (/^\s*cli_auth_credentials_store\s*=/.test(current))
17500
+ return;
17501
+ writeFileSync4(configPath, insertRootConfigLine(current, FILE_CREDENTIALS_LINE), { mode: 384 });
17502
+ }
17503
+
17446
17504
  // src/lib/env.ts
17447
17505
  function renderTemplate(value, profile) {
17448
17506
  return value.replaceAll("{profileDir}", profile.dir).replaceAll("{profileName}", profile.name).replaceAll("{toolId}", profile.tool);
@@ -17459,6 +17517,8 @@ function profileEnv(profile, tool) {
17459
17517
  for (const key of CLAUDE_API_AUTH_ENV_KEYS)
17460
17518
  env[key] = "";
17461
17519
  }
17520
+ if (tool.id === "codex-app")
17521
+ ensureCodexAppProfileConfig(profile.dir);
17462
17522
  return env;
17463
17523
  }
17464
17524
  function formatEnvAssignments(env) {
@@ -17478,9 +17538,9 @@ function shellQuote(value) {
17478
17538
  function commandLine(env, command) {
17479
17539
  return `${formatEnvAssignments(env)} ${command.map(shellQuote).join(" ")}`.trim();
17480
17540
  }
17481
- function commandFor(tool, opts) {
17541
+ function commandFor(profile, tool, opts) {
17482
17542
  const args = [...opts.resume ? tool.resumeArgs ?? [] : [], ...opts.args ?? []];
17483
- return [tool.bin, ...mergeToolArgs(tool, args, { permissions: opts.permissions })];
17543
+ return [tool.bin, ...mergeToolArgs(tool, args, { permissions: opts.permissions, profile })];
17484
17544
  }
17485
17545
  function switchProfile(name, opts = {}) {
17486
17546
  const profile = getProfile(name, opts.tool);
@@ -17497,7 +17557,7 @@ function switchProfile(name, opts = {}) {
17497
17557
  } else {
17498
17558
  useProfile(name, tool.id);
17499
17559
  }
17500
- const command = commandFor(tool, opts);
17560
+ const command = commandFor(profile, tool, opts);
17501
17561
  const restartRequired = opts.resume === true || applied || mode === "env";
17502
17562
  const message = applied ? `${profile.name} is now the live/default ${tool.label} profile` : `${profile.name} is now the active ${tool.label} profile`;
17503
17563
  return {
@@ -17517,22 +17577,22 @@ function switchProfile(name, opts = {}) {
17517
17577
 
17518
17578
  // src/lib/supervisor.ts
17519
17579
  import { createHash } from "node:crypto";
17520
- import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync3, readdirSync, rmSync, writeFileSync as writeFileSync4 } from "node:fs";
17580
+ import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync4, readdirSync, rmSync, writeFileSync as writeFileSync5 } from "node:fs";
17521
17581
  import { createConnection, createServer } from "node:net";
17522
- import { basename, join as join6 } from "node:path";
17582
+ import { basename, join as join7 } from "node:path";
17523
17583
  var STATE_SUFFIX = ".json";
17524
17584
  function supervisorDir() {
17525
- return join6(accountsHome(), "supervisors");
17585
+ return join7(accountsHome(), "supervisors");
17526
17586
  }
17527
17587
  function supervisorStatePath(toolId) {
17528
- return join6(supervisorDir(), `${toolId}${STATE_SUFFIX}`);
17588
+ return join7(supervisorDir(), `${toolId}${STATE_SUFFIX}`);
17529
17589
  }
17530
17590
  function supervisorSocketPath(toolId) {
17531
17591
  if (process.platform === "win32") {
17532
17592
  const hash = createHash("sha1").update(accountsHome()).digest("hex").slice(0, 12);
17533
17593
  return `\\\\.\\pipe\\hasna-accounts-${hash}-${toolId}`;
17534
17594
  }
17535
- return join6(supervisorDir(), `${toolId}.sock`);
17595
+ return join7(supervisorDir(), `${toolId}.sock`);
17536
17596
  }
17537
17597
  function parseState(raw) {
17538
17598
  const data = JSON.parse(raw);
@@ -17543,17 +17603,17 @@ function parseState(raw) {
17543
17603
  }
17544
17604
  function readSupervisorState(toolId) {
17545
17605
  const path = supervisorStatePath(toolId);
17546
- if (!existsSync5(path))
17606
+ if (!existsSync6(path))
17547
17607
  return;
17548
17608
  try {
17549
- return parseState(readFileSync3(path, "utf8"));
17609
+ return parseState(readFileSync4(path, "utf8"));
17550
17610
  } catch {
17551
17611
  return;
17552
17612
  }
17553
17613
  }
17554
17614
  function listSupervisorStates() {
17555
17615
  const dir = supervisorDir();
17556
- if (!existsSync5(dir))
17616
+ if (!existsSync6(dir))
17557
17617
  return [];
17558
17618
  return readdirSync(dir).filter((name) => name.endsWith(STATE_SUFFIX)).map((name) => basename(name, STATE_SUFFIX)).map((toolId) => readSupervisorState(toolId)).filter((state) => state !== undefined);
17559
17619
  }
@@ -17619,7 +17679,7 @@ function ok(data) {
17619
17679
  function fail(message) {
17620
17680
  return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
17621
17681
  }
17622
- var server = new Server({ name: "accounts", version: "0.1.14" }, { capabilities: { tools: {} } });
17682
+ var server = new Server({ name: "accounts", version: "0.1.16" }, { capabilities: { tools: {} } });
17623
17683
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
17624
17684
  tools: [
17625
17685
  {
package/dist/storage.js CHANGED
@@ -4008,6 +4008,7 @@ var toolDefSchema = exports_external.object({
4008
4008
  loginHint: exports_external.string().optional(),
4009
4009
  resumeArgs: exports_external.array(exports_external.string()).optional(),
4010
4010
  permissionArgs: exports_external.record(exports_external.array(exports_external.string())).optional(),
4011
+ launchArgs: exports_external.array(exports_external.string()).optional(),
4011
4012
  accountFile: exports_external.string().optional(),
4012
4013
  emailPath: exports_external.array(exports_external.string()).optional()
4013
4014
  });