@hasna/accounts 0.1.19 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +167 -98
- package/dist/index.js +156 -87
- package/dist/lib/safe-path.d.ts.map +1 -1
- package/dist/mcp.js +142 -73
- package/dist/storage.js +107 -38
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12804,8 +12804,8 @@ More information can be found at: https://a.co/c895JFp`);
|
|
|
12804
12804
|
};
|
|
12805
12805
|
var createUserAgentStringParsingProvider = ({ serviceId, clientVersion }) => async (config2) => {
|
|
12806
12806
|
const module2 = await Promise.resolve().then(() => __toESM(require_es5()));
|
|
12807
|
-
const
|
|
12808
|
-
const parsedUA = typeof window !== "undefined" && window?.navigator?.userAgent ?
|
|
12807
|
+
const parse2 = module2.parse ?? module2.default.parse ?? (() => "");
|
|
12808
|
+
const parsedUA = typeof window !== "undefined" && window?.navigator?.userAgent ? parse2(window.navigator.userAgent) : undefined;
|
|
12809
12809
|
const sections = [
|
|
12810
12810
|
["aws-sdk-js", clientVersion],
|
|
12811
12811
|
["ua", "2.1"],
|
|
@@ -14563,7 +14563,7 @@ var require_dist_cjs9 = __commonJS((exports) => {
|
|
|
14563
14563
|
var require_util = __commonJS((exports) => {
|
|
14564
14564
|
var protocols = require_protocols();
|
|
14565
14565
|
var validate = (str) => typeof str === "string" && str.indexOf("arn:") === 0 && str.split(":").length >= 6;
|
|
14566
|
-
var
|
|
14566
|
+
var parse2 = (arn) => {
|
|
14567
14567
|
const segments = arn.split(":");
|
|
14568
14568
|
if (segments.length < 6 || segments[0] !== "arn")
|
|
14569
14569
|
throw new Error("Malformed ARN");
|
|
@@ -14613,7 +14613,7 @@ var require_util = __commonJS((exports) => {
|
|
|
14613
14613
|
}
|
|
14614
14614
|
exports.build = build;
|
|
14615
14615
|
exports.formatUrl = formatUrl;
|
|
14616
|
-
exports.parse =
|
|
14616
|
+
exports.parse = parse2;
|
|
14617
14617
|
exports.validate = validate;
|
|
14618
14618
|
});
|
|
14619
14619
|
|
|
@@ -30104,12 +30104,12 @@ var require_fromHttp = __commonJS((exports) => {
|
|
|
30104
30104
|
var fromHttp = (options = {}) => {
|
|
30105
30105
|
options.logger?.debug("@aws-sdk/credential-provider-http - fromHttp");
|
|
30106
30106
|
let host;
|
|
30107
|
-
const
|
|
30107
|
+
const relative2 = options.awsContainerCredentialsRelativeUri ?? process.env[AWS_CONTAINER_CREDENTIALS_RELATIVE_URI];
|
|
30108
30108
|
const full = options.awsContainerCredentialsFullUri ?? process.env[AWS_CONTAINER_CREDENTIALS_FULL_URI];
|
|
30109
30109
|
const token = options.awsContainerAuthorizationToken ?? process.env[AWS_CONTAINER_AUTHORIZATION_TOKEN];
|
|
30110
30110
|
const tokenFile = options.awsContainerAuthorizationTokenFile ?? process.env[AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE];
|
|
30111
30111
|
const warn = options.logger?.constructor?.name === "NoOpLogger" || !options.logger?.warn ? console.warn : options.logger.warn.bind(options.logger);
|
|
30112
|
-
if (
|
|
30112
|
+
if (relative2 && full) {
|
|
30113
30113
|
warn("@aws-sdk/credential-provider-http: " + "you have set both awsContainerCredentialsRelativeUri and awsContainerCredentialsFullUri.");
|
|
30114
30114
|
warn("awsContainerCredentialsFullUri will take precedence.");
|
|
30115
30115
|
}
|
|
@@ -30119,8 +30119,8 @@ var require_fromHttp = __commonJS((exports) => {
|
|
|
30119
30119
|
}
|
|
30120
30120
|
if (full) {
|
|
30121
30121
|
host = full;
|
|
30122
|
-
} else if (
|
|
30123
|
-
host = `${DEFAULT_LINK_LOCAL_HOST}${
|
|
30122
|
+
} else if (relative2) {
|
|
30123
|
+
host = `${DEFAULT_LINK_LOCAL_HOST}${relative2}`;
|
|
30124
30124
|
} else {
|
|
30125
30125
|
throw new config_1.CredentialsProviderError(`No HTTP credential provider host provided.
|
|
30126
30126
|
Set AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI.`, { logger: options.logger });
|
|
@@ -36799,7 +36799,7 @@ var require_dist_cjs22 = __commonJS((exports) => {
|
|
|
36799
36799
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
36800
36800
|
import { existsSync as existsSync13, readFileSync as readFileSync8 } from "node:fs";
|
|
36801
36801
|
import { homedir as homedir6 } from "node:os";
|
|
36802
|
-
import { dirname as dirname5, join as
|
|
36802
|
+
import { dirname as dirname5, join as join14 } from "node:path";
|
|
36803
36803
|
import { fileURLToPath } from "node:url";
|
|
36804
36804
|
|
|
36805
36805
|
// node_modules/commander/esm.mjs
|
|
@@ -42002,62 +42002,131 @@ class AccountsError extends Error {
|
|
|
42002
42002
|
|
|
42003
42003
|
// src/lib/tools.ts
|
|
42004
42004
|
import { homedir as homedir3 } from "node:os";
|
|
42005
|
-
import { join as
|
|
42005
|
+
import { join as join4 } from "node:path";
|
|
42006
42006
|
|
|
42007
42007
|
// src/storage.ts
|
|
42008
42008
|
import { homedir as homedir2 } from "node:os";
|
|
42009
42009
|
import { hostname } from "node:os";
|
|
42010
|
-
import { join as
|
|
42010
|
+
import { join as join3 } from "node:path";
|
|
42011
42011
|
import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "node:fs";
|
|
42012
42012
|
|
|
42013
42013
|
// src/lib/safe-path.ts
|
|
42014
42014
|
import { existsSync as existsSync2, lstatSync, mkdirSync, realpathSync } from "node:fs";
|
|
42015
|
-
import { dirname, resolve } from "node:path";
|
|
42015
|
+
import { dirname, isAbsolute, join as join2, parse, relative, resolve, sep } from "node:path";
|
|
42016
|
+
function lstatIfExists(path) {
|
|
42017
|
+
try {
|
|
42018
|
+
return lstatSync(path);
|
|
42019
|
+
} catch (err) {
|
|
42020
|
+
if (err.code !== "ENOENT")
|
|
42021
|
+
throw err;
|
|
42022
|
+
return;
|
|
42023
|
+
}
|
|
42024
|
+
}
|
|
42016
42025
|
function throwIfSymlink(path, label) {
|
|
42017
|
-
if (
|
|
42026
|
+
if (lstatIfExists(path)?.isSymbolicLink()) {
|
|
42018
42027
|
throw new AccountsError(`${label}: ${path}`);
|
|
42019
42028
|
}
|
|
42020
42029
|
}
|
|
42021
|
-
function
|
|
42022
|
-
|
|
42023
|
-
|
|
42024
|
-
|
|
42025
|
-
|
|
42026
|
-
|
|
42027
|
-
|
|
42028
|
-
|
|
42029
|
-
|
|
42030
|
-
|
|
42031
|
-
|
|
42032
|
-
|
|
42033
|
-
}
|
|
42034
|
-
|
|
42035
|
-
|
|
42036
|
-
|
|
42037
|
-
|
|
42030
|
+
function isAllowedSystemDirectorySymlink(path) {
|
|
42031
|
+
if (path !== "/var" && path !== "/tmp")
|
|
42032
|
+
return false;
|
|
42033
|
+
try {
|
|
42034
|
+
return realpathSync(path) === `/private${path}`;
|
|
42035
|
+
} catch {
|
|
42036
|
+
return false;
|
|
42037
|
+
}
|
|
42038
|
+
}
|
|
42039
|
+
function assertDirectory(path, label, opts) {
|
|
42040
|
+
const stat = lstatIfExists(path);
|
|
42041
|
+
if (!stat) {
|
|
42042
|
+
throw new AccountsError(`refusing to write under missing directory: ${path}`);
|
|
42043
|
+
}
|
|
42044
|
+
if (stat.isSymbolicLink()) {
|
|
42045
|
+
if (opts?.allowSystemSymlink && isAllowedSystemDirectorySymlink(path))
|
|
42046
|
+
return;
|
|
42047
|
+
throw new AccountsError(`${label}: ${path}`);
|
|
42048
|
+
}
|
|
42049
|
+
if (!stat.isDirectory()) {
|
|
42050
|
+
throw new AccountsError(`refusing to write under non-directory path: ${path}`);
|
|
42051
|
+
}
|
|
42052
|
+
}
|
|
42053
|
+
function assertInsideBase(absPath, base, originalPath) {
|
|
42054
|
+
const rel = relative(base, absPath);
|
|
42055
|
+
if (rel === "")
|
|
42056
|
+
return rel;
|
|
42057
|
+
if (rel === ".." || rel.startsWith(".." + sep) || isAbsolute(rel)) {
|
|
42058
|
+
throw new AccountsError(`refusing to write outside profile directory: ${originalPath}`);
|
|
42059
|
+
}
|
|
42060
|
+
return rel;
|
|
42061
|
+
}
|
|
42062
|
+
function assertExistingDirectoryComponentsSafe(path, label) {
|
|
42063
|
+
const root = parse(path).root;
|
|
42064
|
+
const rel = relative(root, path);
|
|
42065
|
+
const segments = rel ? rel.split(sep).filter(Boolean) : [];
|
|
42066
|
+
let cursor = root;
|
|
42067
|
+
assertDirectory(cursor, label, { allowSystemSymlink: true });
|
|
42068
|
+
for (const segment of segments) {
|
|
42069
|
+
cursor = join2(cursor, segment);
|
|
42070
|
+
if (!lstatIfExists(cursor))
|
|
42071
|
+
return;
|
|
42072
|
+
assertDirectory(cursor, label, { allowSystemSymlink: true });
|
|
42073
|
+
}
|
|
42074
|
+
}
|
|
42075
|
+
function ensureBoundaryRootSafe(base) {
|
|
42076
|
+
const missing = [];
|
|
42077
|
+
let cursor = base;
|
|
42078
|
+
while (!lstatIfExists(cursor)) {
|
|
42079
|
+
missing.unshift(cursor);
|
|
42080
|
+
const parent = dirname(cursor);
|
|
42081
|
+
if (parent === cursor)
|
|
42082
|
+
break;
|
|
42083
|
+
cursor = parent;
|
|
42084
|
+
}
|
|
42085
|
+
assertDirectory(cursor, "refusing to use symlink base directory");
|
|
42086
|
+
for (const dir of missing) {
|
|
42087
|
+
if (lstatIfExists(dir)) {
|
|
42088
|
+
assertDirectory(dir, "refusing to use symlink base directory");
|
|
42089
|
+
} else {
|
|
42090
|
+
mkdirSync(dir);
|
|
42091
|
+
assertDirectory(dir, "refusing to use symlink base directory");
|
|
42038
42092
|
}
|
|
42039
|
-
}
|
|
42040
|
-
|
|
42041
|
-
|
|
42042
|
-
|
|
42043
|
-
|
|
42044
|
-
|
|
42045
|
-
|
|
42046
|
-
|
|
42093
|
+
}
|
|
42094
|
+
assertDirectory(base, "refusing to use symlink base directory");
|
|
42095
|
+
}
|
|
42096
|
+
function ensureDirectoryChainSafe(parent, startAt) {
|
|
42097
|
+
const root = startAt ?? parse(parent).root;
|
|
42098
|
+
const rel = relative(root, parent);
|
|
42099
|
+
const segments = rel ? rel.split(sep).filter(Boolean) : [];
|
|
42100
|
+
let cursor = root;
|
|
42101
|
+
if (startAt)
|
|
42102
|
+
assertDirectory(startAt, "refusing to write under symlink directory");
|
|
42103
|
+
for (const segment of segments) {
|
|
42104
|
+
cursor = join2(cursor, segment);
|
|
42105
|
+
if (lstatIfExists(cursor)) {
|
|
42106
|
+
assertDirectory(cursor, "refusing to write under symlink directory");
|
|
42107
|
+
} else {
|
|
42108
|
+
mkdirSync(cursor);
|
|
42109
|
+
assertDirectory(cursor, "refusing to write under symlink directory");
|
|
42047
42110
|
}
|
|
42048
42111
|
}
|
|
42049
42112
|
}
|
|
42050
42113
|
function assertSafeWritePath(filePath, opts) {
|
|
42051
42114
|
const absFile = resolve(filePath);
|
|
42052
42115
|
const parent = dirname(absFile);
|
|
42053
|
-
|
|
42054
|
-
|
|
42116
|
+
const base = opts?.mustStayUnder ? resolve(opts.mustStayUnder) : undefined;
|
|
42117
|
+
if (base) {
|
|
42118
|
+
assertInsideBase(absFile, base, filePath);
|
|
42119
|
+
assertExistingDirectoryComponentsSafe(base, "refusing to use symlink base directory");
|
|
42120
|
+
ensureBoundaryRootSafe(base);
|
|
42121
|
+
ensureDirectoryChainSafe(parent, base);
|
|
42122
|
+
} else {
|
|
42123
|
+
ensureDirectoryChainSafe(parent);
|
|
42124
|
+
}
|
|
42055
42125
|
throwIfSymlink(absFile, "refusing to write through symlink");
|
|
42056
|
-
assertDirChainSafe(absFile, opts?.mustStayUnder);
|
|
42057
42126
|
const resolved = realpathSync(existsSync2(absFile) ? absFile : parent);
|
|
42058
|
-
if (
|
|
42059
|
-
const
|
|
42060
|
-
if (resolved !==
|
|
42127
|
+
if (base) {
|
|
42128
|
+
const realBase = realpathSync(base);
|
|
42129
|
+
if (resolved !== realBase && !resolved.startsWith(realBase + sep)) {
|
|
42061
42130
|
throw new AccountsError(`refusing to write outside profile directory: ${filePath}`);
|
|
42062
42131
|
}
|
|
42063
42132
|
}
|
|
@@ -42096,16 +42165,16 @@ function accountsHome() {
|
|
|
42096
42165
|
const override = process.env.ACCOUNTS_HOME;
|
|
42097
42166
|
if (override && override.trim())
|
|
42098
42167
|
return validateEnvPath(override, "ACCOUNTS_HOME");
|
|
42099
|
-
return
|
|
42168
|
+
return join3(homedir2(), ".hasna", "accounts");
|
|
42100
42169
|
}
|
|
42101
42170
|
function storePath() {
|
|
42102
42171
|
const override = process.env.ACCOUNTS_STORE_PATH;
|
|
42103
42172
|
if (override && override.trim())
|
|
42104
42173
|
return validateEnvPath(override, "ACCOUNTS_STORE_PATH");
|
|
42105
|
-
return
|
|
42174
|
+
return join3(accountsHome(), "accounts.json");
|
|
42106
42175
|
}
|
|
42107
42176
|
function profilesDir() {
|
|
42108
|
-
return
|
|
42177
|
+
return join3(accountsHome(), "profiles");
|
|
42109
42178
|
}
|
|
42110
42179
|
var EMPTY_STORE = { version: 1, current: {}, applied: {}, profiles: [], tools: [] };
|
|
42111
42180
|
function loadStore() {
|
|
@@ -42148,7 +42217,7 @@ function loadStore() {
|
|
|
42148
42217
|
function saveStore(store) {
|
|
42149
42218
|
const path = storePath();
|
|
42150
42219
|
assertSafeWritePath(path, { mustStayUnder: accountsHome() });
|
|
42151
|
-
mkdirSync2(
|
|
42220
|
+
mkdirSync2(join3(path, ".."), { recursive: true });
|
|
42152
42221
|
if (existsSync3(path))
|
|
42153
42222
|
chmodSync(path, 384);
|
|
42154
42223
|
writeFileSync(path, JSON.stringify(store, null, 2) + `
|
|
@@ -42302,7 +42371,7 @@ var BUILTIN_TOOLS = [
|
|
|
42302
42371
|
extraEnv: {
|
|
42303
42372
|
TELEGRAM_STATE_DIR: "{profileDir}/channels/telegram"
|
|
42304
42373
|
},
|
|
42305
|
-
defaultDir:
|
|
42374
|
+
defaultDir: join4(homedir3(), ".claude"),
|
|
42306
42375
|
bin: "claude",
|
|
42307
42376
|
loginHint: "run /login inside Claude, then /exit when done",
|
|
42308
42377
|
resumeArgs: ["--continue"],
|
|
@@ -42322,7 +42391,7 @@ var BUILTIN_TOOLS = [
|
|
|
42322
42391
|
id: "codex-app",
|
|
42323
42392
|
label: "Codex App",
|
|
42324
42393
|
envVar: "CODEX_HOME",
|
|
42325
|
-
defaultDir:
|
|
42394
|
+
defaultDir: join4(homedir3(), ".codex"),
|
|
42326
42395
|
bin: "/Applications/Codex.app/Contents/MacOS/Codex",
|
|
42327
42396
|
loginHint: "sign in inside Codex.app, then quit the app when the profile is ready",
|
|
42328
42397
|
launchArgs: ["--user-data-dir={profileDir}/electron-user-data"],
|
|
@@ -42332,7 +42401,7 @@ var BUILTIN_TOOLS = [
|
|
|
42332
42401
|
id: "codex",
|
|
42333
42402
|
label: "Codex CLI",
|
|
42334
42403
|
envVar: "CODEX_HOME",
|
|
42335
|
-
defaultDir:
|
|
42404
|
+
defaultDir: join4(homedir3(), ".codex"),
|
|
42336
42405
|
bin: "codex",
|
|
42337
42406
|
loginArgs: ["login"],
|
|
42338
42407
|
loginHint: "complete the Codex login flow for this CODEX_HOME",
|
|
@@ -42345,7 +42414,7 @@ var BUILTIN_TOOLS = [
|
|
|
42345
42414
|
id: "takumi",
|
|
42346
42415
|
label: "Takumi",
|
|
42347
42416
|
envVar: "TAKUMI_CONFIG_DIR",
|
|
42348
|
-
defaultDir:
|
|
42417
|
+
defaultDir: join4(homedir3(), ".takumi"),
|
|
42349
42418
|
bin: "takumi",
|
|
42350
42419
|
loginHint: "complete Takumi auth in this TAKUMI_CONFIG_DIR",
|
|
42351
42420
|
resumeArgs: ["--continue"],
|
|
@@ -42365,7 +42434,7 @@ var BUILTIN_TOOLS = [
|
|
|
42365
42434
|
id: "gemini",
|
|
42366
42435
|
label: "Gemini CLI",
|
|
42367
42436
|
envVar: "GEMINI_CONFIG_DIR",
|
|
42368
|
-
defaultDir:
|
|
42437
|
+
defaultDir: join4(homedir3(), ".gemini"),
|
|
42369
42438
|
bin: "gemini",
|
|
42370
42439
|
loginHint: "complete Gemini auth in this GEMINI_CONFIG_DIR",
|
|
42371
42440
|
permissionArgs: {
|
|
@@ -42383,7 +42452,7 @@ var BUILTIN_TOOLS = [
|
|
|
42383
42452
|
XDG_CONFIG_HOME: "{profileDir}/xdg-config",
|
|
42384
42453
|
XDG_DATA_HOME: "{profileDir}/xdg-data"
|
|
42385
42454
|
},
|
|
42386
|
-
defaultDir:
|
|
42455
|
+
defaultDir: join4(homedir3(), ".config", "opencode"),
|
|
42387
42456
|
bin: "opencode",
|
|
42388
42457
|
loginArgs: ["auth", "login"],
|
|
42389
42458
|
loginHint: "complete opencode auth login for this isolated config/data root",
|
|
@@ -42393,7 +42462,7 @@ var BUILTIN_TOOLS = [
|
|
|
42393
42462
|
id: "cursor",
|
|
42394
42463
|
label: "Cursor Agent",
|
|
42395
42464
|
envVar: "CURSOR_CONFIG_DIR",
|
|
42396
|
-
defaultDir:
|
|
42465
|
+
defaultDir: join4(homedir3(), ".cursor"),
|
|
42397
42466
|
bin: "cursor-agent",
|
|
42398
42467
|
loginArgs: ["login"],
|
|
42399
42468
|
loginHint: "complete cursor-agent login for this CURSOR_CONFIG_DIR"
|
|
@@ -42402,7 +42471,7 @@ var BUILTIN_TOOLS = [
|
|
|
42402
42471
|
id: "pi",
|
|
42403
42472
|
label: "Pi Coding Agent",
|
|
42404
42473
|
envVar: "PI_CODING_AGENT_HOME",
|
|
42405
|
-
defaultDir:
|
|
42474
|
+
defaultDir: join4(homedir3(), ".pi"),
|
|
42406
42475
|
bin: "pi",
|
|
42407
42476
|
loginHint: "complete Pi coding agent auth in this PI_CODING_AGENT_HOME"
|
|
42408
42477
|
},
|
|
@@ -42410,7 +42479,7 @@ var BUILTIN_TOOLS = [
|
|
|
42410
42479
|
id: "hermes",
|
|
42411
42480
|
label: "Hermes",
|
|
42412
42481
|
envVar: "HERMES_HOME",
|
|
42413
|
-
defaultDir:
|
|
42482
|
+
defaultDir: join4(homedir3(), ".hermes"),
|
|
42414
42483
|
bin: "hermes",
|
|
42415
42484
|
loginHint: "complete Hermes auth in this HERMES_HOME",
|
|
42416
42485
|
permissionArgs: {
|
|
@@ -42422,7 +42491,7 @@ var BUILTIN_TOOLS = [
|
|
|
42422
42491
|
id: "kimi",
|
|
42423
42492
|
label: "Kimi Code",
|
|
42424
42493
|
envVar: "KIMI_CODE_HOME",
|
|
42425
|
-
defaultDir:
|
|
42494
|
+
defaultDir: join4(homedir3(), ".kimi-code"),
|
|
42426
42495
|
bin: "kimi",
|
|
42427
42496
|
loginArgs: ["login"],
|
|
42428
42497
|
loginHint: "complete kimi login for this KIMI_CODE_HOME",
|
|
@@ -42437,7 +42506,7 @@ var BUILTIN_TOOLS = [
|
|
|
42437
42506
|
id: "grok",
|
|
42438
42507
|
label: "Grok Build",
|
|
42439
42508
|
envVar: "HOME",
|
|
42440
|
-
defaultDir:
|
|
42509
|
+
defaultDir: join4(homedir3(), ".grok"),
|
|
42441
42510
|
bin: "grok",
|
|
42442
42511
|
loginArgs: ["login"],
|
|
42443
42512
|
loginHint: "complete grok login in this process-scoped HOME; prefer launch/shell over exporting HOME globally"
|
|
@@ -42544,18 +42613,18 @@ function removeCustomTool(id) {
|
|
|
42544
42613
|
|
|
42545
42614
|
// src/lib/profiles.ts
|
|
42546
42615
|
import { homedir as homedir4 } from "node:os";
|
|
42547
|
-
import { isAbsolute, join as
|
|
42616
|
+
import { isAbsolute as isAbsolute2, join as join6, relative as relative2, resolve as resolve2 } from "node:path";
|
|
42548
42617
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3, rmSync } from "node:fs";
|
|
42549
42618
|
|
|
42550
42619
|
// src/lib/detect.ts
|
|
42551
42620
|
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "node:fs";
|
|
42552
|
-
import { dirname as dirname2, join as
|
|
42621
|
+
import { dirname as dirname2, join as join5 } from "node:path";
|
|
42553
42622
|
function detectEmail(dir, tool) {
|
|
42554
42623
|
if (!tool.accountFile || !tool.emailPath)
|
|
42555
42624
|
return;
|
|
42556
|
-
const candidates = [
|
|
42625
|
+
const candidates = [join5(dir, tool.accountFile)];
|
|
42557
42626
|
if (dir === tool.defaultDir)
|
|
42558
|
-
candidates.push(
|
|
42627
|
+
candidates.push(join5(dirname2(dir), tool.accountFile));
|
|
42559
42628
|
for (const file of candidates) {
|
|
42560
42629
|
const email = readEmail(file, tool.emailPath);
|
|
42561
42630
|
if (email)
|
|
@@ -42591,8 +42660,8 @@ function expandPath(p) {
|
|
|
42591
42660
|
if (out === "~")
|
|
42592
42661
|
out = homedir4();
|
|
42593
42662
|
else if (out.startsWith("~/"))
|
|
42594
|
-
out =
|
|
42595
|
-
return
|
|
42663
|
+
out = join6(homedir4(), out.slice(2));
|
|
42664
|
+
return isAbsolute2(out) ? out : resolve2(process.cwd(), out);
|
|
42596
42665
|
}
|
|
42597
42666
|
function listProfiles(toolId) {
|
|
42598
42667
|
const profiles = loadStore().profiles;
|
|
@@ -42603,8 +42672,8 @@ function profileMatches(name, toolId) {
|
|
|
42603
42672
|
return loadStore().profiles.filter((p) => p.name === name && (!toolId || p.tool === toolId));
|
|
42604
42673
|
}
|
|
42605
42674
|
function isManagedProfileDir(dir) {
|
|
42606
|
-
const rel =
|
|
42607
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
42675
|
+
const rel = relative2(resolve2(profilesDir()), resolve2(dir));
|
|
42676
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
|
|
42608
42677
|
}
|
|
42609
42678
|
function getProfile(name, toolId) {
|
|
42610
42679
|
const matches = profileMatches(name, toolId);
|
|
@@ -42629,7 +42698,7 @@ function addProfile(opts) {
|
|
|
42629
42698
|
if (store.profiles.some((p) => p.name === name && p.tool === toolId)) {
|
|
42630
42699
|
throw new AccountsError(`a ${toolId} profile named "${name}" already exists`);
|
|
42631
42700
|
}
|
|
42632
|
-
const dir = opts.dir ? expandPath(opts.dir) :
|
|
42701
|
+
const dir = opts.dir ? expandPath(opts.dir) : join6(profilesDir(), toolId, name);
|
|
42633
42702
|
if (store.profiles.some((p) => p.dir === dir)) {
|
|
42634
42703
|
throw new AccountsError(`a profile already uses config dir ${dir}`);
|
|
42635
42704
|
}
|
|
@@ -42771,11 +42840,11 @@ function currentProfile(toolId) {
|
|
|
42771
42840
|
|
|
42772
42841
|
// src/lib/claude-auth.ts
|
|
42773
42842
|
import { copyFileSync, existsSync as existsSync6, lstatSync as lstatSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync3, statSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
42774
|
-
import { dirname as dirname4, join as
|
|
42843
|
+
import { dirname as dirname4, join as join8 } from "node:path";
|
|
42775
42844
|
|
|
42776
42845
|
// src/lib/claude-layout.ts
|
|
42777
42846
|
import { homedir as homedir5 } from "node:os";
|
|
42778
|
-
import { dirname as dirname3, join as
|
|
42847
|
+
import { dirname as dirname3, join as join7 } from "node:path";
|
|
42779
42848
|
var CLAUDE_KEYCHAIN_SERVICE = "Claude Code-credentials";
|
|
42780
42849
|
var ACCOUNTS_AUTH_DIR = ".accounts-auth";
|
|
42781
42850
|
var OAUTH_SNAPSHOT = "oauth-account.json";
|
|
@@ -42787,32 +42856,32 @@ function liveClaudeBase() {
|
|
|
42787
42856
|
}
|
|
42788
42857
|
function liveClaudePaths() {
|
|
42789
42858
|
const base = liveClaudeBase();
|
|
42790
|
-
const configDir =
|
|
42859
|
+
const configDir = join7(base, ".claude");
|
|
42791
42860
|
return {
|
|
42792
42861
|
configDir,
|
|
42793
|
-
homeJson:
|
|
42794
|
-
credentialsFile:
|
|
42862
|
+
homeJson: join7(base, ".claude.json"),
|
|
42863
|
+
credentialsFile: join7(configDir, ".credentials.json")
|
|
42795
42864
|
};
|
|
42796
42865
|
}
|
|
42797
42866
|
function profileAccountJsonPaths(profileDir, tool) {
|
|
42798
42867
|
if (!tool.accountFile)
|
|
42799
42868
|
return [];
|
|
42800
|
-
const paths = [
|
|
42869
|
+
const paths = [join7(profileDir, tool.accountFile)];
|
|
42801
42870
|
if (profileDir === tool.defaultDir)
|
|
42802
|
-
paths.push(
|
|
42871
|
+
paths.push(join7(dirname3(profileDir), tool.accountFile));
|
|
42803
42872
|
return paths;
|
|
42804
42873
|
}
|
|
42805
42874
|
function profileAuthDir(profileDir) {
|
|
42806
|
-
return
|
|
42875
|
+
return join7(profileDir, ACCOUNTS_AUTH_DIR);
|
|
42807
42876
|
}
|
|
42808
42877
|
function profileOAuthSnapshot(profileDir) {
|
|
42809
|
-
return
|
|
42878
|
+
return join7(profileAuthDir(profileDir), OAUTH_SNAPSHOT);
|
|
42810
42879
|
}
|
|
42811
42880
|
function profileCredentialsSnapshot(profileDir) {
|
|
42812
|
-
return
|
|
42881
|
+
return join7(profileAuthDir(profileDir), CREDENTIALS_SNAPSHOT);
|
|
42813
42882
|
}
|
|
42814
42883
|
function profileKeychainSnapshot(profileDir) {
|
|
42815
|
-
return
|
|
42884
|
+
return join7(profileAuthDir(profileDir), KEYCHAIN_SNAPSHOT);
|
|
42816
42885
|
}
|
|
42817
42886
|
|
|
42818
42887
|
// src/lib/keychain.ts
|
|
@@ -42966,7 +43035,7 @@ function mergeOAuthInto(paths, oauth, allowDelete, stayUnder) {
|
|
|
42966
43035
|
}
|
|
42967
43036
|
}
|
|
42968
43037
|
function sanitizeSettingsFile(configDir, stayUnder) {
|
|
42969
|
-
const settingsPath =
|
|
43038
|
+
const settingsPath = join8(configDir, "settings.json");
|
|
42970
43039
|
const settings = readJsonFile(settingsPath);
|
|
42971
43040
|
if (!settings)
|
|
42972
43041
|
return false;
|
|
@@ -43013,7 +43082,7 @@ function liveOAuthEmail() {
|
|
|
43013
43082
|
}
|
|
43014
43083
|
function snapshotLiveAuthToProfile(profileDir, _tool) {
|
|
43015
43084
|
const authDir = profileAuthDir(profileDir);
|
|
43016
|
-
assertSafeWritePath(
|
|
43085
|
+
assertSafeWritePath(join8(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
|
|
43017
43086
|
mkdirSync4(authDir, { recursive: true });
|
|
43018
43087
|
const live = liveClaudePaths();
|
|
43019
43088
|
const oauth = readOAuthFromPaths([live.homeJson]);
|
|
@@ -43032,14 +43101,14 @@ function snapshotLiveAuthToProfile(profileDir, _tool) {
|
|
|
43032
43101
|
}
|
|
43033
43102
|
function ensureProfileAuthSnapshot(profileDir, tool, opts = {}) {
|
|
43034
43103
|
const authDir = profileAuthDir(profileDir);
|
|
43035
|
-
assertSafeWritePath(
|
|
43104
|
+
assertSafeWritePath(join8(authDir, OAUTH_SNAPSHOT), { mustStayUnder: profileDir });
|
|
43036
43105
|
mkdirSync4(authDir, { recursive: true });
|
|
43037
43106
|
const oauthSource = findOAuthSource(profileAccountJsonPaths(profileDir, tool));
|
|
43038
43107
|
const oauthSnap = profileOAuthSnapshot(profileDir);
|
|
43039
43108
|
if (oauthSource && (opts.overwrite || snapshotIsStale(oauthSource.path, oauthSnap))) {
|
|
43040
43109
|
writeJsonFile(oauthSnap, { oauthAccount: oauthSource.oauth }, profileDir);
|
|
43041
43110
|
}
|
|
43042
|
-
const credFile =
|
|
43111
|
+
const credFile = join8(profileDir, ".credentials.json");
|
|
43043
43112
|
const credSnap = profileCredentialsSnapshot(profileDir);
|
|
43044
43113
|
if (existsSync6(credFile) && (opts.overwrite || snapshotIsStale(credFile, credSnap))) {
|
|
43045
43114
|
assertSafeWritePath(credSnap, { mustStayUnder: profileDir });
|
|
@@ -43101,9 +43170,9 @@ function hasAuthSnapshot(profileDir) {
|
|
|
43101
43170
|
|
|
43102
43171
|
// src/lib/apply-lock.ts
|
|
43103
43172
|
import { closeSync, existsSync as existsSync7, mkdirSync as mkdirSync5, openSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
43104
|
-
import { join as
|
|
43173
|
+
import { join as join9 } from "node:path";
|
|
43105
43174
|
function lockPath() {
|
|
43106
|
-
return
|
|
43175
|
+
return join9(accountsHome(), ".apply.lock");
|
|
43107
43176
|
}
|
|
43108
43177
|
function withApplyLock(fn) {
|
|
43109
43178
|
const home = accountsHome();
|
|
@@ -43352,7 +43421,7 @@ function listAgentsAcrossProfiles(opts = {}) {
|
|
|
43352
43421
|
|
|
43353
43422
|
// src/lib/import-profile.ts
|
|
43354
43423
|
import { cpSync, existsSync as existsSync9 } from "node:fs";
|
|
43355
|
-
import { join as
|
|
43424
|
+
import { join as join10 } from "node:path";
|
|
43356
43425
|
function importProfile(opts) {
|
|
43357
43426
|
const toolId = opts.tool ?? DEFAULT_TOOL;
|
|
43358
43427
|
const tool = getTool(toolId);
|
|
@@ -43362,7 +43431,7 @@ function importProfile(opts) {
|
|
|
43362
43431
|
throw new AccountsError(`config dir does not exist: ${sourceDir}`);
|
|
43363
43432
|
}
|
|
43364
43433
|
if (opts.copy) {
|
|
43365
|
-
const targetDir =
|
|
43434
|
+
const targetDir = join10(profilesDir(), toolId, name);
|
|
43366
43435
|
if (existsSync9(targetDir)) {
|
|
43367
43436
|
throw new AccountsError(`managed copy target already exists: ${targetDir}`);
|
|
43368
43437
|
}
|
|
@@ -43448,7 +43517,7 @@ async function pickProfile(opts = {}) {
|
|
|
43448
43517
|
|
|
43449
43518
|
// src/lib/hook.ts
|
|
43450
43519
|
import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
43451
|
-
import { join as
|
|
43520
|
+
import { join as join11 } from "node:path";
|
|
43452
43521
|
var HOOK_FILE = "claude-hook.sh";
|
|
43453
43522
|
var MARKER = "# accounts-claude-hook";
|
|
43454
43523
|
var NAME_PATTERN = "^[a-z0-9][a-z0-9-]*$";
|
|
@@ -43456,7 +43525,7 @@ function shellQuotePath(path) {
|
|
|
43456
43525
|
return `'${path.replace(/'/g, `'\\''`)}'`;
|
|
43457
43526
|
}
|
|
43458
43527
|
function hookPath() {
|
|
43459
|
-
return
|
|
43528
|
+
return join11(accountsHome(), HOOK_FILE);
|
|
43460
43529
|
}
|
|
43461
43530
|
function hookScript() {
|
|
43462
43531
|
const quotedHook = shellQuotePath(hookPath());
|
|
@@ -43507,7 +43576,7 @@ function shellSnippet() {
|
|
|
43507
43576
|
|
|
43508
43577
|
// src/lib/codex-app.ts
|
|
43509
43578
|
import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
43510
|
-
import { join as
|
|
43579
|
+
import { join as join12 } from "node:path";
|
|
43511
43580
|
var FILE_CREDENTIALS_LINE = 'cli_auth_credentials_store = "file"';
|
|
43512
43581
|
function insertRootConfigLine(config, line) {
|
|
43513
43582
|
if (config.trim() === "")
|
|
@@ -43534,7 +43603,7 @@ ${after}${after.endsWith(`
|
|
|
43534
43603
|
}
|
|
43535
43604
|
function ensureCodexAppProfileConfig(profileDir) {
|
|
43536
43605
|
mkdirSync7(profileDir, { recursive: true });
|
|
43537
|
-
const configPath =
|
|
43606
|
+
const configPath = join12(profileDir, "config.toml");
|
|
43538
43607
|
const current = existsSync11(configPath) ? readFileSync6(configPath, "utf8") : "";
|
|
43539
43608
|
if (/^\s*cli_auth_credentials_store\s*=/.test(current))
|
|
43540
43609
|
return;
|
|
@@ -43634,20 +43703,20 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
43634
43703
|
import { createHash } from "node:crypto";
|
|
43635
43704
|
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync7, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
43636
43705
|
import { createConnection, createServer } from "node:net";
|
|
43637
|
-
import { basename, join as
|
|
43706
|
+
import { basename, join as join13 } from "node:path";
|
|
43638
43707
|
var STATE_SUFFIX = ".json";
|
|
43639
43708
|
function supervisorDir() {
|
|
43640
|
-
return
|
|
43709
|
+
return join13(accountsHome(), "supervisors");
|
|
43641
43710
|
}
|
|
43642
43711
|
function supervisorStatePath(toolId) {
|
|
43643
|
-
return
|
|
43712
|
+
return join13(supervisorDir(), `${toolId}${STATE_SUFFIX}`);
|
|
43644
43713
|
}
|
|
43645
43714
|
function supervisorSocketPath(toolId) {
|
|
43646
43715
|
if (process.platform === "win32") {
|
|
43647
43716
|
const hash = createHash("sha1").update(accountsHome()).digest("hex").slice(0, 12);
|
|
43648
43717
|
return `\\\\.\\pipe\\hasna-accounts-${hash}-${toolId}`;
|
|
43649
43718
|
}
|
|
43650
|
-
return
|
|
43719
|
+
return join13(supervisorDir(), `${toolId}.sock`);
|
|
43651
43720
|
}
|
|
43652
43721
|
function nowIso2() {
|
|
43653
43722
|
return new Date().toISOString();
|
|
@@ -44245,7 +44314,7 @@ program2.command("switch").argument("<name>", "profile name").argument("[args...
|
|
|
44245
44314
|
}
|
|
44246
44315
|
}));
|
|
44247
44316
|
var hook = program2.command("hook").description("install a shell wrapper for claude");
|
|
44248
|
-
hook.command("install").description(`write ${
|
|
44317
|
+
hook.command("install").description(`write ${join14(accountsHome(), "claude-hook.sh")}`).action(action(() => {
|
|
44249
44318
|
const { path, created } = installHook();
|
|
44250
44319
|
console.log(source_default.green(created ? `✓ installed hook at ${path}` : `✓ updated hook at ${path}`));
|
|
44251
44320
|
console.log(source_default.dim(` add to ~/.zshrc: ${shellSnippet()}`));
|
|
@@ -44485,7 +44554,7 @@ tools.command("add").argument("<id>", "tool id, e.g. cursor").description("regis
|
|
|
44485
44554
|
label: opts.label,
|
|
44486
44555
|
envVar: opts.envVar,
|
|
44487
44556
|
bin: opts.bin,
|
|
44488
|
-
defaultDir: opts.defaultDir ? expandPath(opts.defaultDir) :
|
|
44557
|
+
defaultDir: opts.defaultDir ? expandPath(opts.defaultDir) : join14(homedir6(), `.${id}`),
|
|
44489
44558
|
...Object.keys(extraEnv).length > 0 ? { extraEnv } : {},
|
|
44490
44559
|
...opts.loginArg ? { loginArgs: opts.loginArg } : {},
|
|
44491
44560
|
...opts.launchArg ? { launchArgs: opts.launchArg } : {},
|
|
@@ -44557,7 +44626,7 @@ program2.parseAsync(process.argv);
|
|
|
44557
44626
|
function getVersion() {
|
|
44558
44627
|
try {
|
|
44559
44628
|
const here = dirname5(fileURLToPath(import.meta.url));
|
|
44560
|
-
for (const candidate of [
|
|
44629
|
+
for (const candidate of [join14(here, "..", "package.json"), join14(here, "package.json")]) {
|
|
44561
44630
|
if (existsSync13(candidate)) {
|
|
44562
44631
|
const pkg = JSON.parse(readFileSync8(candidate, "utf8"));
|
|
44563
44632
|
if (pkg.version)
|