@vibe-lark/larkpal 0.1.85 → 0.1.86
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/account-id-BM1T6029-DYjVxojW.mjs +46 -0
- package/dist/activation-context--5yu1dPF-Bwsn3moT.mjs +172 -0
- package/dist/anthropic-TH8ERTXK.mjs +5962 -0
- package/dist/assistant-visible-text-DuFWokAt-CsbII5KS.mjs +596 -0
- package/dist/azure-openai-responses-Bt_Ag9Er.mjs +166 -0
- package/dist/boundary-file-read-BSd9MXPy--KThL5e6.mjs +594 -0
- package/dist/browser-lifecycle-cleanup-BdNsMhMD-O3tnAM4i.mjs +60 -0
- package/dist/build-DgTrEpge.mjs +3333 -0
- package/dist/bundled-compat-BpaDaAAu-D7oazKjD.mjs +5216 -0
- package/dist/bundled-dir-U738ay4K-DXK0q_TV.mjs +258 -0
- package/dist/call-DimWbpgJ-ColD4W-y.mjs +9993 -0
- package/dist/channel-bootstrap.runtime-BVclcGv1-DJv_Z-Kr.mjs +2 -0
- package/dist/channel-bootstrap.runtime-Cwcr38m2-VRfVCR-i.mjs +33 -0
- package/dist/chunk-D6SyT4dJ.mjs +36 -0
- package/dist/cli.mjs +6 -6
- package/dist/command-format-LSnUCVVF-BQ2SMKka.mjs +685 -0
- package/dist/config-Bim2pi8a-BQUdfiEi.mjs +9 -0
- package/dist/delivery-context.shared-j5hC5qb1-CI83RXXZ.mjs +72 -0
- package/dist/diagnostic-ClMwNnUA-D6nUtLnb.mjs +140 -0
- package/dist/dist-CEGw8-2W.mjs +429 -0
- package/dist/dist-DD2aJ2UL.mjs +125135 -0
- package/dist/env-api-keys-BVvSg7T2.mjs +68 -0
- package/dist/event-stream-xaQWmyas.mjs +15226 -0
- package/dist/facade-loader-DFzIYYt_-CIr4HKtE.mjs +194 -0
- package/dist/from-DF7cl2wz.mjs +3842 -0
- package/dist/gateway-method-policy-C7rf0SeV-CJQMEYIE.mjs +28 -0
- package/dist/github-copilot-headers-DjqWtUoP.mjs +22 -0
- package/dist/google-C2pVrgBZ.mjs +336 -0
- package/dist/google-gemini-cli-BBxgS5Ho.mjs +623 -0
- package/dist/google-shared-BsWgwEk1.mjs +22791 -0
- package/dist/google-vertex-BsVLJrrC.mjs +358 -0
- package/dist/hash-DAFtW_W7.mjs +16 -0
- package/dist/headers-R3HdCbAE.mjs +8 -0
- package/dist/home-dir-C44RaPME-CBRS4HLP.mjs +93 -0
- package/dist/ids-BPsM98Uu-CwuxvUai.mjs +77 -0
- package/dist/image-2w3cApg7-CxpHvoB5.mjs +207 -0
- package/dist/io-CH2g3vsv-BOGlLlB8.mjs +26218 -0
- package/dist/jiti-loader-cache-Bat69wam-D6hCxboy.mjs +5049 -0
- package/dist/json-file-BQRNuxmK-DhJM5NsG.mjs +108 -0
- package/dist/json-parse-v_HIJjjI.mjs +381 -0
- package/dist/jws-GFcTvvVT.mjs +2291 -0
- package/dist/{lark-cli-provider-7LvtOIF_.mjs → lark-cli-provider-BARgbbmo.mjs} +1 -1
- package/dist/{live-smoke-nvTUPtrv.mjs → live-smoke-BhkBOcH9.mjs} +3 -3
- package/dist/load-context-mb7uvLSn-B10MAi3I.mjs +29 -0
- package/dist/loader-708jrx4Y-BOswuvpe.mjs +5053 -0
- package/dist/main.mjs +56550 -205
- package/dist/manifest-registry-_hxKCS2K-CZdeyN0f.mjs +3512 -0
- package/dist/mcp-server.mjs +1 -1
- package/dist/message-channel-Bk_YHfQg-AeNrPPpp.mjs +50 -0
- package/dist/message-channel-core-DTA--Gjh-CY4Tkb7N.mjs +29 -0
- package/dist/message.config.runtime-K-k4XOyq-DZTmXomP.mjs +2 -0
- package/dist/message.gateway.runtime-DqHOHRTQ-DH4ml0YF.mjs +2 -0
- package/dist/mistral-CaR4DiLu.mjs +28657 -0
- package/dist/model-auth-env-oyg2Hexc-DU_rOUU5.mjs +1306 -0
- package/dist/models-config-BmpSQJQF-Gfvh1n3A.mjs +1282 -0
- package/dist/models-config.runtime-BsU_22xk.mjs +2 -0
- package/dist/multipart-parser-DedmaB5g.mjs +294 -0
- package/dist/oauth-DOJeGfcE.mjs +6392 -0
- package/dist/openai-BDtIh3Ja.mjs +6693 -0
- package/dist/openai-codex-responses-C5EORu31.mjs +664 -0
- package/dist/openai-completions-CR_cS6gX.mjs +669 -0
- package/dist/openai-responses-oGxwZyuC.mjs +184 -0
- package/dist/openai-responses-shared-BixMSDZE.mjs +398 -0
- package/dist/paths-D6msg0S1-C2lYuisN.mjs +189 -0
- package/dist/paths-D92DjaZ--CTOESW2b.mjs +192 -0
- package/dist/pi-model-discovery-Bd0TWzo8-BFsJmeMb.mjs +227 -0
- package/dist/pi-model-discovery-runtime-CCCZxkd8.mjs +2 -0
- package/dist/pi-tools.before-tool-call.runtime-Bn7uqKie-C5ewk8kK.mjs +399 -0
- package/dist/plugin-auto-enable-DdH3n9V8-DsA1isaF.mjs +1456 -0
- package/dist/process-scoped-map-B2cWkYET-CXwUZ8CZ.mjs +61 -0
- package/dist/provider-discovery.runtime-BPzz1PFj.mjs +58 -0
- package/dist/provider-model-compat-CFqcq0it-BDDuBI3A.mjs +118 -0
- package/dist/provider-runtime-C8rljsNs-CIT93zoy.mjs +2 -0
- package/dist/provider-runtime-CT50mNIX-BwEV6GyO.mjs +573 -0
- package/dist/provider-stream-COLujAAo-CbJPDngm.mjs +35449 -0
- package/dist/providers.runtime-Ba7tOlq7-CXkhkzU9.mjs +219 -0
- package/dist/public-surface-loader-BVl0NQAE-C0piXtsT.mjs +117 -0
- package/dist/resolve-C33B7eeu-BNvYTl6k.mjs +1041 -0
- package/dist/runtime-Cym-fqI8-DaSDMH-a.mjs +120 -0
- package/dist/runtime-channel-state-CohMybAh-hXR6y5Gx.mjs +19 -0
- package/dist/runtime-snapshot-C54O1-gI-40cbyi7P.mjs +677 -0
- package/dist/runtime-state-IBOIXKOx-Bf9tcLvc.mjs +10 -0
- package/dist/runtime-web-tools-fallback.runtime-Ca-qn1mj-BCVImm7a.mjs +39 -0
- package/dist/runtime-web-tools-manifest.runtime-BgxQTjmq-Cb4nJkRT.mjs +2 -0
- package/dist/runtime-web-tools-public-artifacts.runtime-D9qcoWIX-BrQdXzOQ.mjs +2 -0
- package/dist/session-archive.runtime-B52_5vs4-BG-_IwNJ.mjs +2 -0
- package/dist/session-key-Cn2QoOyX-CuHbJMgR.mjs +82 -0
- package/dist/session-transcript-files.fs-DEeFXruQ-B1PF6nLy.mjs +147 -0
- package/dist/src-BgCX0MLG.mjs +813 -0
- package/dist/src-DYbqlAqf.mjs +1177 -0
- package/dist/subagent-announce-L5WsQatW-CQWI9GMd.mjs +344 -0
- package/dist/subagent-announce.registry.runtime-DiqZyeTs-BKuniyi3.mjs +28 -0
- package/dist/subagent-registry-steer-runtime-DFgZFC0j-BhBz0roy.mjs +211 -0
- package/dist/subagent-system-prompt-C1qnN--K-DpnTFP47.mjs +3061 -0
- package/dist/target-parsing-loaded-DKkb6jJY-BMD4CkpS.mjs +1002 -0
- package/dist/task-registry-delivery-runtime-Dd1CUkZF-C8U40a3O.mjs +2950 -0
- package/dist/task-registry-delivery-runtime-ragbeVx5-CNbFAkjD.mjs +2 -0
- package/dist/thinking-Bh-7MqXz-D3woGbO7.mjs +2 -0
- package/dist/transcript-E_-ISOkD-DWCfZP2p.mjs +2019 -0
- package/dist/transcript.runtime-BqhvZZdl-BPy42vBP.mjs +2 -0
- package/dist/transform-messages-DbhIzTxq.mjs +207 -0
- package/dist/web-provider-public-artifacts-BlpRwIUS-CGPSV4W2.mjs +295 -0
- package/dist/web-search-providers.runtime--0aUtC3b-DyuhC95V.mjs +200 -0
- package/package.json +3 -3
- package/dist/rolldown-runtime-wcPFST8Q.mjs +0 -13
- /package/dist/{interactive-init-B6j8j_Ap.mjs → interactive-init-BXQBalNr.mjs} +0 -0
|
@@ -0,0 +1,1306 @@
|
|
|
1
|
+
import { c as normalizeOptionalString } from "./home-dir-C44RaPME-CBRS4HLP.mjs";
|
|
2
|
+
import { a as resolveOAuthPath, o as resolveStateDir } from "./paths-D92DjaZ--CTOESW2b.mjs";
|
|
3
|
+
import { l as resolveUserPath } from "./bundled-dir-U738ay4K-DXK0q_TV.mjs";
|
|
4
|
+
import { c as resolveProviderIdForAuth, o as listKnownProviderAuthEnvVarNames, s as resolveProviderAuthEnvVarCandidates, t as getShellEnvAppliedKeys } from "./io-CH2g3vsv-BOGlLlB8.mjs";
|
|
5
|
+
import { St as createSubsystemLogger, bt as normalizeSecretInputString, l as normalizeProviderId, vt as coerceSecretRef } from "./bundled-compat-BpaDaAAu-D7oazKjD.mjs";
|
|
6
|
+
import { o as loadPluginManifestRegistry } from "./manifest-registry-_hxKCS2K-CZdeyN0f.mjs";
|
|
7
|
+
import { t as DEFAULT_AGENT_ID } from "./session-key-Cn2QoOyX-CuHbJMgR.mjs";
|
|
8
|
+
import { r as isPidAlive, t as resolveProcessScopedMap } from "./process-scoped-map-B2cWkYET-CXwUZ8CZ.mjs";
|
|
9
|
+
import { n as saveJsonFile, t as loadJsonFile } from "./json-file-BQRNuxmK-DhJM5NsG.mjs";
|
|
10
|
+
import { p as resolvePluginSetupProvider } from "./plugin-auto-enable-DdH3n9V8-DsA1isaF.mjs";
|
|
11
|
+
import { E as resolveExternalAuthProfilesWithPlugins } from "./provider-runtime-CT50mNIX-BwEV6GyO.mjs";
|
|
12
|
+
import fs from "node:fs";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import fs$1 from "node:fs/promises";
|
|
15
|
+
import os from "node:os";
|
|
16
|
+
import "node:child_process";
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/file-lock-7-B8nAS7.js
|
|
19
|
+
const HELD_LOCKS = resolveProcessScopedMap(Symbol.for("openclaw.fileLockHeldLocks"));
|
|
20
|
+
const CLEANUP_REGISTERED_KEY = Symbol.for("openclaw.fileLockCleanupRegistered");
|
|
21
|
+
function releaseAllLocksSync() {
|
|
22
|
+
for (const [normalizedFile, held] of HELD_LOCKS) {
|
|
23
|
+
held.handle.close().catch(() => void 0);
|
|
24
|
+
rmLockPathSync(held.lockPath);
|
|
25
|
+
HELD_LOCKS.delete(normalizedFile);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function rmLockPathSync(lockPath) {
|
|
29
|
+
try {
|
|
30
|
+
fs.rmSync(lockPath, { force: true });
|
|
31
|
+
} catch {}
|
|
32
|
+
}
|
|
33
|
+
function ensureExitCleanupRegistered() {
|
|
34
|
+
const proc = process;
|
|
35
|
+
if (proc[CLEANUP_REGISTERED_KEY]) return;
|
|
36
|
+
proc[CLEANUP_REGISTERED_KEY] = true;
|
|
37
|
+
process.on("exit", releaseAllLocksSync);
|
|
38
|
+
}
|
|
39
|
+
function computeDelayMs(retries, attempt) {
|
|
40
|
+
const base = Math.min(retries.maxTimeout, Math.max(retries.minTimeout, retries.minTimeout * retries.factor ** attempt));
|
|
41
|
+
const jitter = retries.randomize ? 1 + Math.random() : 1;
|
|
42
|
+
return Math.min(retries.maxTimeout, Math.round(base * jitter));
|
|
43
|
+
}
|
|
44
|
+
async function readLockPayload(lockPath) {
|
|
45
|
+
try {
|
|
46
|
+
const raw = await fs$1.readFile(lockPath, "utf8");
|
|
47
|
+
const parsed = JSON.parse(raw);
|
|
48
|
+
if (typeof parsed.pid !== "number" || typeof parsed.createdAt !== "string") return null;
|
|
49
|
+
return {
|
|
50
|
+
pid: parsed.pid,
|
|
51
|
+
createdAt: parsed.createdAt
|
|
52
|
+
};
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function resolveNormalizedFilePath(filePath) {
|
|
58
|
+
const resolved = path.resolve(filePath);
|
|
59
|
+
const dir = path.dirname(resolved);
|
|
60
|
+
await fs$1.mkdir(dir, { recursive: true });
|
|
61
|
+
try {
|
|
62
|
+
const realDir = await fs$1.realpath(dir);
|
|
63
|
+
return path.join(realDir, path.basename(resolved));
|
|
64
|
+
} catch {
|
|
65
|
+
return resolved;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function isStaleLock(lockPath, staleMs) {
|
|
69
|
+
const payload = await readLockPayload(lockPath);
|
|
70
|
+
if (payload?.pid && !isPidAlive(payload.pid)) return true;
|
|
71
|
+
if (payload?.createdAt) {
|
|
72
|
+
const createdAt = Date.parse(payload.createdAt);
|
|
73
|
+
if (!Number.isFinite(createdAt) || Date.now() - createdAt > staleMs) return true;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const stat = await fs$1.stat(lockPath);
|
|
77
|
+
return Date.now() - stat.mtimeMs > staleMs;
|
|
78
|
+
} catch {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const FILE_LOCK_TIMEOUT_ERROR_CODE = "file_lock_timeout";
|
|
83
|
+
function createFileLockTimeoutError(normalizedFile, lockPath) {
|
|
84
|
+
const error = /* @__PURE__ */ new Error(`file lock timeout for ${normalizedFile}`);
|
|
85
|
+
return Object.assign(error, {
|
|
86
|
+
code: FILE_LOCK_TIMEOUT_ERROR_CODE,
|
|
87
|
+
lockPath
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async function releaseHeldLock(normalizedFile) {
|
|
91
|
+
const current = HELD_LOCKS.get(normalizedFile);
|
|
92
|
+
if (!current) return;
|
|
93
|
+
current.count -= 1;
|
|
94
|
+
if (current.count > 0) return;
|
|
95
|
+
HELD_LOCKS.delete(normalizedFile);
|
|
96
|
+
await current.handle.close().catch(() => void 0);
|
|
97
|
+
await fs$1.rm(current.lockPath, { force: true }).catch(() => void 0);
|
|
98
|
+
}
|
|
99
|
+
/** Acquire a re-entrant process-local file lock backed by a `.lock` sidecar file. */
|
|
100
|
+
async function acquireFileLock(filePath, options) {
|
|
101
|
+
ensureExitCleanupRegistered();
|
|
102
|
+
const normalizedFile = await resolveNormalizedFilePath(filePath);
|
|
103
|
+
const lockPath = `${normalizedFile}.lock`;
|
|
104
|
+
const held = HELD_LOCKS.get(normalizedFile);
|
|
105
|
+
if (held) {
|
|
106
|
+
held.count += 1;
|
|
107
|
+
return {
|
|
108
|
+
lockPath,
|
|
109
|
+
release: () => releaseHeldLock(normalizedFile)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
for (let attempt = 0; attempt <= options.retries.retries; attempt += 1) try {
|
|
113
|
+
const handle = await fs$1.open(lockPath, "wx");
|
|
114
|
+
await handle.writeFile(JSON.stringify({
|
|
115
|
+
pid: process.pid,
|
|
116
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
117
|
+
}, null, 2), "utf8");
|
|
118
|
+
HELD_LOCKS.set(normalizedFile, {
|
|
119
|
+
count: 1,
|
|
120
|
+
handle,
|
|
121
|
+
lockPath
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
lockPath,
|
|
125
|
+
release: () => releaseHeldLock(normalizedFile)
|
|
126
|
+
};
|
|
127
|
+
} catch (err) {
|
|
128
|
+
if (err.code !== "EEXIST") throw err;
|
|
129
|
+
if (await isStaleLock(lockPath, options.stale)) {
|
|
130
|
+
await fs$1.rm(lockPath, { force: true }).catch(() => void 0);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (attempt >= options.retries.retries) break;
|
|
134
|
+
await new Promise((resolve) => setTimeout(resolve, computeDelayMs(options.retries, attempt)));
|
|
135
|
+
}
|
|
136
|
+
throw createFileLockTimeoutError(normalizedFile, lockPath);
|
|
137
|
+
}
|
|
138
|
+
/** Run an async callback while holding a file lock, always releasing the lock afterward. */
|
|
139
|
+
async function withFileLock(filePath, options, fn) {
|
|
140
|
+
const lock = await acquireFileLock(filePath, options);
|
|
141
|
+
try {
|
|
142
|
+
return await fn();
|
|
143
|
+
} finally {
|
|
144
|
+
await lock.release();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/agent-paths-yYk0N-bh.js
|
|
149
|
+
function resolveOpenClawAgentDir(env = process.env) {
|
|
150
|
+
const override = env.OPENCLAW_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim();
|
|
151
|
+
if (override) return resolveUserPath(override, env);
|
|
152
|
+
return resolveUserPath(path.join(resolveStateDir(env), "agents", DEFAULT_AGENT_ID, "agent"), env);
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/source-check-80U6FTE-.js
|
|
156
|
+
const AUTH_PROFILE_FILENAME = "auth-profiles.json";
|
|
157
|
+
const AUTH_STATE_FILENAME = "auth-state.json";
|
|
158
|
+
const LEGACY_AUTH_FILENAME = "auth.json";
|
|
159
|
+
function resolveAuthStorePath(agentDir) {
|
|
160
|
+
const resolved = resolveUserPath(agentDir ?? resolveOpenClawAgentDir());
|
|
161
|
+
return path.join(resolved, AUTH_PROFILE_FILENAME);
|
|
162
|
+
}
|
|
163
|
+
function resolveLegacyAuthStorePath(agentDir) {
|
|
164
|
+
const resolved = resolveUserPath(agentDir ?? resolveOpenClawAgentDir());
|
|
165
|
+
return path.join(resolved, LEGACY_AUTH_FILENAME);
|
|
166
|
+
}
|
|
167
|
+
function resolveAuthStatePath(agentDir) {
|
|
168
|
+
const resolved = resolveUserPath(agentDir ?? resolveOpenClawAgentDir());
|
|
169
|
+
return path.join(resolved, AUTH_STATE_FILENAME);
|
|
170
|
+
}
|
|
171
|
+
function resolveAuthStorePathForDisplay(agentDir) {
|
|
172
|
+
const pathname = resolveAuthStorePath(agentDir);
|
|
173
|
+
return pathname.startsWith("~") ? pathname : resolveUserPath(pathname);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Resolve the path of the cross-agent, per-profile OAuth refresh coordination
|
|
177
|
+
* lock. The filename hashes `provider\0profileId` so it is filesystem-safe
|
|
178
|
+
* for arbitrary unicode/control-character inputs and always bounded in
|
|
179
|
+
* length. The NUL separator makes it impossible to collide two distinct
|
|
180
|
+
* `(provider, profileId)` pairs by string concatenation.
|
|
181
|
+
*
|
|
182
|
+
* This lock is the serialization point that prevents the `refresh_token_reused`
|
|
183
|
+
* storm when N agents share one OAuth profile (see issue #26322): every agent
|
|
184
|
+
* that attempts a refresh acquires this same file lock, so only one HTTP
|
|
185
|
+
* refresh is in-flight at a time and peers can adopt the resulting fresh
|
|
186
|
+
* credentials instead of racing against a single-use refresh token.
|
|
187
|
+
*
|
|
188
|
+
* The key intentionally includes `provider` so that two profiles that
|
|
189
|
+
* happen to share a `profileId` across providers (operator-renamed profile,
|
|
190
|
+
* test fixture, etc.) do not needlessly serialize against each other.
|
|
191
|
+
*/
|
|
192
|
+
function resolveOAuthRefreshLockPath(provider, profileId) {
|
|
193
|
+
const hash = createHash("sha256");
|
|
194
|
+
hash.update(provider, "utf8");
|
|
195
|
+
hash.update("\0", "utf8");
|
|
196
|
+
hash.update(profileId, "utf8");
|
|
197
|
+
const safeId = `sha256-${hash.digest("hex")}`;
|
|
198
|
+
return path.join(resolveStateDir(), "locks", "oauth-refresh", safeId);
|
|
199
|
+
}
|
|
200
|
+
const runtimeAuthStoreSnapshots = /* @__PURE__ */ new Map();
|
|
201
|
+
function resolveRuntimeStoreKey(agentDir) {
|
|
202
|
+
return resolveAuthStorePath(agentDir);
|
|
203
|
+
}
|
|
204
|
+
function cloneAuthProfileStore$1(store) {
|
|
205
|
+
return structuredClone(store);
|
|
206
|
+
}
|
|
207
|
+
function getRuntimeAuthProfileStoreSnapshot(agentDir) {
|
|
208
|
+
const store = runtimeAuthStoreSnapshots.get(resolveRuntimeStoreKey(agentDir));
|
|
209
|
+
return store ? cloneAuthProfileStore$1(store) : void 0;
|
|
210
|
+
}
|
|
211
|
+
function hasRuntimeAuthProfileStoreSnapshot(agentDir) {
|
|
212
|
+
return runtimeAuthStoreSnapshots.has(resolveRuntimeStoreKey(agentDir));
|
|
213
|
+
}
|
|
214
|
+
function setRuntimeAuthProfileStoreSnapshot(store, agentDir) {
|
|
215
|
+
runtimeAuthStoreSnapshots.set(resolveRuntimeStoreKey(agentDir), cloneAuthProfileStore$1(store));
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/store-DvC8xs3S.js
|
|
219
|
+
const MINIMAX_CLI_PROFILE_ID = "minimax-portal:minimax-cli";
|
|
220
|
+
const AUTH_STORE_LOCK_OPTIONS = {
|
|
221
|
+
retries: {
|
|
222
|
+
retries: 10,
|
|
223
|
+
factor: 2,
|
|
224
|
+
minTimeout: 100,
|
|
225
|
+
maxTimeout: 1e4,
|
|
226
|
+
randomize: true
|
|
227
|
+
},
|
|
228
|
+
stale: 3e4
|
|
229
|
+
};
|
|
230
|
+
const OAUTH_REFRESH_LOCK_OPTIONS = {
|
|
231
|
+
retries: {
|
|
232
|
+
retries: 20,
|
|
233
|
+
factor: 2,
|
|
234
|
+
minTimeout: 100,
|
|
235
|
+
maxTimeout: 1e4,
|
|
236
|
+
randomize: true
|
|
237
|
+
},
|
|
238
|
+
stale: 18e4
|
|
239
|
+
};
|
|
240
|
+
const OAUTH_REFRESH_CALL_TIMEOUT_MS = 12e4;
|
|
241
|
+
const EXTERNAL_CLI_SYNC_TTL_MS = 900 * 1e3;
|
|
242
|
+
const log$1 = createSubsystemLogger("agents/auth-profiles");
|
|
243
|
+
createSubsystemLogger("agents/auth-profiles");
|
|
244
|
+
const MINIMAX_CLI_CREDENTIALS_RELATIVE_PATH = ".minimax/oauth_creds.json";
|
|
245
|
+
let minimaxCliCache = null;
|
|
246
|
+
function resolveMiniMaxCliCredentialsPath(homeDir) {
|
|
247
|
+
const baseDir = homeDir ?? resolveUserPath("~");
|
|
248
|
+
return path.join(baseDir, MINIMAX_CLI_CREDENTIALS_RELATIVE_PATH);
|
|
249
|
+
}
|
|
250
|
+
function readFileMtimeMs(filePath) {
|
|
251
|
+
try {
|
|
252
|
+
return fs.statSync(filePath).mtimeMs;
|
|
253
|
+
} catch {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function readCachedCliCredential(options) {
|
|
258
|
+
const { ttlMs, cache, cacheKey, read, setCache, readSourceFingerprint } = options;
|
|
259
|
+
if (ttlMs <= 0) return read();
|
|
260
|
+
const now = Date.now();
|
|
261
|
+
const sourceFingerprint = readSourceFingerprint?.();
|
|
262
|
+
if (cache && cache.cacheKey === cacheKey && cache.sourceFingerprint === sourceFingerprint && now - cache.readAt < ttlMs) return cache.value;
|
|
263
|
+
const value = read();
|
|
264
|
+
const cachedSourceFingerprint = readSourceFingerprint?.();
|
|
265
|
+
if (!readSourceFingerprint || cachedSourceFingerprint === sourceFingerprint) setCache({
|
|
266
|
+
value,
|
|
267
|
+
readAt: now,
|
|
268
|
+
cacheKey,
|
|
269
|
+
sourceFingerprint: cachedSourceFingerprint
|
|
270
|
+
});
|
|
271
|
+
else setCache(null);
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
function readPortalCliOauthCredentials(credPath, provider) {
|
|
275
|
+
const raw = loadJsonFile(credPath);
|
|
276
|
+
if (!raw || typeof raw !== "object") return null;
|
|
277
|
+
const data = raw;
|
|
278
|
+
const accessToken = data.access_token;
|
|
279
|
+
const refreshToken = data.refresh_token;
|
|
280
|
+
const expiresAt = data.expiry_date;
|
|
281
|
+
if (typeof accessToken !== "string" || !accessToken) return null;
|
|
282
|
+
if (typeof refreshToken !== "string" || !refreshToken) return null;
|
|
283
|
+
if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt)) return null;
|
|
284
|
+
return {
|
|
285
|
+
type: "oauth",
|
|
286
|
+
provider,
|
|
287
|
+
access: accessToken,
|
|
288
|
+
refresh: refreshToken,
|
|
289
|
+
expires: expiresAt
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function readMiniMaxCliCredentials(options) {
|
|
293
|
+
return readPortalCliOauthCredentials(resolveMiniMaxCliCredentialsPath(options?.homeDir), "minimax-portal");
|
|
294
|
+
}
|
|
295
|
+
function readMiniMaxCliCredentialsCached(options) {
|
|
296
|
+
const credPath = resolveMiniMaxCliCredentialsPath(options?.homeDir);
|
|
297
|
+
return readCachedCliCredential({
|
|
298
|
+
ttlMs: options?.ttlMs ?? 0,
|
|
299
|
+
cache: minimaxCliCache,
|
|
300
|
+
cacheKey: credPath,
|
|
301
|
+
read: () => readMiniMaxCliCredentials({ homeDir: options?.homeDir }),
|
|
302
|
+
setCache: (next) => {
|
|
303
|
+
minimaxCliCache = next;
|
|
304
|
+
},
|
|
305
|
+
readSourceFingerprint: () => readFileMtimeMs(credPath)
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
function resolveTokenExpiryState(expires, now = Date.now(), opts) {
|
|
309
|
+
if (expires === void 0) return "missing";
|
|
310
|
+
if (typeof expires !== "number") return "invalid_expires";
|
|
311
|
+
if (!Number.isFinite(expires) || expires <= 0) return "invalid_expires";
|
|
312
|
+
const remainingMs = expires - now;
|
|
313
|
+
if (remainingMs <= 0) return "expired";
|
|
314
|
+
const expiringWithinMs = Math.max(0, opts?.expiringWithinMs ?? 0);
|
|
315
|
+
if (expiringWithinMs > 0 && remainingMs <= expiringWithinMs) return "expiring";
|
|
316
|
+
return "valid";
|
|
317
|
+
}
|
|
318
|
+
function hasUsableOAuthCredential$1(credential, opts) {
|
|
319
|
+
if (!credential || credential.type !== "oauth") return false;
|
|
320
|
+
if (typeof credential.access !== "string" || credential.access.trim().length === 0) return false;
|
|
321
|
+
const now = opts?.now ?? Date.now();
|
|
322
|
+
const refreshMarginMs = Math.max(0, opts?.refreshMarginMs ?? 3e5);
|
|
323
|
+
return resolveTokenExpiryState(credential.expires, now, { expiringWithinMs: refreshMarginMs }) === "valid";
|
|
324
|
+
}
|
|
325
|
+
function hasConfiguredSecretRef(value) {
|
|
326
|
+
return coerceSecretRef(value) !== null;
|
|
327
|
+
}
|
|
328
|
+
function hasConfiguredSecretString(value) {
|
|
329
|
+
return normalizeSecretInputString(value) !== void 0;
|
|
330
|
+
}
|
|
331
|
+
function evaluateStoredCredentialEligibility(params) {
|
|
332
|
+
const now = params.now ?? Date.now();
|
|
333
|
+
const credential = params.credential;
|
|
334
|
+
if (credential.type === "api_key") {
|
|
335
|
+
const hasKey = hasConfiguredSecretString(credential.key);
|
|
336
|
+
const hasKeyRef = hasConfiguredSecretRef(credential.keyRef);
|
|
337
|
+
if (!hasKey && !hasKeyRef) return {
|
|
338
|
+
eligible: false,
|
|
339
|
+
reasonCode: "missing_credential"
|
|
340
|
+
};
|
|
341
|
+
return {
|
|
342
|
+
eligible: true,
|
|
343
|
+
reasonCode: "ok"
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
if (credential.type === "token") {
|
|
347
|
+
const hasToken = hasConfiguredSecretString(credential.token);
|
|
348
|
+
const hasTokenRef = hasConfiguredSecretRef(credential.tokenRef);
|
|
349
|
+
if (!hasToken && !hasTokenRef) return {
|
|
350
|
+
eligible: false,
|
|
351
|
+
reasonCode: "missing_credential"
|
|
352
|
+
};
|
|
353
|
+
const expiryState = resolveTokenExpiryState(credential.expires, now);
|
|
354
|
+
if (expiryState === "invalid_expires") return {
|
|
355
|
+
eligible: false,
|
|
356
|
+
reasonCode: "invalid_expires"
|
|
357
|
+
};
|
|
358
|
+
if (expiryState === "expired") return {
|
|
359
|
+
eligible: false,
|
|
360
|
+
reasonCode: "expired"
|
|
361
|
+
};
|
|
362
|
+
return {
|
|
363
|
+
eligible: true,
|
|
364
|
+
reasonCode: "ok"
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
if (normalizeSecretInputString(credential.access) === void 0 && normalizeSecretInputString(credential.refresh) === void 0) return {
|
|
368
|
+
eligible: false,
|
|
369
|
+
reasonCode: "missing_credential"
|
|
370
|
+
};
|
|
371
|
+
return {
|
|
372
|
+
eligible: true,
|
|
373
|
+
reasonCode: "ok"
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
function areOAuthCredentialsEquivalent(a, b) {
|
|
377
|
+
if (!a || a.type !== "oauth") return false;
|
|
378
|
+
return a.provider === b.provider && a.access === b.access && a.refresh === b.refresh && a.expires === b.expires && a.email === b.email && a.enterpriseUrl === b.enterpriseUrl && a.projectId === b.projectId && a.accountId === b.accountId && a.idToken === b.idToken;
|
|
379
|
+
}
|
|
380
|
+
function hasNewerStoredOAuthCredential(existing, incoming) {
|
|
381
|
+
return Boolean(existing && existing.provider === incoming.provider && Number.isFinite(existing.expires) && (!Number.isFinite(incoming.expires) || existing.expires > incoming.expires));
|
|
382
|
+
}
|
|
383
|
+
function shouldReplaceStoredOAuthCredential(existing, incoming) {
|
|
384
|
+
if (!existing || existing.type !== "oauth") return true;
|
|
385
|
+
if (areOAuthCredentialsEquivalent(existing, incoming)) return false;
|
|
386
|
+
return !hasNewerStoredOAuthCredential(existing, incoming);
|
|
387
|
+
}
|
|
388
|
+
function hasUsableOAuthCredential(credential, now = Date.now()) {
|
|
389
|
+
return hasUsableOAuthCredential$1(credential, { now });
|
|
390
|
+
}
|
|
391
|
+
function normalizeAuthIdentityToken$1(value) {
|
|
392
|
+
const trimmed = value?.trim();
|
|
393
|
+
return trimmed ? trimmed : void 0;
|
|
394
|
+
}
|
|
395
|
+
function normalizeAuthEmailToken$1(value) {
|
|
396
|
+
return normalizeAuthIdentityToken$1(value)?.toLowerCase();
|
|
397
|
+
}
|
|
398
|
+
function hasOAuthIdentity(credential) {
|
|
399
|
+
return normalizeAuthIdentityToken$1(credential.accountId) !== void 0 || normalizeAuthEmailToken$1(credential.email) !== void 0;
|
|
400
|
+
}
|
|
401
|
+
function hasMatchingOAuthIdentity(existing, incoming) {
|
|
402
|
+
const existingAccountId = normalizeAuthIdentityToken$1(existing.accountId);
|
|
403
|
+
const incomingAccountId = normalizeAuthIdentityToken$1(incoming.accountId);
|
|
404
|
+
if (existingAccountId !== void 0 && incomingAccountId !== void 0) return existingAccountId === incomingAccountId;
|
|
405
|
+
const existingEmail = normalizeAuthEmailToken$1(existing.email);
|
|
406
|
+
const incomingEmail = normalizeAuthEmailToken$1(incoming.email);
|
|
407
|
+
if (existingEmail !== void 0 && incomingEmail !== void 0) return existingEmail === incomingEmail;
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
function isSafeToAdoptBootstrapOAuthIdentity(existing, incoming) {
|
|
411
|
+
if (!existing || existing.type !== "oauth") return true;
|
|
412
|
+
if (existing.provider !== incoming.provider) return false;
|
|
413
|
+
if (areOAuthCredentialsEquivalent(existing, incoming)) return true;
|
|
414
|
+
if (!hasOAuthIdentity(existing)) return true;
|
|
415
|
+
return hasMatchingOAuthIdentity(existing, incoming);
|
|
416
|
+
}
|
|
417
|
+
function isSafeToAdoptMainStoreOAuthIdentity(existing, incoming) {
|
|
418
|
+
if (!existing || existing.type !== "oauth") return false;
|
|
419
|
+
if (existing.provider !== incoming.provider) return false;
|
|
420
|
+
if (areOAuthCredentialsEquivalent(existing, incoming)) return true;
|
|
421
|
+
if (!hasOAuthIdentity(existing)) return true;
|
|
422
|
+
return hasMatchingOAuthIdentity(existing, incoming);
|
|
423
|
+
}
|
|
424
|
+
function shouldBootstrapFromExternalCliCredential(params) {
|
|
425
|
+
const now = params.now ?? Date.now();
|
|
426
|
+
if (hasUsableOAuthCredential(params.existing, now)) return false;
|
|
427
|
+
return hasUsableOAuthCredential(params.imported, now);
|
|
428
|
+
}
|
|
429
|
+
function overlayRuntimeExternalOAuthProfiles(store, profiles) {
|
|
430
|
+
const externalProfiles = Array.from(profiles);
|
|
431
|
+
if (externalProfiles.length === 0) return store;
|
|
432
|
+
const next = structuredClone(store);
|
|
433
|
+
for (const profile of externalProfiles) next.profiles[profile.profileId] = profile.credential;
|
|
434
|
+
return next;
|
|
435
|
+
}
|
|
436
|
+
function shouldPersistRuntimeExternalOAuthProfile(params) {
|
|
437
|
+
for (const profile of params.profiles) {
|
|
438
|
+
if (profile.profileId !== params.profileId) continue;
|
|
439
|
+
if (profile.persistence === "persisted") return true;
|
|
440
|
+
return !areOAuthCredentialsEquivalent(profile.credential, params.credential);
|
|
441
|
+
}
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
function normalizeAuthIdentityToken(value) {
|
|
445
|
+
const trimmed = value?.trim();
|
|
446
|
+
return trimmed ? trimmed : void 0;
|
|
447
|
+
}
|
|
448
|
+
function normalizeAuthEmailToken(value) {
|
|
449
|
+
return normalizeAuthIdentityToken(value)?.toLowerCase();
|
|
450
|
+
}
|
|
451
|
+
function isSafeToUseExternalCliCredential(existing, imported) {
|
|
452
|
+
if (!existing) return true;
|
|
453
|
+
if (existing.provider !== imported.provider) return false;
|
|
454
|
+
const existingAccountId = normalizeAuthIdentityToken(existing.accountId);
|
|
455
|
+
const importedAccountId = normalizeAuthIdentityToken(imported.accountId);
|
|
456
|
+
const existingEmail = normalizeAuthEmailToken(existing.email);
|
|
457
|
+
const importedEmail = normalizeAuthEmailToken(imported.email);
|
|
458
|
+
if (existingAccountId !== void 0 && importedAccountId !== void 0) return existingAccountId === importedAccountId;
|
|
459
|
+
if (existingEmail !== void 0 && importedEmail !== void 0) return existingEmail === importedEmail;
|
|
460
|
+
if (existingAccountId !== void 0 || existingEmail !== void 0) return false;
|
|
461
|
+
return true;
|
|
462
|
+
}
|
|
463
|
+
const EXTERNAL_CLI_SYNC_PROVIDERS = [{
|
|
464
|
+
profileId: MINIMAX_CLI_PROFILE_ID,
|
|
465
|
+
provider: "minimax-portal",
|
|
466
|
+
readCredentials: () => readMiniMaxCliCredentialsCached({ ttlMs: EXTERNAL_CLI_SYNC_TTL_MS })
|
|
467
|
+
}];
|
|
468
|
+
function resolveExternalCliSyncProvider(params) {
|
|
469
|
+
const provider = EXTERNAL_CLI_SYNC_PROVIDERS.find((entry) => entry.profileId === params.profileId);
|
|
470
|
+
if (!provider) return null;
|
|
471
|
+
if (params.credential && provider.provider !== params.credential.provider) return null;
|
|
472
|
+
return provider;
|
|
473
|
+
}
|
|
474
|
+
function readExternalCliBootstrapCredential(params) {
|
|
475
|
+
const provider = resolveExternalCliSyncProvider(params);
|
|
476
|
+
if (!provider) return null;
|
|
477
|
+
return provider.readCredentials();
|
|
478
|
+
}
|
|
479
|
+
const readManagedExternalCliCredential = readExternalCliBootstrapCredential;
|
|
480
|
+
function resolveExternalCliAuthProfiles(store) {
|
|
481
|
+
const profiles = [];
|
|
482
|
+
const now = Date.now();
|
|
483
|
+
for (const providerConfig of EXTERNAL_CLI_SYNC_PROVIDERS) {
|
|
484
|
+
const creds = providerConfig.readCredentials();
|
|
485
|
+
if (!creds) continue;
|
|
486
|
+
const existing = store.profiles[providerConfig.profileId];
|
|
487
|
+
const existingOAuth = existing?.type === "oauth" && existing.provider === providerConfig.provider ? existing : void 0;
|
|
488
|
+
if (existing && !existingOAuth) {
|
|
489
|
+
log$1.debug("kept explicit local auth over external cli bootstrap", {
|
|
490
|
+
profileId: providerConfig.profileId,
|
|
491
|
+
provider: providerConfig.provider,
|
|
492
|
+
localType: existing.type,
|
|
493
|
+
localProvider: existing.provider
|
|
494
|
+
});
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
if (existingOAuth && !isSafeToUseExternalCliCredential(existingOAuth, creds)) {
|
|
498
|
+
log$1.warn("refused external cli oauth bootstrap: identity mismatch", {
|
|
499
|
+
profileId: providerConfig.profileId,
|
|
500
|
+
provider: providerConfig.provider
|
|
501
|
+
});
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (existingOAuth && !isSafeToAdoptBootstrapOAuthIdentity(existingOAuth, creds) && !areOAuthCredentialsEquivalent(existingOAuth, creds)) {
|
|
505
|
+
log$1.warn("refused external cli oauth bootstrap: identity mismatch or missing binding", {
|
|
506
|
+
profileId: providerConfig.profileId,
|
|
507
|
+
provider: providerConfig.provider
|
|
508
|
+
});
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
if (!shouldBootstrapFromExternalCliCredential({
|
|
512
|
+
existing: existingOAuth,
|
|
513
|
+
imported: creds,
|
|
514
|
+
now
|
|
515
|
+
})) {
|
|
516
|
+
if (existingOAuth) log$1.debug("kept usable local oauth over external cli bootstrap", {
|
|
517
|
+
profileId: providerConfig.profileId,
|
|
518
|
+
provider: providerConfig.provider,
|
|
519
|
+
localExpires: existingOAuth.expires,
|
|
520
|
+
externalExpires: creds.expires
|
|
521
|
+
});
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
log$1.debug("used external cli oauth bootstrap because local oauth was missing or unusable", {
|
|
525
|
+
profileId: providerConfig.profileId,
|
|
526
|
+
provider: providerConfig.provider,
|
|
527
|
+
localExpires: existingOAuth?.expires,
|
|
528
|
+
externalExpires: creds.expires
|
|
529
|
+
});
|
|
530
|
+
profiles.push({
|
|
531
|
+
profileId: providerConfig.profileId,
|
|
532
|
+
credential: creds
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
return profiles;
|
|
536
|
+
}
|
|
537
|
+
let resolveExternalAuthProfilesForRuntime;
|
|
538
|
+
function normalizeExternalAuthProfile(profile) {
|
|
539
|
+
if (!profile?.profileId || !profile.credential) return null;
|
|
540
|
+
return {
|
|
541
|
+
...profile,
|
|
542
|
+
persistence: profile.persistence ?? "runtime-only"
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function resolveExternalAuthProfileMap(params) {
|
|
546
|
+
const env = params.env ?? process.env;
|
|
547
|
+
const profiles = (resolveExternalAuthProfilesForRuntime ?? resolveExternalAuthProfilesWithPlugins)({
|
|
548
|
+
env,
|
|
549
|
+
context: {
|
|
550
|
+
config: void 0,
|
|
551
|
+
agentDir: params.agentDir,
|
|
552
|
+
workspaceDir: void 0,
|
|
553
|
+
env,
|
|
554
|
+
store: params.store
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
558
|
+
const cliProfiles = resolveExternalCliAuthProfiles?.(params.store) ?? [];
|
|
559
|
+
for (const profile of cliProfiles) resolved.set(profile.profileId, {
|
|
560
|
+
profileId: profile.profileId,
|
|
561
|
+
credential: profile.credential,
|
|
562
|
+
persistence: "runtime-only"
|
|
563
|
+
});
|
|
564
|
+
for (const rawProfile of profiles) {
|
|
565
|
+
const profile = normalizeExternalAuthProfile(rawProfile);
|
|
566
|
+
if (!profile) continue;
|
|
567
|
+
resolved.set(profile.profileId, profile);
|
|
568
|
+
}
|
|
569
|
+
return resolved;
|
|
570
|
+
}
|
|
571
|
+
function listRuntimeExternalAuthProfiles(params) {
|
|
572
|
+
return Array.from(resolveExternalAuthProfileMap({
|
|
573
|
+
store: params.store,
|
|
574
|
+
agentDir: params.agentDir,
|
|
575
|
+
env: params.env
|
|
576
|
+
}).values());
|
|
577
|
+
}
|
|
578
|
+
function overlayExternalAuthProfiles(store, params) {
|
|
579
|
+
return overlayRuntimeExternalOAuthProfiles(store, listRuntimeExternalAuthProfiles({
|
|
580
|
+
store,
|
|
581
|
+
agentDir: params?.agentDir,
|
|
582
|
+
env: params?.env
|
|
583
|
+
}));
|
|
584
|
+
}
|
|
585
|
+
function shouldPersistExternalAuthProfile(params) {
|
|
586
|
+
const profiles = listRuntimeExternalAuthProfiles({
|
|
587
|
+
store: params.store,
|
|
588
|
+
agentDir: params.agentDir,
|
|
589
|
+
env: params.env
|
|
590
|
+
});
|
|
591
|
+
return shouldPersistRuntimeExternalOAuthProfile({
|
|
592
|
+
profileId: params.profileId,
|
|
593
|
+
credential: params.credential,
|
|
594
|
+
profiles
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
function ensureAuthStoreFile(pathname) {
|
|
598
|
+
if (fs.existsSync(pathname)) return;
|
|
599
|
+
saveJsonFile(pathname, {
|
|
600
|
+
version: 1,
|
|
601
|
+
profiles: {}
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
function normalizeAuthProfileOrder(raw) {
|
|
605
|
+
if (!raw || typeof raw !== "object") return;
|
|
606
|
+
const normalized = Object.entries(raw).reduce((acc, [provider, value]) => {
|
|
607
|
+
if (!Array.isArray(value)) return acc;
|
|
608
|
+
const list = value.map((entry) => normalizeOptionalString(entry) ?? "").filter(Boolean);
|
|
609
|
+
if (list.length > 0) acc[provider] = list;
|
|
610
|
+
return acc;
|
|
611
|
+
}, {});
|
|
612
|
+
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
613
|
+
}
|
|
614
|
+
function coerceAuthProfileState(raw) {
|
|
615
|
+
if (!raw || typeof raw !== "object") return {};
|
|
616
|
+
const record = raw;
|
|
617
|
+
return {
|
|
618
|
+
order: normalizeAuthProfileOrder(record.order),
|
|
619
|
+
lastGood: record.lastGood && typeof record.lastGood === "object" ? record.lastGood : void 0,
|
|
620
|
+
usageStats: record.usageStats && typeof record.usageStats === "object" ? record.usageStats : void 0
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function mergeAuthProfileState(base, override) {
|
|
624
|
+
const mergeRecord = (left, right) => {
|
|
625
|
+
if (!left && !right) return;
|
|
626
|
+
if (!left) return { ...right };
|
|
627
|
+
if (!right) return { ...left };
|
|
628
|
+
return {
|
|
629
|
+
...left,
|
|
630
|
+
...right
|
|
631
|
+
};
|
|
632
|
+
};
|
|
633
|
+
return {
|
|
634
|
+
order: mergeRecord(base.order, override.order),
|
|
635
|
+
lastGood: mergeRecord(base.lastGood, override.lastGood),
|
|
636
|
+
usageStats: mergeRecord(base.usageStats, override.usageStats)
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
function loadPersistedAuthProfileState(agentDir) {
|
|
640
|
+
return coerceAuthProfileState(loadJsonFile(resolveAuthStatePath(agentDir)));
|
|
641
|
+
}
|
|
642
|
+
function buildPersistedAuthProfileState(store) {
|
|
643
|
+
const state = coerceAuthProfileState(store);
|
|
644
|
+
if (!state.order && !state.lastGood && !state.usageStats) return null;
|
|
645
|
+
return {
|
|
646
|
+
version: 1,
|
|
647
|
+
...state.order ? { order: state.order } : {},
|
|
648
|
+
...state.lastGood ? { lastGood: state.lastGood } : {},
|
|
649
|
+
...state.usageStats ? { usageStats: state.usageStats } : {}
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
function savePersistedAuthProfileState(store, agentDir) {
|
|
653
|
+
const payload = buildPersistedAuthProfileState(store);
|
|
654
|
+
const statePath = resolveAuthStatePath(agentDir);
|
|
655
|
+
if (!payload) {
|
|
656
|
+
try {
|
|
657
|
+
fs.unlinkSync(statePath);
|
|
658
|
+
} catch (error) {
|
|
659
|
+
if (error?.code !== "ENOENT") throw error;
|
|
660
|
+
}
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
saveJsonFile(statePath, payload);
|
|
664
|
+
return payload;
|
|
665
|
+
}
|
|
666
|
+
const AUTH_PROFILE_TYPES = new Set([
|
|
667
|
+
"api_key",
|
|
668
|
+
"oauth",
|
|
669
|
+
"token"
|
|
670
|
+
]);
|
|
671
|
+
function normalizeSecretBackedField(params) {
|
|
672
|
+
const value = params.entry[params.valueField];
|
|
673
|
+
if (value == null || typeof value === "string") return;
|
|
674
|
+
const ref = coerceSecretRef(value);
|
|
675
|
+
if (ref && !coerceSecretRef(params.entry[params.refField])) params.entry[params.refField] = ref;
|
|
676
|
+
delete params.entry[params.valueField];
|
|
677
|
+
}
|
|
678
|
+
function normalizeRawCredentialEntry(raw) {
|
|
679
|
+
const entry = { ...raw };
|
|
680
|
+
if (!("type" in entry) && typeof entry["mode"] === "string") entry["type"] = entry["mode"];
|
|
681
|
+
if (!("key" in entry) && typeof entry["apiKey"] === "string") entry["key"] = entry["apiKey"];
|
|
682
|
+
normalizeSecretBackedField({
|
|
683
|
+
entry,
|
|
684
|
+
valueField: "key",
|
|
685
|
+
refField: "keyRef"
|
|
686
|
+
});
|
|
687
|
+
normalizeSecretBackedField({
|
|
688
|
+
entry,
|
|
689
|
+
valueField: "token",
|
|
690
|
+
refField: "tokenRef"
|
|
691
|
+
});
|
|
692
|
+
return entry;
|
|
693
|
+
}
|
|
694
|
+
function parseCredentialEntry(raw, fallbackProvider) {
|
|
695
|
+
if (!raw || typeof raw !== "object") return {
|
|
696
|
+
ok: false,
|
|
697
|
+
reason: "non_object"
|
|
698
|
+
};
|
|
699
|
+
const typed = normalizeRawCredentialEntry(raw);
|
|
700
|
+
if (!AUTH_PROFILE_TYPES.has(typed.type)) return {
|
|
701
|
+
ok: false,
|
|
702
|
+
reason: "invalid_type"
|
|
703
|
+
};
|
|
704
|
+
const provider = typed.provider ?? fallbackProvider;
|
|
705
|
+
if (typeof provider !== "string" || provider.trim().length === 0) return {
|
|
706
|
+
ok: false,
|
|
707
|
+
reason: "missing_provider"
|
|
708
|
+
};
|
|
709
|
+
return {
|
|
710
|
+
ok: true,
|
|
711
|
+
credential: {
|
|
712
|
+
...typed,
|
|
713
|
+
provider
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function warnRejectedCredentialEntries(source, rejected) {
|
|
718
|
+
if (rejected.length === 0) return;
|
|
719
|
+
const reasons = rejected.reduce((acc, current) => {
|
|
720
|
+
acc[current.reason] = (acc[current.reason] ?? 0) + 1;
|
|
721
|
+
return acc;
|
|
722
|
+
}, {});
|
|
723
|
+
log$1.warn("ignored invalid auth profile entries during store load", {
|
|
724
|
+
source,
|
|
725
|
+
dropped: rejected.length,
|
|
726
|
+
reasons,
|
|
727
|
+
keys: rejected.slice(0, 10).map((entry) => entry.key)
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
function coerceLegacyAuthStore(raw) {
|
|
731
|
+
if (!raw || typeof raw !== "object") return null;
|
|
732
|
+
const record = raw;
|
|
733
|
+
if ("profiles" in record) return null;
|
|
734
|
+
const entries = {};
|
|
735
|
+
const rejected = [];
|
|
736
|
+
for (const [key, value] of Object.entries(record)) {
|
|
737
|
+
const parsed = parseCredentialEntry(value, key);
|
|
738
|
+
if (!parsed.ok) {
|
|
739
|
+
rejected.push({
|
|
740
|
+
key,
|
|
741
|
+
reason: parsed.reason
|
|
742
|
+
});
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
entries[key] = parsed.credential;
|
|
746
|
+
}
|
|
747
|
+
warnRejectedCredentialEntries("auth.json", rejected);
|
|
748
|
+
return Object.keys(entries).length > 0 ? entries : null;
|
|
749
|
+
}
|
|
750
|
+
function coercePersistedAuthProfileStore(raw) {
|
|
751
|
+
if (!raw || typeof raw !== "object") return null;
|
|
752
|
+
const record = raw;
|
|
753
|
+
if (!record.profiles || typeof record.profiles !== "object") return null;
|
|
754
|
+
const profiles = record.profiles;
|
|
755
|
+
const normalized = {};
|
|
756
|
+
const rejected = [];
|
|
757
|
+
for (const [key, value] of Object.entries(profiles)) {
|
|
758
|
+
const parsed = parseCredentialEntry(value);
|
|
759
|
+
if (!parsed.ok) {
|
|
760
|
+
rejected.push({
|
|
761
|
+
key,
|
|
762
|
+
reason: parsed.reason
|
|
763
|
+
});
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
normalized[key] = parsed.credential;
|
|
767
|
+
}
|
|
768
|
+
warnRejectedCredentialEntries("auth-profiles.json", rejected);
|
|
769
|
+
return {
|
|
770
|
+
version: Number(record.version ?? 1),
|
|
771
|
+
profiles: normalized,
|
|
772
|
+
...coerceAuthProfileState(record)
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
function mergeRecord(base, override) {
|
|
776
|
+
if (!base && !override) return;
|
|
777
|
+
if (!base) return { ...override };
|
|
778
|
+
if (!override) return { ...base };
|
|
779
|
+
return {
|
|
780
|
+
...base,
|
|
781
|
+
...override
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
function dedupeMergedProfileOrder(profileIds) {
|
|
785
|
+
return Array.from(new Set(profileIds));
|
|
786
|
+
}
|
|
787
|
+
function hasComparableOAuthIdentityConflict(existing, candidate) {
|
|
788
|
+
const existingAccountId = normalizeAuthIdentityToken$1(existing.accountId);
|
|
789
|
+
const candidateAccountId = normalizeAuthIdentityToken$1(candidate.accountId);
|
|
790
|
+
if (existingAccountId !== void 0 && candidateAccountId !== void 0 && existingAccountId !== candidateAccountId) return true;
|
|
791
|
+
const existingEmail = normalizeAuthEmailToken$1(existing.email);
|
|
792
|
+
const candidateEmail = normalizeAuthEmailToken$1(candidate.email);
|
|
793
|
+
return existingEmail !== void 0 && candidateEmail !== void 0 && existingEmail !== candidateEmail;
|
|
794
|
+
}
|
|
795
|
+
function isLegacyDefaultOAuthProfile(profileId, credential) {
|
|
796
|
+
return profileId === `${normalizeProviderId(credential.provider)}:default`;
|
|
797
|
+
}
|
|
798
|
+
function isNewerUsableOAuthCredential(existing, candidate) {
|
|
799
|
+
if (!hasUsableOAuthCredential(candidate)) return false;
|
|
800
|
+
if (!hasUsableOAuthCredential(existing)) return true;
|
|
801
|
+
return Number.isFinite(candidate.expires) && (!Number.isFinite(existing.expires) || candidate.expires > existing.expires);
|
|
802
|
+
}
|
|
803
|
+
function findMainStoreOAuthReplacement(params) {
|
|
804
|
+
const providerKey = normalizeProviderId(params.legacyCredential.provider);
|
|
805
|
+
const candidates = Object.entries(params.base.profiles).flatMap(([profileId, credential]) => {
|
|
806
|
+
if (profileId === params.legacyProfileId || credential.type !== "oauth" || normalizeProviderId(credential.provider) !== providerKey) return [];
|
|
807
|
+
return [[profileId, credential]];
|
|
808
|
+
}).filter(([, credential]) => isNewerUsableOAuthCredential(params.legacyCredential, credential)).toSorted(([leftId, leftCredential], [rightId, rightCredential]) => {
|
|
809
|
+
const leftExpires = Number.isFinite(leftCredential.expires) ? leftCredential.expires : 0;
|
|
810
|
+
const rightExpires = Number.isFinite(rightCredential.expires) ? rightCredential.expires : 0;
|
|
811
|
+
if (rightExpires !== leftExpires) return rightExpires - leftExpires;
|
|
812
|
+
return leftId.localeCompare(rightId);
|
|
813
|
+
});
|
|
814
|
+
const exactIdentityCandidates = candidates.filter(([, credential]) => isSafeToAdoptMainStoreOAuthIdentity(params.legacyCredential, credential));
|
|
815
|
+
if (exactIdentityCandidates.length > 0) {
|
|
816
|
+
if (!hasOAuthIdentity(params.legacyCredential) && exactIdentityCandidates.length > 1) return;
|
|
817
|
+
return exactIdentityCandidates[0]?.[0];
|
|
818
|
+
}
|
|
819
|
+
if (hasUsableOAuthCredential(params.legacyCredential)) return;
|
|
820
|
+
const fallbackCandidates = candidates.filter(([, credential]) => !hasComparableOAuthIdentityConflict(params.legacyCredential, credential));
|
|
821
|
+
if (fallbackCandidates.length !== 1) return;
|
|
822
|
+
return fallbackCandidates[0]?.[0];
|
|
823
|
+
}
|
|
824
|
+
function replaceMergedProfileReferences(params) {
|
|
825
|
+
const { store, base, replacements } = params;
|
|
826
|
+
if (replacements.size === 0) return store;
|
|
827
|
+
const profiles = { ...store.profiles };
|
|
828
|
+
for (const [legacyProfileId, replacementProfileId] of replacements) {
|
|
829
|
+
const baseCredential = base.profiles[legacyProfileId];
|
|
830
|
+
if (baseCredential) profiles[legacyProfileId] = baseCredential;
|
|
831
|
+
else delete profiles[legacyProfileId];
|
|
832
|
+
const replacementBaseCredential = base.profiles[replacementProfileId];
|
|
833
|
+
const replacementCredential = profiles[replacementProfileId];
|
|
834
|
+
if (replacementBaseCredential && (!replacementCredential || replacementCredential.type === "oauth" && replacementBaseCredential.type === "oauth" && isNewerUsableOAuthCredential(replacementCredential, replacementBaseCredential))) profiles[replacementProfileId] = replacementBaseCredential;
|
|
835
|
+
}
|
|
836
|
+
const order = store.order ? Object.fromEntries(Object.entries(store.order).map(([provider, profileIds]) => [provider, dedupeMergedProfileOrder(profileIds.map((profileId) => replacements.get(profileId) ?? profileId))])) : void 0;
|
|
837
|
+
const lastGood = store.lastGood ? Object.fromEntries(Object.entries(store.lastGood).map(([provider, profileId]) => [provider, replacements.get(profileId) ?? profileId])) : void 0;
|
|
838
|
+
const usageStats = store.usageStats ? { ...store.usageStats } : void 0;
|
|
839
|
+
if (usageStats) for (const legacyProfileId of replacements.keys()) {
|
|
840
|
+
const baseStats = base.usageStats?.[legacyProfileId];
|
|
841
|
+
if (baseStats) usageStats[legacyProfileId] = baseStats;
|
|
842
|
+
else delete usageStats[legacyProfileId];
|
|
843
|
+
}
|
|
844
|
+
return {
|
|
845
|
+
...store,
|
|
846
|
+
profiles,
|
|
847
|
+
...order && Object.keys(order).length > 0 ? { order } : { order: void 0 },
|
|
848
|
+
...lastGood && Object.keys(lastGood).length > 0 ? { lastGood } : { lastGood: void 0 },
|
|
849
|
+
...usageStats && Object.keys(usageStats).length > 0 ? { usageStats } : { usageStats: void 0 }
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
function reconcileMainStoreOAuthProfileDrift(params) {
|
|
853
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
854
|
+
for (const [profileId, credential] of Object.entries(params.override.profiles)) {
|
|
855
|
+
if (credential.type !== "oauth" || !isLegacyDefaultOAuthProfile(profileId, credential)) continue;
|
|
856
|
+
const replacementProfileId = findMainStoreOAuthReplacement({
|
|
857
|
+
base: params.base,
|
|
858
|
+
legacyProfileId: profileId,
|
|
859
|
+
legacyCredential: credential
|
|
860
|
+
});
|
|
861
|
+
if (replacementProfileId) replacements.set(profileId, replacementProfileId);
|
|
862
|
+
}
|
|
863
|
+
return replaceMergedProfileReferences({
|
|
864
|
+
store: params.merged,
|
|
865
|
+
base: params.base,
|
|
866
|
+
replacements
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
function mergeAuthProfileStores(base, override) {
|
|
870
|
+
if (Object.keys(override.profiles).length === 0 && !override.order && !override.lastGood && !override.usageStats) return base;
|
|
871
|
+
return reconcileMainStoreOAuthProfileDrift({
|
|
872
|
+
base,
|
|
873
|
+
override,
|
|
874
|
+
merged: {
|
|
875
|
+
version: Math.max(base.version, override.version ?? base.version),
|
|
876
|
+
profiles: {
|
|
877
|
+
...base.profiles,
|
|
878
|
+
...override.profiles
|
|
879
|
+
},
|
|
880
|
+
order: mergeRecord(base.order, override.order),
|
|
881
|
+
lastGood: mergeRecord(base.lastGood, override.lastGood),
|
|
882
|
+
usageStats: mergeRecord(base.usageStats, override.usageStats)
|
|
883
|
+
}
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
function buildPersistedAuthProfileSecretsStore(store, shouldPersistProfile) {
|
|
887
|
+
return {
|
|
888
|
+
version: 1,
|
|
889
|
+
profiles: Object.fromEntries(Object.entries(store.profiles).flatMap(([profileId, credential]) => {
|
|
890
|
+
if (shouldPersistProfile && !shouldPersistProfile({
|
|
891
|
+
profileId,
|
|
892
|
+
credential
|
|
893
|
+
})) return [];
|
|
894
|
+
if (credential.type === "api_key" && credential.keyRef && credential.key !== void 0) {
|
|
895
|
+
const sanitized = { ...credential };
|
|
896
|
+
delete sanitized.key;
|
|
897
|
+
return [[profileId, sanitized]];
|
|
898
|
+
}
|
|
899
|
+
if (credential.type === "token" && credential.tokenRef && credential.token !== void 0) {
|
|
900
|
+
const sanitized = { ...credential };
|
|
901
|
+
delete sanitized.token;
|
|
902
|
+
return [[profileId, sanitized]];
|
|
903
|
+
}
|
|
904
|
+
return [[profileId, credential]];
|
|
905
|
+
}))
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
function applyLegacyAuthStore(store, legacy) {
|
|
909
|
+
for (const [provider, cred] of Object.entries(legacy)) {
|
|
910
|
+
const profileId = `${provider}:default`;
|
|
911
|
+
const credentialProvider = cred.provider ?? provider;
|
|
912
|
+
if (cred.type === "api_key") {
|
|
913
|
+
store.profiles[profileId] = {
|
|
914
|
+
type: "api_key",
|
|
915
|
+
provider: credentialProvider,
|
|
916
|
+
key: cred.key,
|
|
917
|
+
...cred.email ? { email: cred.email } : {}
|
|
918
|
+
};
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
if (cred.type === "token") {
|
|
922
|
+
store.profiles[profileId] = {
|
|
923
|
+
type: "token",
|
|
924
|
+
provider: credentialProvider,
|
|
925
|
+
token: cred.token,
|
|
926
|
+
...typeof cred.expires === "number" ? { expires: cred.expires } : {},
|
|
927
|
+
...cred.email ? { email: cred.email } : {}
|
|
928
|
+
};
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
store.profiles[profileId] = {
|
|
932
|
+
type: "oauth",
|
|
933
|
+
provider: credentialProvider,
|
|
934
|
+
access: cred.access,
|
|
935
|
+
refresh: cred.refresh,
|
|
936
|
+
expires: cred.expires,
|
|
937
|
+
...cred.enterpriseUrl ? { enterpriseUrl: cred.enterpriseUrl } : {},
|
|
938
|
+
...cred.projectId ? { projectId: cred.projectId } : {},
|
|
939
|
+
...cred.accountId ? { accountId: cred.accountId } : {},
|
|
940
|
+
...cred.email ? { email: cred.email } : {}
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
function mergeOAuthFileIntoStore(store) {
|
|
945
|
+
const oauthRaw = loadJsonFile(resolveOAuthPath());
|
|
946
|
+
if (!oauthRaw || typeof oauthRaw !== "object") return false;
|
|
947
|
+
const oauthEntries = oauthRaw;
|
|
948
|
+
let mutated = false;
|
|
949
|
+
for (const [provider, creds] of Object.entries(oauthEntries)) {
|
|
950
|
+
if (!creds || typeof creds !== "object") continue;
|
|
951
|
+
const profileId = `${provider}:default`;
|
|
952
|
+
if (store.profiles[profileId]) continue;
|
|
953
|
+
store.profiles[profileId] = {
|
|
954
|
+
type: "oauth",
|
|
955
|
+
provider,
|
|
956
|
+
...creds
|
|
957
|
+
};
|
|
958
|
+
mutated = true;
|
|
959
|
+
}
|
|
960
|
+
return mutated;
|
|
961
|
+
}
|
|
962
|
+
function loadPersistedAuthProfileStore(agentDir) {
|
|
963
|
+
const raw = loadJsonFile(resolveAuthStorePath(agentDir));
|
|
964
|
+
const store = coercePersistedAuthProfileStore(raw);
|
|
965
|
+
if (!store) return null;
|
|
966
|
+
return {
|
|
967
|
+
...store,
|
|
968
|
+
...mergeAuthProfileState(coerceAuthProfileState(raw), loadPersistedAuthProfileState(agentDir))
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
function loadLegacyAuthProfileStore(agentDir) {
|
|
972
|
+
return coerceLegacyAuthStore(loadJsonFile(resolveLegacyAuthStorePath(agentDir)));
|
|
973
|
+
}
|
|
974
|
+
const loadedAuthStoreCache = /* @__PURE__ */ new Map();
|
|
975
|
+
function cloneAuthProfileStore(store) {
|
|
976
|
+
return structuredClone(store);
|
|
977
|
+
}
|
|
978
|
+
function resolveRuntimeAuthProfileStore(agentDir) {
|
|
979
|
+
const mainKey = resolveAuthStorePath(void 0);
|
|
980
|
+
const requestedKey = resolveAuthStorePath(agentDir);
|
|
981
|
+
const mainStore = getRuntimeAuthProfileStoreSnapshot(void 0);
|
|
982
|
+
const requestedStore = getRuntimeAuthProfileStoreSnapshot(agentDir);
|
|
983
|
+
if (!agentDir || requestedKey === mainKey) {
|
|
984
|
+
if (!mainStore) return null;
|
|
985
|
+
return mainStore;
|
|
986
|
+
}
|
|
987
|
+
if (mainStore && requestedStore) return mergeAuthProfileStores(mainStore, requestedStore);
|
|
988
|
+
if (requestedStore) return requestedStore;
|
|
989
|
+
if (mainStore) return mainStore;
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
992
|
+
function readAuthStoreMtimeMs(authPath) {
|
|
993
|
+
try {
|
|
994
|
+
return fs.statSync(authPath).mtimeMs;
|
|
995
|
+
} catch {
|
|
996
|
+
return null;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
function readCachedAuthProfileStore(params) {
|
|
1000
|
+
const cached = loadedAuthStoreCache.get(params.authPath);
|
|
1001
|
+
if (!cached || cached.authMtimeMs !== params.authMtimeMs || cached.stateMtimeMs !== params.stateMtimeMs) return null;
|
|
1002
|
+
if (Date.now() - cached.syncedAtMs >= 9e5) return null;
|
|
1003
|
+
return cloneAuthProfileStore(cached.store);
|
|
1004
|
+
}
|
|
1005
|
+
function writeCachedAuthProfileStore(params) {
|
|
1006
|
+
loadedAuthStoreCache.set(params.authPath, {
|
|
1007
|
+
authMtimeMs: params.authMtimeMs,
|
|
1008
|
+
stateMtimeMs: params.stateMtimeMs,
|
|
1009
|
+
syncedAtMs: Date.now(),
|
|
1010
|
+
store: cloneAuthProfileStore(params.store)
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
async function updateAuthProfileStoreWithLock(params) {
|
|
1014
|
+
const authPath = resolveAuthStorePath(params.agentDir);
|
|
1015
|
+
ensureAuthStoreFile(authPath);
|
|
1016
|
+
try {
|
|
1017
|
+
return await withFileLock(authPath, AUTH_STORE_LOCK_OPTIONS, async () => {
|
|
1018
|
+
const store = loadAuthProfileStoreForAgent(params.agentDir);
|
|
1019
|
+
if (params.updater(store)) saveAuthProfileStore(store, params.agentDir);
|
|
1020
|
+
return store;
|
|
1021
|
+
});
|
|
1022
|
+
} catch {
|
|
1023
|
+
return null;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
function loadAuthProfileStoreForAgent(agentDir, options) {
|
|
1027
|
+
const readOnly = options?.readOnly === true;
|
|
1028
|
+
const authPath = resolveAuthStorePath(agentDir);
|
|
1029
|
+
const statePath = resolveAuthStatePath(agentDir);
|
|
1030
|
+
const authMtimeMs = readAuthStoreMtimeMs(authPath);
|
|
1031
|
+
const stateMtimeMs = readAuthStoreMtimeMs(statePath);
|
|
1032
|
+
if (!readOnly) {
|
|
1033
|
+
const cached = readCachedAuthProfileStore({
|
|
1034
|
+
authPath,
|
|
1035
|
+
authMtimeMs,
|
|
1036
|
+
stateMtimeMs
|
|
1037
|
+
});
|
|
1038
|
+
if (cached) return cached;
|
|
1039
|
+
}
|
|
1040
|
+
const asStore = loadPersistedAuthProfileStore(agentDir);
|
|
1041
|
+
if (asStore) {
|
|
1042
|
+
if (!readOnly) writeCachedAuthProfileStore({
|
|
1043
|
+
authPath,
|
|
1044
|
+
authMtimeMs: readAuthStoreMtimeMs(authPath),
|
|
1045
|
+
stateMtimeMs: readAuthStoreMtimeMs(statePath),
|
|
1046
|
+
store: asStore
|
|
1047
|
+
});
|
|
1048
|
+
return asStore;
|
|
1049
|
+
}
|
|
1050
|
+
if (agentDir && !readOnly) {
|
|
1051
|
+
const mainStore = loadPersistedAuthProfileStore();
|
|
1052
|
+
if (mainStore && Object.keys(mainStore.profiles).length > 0) {
|
|
1053
|
+
saveJsonFile(authPath, buildPersistedAuthProfileSecretsStore(mainStore));
|
|
1054
|
+
log$1.info("inherited auth-profiles from main agent", { agentDir });
|
|
1055
|
+
const inherited = {
|
|
1056
|
+
version: mainStore.version,
|
|
1057
|
+
profiles: { ...mainStore.profiles }
|
|
1058
|
+
};
|
|
1059
|
+
writeCachedAuthProfileStore({
|
|
1060
|
+
authPath,
|
|
1061
|
+
authMtimeMs: readAuthStoreMtimeMs(authPath),
|
|
1062
|
+
stateMtimeMs: readAuthStoreMtimeMs(statePath),
|
|
1063
|
+
store: inherited
|
|
1064
|
+
});
|
|
1065
|
+
return inherited;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
const legacy = loadLegacyAuthProfileStore(agentDir);
|
|
1069
|
+
const store = {
|
|
1070
|
+
version: 1,
|
|
1071
|
+
profiles: {}
|
|
1072
|
+
};
|
|
1073
|
+
if (legacy) applyLegacyAuthStore(store, legacy);
|
|
1074
|
+
const mergedOAuth = mergeOAuthFileIntoStore(store);
|
|
1075
|
+
const forceReadOnly = process.env.OPENCLAW_AUTH_STORE_READONLY === "1";
|
|
1076
|
+
const shouldWrite = !readOnly && !forceReadOnly && (legacy !== null || mergedOAuth);
|
|
1077
|
+
if (shouldWrite) saveAuthProfileStore(store, agentDir);
|
|
1078
|
+
if (shouldWrite && legacy !== null) {
|
|
1079
|
+
const legacyPath = resolveLegacyAuthStorePath(agentDir);
|
|
1080
|
+
try {
|
|
1081
|
+
fs.unlinkSync(legacyPath);
|
|
1082
|
+
} catch (err) {
|
|
1083
|
+
if (err?.code !== "ENOENT") log$1.warn("failed to delete legacy auth.json after migration", {
|
|
1084
|
+
err,
|
|
1085
|
+
legacyPath
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
if (!readOnly) writeCachedAuthProfileStore({
|
|
1090
|
+
authPath,
|
|
1091
|
+
authMtimeMs: readAuthStoreMtimeMs(authPath),
|
|
1092
|
+
stateMtimeMs: readAuthStoreMtimeMs(statePath),
|
|
1093
|
+
store
|
|
1094
|
+
});
|
|
1095
|
+
return store;
|
|
1096
|
+
}
|
|
1097
|
+
function loadAuthProfileStoreForRuntime(agentDir, options) {
|
|
1098
|
+
const store = loadAuthProfileStoreForAgent(agentDir, options);
|
|
1099
|
+
const authPath = resolveAuthStorePath(agentDir);
|
|
1100
|
+
const mainAuthPath = resolveAuthStorePath();
|
|
1101
|
+
if (!agentDir || authPath === mainAuthPath) return overlayExternalAuthProfiles(store, { agentDir });
|
|
1102
|
+
return overlayExternalAuthProfiles(mergeAuthProfileStores(loadAuthProfileStoreForAgent(void 0, options), store), { agentDir });
|
|
1103
|
+
}
|
|
1104
|
+
function loadAuthProfileStoreForSecretsRuntime(agentDir) {
|
|
1105
|
+
return loadAuthProfileStoreForRuntime(agentDir, {
|
|
1106
|
+
readOnly: true,
|
|
1107
|
+
allowKeychainPrompt: false
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
function ensureAuthProfileStore(agentDir, options) {
|
|
1111
|
+
return overlayExternalAuthProfiles(ensureAuthProfileStoreWithoutExternalProfiles(agentDir, options), { agentDir });
|
|
1112
|
+
}
|
|
1113
|
+
function ensureAuthProfileStoreWithoutExternalProfiles(agentDir, options) {
|
|
1114
|
+
const runtimeStore = resolveRuntimeAuthProfileStore(agentDir);
|
|
1115
|
+
if (runtimeStore) return runtimeStore;
|
|
1116
|
+
const store = loadAuthProfileStoreForAgent(agentDir, options);
|
|
1117
|
+
const authPath = resolveAuthStorePath(agentDir);
|
|
1118
|
+
const mainAuthPath = resolveAuthStorePath();
|
|
1119
|
+
if (!agentDir || authPath === mainAuthPath) return store;
|
|
1120
|
+
return mergeAuthProfileStores(loadAuthProfileStoreForAgent(void 0, options), store);
|
|
1121
|
+
}
|
|
1122
|
+
function saveAuthProfileStore(store, agentDir, options) {
|
|
1123
|
+
const authPath = resolveAuthStorePath(agentDir);
|
|
1124
|
+
const statePath = resolveAuthStatePath(agentDir);
|
|
1125
|
+
saveJsonFile(authPath, buildPersistedAuthProfileSecretsStore(store, ({ profileId, credential }) => {
|
|
1126
|
+
if (credential.type !== "oauth") return true;
|
|
1127
|
+
if (options?.filterExternalAuthProfiles === false) return true;
|
|
1128
|
+
return shouldPersistExternalAuthProfile({
|
|
1129
|
+
store,
|
|
1130
|
+
profileId,
|
|
1131
|
+
credential,
|
|
1132
|
+
agentDir
|
|
1133
|
+
});
|
|
1134
|
+
}));
|
|
1135
|
+
savePersistedAuthProfileState(store, agentDir);
|
|
1136
|
+
const runtimeStore = cloneAuthProfileStore(store);
|
|
1137
|
+
writeCachedAuthProfileStore({
|
|
1138
|
+
authPath,
|
|
1139
|
+
authMtimeMs: readAuthStoreMtimeMs(authPath),
|
|
1140
|
+
stateMtimeMs: readAuthStoreMtimeMs(statePath),
|
|
1141
|
+
store: runtimeStore
|
|
1142
|
+
});
|
|
1143
|
+
if (hasRuntimeAuthProfileStoreSnapshot(agentDir)) setRuntimeAuthProfileStoreSnapshot(runtimeStore, agentDir);
|
|
1144
|
+
}
|
|
1145
|
+
//#endregion
|
|
1146
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/normalize-secret-input-k9H_9vvf.js
|
|
1147
|
+
/**
|
|
1148
|
+
* Secret normalization for copy/pasted credentials.
|
|
1149
|
+
*
|
|
1150
|
+
* Common footgun: line breaks (especially `\r`) embedded in API keys/tokens.
|
|
1151
|
+
* We strip line breaks anywhere, then trim whitespace at the ends.
|
|
1152
|
+
*
|
|
1153
|
+
* Another frequent source of runtime failures is rich-text/Unicode artifacts
|
|
1154
|
+
* (smart punctuation, box-drawing chars, etc.) pasted into API keys. These can
|
|
1155
|
+
* break HTTP header construction (`ByteString` violations). Drop non-Latin1
|
|
1156
|
+
* code points so malformed keys fail as auth errors instead of crashing request
|
|
1157
|
+
* setup.
|
|
1158
|
+
*
|
|
1159
|
+
* Intentionally does NOT remove ordinary spaces inside the string to avoid
|
|
1160
|
+
* silently altering "Bearer <token>" style values.
|
|
1161
|
+
*/
|
|
1162
|
+
function normalizeSecretInput(value) {
|
|
1163
|
+
if (typeof value !== "string") return "";
|
|
1164
|
+
const collapsed = value.replace(/[\r\n\u2028\u2029]+/g, "");
|
|
1165
|
+
let latin1Only = "";
|
|
1166
|
+
for (const char of collapsed) {
|
|
1167
|
+
const codePoint = char.codePointAt(0);
|
|
1168
|
+
if (typeof codePoint === "number" && codePoint <= 255) latin1Only += char;
|
|
1169
|
+
}
|
|
1170
|
+
return latin1Only.trim();
|
|
1171
|
+
}
|
|
1172
|
+
function normalizeOptionalSecretInput(value) {
|
|
1173
|
+
const normalized = normalizeSecretInput(value);
|
|
1174
|
+
return normalized ? normalized : void 0;
|
|
1175
|
+
}
|
|
1176
|
+
//#endregion
|
|
1177
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/model-auth-markers-U2294Wcj.js
|
|
1178
|
+
function resolveProviderEnvApiKeyCandidates(params) {
|
|
1179
|
+
return resolveProviderAuthEnvVarCandidates(params);
|
|
1180
|
+
}
|
|
1181
|
+
resolveProviderEnvApiKeyCandidates();
|
|
1182
|
+
function listKnownProviderEnvApiKeyNames() {
|
|
1183
|
+
return listKnownProviderAuthEnvVarNames();
|
|
1184
|
+
}
|
|
1185
|
+
const OAUTH_API_KEY_MARKER_PREFIX = "oauth:";
|
|
1186
|
+
const CUSTOM_LOCAL_AUTH_MARKER = "custom-local";
|
|
1187
|
+
const GCP_VERTEX_CREDENTIALS_MARKER = "gcp-vertex-credentials";
|
|
1188
|
+
const NON_ENV_SECRETREF_MARKER = "secretref-managed";
|
|
1189
|
+
const SECRETREF_ENV_HEADER_MARKER_PREFIX = "secretref-env:";
|
|
1190
|
+
const AWS_SDK_ENV_MARKERS = new Set([
|
|
1191
|
+
"AWS_BEARER_TOKEN_BEDROCK",
|
|
1192
|
+
"AWS_ACCESS_KEY_ID",
|
|
1193
|
+
"AWS_PROFILE"
|
|
1194
|
+
]);
|
|
1195
|
+
const CORE_NON_SECRET_API_KEY_MARKERS = [CUSTOM_LOCAL_AUTH_MARKER, NON_ENV_SECRETREF_MARKER];
|
|
1196
|
+
let knownEnvApiKeyMarkersCache;
|
|
1197
|
+
let knownNonSecretApiKeyMarkersCache;
|
|
1198
|
+
const LEGACY_ENV_API_KEY_MARKERS = [
|
|
1199
|
+
"GOOGLE_API_KEY",
|
|
1200
|
+
"DEEPSEEK_API_KEY",
|
|
1201
|
+
"PERPLEXITY_API_KEY",
|
|
1202
|
+
"FIREWORKS_API_KEY",
|
|
1203
|
+
"NOVITA_API_KEY",
|
|
1204
|
+
"AZURE_OPENAI_API_KEY",
|
|
1205
|
+
"AZURE_API_KEY",
|
|
1206
|
+
"MINIMAX_CODE_PLAN_KEY"
|
|
1207
|
+
];
|
|
1208
|
+
function listKnownEnvApiKeyMarkers() {
|
|
1209
|
+
knownEnvApiKeyMarkersCache ??= new Set([
|
|
1210
|
+
...listKnownProviderEnvApiKeyNames(),
|
|
1211
|
+
...LEGACY_ENV_API_KEY_MARKERS,
|
|
1212
|
+
...AWS_SDK_ENV_MARKERS
|
|
1213
|
+
]);
|
|
1214
|
+
return knownEnvApiKeyMarkersCache;
|
|
1215
|
+
}
|
|
1216
|
+
function listKnownNonSecretApiKeyMarkers() {
|
|
1217
|
+
knownNonSecretApiKeyMarkersCache ??= [...new Set([...CORE_NON_SECRET_API_KEY_MARKERS, ...loadPluginManifestRegistry({ cache: true }).plugins.flatMap((plugin) => plugin.origin === "bundled" ? plugin.nonSecretAuthMarkers ?? [] : [])])];
|
|
1218
|
+
return [...knownNonSecretApiKeyMarkersCache];
|
|
1219
|
+
}
|
|
1220
|
+
function isAwsSdkAuthMarker(value) {
|
|
1221
|
+
return AWS_SDK_ENV_MARKERS.has(value.trim());
|
|
1222
|
+
}
|
|
1223
|
+
function isKnownEnvApiKeyMarker(value) {
|
|
1224
|
+
const trimmed = value.trim();
|
|
1225
|
+
return listKnownEnvApiKeyMarkers().has(trimmed) && !isAwsSdkAuthMarker(trimmed);
|
|
1226
|
+
}
|
|
1227
|
+
function isOAuthApiKeyMarker(value) {
|
|
1228
|
+
return value.trim().startsWith(OAUTH_API_KEY_MARKER_PREFIX);
|
|
1229
|
+
}
|
|
1230
|
+
function resolveNonEnvSecretRefApiKeyMarker(_source) {
|
|
1231
|
+
return NON_ENV_SECRETREF_MARKER;
|
|
1232
|
+
}
|
|
1233
|
+
function resolveNonEnvSecretRefHeaderValueMarker(_source) {
|
|
1234
|
+
return NON_ENV_SECRETREF_MARKER;
|
|
1235
|
+
}
|
|
1236
|
+
function resolveEnvSecretRefHeaderValueMarker(envVarName) {
|
|
1237
|
+
return `${SECRETREF_ENV_HEADER_MARKER_PREFIX}${envVarName.trim()}`;
|
|
1238
|
+
}
|
|
1239
|
+
function isNonSecretApiKeyMarker(value, opts) {
|
|
1240
|
+
const trimmed = value.trim();
|
|
1241
|
+
if (!trimmed) return false;
|
|
1242
|
+
if (isOAuthApiKeyMarker(trimmed) || listKnownNonSecretApiKeyMarkers().includes(trimmed) || isAwsSdkAuthMarker(trimmed)) return true;
|
|
1243
|
+
if (opts?.includeEnvVarName === false) return false;
|
|
1244
|
+
return listKnownEnvApiKeyMarkers().has(trimmed);
|
|
1245
|
+
}
|
|
1246
|
+
//#endregion
|
|
1247
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/model-auth-env-oyg2Hexc.js
|
|
1248
|
+
function hasGoogleVertexAdcCredentials(env) {
|
|
1249
|
+
const explicitCredentialsPath = normalizeOptionalSecretInput(env.GOOGLE_APPLICATION_CREDENTIALS);
|
|
1250
|
+
if (explicitCredentialsPath) return fs.existsSync(explicitCredentialsPath);
|
|
1251
|
+
const homeDir = normalizeOptionalSecretInput(env.HOME) ?? os.homedir();
|
|
1252
|
+
return fs.existsSync(path.join(homeDir, ".config", "gcloud", "application_default_credentials.json"));
|
|
1253
|
+
}
|
|
1254
|
+
function resolveGoogleVertexEnvApiKey(env) {
|
|
1255
|
+
const explicitApiKey = normalizeOptionalSecretInput(env.GOOGLE_CLOUD_API_KEY);
|
|
1256
|
+
if (explicitApiKey) return explicitApiKey;
|
|
1257
|
+
const hasProject = Boolean(env.GOOGLE_CLOUD_PROJECT || env.GCLOUD_PROJECT);
|
|
1258
|
+
const hasLocation = Boolean(env.GOOGLE_CLOUD_LOCATION);
|
|
1259
|
+
return hasProject && hasLocation && hasGoogleVertexAdcCredentials(env) ? GCP_VERTEX_CREDENTIALS_MARKER : void 0;
|
|
1260
|
+
}
|
|
1261
|
+
function resolveEnvApiKey(provider, env = process.env) {
|
|
1262
|
+
const normalized = resolveProviderIdForAuth(provider, { env });
|
|
1263
|
+
const candidateMap = resolveProviderEnvApiKeyCandidates({ env });
|
|
1264
|
+
const applied = new Set(getShellEnvAppliedKeys());
|
|
1265
|
+
const pick = (envVar) => {
|
|
1266
|
+
const value = normalizeOptionalSecretInput(env[envVar]);
|
|
1267
|
+
if (!value) return null;
|
|
1268
|
+
return {
|
|
1269
|
+
apiKey: value,
|
|
1270
|
+
source: applied.has(envVar) ? `shell env: ${envVar}` : `env: ${envVar}`
|
|
1271
|
+
};
|
|
1272
|
+
};
|
|
1273
|
+
const candidates = Object.hasOwn(candidateMap, normalized) ? candidateMap[normalized] : void 0;
|
|
1274
|
+
if (Array.isArray(candidates)) {
|
|
1275
|
+
for (const envVar of candidates) {
|
|
1276
|
+
const resolved = pick(envVar);
|
|
1277
|
+
if (resolved) return resolved;
|
|
1278
|
+
}
|
|
1279
|
+
return null;
|
|
1280
|
+
}
|
|
1281
|
+
if (normalized === "google-vertex") {
|
|
1282
|
+
const envKey = resolveGoogleVertexEnvApiKey(env);
|
|
1283
|
+
if (!envKey) return null;
|
|
1284
|
+
return {
|
|
1285
|
+
apiKey: envKey,
|
|
1286
|
+
source: "gcloud adc"
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
const setupProvider = resolvePluginSetupProvider({
|
|
1290
|
+
provider: normalized,
|
|
1291
|
+
env
|
|
1292
|
+
});
|
|
1293
|
+
if (setupProvider?.resolveConfigApiKey) {
|
|
1294
|
+
const resolved = setupProvider.resolveConfigApiKey({
|
|
1295
|
+
provider: normalized,
|
|
1296
|
+
env
|
|
1297
|
+
});
|
|
1298
|
+
if (resolved?.trim()) return {
|
|
1299
|
+
apiKey: resolved,
|
|
1300
|
+
source: resolved === "gcp-vertex-credentials" ? "gcloud adc" : "env"
|
|
1301
|
+
};
|
|
1302
|
+
}
|
|
1303
|
+
return null;
|
|
1304
|
+
}
|
|
1305
|
+
//#endregion
|
|
1306
|
+
export { resolveAuthStorePath as A, log$1 as C, shouldBootstrapFromExternalCliCredential as D, saveAuthProfileStore as E, resolveOAuthRefreshLockPath as M, resolveOpenClawAgentDir as N, shouldReplaceStoredOAuthCredential as O, withFileLock as P, loadAuthProfileStoreForSecretsRuntime as S, resolveTokenExpiryState as T, ensureAuthStoreFile as _, isNonSecretApiKeyMarker as a, isSafeToAdoptBootstrapOAuthIdentity as b, resolveNonEnvSecretRefHeaderValueMarker as c, normalizeSecretInput as d, AUTH_STORE_LOCK_OPTIONS as f, ensureAuthProfileStore as g, areOAuthCredentialsEquivalent as h, isKnownEnvApiKeyMarker as i, resolveAuthStorePathForDisplay as j, updateAuthProfileStoreWithLock as k, resolveProviderEnvApiKeyCandidates as l, OAUTH_REFRESH_LOCK_OPTIONS as m, CUSTOM_LOCAL_AUTH_MARKER as n, resolveEnvSecretRefHeaderValueMarker as o, OAUTH_REFRESH_CALL_TIMEOUT_MS as p, NON_ENV_SECRETREF_MARKER as r, resolveNonEnvSecretRefApiKeyMarker as s, resolveEnvApiKey as t, normalizeOptionalSecretInput as u, evaluateStoredCredentialEligibility as v, readManagedExternalCliCredential as w, isSafeToAdoptMainStoreOAuthIdentity as x, hasUsableOAuthCredential as y };
|