@rynfar/meridian 1.41.1 → 1.42.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -4
- package/dist/cli-3jqvrake.js +279 -0
- package/dist/{cli-e289rj3k.js → cli-7k1fcprd.js} +64 -1
- package/dist/{cli-51a9sav0.js → cli-8xzxm1cq.js} +115 -283
- package/dist/{cli-vdp9s10c.js → cli-cx463q74.js} +8 -0
- package/dist/cli.js +25 -12
- package/dist/{profileCli-5f15dx7k.js → profileCli-c7cvkv5q.js} +129 -17
- package/dist/{profiles-edzz1ffd.js → profiles-rdd84b45.js} +1 -1
- package/dist/proxy/cwd.d.ts +42 -0
- package/dist/proxy/cwd.d.ts.map +1 -0
- package/dist/proxy/errors.d.ts +14 -4
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/models.d.ts +57 -4
- package/dist/proxy/models.d.ts.map +1 -1
- package/dist/proxy/oauthUsage.d.ts +17 -7
- package/dist/proxy/oauthUsage.d.ts.map +1 -1
- package/dist/proxy/plugins/loader.d.ts.map +1 -1
- package/dist/proxy/profiles.d.ts +12 -4
- package/dist/proxy/profiles.d.ts.map +1 -1
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/tokenRefresh.d.ts +41 -0
- package/dist/proxy/tokenRefresh.d.ts.map +1 -1
- package/dist/server.js +4 -3
- package/dist/{tokenRefresh-psq94r54.js → tokenRefresh-swetnf89.js} +10 -2
- package/package.json +2 -2
|
@@ -86,6 +86,14 @@ function resolveProfile(profiles, defaultProfile, requestedId) {
|
|
|
86
86
|
return buildResolvedProfile(profile);
|
|
87
87
|
}
|
|
88
88
|
function buildResolvedProfile(profile) {
|
|
89
|
+
if (profile.oauthToken || profile.type === "oauth-token") {
|
|
90
|
+
const env2 = {};
|
|
91
|
+
if (profile.oauthToken) {
|
|
92
|
+
env2.CLAUDE_CODE_OAUTH_TOKEN = profile.oauthToken;
|
|
93
|
+
env2.CLAUDE_CONFIG_DIR = join(homedir(), ".config", "meridian", "profiles", profile.id);
|
|
94
|
+
}
|
|
95
|
+
return { id: profile.id, type: "oauth-token", env: env2 };
|
|
96
|
+
}
|
|
89
97
|
const type = profile.type ?? "claude-max";
|
|
90
98
|
if (type === "api") {
|
|
91
99
|
const env2 = {};
|
package/dist/cli.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
startProxyServer
|
|
4
|
-
} from "./cli-
|
|
5
|
-
import"./cli-
|
|
4
|
+
} from "./cli-8xzxm1cq.js";
|
|
5
|
+
import"./cli-cx463q74.js";
|
|
6
6
|
import"./cli-sry5aqdj.js";
|
|
7
7
|
import"./cli-4rqtm83g.js";
|
|
8
|
+
import {
|
|
9
|
+
resolveClaudeExecutableAsync
|
|
10
|
+
} from "./cli-3jqvrake.js";
|
|
8
11
|
import"./cli-340h1chz.js";
|
|
9
12
|
import"./cli-rtab0qa6.js";
|
|
10
|
-
import"./cli-
|
|
13
|
+
import"./cli-7k1fcprd.js";
|
|
11
14
|
import {
|
|
12
15
|
__require
|
|
13
16
|
} from "./cli-p9swy5t3.js";
|
|
14
17
|
|
|
15
18
|
// bin/cli.ts
|
|
16
19
|
import { createRequire } from "module";
|
|
17
|
-
import { exec as execCallback } from "child_process";
|
|
20
|
+
import { exec as execCallback, execFile as execFileCallback } from "child_process";
|
|
18
21
|
import { promisify } from "util";
|
|
19
22
|
var require2 = createRequire(import.meta.url);
|
|
20
23
|
var { version } = require2("../package.json");
|
|
@@ -50,12 +53,18 @@ See https://github.com/rynfar/meridian for full documentation.`);
|
|
|
50
53
|
process.exit(0);
|
|
51
54
|
}
|
|
52
55
|
if (args[0] === "profile") {
|
|
53
|
-
const { profileAdd, profileList, profileRemove, profileSwitch, profileLogin, profileHelp } = await import("./profileCli-
|
|
56
|
+
const { profileAdd, profileAddOauthToken, profileList, profileRemove, profileSwitch, profileLogin, profileHelp } = await import("./profileCli-c7cvkv5q.js");
|
|
54
57
|
const subcommand = args[1];
|
|
55
58
|
const profileId = args[2];
|
|
56
|
-
if (subcommand === "add" && profileId)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
if (subcommand === "add" && profileId) {
|
|
60
|
+
const oauthFlagIdx = args.indexOf("--oauth-token", 3);
|
|
61
|
+
if (oauthFlagIdx >= 0) {
|
|
62
|
+
const tokenArg = args[oauthFlagIdx + 1];
|
|
63
|
+
await profileAddOauthToken(profileId, tokenArg);
|
|
64
|
+
} else {
|
|
65
|
+
profileAdd(profileId);
|
|
66
|
+
}
|
|
67
|
+
} else if (subcommand === "list" || subcommand === "ls")
|
|
59
68
|
profileList();
|
|
60
69
|
else if (subcommand === "remove" && profileId)
|
|
61
70
|
profileRemove(profileId);
|
|
@@ -89,7 +98,7 @@ Restart OpenCode for the plugin to take effect.`);
|
|
|
89
98
|
process.exit(0);
|
|
90
99
|
}
|
|
91
100
|
if (args[0] === "refresh-token") {
|
|
92
|
-
const { refreshOAuthToken } = await import("./tokenRefresh-
|
|
101
|
+
const { refreshOAuthToken } = await import("./tokenRefresh-swetnf89.js");
|
|
93
102
|
const success = await refreshOAuthToken();
|
|
94
103
|
if (success) {
|
|
95
104
|
console.log("Token refreshed successfully");
|
|
@@ -100,6 +109,7 @@ if (args[0] === "refresh-token") {
|
|
|
100
109
|
}
|
|
101
110
|
}
|
|
102
111
|
var exec = promisify(execCallback);
|
|
112
|
+
var execFile = promisify(execFileCallback);
|
|
103
113
|
process.on("uncaughtException", (err) => {
|
|
104
114
|
console.error(`[PROXY] Uncaught exception (recovered): ${err.message}`);
|
|
105
115
|
});
|
|
@@ -120,7 +130,10 @@ try {
|
|
|
120
130
|
} catch (e) {
|
|
121
131
|
console.error(`[meridian] Failed to parse MERIDIAN_PROFILES: ${e instanceof Error ? e.message : e}`);
|
|
122
132
|
}
|
|
123
|
-
async function runCli(start = startProxyServer,
|
|
133
|
+
async function runCli(start = startProxyServer, runAuthCheck = async () => {
|
|
134
|
+
const claudePath = await resolveClaudeExecutableAsync();
|
|
135
|
+
return execFile(claudePath, ["auth", "status"], { timeout: 5000 });
|
|
136
|
+
}) {
|
|
124
137
|
try {
|
|
125
138
|
const { findOpencodeConfigPath, checkPluginConfigured, findPluginPath } = await import("./setup-v5pnqe04.js");
|
|
126
139
|
const configPath = findOpencodeConfigPath();
|
|
@@ -134,7 +147,7 @@ async function runCli(start = startProxyServer, runExec = exec) {
|
|
|
134
147
|
}
|
|
135
148
|
} catch {}
|
|
136
149
|
try {
|
|
137
|
-
const { stdout } = await
|
|
150
|
+
const { stdout } = await runAuthCheck();
|
|
138
151
|
const auth = JSON.parse(stdout);
|
|
139
152
|
if (!auth.loggedIn) {
|
|
140
153
|
console.error("\x1B[31m✗ Not logged in to Claude.\x1B[0m Run: claude login");
|
|
@@ -147,7 +160,7 @@ async function runCli(start = startProxyServer, runExec = exec) {
|
|
|
147
160
|
console.error("\x1B[33m⚠ Could not verify Claude auth status. If requests fail, run: claude login\x1B[0m");
|
|
148
161
|
}
|
|
149
162
|
if (!profiles) {
|
|
150
|
-
const { enableDiskProfileDiscovery } = await import("./profiles-
|
|
163
|
+
const { enableDiskProfileDiscovery } = await import("./profiles-rdd84b45.js");
|
|
151
164
|
enableDiskProfileDiscovery();
|
|
152
165
|
}
|
|
153
166
|
const proxy = await start({ port, host, idleTimeoutSeconds, profiles, defaultProfile, version });
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveClaudeExecutableSync
|
|
3
|
+
} from "./cli-3jqvrake.js";
|
|
1
4
|
import {
|
|
2
5
|
setSetting
|
|
3
6
|
} from "./cli-340h1chz.js";
|
|
@@ -6,7 +9,7 @@ import"./cli-p9swy5t3.js";
|
|
|
6
9
|
// src/proxy/profileCli.ts
|
|
7
10
|
import { mkdirSync, existsSync, rmSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
11
|
import { join } from "node:path";
|
|
9
|
-
import {
|
|
12
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
10
13
|
import { homedir } from "node:os";
|
|
11
14
|
var PROFILES_DIR = join(homedir(), ".config", "meridian", "profiles");
|
|
12
15
|
var CONFIG_FILE = join(homedir(), ".config", "meridian", "profiles.json");
|
|
@@ -32,8 +35,13 @@ function saveProfileConfig(profiles) {
|
|
|
32
35
|
`, { mode: 384 });
|
|
33
36
|
}
|
|
34
37
|
function getAuthStatus(configDir) {
|
|
38
|
+
const resolved = resolveClaudeExecutableSync();
|
|
39
|
+
if (!resolved) {
|
|
40
|
+
console.warn(`[meridian] Could not resolve a Claude executable for auth check (set MERIDIAN_CLAUDE_PATH or install @anthropic-ai/claude-code)`);
|
|
41
|
+
return { loggedIn: false };
|
|
42
|
+
}
|
|
35
43
|
try {
|
|
36
|
-
const result =
|
|
44
|
+
const result = execFileSync(resolved.path, ["auth", "status"], {
|
|
37
45
|
timeout: 5000,
|
|
38
46
|
env: { ...process.env, CLAUDE_CONFIG_DIR: configDir },
|
|
39
47
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -97,7 +105,13 @@ function profileAdd(id) {
|
|
|
97
105
|
console.log();
|
|
98
106
|
console.log(" Press Ctrl+C to cancel, or wait for the browser to open...");
|
|
99
107
|
console.log();
|
|
100
|
-
const
|
|
108
|
+
const resolvedAuth = resolveClaudeExecutableSync();
|
|
109
|
+
if (!resolvedAuth) {
|
|
110
|
+
console.error("\x1B[31m✗ Could not find a Claude executable to run auth login.\x1B[0m");
|
|
111
|
+
console.error(" Install via: npm install -g @anthropic-ai/claude-code, or set MERIDIAN_CLAUDE_PATH=/path/to/claude");
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
const result = spawnSync(resolvedAuth.path, ["auth", "login"], {
|
|
101
115
|
env: { ...process.env, CLAUDE_CONFIG_DIR: configDir },
|
|
102
116
|
stdio: "inherit"
|
|
103
117
|
});
|
|
@@ -116,6 +130,33 @@ function profileAdd(id) {
|
|
|
116
130
|
saveProfileConfig(profiles);
|
|
117
131
|
printEnvHint(profiles);
|
|
118
132
|
}
|
|
133
|
+
async function profileAddOauthToken(id, tokenArg) {
|
|
134
|
+
if (!id || /[^a-zA-Z0-9_-]/.test(id)) {
|
|
135
|
+
console.error("\x1B[31m✗ Invalid profile ID.\x1B[0m Use only letters, numbers, hyphens, underscores.");
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
const profiles = loadProfileConfig();
|
|
139
|
+
if (profiles.find((p) => p.id === id)) {
|
|
140
|
+
console.error(`\x1B[31m✗ Profile "${id}" already exists.\x1B[0m`);
|
|
141
|
+
console.error(` Run: meridian profile list`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
let token = tokenArg?.trim() ?? "";
|
|
145
|
+
if (!token) {
|
|
146
|
+
console.log(`\x1B[36mAdding profile: ${id} (OAuth token)\x1B[0m`);
|
|
147
|
+
console.log(` Generate a token with: \x1B[1mclaude setup-token\x1B[0m`);
|
|
148
|
+
console.log();
|
|
149
|
+
token = promptToken(`Paste OAuth token for "${id}" (input hidden):`);
|
|
150
|
+
}
|
|
151
|
+
if (!token) {
|
|
152
|
+
console.error("\x1B[31m✗ Empty token. Aborted.\x1B[0m");
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
profiles.push({ id, type: "oauth-token", oauthToken: token });
|
|
156
|
+
saveProfileConfig(profiles);
|
|
157
|
+
console.log(`\x1B[32m✓ Profile "${id}" added (OAuth token).\x1B[0m`);
|
|
158
|
+
printEnvHint(profiles);
|
|
159
|
+
}
|
|
119
160
|
function profileList() {
|
|
120
161
|
const profiles = loadProfileConfig();
|
|
121
162
|
if (profiles.length === 0) {
|
|
@@ -126,6 +167,10 @@ function profileList() {
|
|
|
126
167
|
console.log(`Profiles:
|
|
127
168
|
`);
|
|
128
169
|
for (const p of profiles) {
|
|
170
|
+
if (p.oauthToken || p.type === "oauth-token") {
|
|
171
|
+
console.log(` ${p.id.padEnd(20)} \x1B[32m✓ OAuth token\x1B[0m`);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
129
174
|
const auth = getAuthStatus(p.claudeConfigDir ?? "");
|
|
130
175
|
const status = auth.loggedIn ? `\x1B[32m✓ ${auth.email} (${auth.subscriptionType || "unknown"})\x1B[0m` : "\x1B[31m✗ not logged in\x1B[0m";
|
|
131
176
|
console.log(` ${p.id.padEnd(20)} ${status}`);
|
|
@@ -133,6 +178,18 @@ function profileList() {
|
|
|
133
178
|
console.log();
|
|
134
179
|
printEnvHint(profiles);
|
|
135
180
|
}
|
|
181
|
+
function dirsToRemoveOnProfileRemove(profile, profilesDir) {
|
|
182
|
+
const dirs = [];
|
|
183
|
+
if (profile.claudeConfigDir && profile.claudeConfigDir.startsWith(profilesDir)) {
|
|
184
|
+
dirs.push(profile.claudeConfigDir);
|
|
185
|
+
}
|
|
186
|
+
if (profile.oauthToken || profile.type === "oauth-token") {
|
|
187
|
+
const isolationDir = join(profilesDir, profile.id);
|
|
188
|
+
if (!dirs.includes(isolationDir))
|
|
189
|
+
dirs.push(isolationDir);
|
|
190
|
+
}
|
|
191
|
+
return dirs;
|
|
192
|
+
}
|
|
136
193
|
function profileRemove(id) {
|
|
137
194
|
const profiles = loadProfileConfig();
|
|
138
195
|
const idx = profiles.findIndex((p) => p.id === id);
|
|
@@ -140,11 +197,13 @@ function profileRemove(id) {
|
|
|
140
197
|
console.error(`\x1B[31m✗ Profile "${id}" not found.\x1B[0m`);
|
|
141
198
|
process.exit(1);
|
|
142
199
|
}
|
|
143
|
-
const
|
|
200
|
+
const removed = profiles[idx];
|
|
201
|
+
const dirsToRemove = dirsToRemoveOnProfileRemove(removed, PROFILES_DIR);
|
|
144
202
|
profiles.splice(idx, 1);
|
|
145
203
|
saveProfileConfig(profiles);
|
|
146
|
-
|
|
147
|
-
|
|
204
|
+
for (const dir of dirsToRemove) {
|
|
205
|
+
if (existsSync(dir))
|
|
206
|
+
rmSync(dir, { recursive: true, force: true });
|
|
148
207
|
}
|
|
149
208
|
console.log(`\x1B[32m✓ Profile "${id}" removed.\x1B[0m`);
|
|
150
209
|
if (profiles.length > 0) {
|
|
@@ -181,11 +240,22 @@ function profileLogin(id) {
|
|
|
181
240
|
console.error(`\x1B[31m✗ Profile "${id}" not found.\x1B[0m Run: meridian profile add ${id}`);
|
|
182
241
|
process.exit(1);
|
|
183
242
|
}
|
|
243
|
+
if (profile.oauthToken || profile.type === "oauth-token") {
|
|
244
|
+
console.error(`\x1B[31m✗ Profile "${id}" uses an OAuth token; \`claude auth login\` does not apply.\x1B[0m`);
|
|
245
|
+
console.error(` To replace the token: meridian profile remove ${id} && meridian profile add ${id} --oauth-token`);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
184
248
|
console.log(`\x1B[36mRe-authenticating profile: ${id}\x1B[0m`);
|
|
185
249
|
console.log();
|
|
186
250
|
console.log("\x1B[33m⚠ Make sure you're signed into the correct Claude account in your browser.\x1B[0m");
|
|
187
251
|
console.log();
|
|
188
|
-
const
|
|
252
|
+
const resolvedLogin = resolveClaudeExecutableSync();
|
|
253
|
+
if (!resolvedLogin) {
|
|
254
|
+
console.error("\x1B[31m✗ Could not find a Claude executable to run auth login.\x1B[0m");
|
|
255
|
+
console.error(" Install via: npm install -g @anthropic-ai/claude-code, or set MERIDIAN_CLAUDE_PATH=/path/to/claude");
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
const result = spawnSync(resolvedLogin.path, ["auth", "login"], {
|
|
189
259
|
env: { ...process.env, CLAUDE_CONFIG_DIR: profile.claudeConfigDir },
|
|
190
260
|
stdio: "inherit"
|
|
191
261
|
});
|
|
@@ -209,6 +279,41 @@ function promptYesNo(question) {
|
|
|
209
279
|
const answer = (result.stdout?.toString().trim() ?? "").toLowerCase();
|
|
210
280
|
return answer !== "n" && answer !== "no";
|
|
211
281
|
}
|
|
282
|
+
function promptToken(question) {
|
|
283
|
+
process.stderr.write(`${question}
|
|
284
|
+
> `);
|
|
285
|
+
const script = [
|
|
286
|
+
`const stdin = process.stdin;`,
|
|
287
|
+
`if (!stdin.isTTY) {`,
|
|
288
|
+
` let buf = "";`,
|
|
289
|
+
` stdin.setEncoding("utf8");`,
|
|
290
|
+
` stdin.on("data", (c) => { buf += c; });`,
|
|
291
|
+
` stdin.on("end", () => { process.stdout.write(buf.split(/\\r?\\n/)[0] || ""); process.exit(0); });`,
|
|
292
|
+
`} else {`,
|
|
293
|
+
` stdin.setRawMode(true); stdin.resume(); stdin.setEncoding("utf8");`,
|
|
294
|
+
` let input = "";`,
|
|
295
|
+
` stdin.on("data", (key) => {`,
|
|
296
|
+
` if (key === "\\u0003") { process.stderr.write("\\n"); process.exit(1); }`,
|
|
297
|
+
` else if (key === "\\r" || key === "\\n") {`,
|
|
298
|
+
` stdin.setRawMode(false); process.stderr.write("\\n");`,
|
|
299
|
+
` process.stdout.write(input); process.exit(0);`,
|
|
300
|
+
` }`,
|
|
301
|
+
` else if (key === "\\u007f" || key === "\\b") {`,
|
|
302
|
+
` if (input.length > 0) input = input.slice(0, -1);`,
|
|
303
|
+
` }`,
|
|
304
|
+
` else { input += key; }`,
|
|
305
|
+
` });`,
|
|
306
|
+
`}`
|
|
307
|
+
].join(`
|
|
308
|
+
`);
|
|
309
|
+
const result = spawnSync("node", ["-e", script], { stdio: ["inherit", "pipe", "inherit"] });
|
|
310
|
+
if (result.status !== 0) {
|
|
311
|
+
process.stderr.write(`
|
|
312
|
+
`);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
return (result.stdout?.toString() ?? "").trim();
|
|
316
|
+
}
|
|
212
317
|
function printEnvHint(_profiles) {
|
|
213
318
|
console.log(`\x1B[90mConfig: ${CONFIG_FILE}\x1B[0m`);
|
|
214
319
|
console.log("\x1B[90mProfiles are picked up automatically — no restart needed.\x1B[0m");
|
|
@@ -217,17 +322,22 @@ function profileHelp() {
|
|
|
217
322
|
console.log(`meridian profile — manage Claude account profiles
|
|
218
323
|
|
|
219
324
|
Commands:
|
|
220
|
-
meridian profile add <name>
|
|
221
|
-
meridian profile
|
|
222
|
-
|
|
223
|
-
meridian profile
|
|
224
|
-
meridian profile
|
|
325
|
+
meridian profile add <name> Add a profile via browser login
|
|
326
|
+
meridian profile add <name> --oauth-token [TOKEN] Add a profile from a \`claude setup-token\` value
|
|
327
|
+
(if TOKEN is omitted, you will be prompted; input is hidden)
|
|
328
|
+
meridian profile list List profiles and auth status
|
|
329
|
+
meridian profile remove <name> Remove a profile
|
|
330
|
+
meridian profile switch <name> Switch the active profile (requires running proxy)
|
|
331
|
+
meridian profile login <name> Re-authenticate an existing profile (claude-max only)
|
|
225
332
|
|
|
226
333
|
Examples:
|
|
227
|
-
meridian profile add personal
|
|
228
|
-
meridian profile add work
|
|
229
|
-
meridian profile
|
|
230
|
-
meridian profile
|
|
334
|
+
meridian profile add personal # Add personal account (browser login)
|
|
335
|
+
meridian profile add work # Add work account
|
|
336
|
+
meridian profile add ci --oauth-token # Add headless CI profile (prompted, no echo)
|
|
337
|
+
meridian profile add ci --oauth-token sk-ant-oat01-...
|
|
338
|
+
# Add headless CI profile (token from CLI argument)
|
|
339
|
+
meridian profile switch work # Switch to work account
|
|
340
|
+
meridian profile list # Show all profiles`);
|
|
231
341
|
}
|
|
232
342
|
export {
|
|
233
343
|
profileSwitch,
|
|
@@ -235,5 +345,7 @@ export {
|
|
|
235
345
|
profileLogin,
|
|
236
346
|
profileList,
|
|
237
347
|
profileHelp,
|
|
238
|
-
|
|
348
|
+
profileAddOauthToken,
|
|
349
|
+
profileAdd,
|
|
350
|
+
dirsToRemoveOnProfileRemove
|
|
239
351
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the SDK subprocess `cwd:` option, falling back to a known-valid
|
|
3
|
+
* path on the proxy host when the resolved working directory doesn't exist.
|
|
4
|
+
*
|
|
5
|
+
* Background — issue #381:
|
|
6
|
+
* When meridian runs on a remote machine (e.g. accessed over Tailscale)
|
|
7
|
+
* and the client (OpenCode/Crush/etc.) runs on a different machine, the
|
|
8
|
+
* adapter extracts the client's reported working directory and passes it
|
|
9
|
+
* to the SDK as `cwd:`. That path doesn't exist on the proxy host, so
|
|
10
|
+
* `child_process.spawn(claude, { cwd })` fails with ENOENT — which the
|
|
11
|
+
* SDK then reports as the misleading "Claude Code native binary not
|
|
12
|
+
* found at ..." error.
|
|
13
|
+
*
|
|
14
|
+
* Falling back to the proxy's own `process.cwd()` lets the SDK spawn
|
|
15
|
+
* succeed; `clientWorkingDirectory` is tracked separately (and emitted
|
|
16
|
+
* into the model's context via buildCwdNote) so the model still hears
|
|
17
|
+
* about the user's real working directory.
|
|
18
|
+
*/
|
|
19
|
+
export interface CwdResolution {
|
|
20
|
+
/** Path passed to the SDK as `cwd:`. Always exists on the proxy host. */
|
|
21
|
+
workingDirectory: string;
|
|
22
|
+
/**
|
|
23
|
+
* The originally-resolved path before existence validation. May not
|
|
24
|
+
* exist on the proxy host. Used as `clientWorkingDirectory` for
|
|
25
|
+
* fingerprint bucketing and the system-prompt cwdNote.
|
|
26
|
+
*/
|
|
27
|
+
claimedWorkingDirectory: string;
|
|
28
|
+
/** True if `workingDirectory` differs from `claimedWorkingDirectory`. */
|
|
29
|
+
fellBack: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface ResolveCwdOpts {
|
|
32
|
+
/** MERIDIAN_WORKDIR / CLAUDE_PROXY_WORKDIR (highest precedence). */
|
|
33
|
+
envOverride: string | undefined;
|
|
34
|
+
/** Adapter's extracted client working directory. */
|
|
35
|
+
adapterCwd: string | undefined;
|
|
36
|
+
/** Last-resort fallback. Must exist; typically `process.cwd()`. */
|
|
37
|
+
fallback: string;
|
|
38
|
+
/** Injection point for tests. Defaults to `node:fs`'s existsSync. */
|
|
39
|
+
exists?: (path: string) => boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare function resolveSdkWorkingDirectory(opts: ResolveCwdOpts): CwdResolution;
|
|
42
|
+
//# sourceMappingURL=cwd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cwd.d.ts","sourceRoot":"","sources":["../../src/proxy/cwd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,uBAAuB,EAAE,MAAM,CAAA;IAC/B,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,oDAAoD;IACpD,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAA;IAChB,qEAAqE;IACrE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;CACnC;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,cAAc,GAAG,aAAa,CAO9E"}
|
package/dist/proxy/errors.d.ts
CHANGED
|
@@ -15,10 +15,20 @@ export declare function classifyError(errMsg: string): ClassifiedError;
|
|
|
15
15
|
* Detect errors caused by an expired or missing OAuth access token.
|
|
16
16
|
* Triggers an inline token refresh + retry in server.ts.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
* - "OAuth token has expired"
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* Patterns, in order of specificity:
|
|
19
|
+
* - "OAuth token has expired" / "Not logged in" — CLI-emitted (subprocess
|
|
20
|
+
* either got 401 with this wording from Anthropic or detected expiry
|
|
21
|
+
* locally before sending).
|
|
22
|
+
* - "invalid_token" / "token_expired" — RFC 6750 resource-server errors that
|
|
23
|
+
* can appear in the API response body.
|
|
24
|
+
* - "401" + ("authentication" | "unauthorized" | "invalid") — generic 401
|
|
25
|
+
* wrapping. Anthropic's API does not always echo the CLI-specific wording,
|
|
26
|
+
* so without this branch a stale access token returns a generic 401 to the
|
|
27
|
+
* proxy and refresh-and-retry never fires (caller sees the 401).
|
|
28
|
+
*
|
|
29
|
+
* False positives only cost one OAuth round-trip — the refresh is single-shot
|
|
30
|
+
* per request (gated by `tokenRefreshed` in server.ts) and surfaces the
|
|
31
|
+
* original error if it doesn't help.
|
|
22
32
|
*/
|
|
23
33
|
export declare function isExpiredTokenError(errMsg: string): boolean;
|
|
24
34
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/proxy/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CA+G7D;AAED
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/proxy/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CA+G7D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAM3D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAO3D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGjE;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,GAAG,cAAc,GAAG,SAAS,GAAG,SAAS,CAAA;IAC5D,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;wCAEoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAuBD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAuCpE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,EAAE,cAAc,EACjB,GAAG,EAAE;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GACA,MAAM,CAYR"}
|
package/dist/proxy/models.d.ts
CHANGED
|
@@ -25,8 +25,12 @@ export declare const CANONICAL_HAIKU_MODEL = "claude-haiku-4-5";
|
|
|
25
25
|
* Build the ANTHROPIC_DEFAULT_{TYPE}_MODEL env record to apply before the
|
|
26
26
|
* inherited process env, so user-set shell values still win but unset
|
|
27
27
|
* variables get Meridian's canonical pins.
|
|
28
|
+
*
|
|
29
|
+
* Accepts an optional `env` arg so unit tests can pass a synthetic env
|
|
30
|
+
* map instead of mutating process.env (which leaks between parallel
|
|
31
|
+
* test files).
|
|
28
32
|
*/
|
|
29
|
-
export declare function resolveSdkModelDefaults(): Record<string, string>;
|
|
33
|
+
export declare function resolveSdkModelDefaults(env?: NodeJS.ProcessEnv): Record<string, string>;
|
|
30
34
|
export interface ClaudeAuthStatus {
|
|
31
35
|
loggedIn?: boolean;
|
|
32
36
|
subscriptionType?: string;
|
|
@@ -71,6 +75,18 @@ export declare function getAuthCacheInfo(profileId?: string): {
|
|
|
71
75
|
* @param envOverrides - Optional env vars for per-profile auth (e.g. CLAUDE_CONFIG_DIR).
|
|
72
76
|
*/
|
|
73
77
|
export declare function getClaudeAuthStatusAsync(profileId?: string, envOverrides?: Record<string, string>): Promise<ClaudeAuthStatus | null>;
|
|
78
|
+
/**
|
|
79
|
+
* Tag identifying which resolver step produced the path. Surfaced at startup
|
|
80
|
+
* and in `/health` so users can self-diagnose "wrong claude got picked"
|
|
81
|
+
* without having to inspect their PATH manually (closes the diagnostic gap
|
|
82
|
+
* from #478, where a Bun-shimmed `claude` on PATH led to silent failures
|
|
83
|
+
* that looked indistinguishable from any other SDK error).
|
|
84
|
+
*/
|
|
85
|
+
export type ClaudeExecutableSource = "env" | "bundled" | "platform-package" | "path-lookup" | "legacy-cli-js";
|
|
86
|
+
export interface ClaudeExecutableInfo {
|
|
87
|
+
path: string;
|
|
88
|
+
source: ClaudeExecutableSource;
|
|
89
|
+
}
|
|
74
90
|
/**
|
|
75
91
|
* Resolve the Claude executable path asynchronously (non-blocking).
|
|
76
92
|
*
|
|
@@ -102,11 +118,48 @@ type ResolverDeps = {
|
|
|
102
118
|
isBun: boolean;
|
|
103
119
|
};
|
|
104
120
|
/**
|
|
105
|
-
* Pure resolver — runs each step and returns the
|
|
106
|
-
*
|
|
107
|
-
*
|
|
121
|
+
* Pure resolver, source-aware variant — runs each step and returns the
|
|
122
|
+
* first hit (path + source tag), or null when all steps miss.
|
|
123
|
+
*
|
|
124
|
+
* Order matters: `env` wins unconditionally (operator escape hatch), then
|
|
125
|
+
* `bundled` (the path the SDK expects), then `platform-package` (postinstall
|
|
126
|
+
* fallback), then `path-lookup` (system PATH — most likely to surface
|
|
127
|
+
* unintended shims, see #478), then `legacy-cli-js` (only matters on stale
|
|
128
|
+
* Bun installs of SDK < 0.2.98).
|
|
129
|
+
*/
|
|
130
|
+
export declare function resolveClaudeExecutableWithSource(deps?: ResolverDeps): Promise<ClaudeExecutableInfo | null>;
|
|
131
|
+
/**
|
|
132
|
+
* Pure resolver — returns the path string only. Kept for callers that
|
|
133
|
+
* don't need the source tag (existing behavior; preserves the existing
|
|
134
|
+
* test surface in claude-executable-resolver.test.ts).
|
|
108
135
|
*/
|
|
109
136
|
export declare function resolveClaudeExecutable(deps?: ResolverDeps): Promise<string | null>;
|
|
137
|
+
/**
|
|
138
|
+
* Synchronous subset of the resolver. Used by CLI commands
|
|
139
|
+
* (`meridian profile list`, `profileAdd`, etc.) that can't await before
|
|
140
|
+
* spawning `claude auth status`.
|
|
141
|
+
*
|
|
142
|
+
* Skips two steps that the async resolver runs:
|
|
143
|
+
* - `path-lookup` — running `which`/`where` synchronously is awkward
|
|
144
|
+
* and platform-fragile; the audit showed bundled + platform-package
|
|
145
|
+
* covers every supported install layout (npm-global, npx/bunx
|
|
146
|
+
* download, Docker, NixOS).
|
|
147
|
+
* - `legacy-cli-js` — only matters for stale Bun installs of SDK < 0.2.98.
|
|
148
|
+
*
|
|
149
|
+
* Closes the diagnostic gap from #478: `getAuthStatus` in profileCli.ts
|
|
150
|
+
* and `getClaudeAuthStatusAsync` in this file previously called
|
|
151
|
+
* `claude auth status` via shell, which fails when `claude` isn't on
|
|
152
|
+
* PATH (Stefan's case — bunx-installed meridian under systemd, no
|
|
153
|
+
* global claude). Both call sites now route through resolved paths.
|
|
154
|
+
*/
|
|
155
|
+
export declare function resolveClaudeExecutableSync(deps?: ResolverDeps): ClaudeExecutableInfo | null;
|
|
156
|
+
/**
|
|
157
|
+
* Returns the cached resolved-executable info — `null` if
|
|
158
|
+
* `resolveClaudeExecutableAsync` hasn't run yet. Used by `/health` and the
|
|
159
|
+
* startup log so the resolver only runs once and both surfaces see the
|
|
160
|
+
* same answer.
|
|
161
|
+
*/
|
|
162
|
+
export declare function getResolvedClaudeExecutableInfo(): ClaudeExecutableInfo | null;
|
|
110
163
|
export declare function resolveClaudeExecutableAsync(): Promise<string>;
|
|
111
164
|
/** Reset cached path — for testing only */
|
|
112
165
|
export declare function resetCachedClaudePath(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/proxy/models.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/proxy/models.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,6 +37,19 @@ export interface OAuthUsageSnapshot {
|
|
|
37
37
|
extraUsage: OAuthExtraUsageInfo | null;
|
|
38
38
|
fetchedAt: number;
|
|
39
39
|
}
|
|
40
|
+
/** Minimal fetch shape used by callAnthropic. Avoids `typeof fetch`'s
|
|
41
|
+
* `preconnect` property, which makes test casts unwieldy. */
|
|
42
|
+
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
43
|
+
export interface FetchOAuthUsageOpts {
|
|
44
|
+
ttlMs?: number;
|
|
45
|
+
force?: boolean;
|
|
46
|
+
store?: CredentialStore;
|
|
47
|
+
profileId?: string | null;
|
|
48
|
+
claudeConfigDir?: string;
|
|
49
|
+
fetchImpl?: FetchLike;
|
|
50
|
+
}
|
|
51
|
+
/** Test-only setter. Pass `null` to clear. */
|
|
52
|
+
export declare function __setFetchOAuthUsageOverride(fn: ((opts?: FetchOAuthUsageOpts) => Promise<OAuthUsageSnapshot | null>) | null): void;
|
|
40
53
|
/**
|
|
41
54
|
* Fetch latest OAuth usage for a specific profile (or the default OAuth
|
|
42
55
|
* account if none specified). Returns null if no OAuth token is available
|
|
@@ -54,14 +67,11 @@ export interface OAuthUsageSnapshot {
|
|
|
54
67
|
* @param claudeConfigDir When provided, reads credentials from this dir's
|
|
55
68
|
* keychain entry (macOS) or `.credentials.json`
|
|
56
69
|
* (Linux) instead of the platform default.
|
|
70
|
+
* @param fetchImpl Override the fetch implementation (for testing).
|
|
71
|
+
* Defaults to globalThis.fetch.
|
|
57
72
|
*/
|
|
58
|
-
export declare function fetchOAuthUsage(opts?:
|
|
59
|
-
ttlMs?: number;
|
|
60
|
-
force?: boolean;
|
|
61
|
-
store?: CredentialStore;
|
|
62
|
-
profileId?: string | null;
|
|
63
|
-
claudeConfigDir?: string;
|
|
64
|
-
}): Promise<OAuthUsageSnapshot | null>;
|
|
73
|
+
export declare function fetchOAuthUsage(opts?: FetchOAuthUsageOpts): Promise<OAuthUsageSnapshot | null>;
|
|
65
74
|
/** Test-only / shutdown helper — clears all cached snapshots and pending fetches. */
|
|
66
75
|
export declare function resetOAuthUsageCache(): void;
|
|
76
|
+
export {};
|
|
67
77
|
//# sourceMappingURL=oauthUsage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauthUsage.d.ts","sourceRoot":"","sources":["../../src/proxy/oauthUsage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAoD,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAgCvG,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAA;IACtC,SAAS,EAAE,MAAM,CAAA;CAClB;
|
|
1
|
+
{"version":3,"file":"oauthUsage.d.ts","sourceRoot":"","sources":["../../src/proxy/oauthUsage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAoD,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAgCvG,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAA;IACtC,SAAS,EAAE,MAAM,CAAA;CAClB;AA6DD;8DAC8D;AAC9D,KAAK,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAmBzE,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB;AAcD,8CAA8C;AAC9C,wBAAgB,4BAA4B,CAC1C,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,GAC9E,IAAI,CAEN;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,eAAe,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAOpG;AAqDD,qFAAqF;AACrF,wBAAgB,oBAAoB,IAAI,IAAI,CAG3C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/proxy/plugins/loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/proxy/plugins/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAgB,YAAY,EAAE,MAAM,SAAS,CAAA;AAStE,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE,CASnE;AAED,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,EAAE,CAAC,CA+IzB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,SAAS,EAAE,CAIxE"}
|
package/dist/proxy/profiles.d.ts
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Multi-profile support.
|
|
3
3
|
*
|
|
4
4
|
* Allows a single Meridian instance to route requests to different Claude
|
|
5
|
-
* accounts. Each profile is a named auth context
|
|
6
|
-
* Max subscriptions,
|
|
5
|
+
* accounts. Each profile is a named auth context — a CLAUDE_CONFIG_DIR for
|
|
6
|
+
* Max subscriptions, an Anthropic API key for direct API access, or a
|
|
7
|
+
* long-lived OAuth token minted by `claude setup-token`.
|
|
7
8
|
*
|
|
8
9
|
* Profile selection priority:
|
|
9
10
|
* 1. x-meridian-profile request header (per-request override)
|
|
@@ -18,11 +19,16 @@
|
|
|
18
19
|
* while avoiding synchronous disk I/O on every request.
|
|
19
20
|
*/
|
|
20
21
|
export declare function loadProfilesFromDisk(): ProfileConfig[];
|
|
21
|
-
export type ProfileType = "claude-max" | "api";
|
|
22
|
+
export type ProfileType = "claude-max" | "api" | "oauth-token";
|
|
22
23
|
export interface ProfileConfig {
|
|
23
24
|
/** Unique profile identifier (e.g. "personal", "work") */
|
|
24
25
|
id: string;
|
|
25
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Auth type. Inferred from the populated credential field when omitted:
|
|
28
|
+
* - `oauthToken` → "oauth-token" (CLAUDE_CODE_OAUTH_TOKEN)
|
|
29
|
+
* - `apiKey`/`baseUrl` → must be combined with explicit `type: "api"`
|
|
30
|
+
* - `claudeConfigDir` → "claude-max" (CLAUDE_CONFIG_DIR)
|
|
31
|
+
*/
|
|
26
32
|
type?: ProfileType;
|
|
27
33
|
/** Path to .claude config directory (claude-max profiles) */
|
|
28
34
|
claudeConfigDir?: string;
|
|
@@ -30,6 +36,8 @@ export interface ProfileConfig {
|
|
|
30
36
|
apiKey?: string;
|
|
31
37
|
/** Anthropic base URL override (api profiles) */
|
|
32
38
|
baseUrl?: string;
|
|
39
|
+
/** Long-lived OAuth token from `claude setup-token` (oauth-token profiles) */
|
|
40
|
+
oauthToken?: string;
|
|
33
41
|
}
|
|
34
42
|
export interface ResolvedProfile {
|
|
35
43
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/proxy/profiles.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/proxy/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAcH;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,aAAa,EAAE,CAkBtD;AAED,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,aAAa,CAAA;AAE9D,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,EAAE,EAAE,MAAM,CAAA;IACV;;;;;OAKG;IACH,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,WAAW,CAAA;IACjB,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC5B;AAOD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAGxD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAEvD;AAED,+CAA+C;AAC/C,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,cAAc,CAAC,EAAE,aAAa,EAAE,GAAG,IAAI,CAY3E;AAUD;;kEAEkE;AAClE,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG,aAAa,EAAE,CAOjG;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,cAAc,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG,OAAO,CAEhF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,aAAa,EAAE,GAAG,SAAS,EACrC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,WAAW,CAAC,EAAE,MAAM,GACnB,eAAe,CAkBjB;AAkCD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,aAAa,EAAE,GAAG,SAAS,EACrC,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAU7D"}
|