@ashx-j/lunr-ai 0.2.23 → 0.2.25
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/api/anthropic-claude-code-bridge.d.ts +6 -0
- package/dist/api/anthropic-claude-code-bridge.d.ts.map +1 -0
- package/dist/api/anthropic-claude-code-bridge.js +582 -0
- package/dist/api/anthropic-claude-code-bridge.js.map +1 -0
- package/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +7 -19
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/auth/anthropic-route.d.ts +7 -0
- package/dist/auth/anthropic-route.d.ts.map +1 -0
- package/dist/auth/anthropic-route.js +25 -0
- package/dist/auth/anthropic-route.js.map +1 -0
- package/dist/auth/oauth/anthropic.d.ts +1 -6
- package/dist/auth/oauth/anthropic.d.ts.map +1 -1
- package/dist/auth/oauth/anthropic.js +214 -277
- package/dist/auth/oauth/anthropic.js.map +1 -1
- package/dist/auth/resolve.d.ts.map +1 -1
- package/dist/auth/resolve.js +27 -0
- package/dist/auth/resolve.js.map +1 -1
- package/dist/auth/types.d.ts +15 -2
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth/types.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/env-api-keys.d.ts.map +1 -1
- package/dist/env-api-keys.js +1 -2
- package/dist/env-api-keys.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +19 -3
- package/dist/models.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +32 -3
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/radius.d.ts.map +1 -1
- package/dist/providers/radius.js +5 -1
- package/dist/providers/radius.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +15 -2
- package/vendor/hermes-claude-subscription-directsdk/ATTRIBUTION.md +9 -0
- package/vendor/hermes-claude-subscription-directsdk/LICENSE +21 -0
- package/vendor/hermes-claude-subscription-directsdk/README.md +179 -0
- package/vendor/hermes-claude-subscription-directsdk/admission.py +201 -0
- package/vendor/hermes-claude-subscription-directsdk/agent/reasoning_effort.py +17 -0
- package/vendor/hermes-claude-subscription-directsdk/directsdk.py +629 -0
- package/vendor/hermes-claude-subscription-directsdk/directsdk_setup.py +116 -0
- package/vendor/hermes-claude-subscription-directsdk/inert_mcp.py +24 -0
- package/vendor/hermes-claude-subscription-directsdk/lunr_bridge.py +89 -0
- package/vendor/hermes-claude-subscription-directsdk/lunr_setup_bridge.py +49 -0
- package/vendor/hermes-claude-subscription-directsdk/manifest.json +32 -0
- package/vendor/hermes-claude-subscription-directsdk/model_catalog.py +44 -0
- package/vendor/hermes-claude-subscription-directsdk/patches/0001-lunr-lifecycle-hooks.patch +14 -0
- package/vendor/hermes-claude-subscription-directsdk/tools/schema_sanitizer.py +23 -0
|
@@ -1,302 +1,239 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const decode = (s) => atob(s);
|
|
13
|
-
const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
14
|
-
const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
15
|
-
const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
|
|
16
|
-
const CALLBACK_HOST = getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
|
|
17
|
-
const CALLBACK_PORT = 53692;
|
|
18
|
-
const CALLBACK_PATH = "/callback";
|
|
19
|
-
const REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
20
|
-
const SCOPES = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";
|
|
21
|
-
async function getNodeApis() {
|
|
22
|
-
if (nodeApis)
|
|
23
|
-
return nodeApis;
|
|
24
|
-
if (!nodeApisPromise) {
|
|
25
|
-
if (typeof process === "undefined" || (!process.versions?.node && !process.versions?.bun)) {
|
|
26
|
-
throw new Error("Anthropic OAuth is only available in Node.js environments");
|
|
27
|
-
}
|
|
28
|
-
nodeApisPromise = import("node:http").then((httpModule) => ({
|
|
29
|
-
createServer: httpModule.createServer,
|
|
30
|
-
}));
|
|
31
|
-
}
|
|
32
|
-
nodeApis = await nodeApisPromise;
|
|
33
|
-
return nodeApis;
|
|
34
|
-
}
|
|
35
|
-
function parseAuthorizationInput(input) {
|
|
36
|
-
const value = input.trim();
|
|
37
|
-
if (!value)
|
|
38
|
-
return {};
|
|
39
|
-
try {
|
|
40
|
-
const url = new URL(value);
|
|
41
|
-
return {
|
|
42
|
-
code: url.searchParams.get("code") ?? undefined,
|
|
43
|
-
state: url.searchParams.get("state") ?? undefined,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
// not a URL
|
|
48
|
-
}
|
|
49
|
-
if (value.includes("#")) {
|
|
50
|
-
const [code, state] = value.split("#", 2);
|
|
51
|
-
return { code, state };
|
|
52
|
-
}
|
|
53
|
-
if (value.includes("code=")) {
|
|
54
|
-
const params = new URLSearchParams(value);
|
|
55
|
-
return {
|
|
56
|
-
code: params.get("code") ?? undefined,
|
|
57
|
-
state: params.get("state") ?? undefined,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
return { code: value };
|
|
61
|
-
}
|
|
62
|
-
function formatErrorDetails(error) {
|
|
63
|
-
if (error instanceof Error) {
|
|
64
|
-
const details = [`${error.name}: ${error.message}`];
|
|
65
|
-
const errorWithCode = error;
|
|
66
|
-
if (errorWithCode.code)
|
|
67
|
-
details.push(`code=${errorWithCode.code}`);
|
|
68
|
-
if (typeof errorWithCode.errno !== "undefined")
|
|
69
|
-
details.push(`errno=${String(errorWithCode.errno)}`);
|
|
70
|
-
if (typeof error.cause !== "undefined") {
|
|
71
|
-
details.push(`cause=${formatErrorDetails(error.cause)}`);
|
|
72
|
-
}
|
|
73
|
-
if (error.stack) {
|
|
74
|
-
details.push(`stack=${error.stack}`);
|
|
75
|
-
}
|
|
76
|
-
return details.join("; ");
|
|
77
|
-
}
|
|
78
|
-
return String(error);
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { access, constants } from "node:fs/promises";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { delimiter, isAbsolute, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { claudeCodeEnvironment, stopNative } from "../../api/anthropic-claude-code-bridge.js";
|
|
8
|
+
const SETUP_WORKER = fileURLToPath(new URL("../../../vendor/hermes-claude-subscription-directsdk/lunr_setup_bridge.py", import.meta.url));
|
|
9
|
+
const VERSION = "2.1.263";
|
|
10
|
+
export function isQualifiedClaudeCodeVersion(value) {
|
|
11
|
+
return new RegExp(`^${VERSION.replaceAll(".", "\\.")}(?:\\s|$)`).test(value);
|
|
79
12
|
}
|
|
80
|
-
async function
|
|
81
|
-
const { createServer } = await getNodeApis();
|
|
13
|
+
async function run(command, args, input, timeout = 25_000) {
|
|
82
14
|
return new Promise((resolve, reject) => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return;
|
|
89
|
-
settled = true;
|
|
90
|
-
resolveWait(value);
|
|
91
|
-
};
|
|
92
|
-
});
|
|
93
|
-
const server = createServer((req, res) => {
|
|
94
|
-
try {
|
|
95
|
-
const url = new URL(req.url || "", "http://localhost");
|
|
96
|
-
if (url.pathname !== CALLBACK_PATH) {
|
|
97
|
-
res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
|
|
98
|
-
res.end(oauthErrorHtml("Callback route not found."));
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
const code = url.searchParams.get("code");
|
|
102
|
-
const state = url.searchParams.get("state");
|
|
103
|
-
const error = url.searchParams.get("error");
|
|
104
|
-
if (error) {
|
|
105
|
-
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
106
|
-
res.end(oauthErrorHtml("Anthropic authentication did not complete.", `Error: ${error}`));
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if (!code || !state) {
|
|
110
|
-
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
111
|
-
res.end(oauthErrorHtml("Missing code or state parameter."));
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (state !== expectedState) {
|
|
115
|
-
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
116
|
-
res.end(oauthErrorHtml("State mismatch."));
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
120
|
-
res.end(oauthSuccessHtml("Anthropic authentication completed. You can close this window."));
|
|
121
|
-
settleWait?.({ code, state });
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
|
|
125
|
-
res.end("Internal error");
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
server.on("error", (err) => {
|
|
129
|
-
reject(err);
|
|
15
|
+
const child = spawn(command, args, {
|
|
16
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
17
|
+
windowsHide: true,
|
|
18
|
+
detached: process.platform !== "win32",
|
|
19
|
+
env: claudeCodeEnvironment(undefined, false),
|
|
130
20
|
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
21
|
+
let output = "";
|
|
22
|
+
let timedOut = false;
|
|
23
|
+
const timer = setTimeout(() => {
|
|
24
|
+
timedOut = true;
|
|
25
|
+
void stopNative(child.pid ?? 0).finally(() => {
|
|
26
|
+
child.kill();
|
|
27
|
+
child.stdout.destroy();
|
|
28
|
+
child.stdin.destroy();
|
|
29
|
+
reject(new Error("Dependency check timed out"));
|
|
139
30
|
});
|
|
31
|
+
}, timeout);
|
|
32
|
+
child.stdout.on("data", (chunk) => {
|
|
33
|
+
output += chunk.toString("utf8");
|
|
34
|
+
if (output.length > 64 * 1024)
|
|
35
|
+
child.kill();
|
|
36
|
+
});
|
|
37
|
+
child.stdin.on("error", () => { });
|
|
38
|
+
child.on("error", reject);
|
|
39
|
+
child.on("close", (code) => {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
if (timedOut)
|
|
42
|
+
return;
|
|
43
|
+
if (code !== 0)
|
|
44
|
+
reject(new Error("Dependency check failed"));
|
|
45
|
+
else
|
|
46
|
+
resolve(output.trim());
|
|
140
47
|
});
|
|
48
|
+
child.stdin.end(input);
|
|
141
49
|
});
|
|
142
50
|
}
|
|
143
|
-
async function
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
51
|
+
async function executable(name) {
|
|
52
|
+
const suffixes = process.platform === "win32" ? ["", ".exe", ".cmd", ".bat"] : [""];
|
|
53
|
+
const directories = isAbsolute(name)
|
|
54
|
+
? [""]
|
|
55
|
+
: [...(process.env.PATH ?? "").split(delimiter), join(homedir(), ".local", "bin")];
|
|
56
|
+
for (const directory of directories) {
|
|
57
|
+
for (const suffix of suffixes) {
|
|
58
|
+
const candidate = directory ? join(directory, `${name}${suffix}`) : `${name}${suffix}`;
|
|
59
|
+
try {
|
|
60
|
+
await access(candidate, constants.X_OK);
|
|
61
|
+
return candidate;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
/* Next location. */
|
|
65
|
+
}
|
|
66
|
+
}
|
|
156
67
|
}
|
|
157
|
-
return
|
|
68
|
+
return undefined;
|
|
158
69
|
}
|
|
159
|
-
async function
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
let tokenData;
|
|
175
|
-
try {
|
|
176
|
-
tokenData = JSON.parse(responseBody);
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
throw new Error(`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`);
|
|
70
|
+
async function pythonInterpreter() {
|
|
71
|
+
for (const name of ["python3", "python"]) {
|
|
72
|
+
const path = await executable(name);
|
|
73
|
+
if (!path)
|
|
74
|
+
continue;
|
|
75
|
+
try {
|
|
76
|
+
const version = await run(path, ["--version"]);
|
|
77
|
+
const match = /^Python (\d+)\.(\d+)/.exec(version);
|
|
78
|
+
if (match && (Number(match[1]) > 3 || (Number(match[1]) === 3 && Number(match[2]) >= 10)))
|
|
79
|
+
return path;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
/* Try another interpreter. */
|
|
83
|
+
}
|
|
180
84
|
}
|
|
181
|
-
return
|
|
182
|
-
type: "oauth",
|
|
183
|
-
refresh: tokenData.refresh_token,
|
|
184
|
-
access: tokenData.access_token,
|
|
185
|
-
expires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000,
|
|
186
|
-
};
|
|
85
|
+
return undefined;
|
|
187
86
|
}
|
|
188
|
-
async function
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
87
|
+
async function install(command, args, interaction) {
|
|
88
|
+
const confirm = await interaction.prompt({
|
|
89
|
+
type: "select",
|
|
90
|
+
message: `Run ${command} ${args.join(" ")}? This downloads software and changes your user-level system installation.`,
|
|
91
|
+
options: [
|
|
92
|
+
{ id: "yes", label: "Install" },
|
|
93
|
+
{ id: "no", label: "Cancel" },
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
if (confirm !== "yes")
|
|
97
|
+
throw new Error("Anthropic subscription setup cancelled");
|
|
98
|
+
interaction.notify({ type: "progress", message: "Running the confirmed installer..." });
|
|
99
|
+
await run(command, args, undefined, 300_000);
|
|
100
|
+
}
|
|
101
|
+
async function setupProbe(python, command, type) {
|
|
102
|
+
const requestId = randomUUID();
|
|
103
|
+
const line = await run(python, ["-s", "-B", "-u", SETUP_WORKER], `${JSON.stringify({ v: 1, requestId, type, command, env: claudeCodeEnvironment(undefined, false) })}\n`, 55_000);
|
|
104
|
+
const record = JSON.parse(line);
|
|
105
|
+
if (!record ||
|
|
106
|
+
typeof record !== "object" ||
|
|
107
|
+
!("v" in record) ||
|
|
108
|
+
record.v !== 1 ||
|
|
109
|
+
!("requestId" in record) ||
|
|
110
|
+
record.requestId !== requestId ||
|
|
111
|
+
!("type" in record) ||
|
|
112
|
+
record.type !== "result" ||
|
|
113
|
+
!("result" in record)) {
|
|
114
|
+
throw new Error("Invalid Claude Code setup response");
|
|
115
|
+
}
|
|
116
|
+
return record.result;
|
|
117
|
+
}
|
|
118
|
+
async function login(interaction) {
|
|
119
|
+
interaction.notify({
|
|
120
|
+
type: "info",
|
|
121
|
+
message: "Claude Code handles subscription authentication and one generation per lunR request. lunR still owns tools, permissions, history, compaction, and subagents. Python 3.10+ and Claude Code are required. No credentials are copied into lunR.",
|
|
122
|
+
});
|
|
123
|
+
let python = await pythonInterpreter();
|
|
124
|
+
if (!python) {
|
|
207
125
|
interaction.notify({
|
|
208
|
-
type: "
|
|
209
|
-
|
|
210
|
-
instructions: "Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.",
|
|
126
|
+
type: "info",
|
|
127
|
+
message: "Install Python 3.10+ from https://www.python.org/downloads/ . This is a separate operating-system installation, not part of lunR.",
|
|
211
128
|
});
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
129
|
+
const packageManager = process.platform === "darwin"
|
|
130
|
+
? await executable("brew")
|
|
131
|
+
: process.platform === "linux"
|
|
132
|
+
? ((await executable("apt-get")) ?? (await executable("dnf")))
|
|
133
|
+
: undefined;
|
|
134
|
+
const installer = process.platform === "win32"
|
|
135
|
+
? { command: "winget", args: ["install", "--id", "Python.Python.3.13", "-e"] }
|
|
136
|
+
: packageManager?.endsWith("apt-get")
|
|
137
|
+
? { command: "sudo", args: [packageManager, "install", "-y", "python3"] }
|
|
138
|
+
: packageManager?.endsWith("dnf")
|
|
139
|
+
? { command: "sudo", args: [packageManager, "install", "-y", "python3"] }
|
|
140
|
+
: packageManager
|
|
141
|
+
? { command: packageManager, args: ["install", "python@3.13"] }
|
|
142
|
+
: undefined;
|
|
143
|
+
const choice = await interaction.prompt({
|
|
144
|
+
type: "select",
|
|
145
|
+
message: "Python 3.10+ is missing. A system installer may request administrator access and change your machine.",
|
|
146
|
+
options: [
|
|
147
|
+
...(installer
|
|
148
|
+
? [{ id: "install", label: `Install through ${installer.command} ${installer.args.join(" ")}` }]
|
|
149
|
+
: []),
|
|
150
|
+
{ id: "cancel", label: "Cancel and install Python yourself" },
|
|
151
|
+
],
|
|
226
152
|
});
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
153
|
+
if (choice === "install" && installer)
|
|
154
|
+
await install(installer.command, installer.args, interaction);
|
|
155
|
+
else
|
|
156
|
+
throw new Error("Install Python 3.10+ and retry /login anthropic");
|
|
157
|
+
python = await pythonInterpreter();
|
|
158
|
+
if (!python)
|
|
159
|
+
throw new Error("Python installation finished but the interpreter is not on PATH. Restart lunR and retry.");
|
|
160
|
+
}
|
|
161
|
+
let command = await executable("claude");
|
|
162
|
+
if (!command) {
|
|
163
|
+
const choice = await interaction.prompt({
|
|
164
|
+
type: "select",
|
|
165
|
+
message: "Claude Code is missing. Installation changes your user-level system and may require a new PATH.",
|
|
166
|
+
options: [
|
|
167
|
+
{ id: "install", label: "Install Claude Code" },
|
|
168
|
+
{ id: "existing", label: "Use existing executable" },
|
|
169
|
+
{ id: "cancel", label: "Cancel" },
|
|
170
|
+
],
|
|
171
|
+
});
|
|
172
|
+
if (choice === "install") {
|
|
173
|
+
if (process.platform === "win32")
|
|
174
|
+
await install("powershell", ["-NoProfile", "-Command", "irm https://claude.ai/install.ps1 | iex"], interaction);
|
|
175
|
+
else
|
|
176
|
+
await install("sh", ["-c", "curl -fsSL https://claude.ai/install.sh | bash"], interaction);
|
|
177
|
+
command = await executable("claude");
|
|
240
178
|
}
|
|
241
|
-
if (
|
|
242
|
-
await
|
|
243
|
-
if (
|
|
244
|
-
throw
|
|
245
|
-
|
|
246
|
-
const parsed = parseAuthorizationInput(manualInput);
|
|
247
|
-
if (parsed.state && parsed.state !== verifier)
|
|
248
|
-
throw new Error("OAuth state mismatch");
|
|
249
|
-
code = parsed.code;
|
|
250
|
-
state = parsed.state ?? verifier;
|
|
251
|
-
}
|
|
179
|
+
else if (choice === "existing") {
|
|
180
|
+
const path = await interaction.prompt({ type: "text", message: "Absolute path to Claude Code executable:" });
|
|
181
|
+
if (!isAbsolute(path))
|
|
182
|
+
throw new Error("Claude Code path must be absolute");
|
|
183
|
+
command = await executable(path);
|
|
252
184
|
}
|
|
253
|
-
|
|
254
|
-
throw new Error("
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
grant_type: "refresh_token",
|
|
273
|
-
client_id: CLIENT_ID,
|
|
274
|
-
refresh_token: refreshToken,
|
|
185
|
+
else
|
|
186
|
+
throw new Error("Anthropic subscription setup cancelled");
|
|
187
|
+
}
|
|
188
|
+
if (!command)
|
|
189
|
+
throw new Error("Claude Code executable not found. Restart lunR after installation and retry.");
|
|
190
|
+
const version = (await setupProbe(python, command, "version"));
|
|
191
|
+
if (!isQualifiedClaudeCodeVersion(version))
|
|
192
|
+
throw new Error(`Claude Code ${VERSION} is the only qualified version. Found ${version.slice(0, 40)}. Subscription requests are disabled until this version is qualified.`);
|
|
193
|
+
let status = (await setupProbe(python, command, "status"));
|
|
194
|
+
if (!status.logged_in || !/Claude (Pro|Max|Team|Enterprise)/i.test(status.plan ?? "")) {
|
|
195
|
+
if (!interaction.handoff)
|
|
196
|
+
throw new Error(`Run "${command}" auth login in a terminal, select a Claude subscription, then retry /login anthropic`);
|
|
197
|
+
const choice = await interaction.prompt({
|
|
198
|
+
type: "select",
|
|
199
|
+
message: "Claude Code needs a subscription login. Hand the terminal to Claude Code now?",
|
|
200
|
+
options: [
|
|
201
|
+
{ id: "login", label: "Run Claude Code login" },
|
|
202
|
+
{ id: "cancel", label: "Cancel" },
|
|
203
|
+
],
|
|
275
204
|
});
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
205
|
+
if (choice !== "login")
|
|
206
|
+
throw new Error("Anthropic subscription setup cancelled");
|
|
207
|
+
await interaction.handoff(python, ["-s", "-B", "-u", SETUP_WORKER, "auth-login", command], claudeCodeEnvironment(undefined, false));
|
|
208
|
+
status = (await setupProbe(python, command, "status"));
|
|
209
|
+
if (!status.logged_in || !/Claude (Pro|Max|Team|Enterprise)/i.test(status.plan ?? ""))
|
|
210
|
+
throw new Error("Claude Code is not signed into a Claude subscription");
|
|
211
|
+
}
|
|
212
|
+
const discovered = await setupProbe(python, command, "discover");
|
|
213
|
+
if (!Array.isArray(discovered) ||
|
|
214
|
+
!discovered.length ||
|
|
215
|
+
discovered.some((row) => !row || typeof row.id !== "string" || row.upstream_requests !== 0)) {
|
|
216
|
+
throw new Error("Claude Code model discovery did not verify zero Messages requests. Setup not saved.");
|
|
286
217
|
}
|
|
287
218
|
return {
|
|
288
|
-
type: "
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
219
|
+
type: "external_claude_code",
|
|
220
|
+
version: 1,
|
|
221
|
+
manager: "claude-code",
|
|
222
|
+
command,
|
|
223
|
+
python,
|
|
224
|
+
accountFingerprint: status.accountFingerprint ?? randomUUID(),
|
|
225
|
+
routes: discovered.map((row) => row.id),
|
|
292
226
|
};
|
|
293
227
|
}
|
|
294
228
|
export const anthropicOAuth = {
|
|
295
|
-
name: "Anthropic
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
async
|
|
299
|
-
|
|
229
|
+
name: "Anthropic subscription through Claude Code",
|
|
230
|
+
loginLabel: "Connect Claude Pro/Max through Claude Code",
|
|
231
|
+
login,
|
|
232
|
+
refresh: async () => {
|
|
233
|
+
throw new Error("Legacy Anthropic OAuth tokens are unsupported. Run /login anthropic.");
|
|
234
|
+
},
|
|
235
|
+
toAuth: async () => {
|
|
236
|
+
throw new Error("Legacy Anthropic OAuth tokens are unsupported. Run /login anthropic.");
|
|
300
237
|
},
|
|
301
238
|
};
|
|
302
239
|
//# sourceMappingURL=anthropic.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/auth/oauth/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback server.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\nimport type { AuthInteraction, OAuthAuth, OAuthCredential } from \"../types.ts\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tredirectUri: string;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\ntype NodeApis = {\n\tcreateServer: typeof import(\"node:http\").createServer;\n};\n\nlet nodeApis: NodeApis | null = null;\nlet nodeApisPromise: Promise<NodeApis> | null = null;\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst CALLBACK_HOST = getProviderEnvValue(\"PI_OAUTH_CALLBACK_HOST\") || \"127.0.0.1\";\nconst CALLBACK_PORT = 53692;\nconst CALLBACK_PATH = \"/callback\";\nconst REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;\nconst SCOPES =\n\t\"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\nasync function getNodeApis(): Promise<NodeApis> {\n\tif (nodeApis) return nodeApis;\n\tif (!nodeApisPromise) {\n\t\tif (typeof process === \"undefined\" || (!process.versions?.node && !process.versions?.bun)) {\n\t\t\tthrow new Error(\"Anthropic OAuth is only available in Node.js environments\");\n\t\t}\n\t\tnodeApisPromise = import(\"node:http\").then((httpModule) => ({\n\t\t\tcreateServer: httpModule.createServer,\n\t\t}));\n\t}\n\tnodeApis = await nodeApisPromise;\n\treturn nodeApis;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn {\n\t\t\tcode: url.searchParams.get(\"code\") ?? undefined,\n\t\t\tstate: url.searchParams.get(\"state\") ?? undefined,\n\t\t};\n\t} catch {\n\t\t// not a URL\n\t}\n\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn { code, state };\n\t}\n\n\tif (value.includes(\"code=\")) {\n\t\tconst params = new URLSearchParams(value);\n\t\treturn {\n\t\t\tcode: params.get(\"code\") ?? undefined,\n\t\t\tstate: params.get(\"state\") ?? undefined,\n\t\t};\n\t}\n\n\treturn { code: value };\n}\n\nfunction formatErrorDetails(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst details: string[] = [`${error.name}: ${error.message}`];\n\t\tconst errorWithCode = error as Error & { code?: string; errno?: number | string; cause?: unknown };\n\t\tif (errorWithCode.code) details.push(`code=${errorWithCode.code}`);\n\t\tif (typeof errorWithCode.errno !== \"undefined\") details.push(`errno=${String(errorWithCode.errno)}`);\n\t\tif (typeof error.cause !== \"undefined\") {\n\t\t\tdetails.push(`cause=${formatErrorDetails(error.cause)}`);\n\t\t}\n\t\tif (error.stack) {\n\t\t\tdetails.push(`stack=${error.stack}`);\n\t\t}\n\t\treturn details.join(\"; \");\n\t}\n\treturn String(error);\n}\n\nasync function startCallbackServer(expectedState: string): Promise<CallbackServerInfo> {\n\tconst { createServer } = await getNodeApis();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet settleWait: ((value: { code: string; state: string } | null) => void) | undefined;\n\t\tconst waitForCodePromise = new Promise<{ code: string; state: string } | null>((resolveWait) => {\n\t\t\tlet settled = false;\n\t\t\tsettleWait = (value) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolveWait(value);\n\t\t\t};\n\t\t});\n\n\t\tconst server = createServer((req, res) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Callback route not found.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Anthropic authentication did not complete.\", `Error: ${error}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!code || !state) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Missing code or state parameter.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (state !== expectedState) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"State mismatch.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(oauthSuccessHtml(\"Anthropic authentication completed. You can close this window.\"));\n\t\t\t\tsettleWait?.({ code, state });\n\t\t\t} catch {\n\t\t\t\tres.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\tres.end(\"Internal error\");\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(CALLBACK_PORT, CALLBACK_HOST, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tredirectUri: REDIRECT_URI,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tsettleWait?.(null);\n\t\t\t\t},\n\t\t\t\twaitForCode: () => waitForCodePromise,\n\t\t\t});\n\t\t});\n\t});\n}\n\nasync function postJson(url: string, body: Record<string, string | number>): Promise<string> {\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tconst responseBody = await response.text();\n\n\tif (!response.ok) {\n\t\tthrow new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);\n\t}\n\n\treturn responseBody;\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tstate: string,\n\tverifier: string,\n\tredirectUri: string,\n): Promise<OAuthCredential> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode,\n\t\t\tstate,\n\t\t\tredirect_uri: redirectUri,\n\t\t\tcode_verifier: verifier,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\tlet tokenData: { access_token: string; refresh_token: string; expires_in: number };\n\ttry {\n\t\ttokenData = JSON.parse(responseBody) as { access_token: string; refresh_token: string; expires_in: number };\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nasync function loginAnthropic(interaction: AuthInteraction): Promise<OAuthCredential> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst server = await startCallbackServer(verifier);\n\tconst manualAbort = new AbortController();\n\tlet code: string | undefined;\n\tlet state: string | undefined;\n\tlet manualInput: string | undefined;\n\tlet manualError: Error | undefined;\n\n\ttry {\n\t\tconst authParams = new URLSearchParams({\n\t\t\tcode: \"true\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES,\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t});\n\t\tinteraction.notify({\n\t\t\ttype: \"auth_url\",\n\t\t\turl: `${AUTHORIZE_URL}?${authParams.toString()}`,\n\t\t\tinstructions:\n\t\t\t\t\"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.\",\n\t\t});\n\n\t\tconst manualPromise = interaction\n\t\t\t.prompt({\n\t\t\t\ttype: \"manual_code\",\n\t\t\t\tmessage: \"Complete login in your browser, or paste the authorization code / redirect URL here:\",\n\t\t\t\tplaceholder: REDIRECT_URI,\n\t\t\t\tsignal: manualAbort.signal,\n\t\t\t})\n\t\t\t.then((input) => {\n\t\t\t\tmanualInput = input;\n\t\t\t\tserver.cancelWait();\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tmanualError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tserver.cancelWait();\n\t\t\t});\n\n\t\tconst result = await server.waitForCode();\n\t\tif (manualError) throw manualError;\n\t\tif (result?.code) {\n\t\t\tcode = result.code;\n\t\t\tstate = result.state;\n\t\t} else if (manualInput) {\n\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\tif (parsed.state && parsed.state !== verifier) throw new Error(\"OAuth state mismatch\");\n\t\t\tcode = parsed.code;\n\t\t\tstate = parsed.state ?? verifier;\n\t\t}\n\n\t\tif (!code) {\n\t\t\tawait manualPromise;\n\t\t\tif (manualError) throw manualError;\n\t\t\tif (manualInput) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) throw new Error(\"OAuth state mismatch\");\n\t\t\t\tcode = parsed.code;\n\t\t\t\tstate = parsed.state ?? verifier;\n\t\t\t}\n\t\t}\n\n\t\tif (!code) throw new Error(\"Missing authorization code\");\n\t\tif (!state) throw new Error(\"Missing OAuth state\");\n\t\tinteraction.notify({ type: \"progress\", message: \"Exchanging authorization code for tokens...\" });\n\t\treturn exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI);\n\t} finally {\n\t\tmanualAbort.abort();\n\t\tserver.server.close();\n\t}\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nasync function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredential> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`);\n\t}\n\n\tlet data: { access_token: string; refresh_token: string; expires_in: number; scope?: string };\n\ttry {\n\t\tdata = JSON.parse(responseBody) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t\tscope?: string;\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nexport const anthropicOAuth: OAuthAuth = {\n\tname: \"Anthropic (Claude Pro/Max)\",\n\tlogin: loginAnthropic,\n\trefresh: (credential) => refreshAnthropicToken(credential.refresh),\n\n\tasync toAuth(credential) {\n\t\treturn { apiKey: credential.access };\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/auth/oauth/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { access, constants } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { delimiter, isAbsolute, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { claudeCodeEnvironment, stopNative } from \"../../api/anthropic-claude-code-bridge.ts\";\nimport type { AuthInteraction, ExternalClaudeCodeCredential, OAuthAuth } from \"../types.ts\";\n\nconst SETUP_WORKER = fileURLToPath(\n\tnew URL(\"../../../vendor/hermes-claude-subscription-directsdk/lunr_setup_bridge.py\", import.meta.url),\n);\nconst VERSION = \"2.1.263\";\n\nexport function isQualifiedClaudeCodeVersion(value: string): boolean {\n\treturn new RegExp(`^${VERSION.replaceAll(\".\", \"\\\\.\")}(?:\\\\s|$)`).test(value);\n}\n\nasync function run(command: string, args: string[], input?: string, timeout = 25_000): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(command, args, {\n\t\t\tstdio: [\"pipe\", \"pipe\", \"ignore\"],\n\t\t\twindowsHide: true,\n\t\t\tdetached: process.platform !== \"win32\",\n\t\t\tenv: claudeCodeEnvironment(undefined, false),\n\t\t});\n\t\tlet output = \"\";\n\t\tlet timedOut = false;\n\t\tconst timer = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\tvoid stopNative(child.pid ?? 0).finally(() => {\n\t\t\t\tchild.kill();\n\t\t\t\tchild.stdout.destroy();\n\t\t\t\tchild.stdin.destroy();\n\t\t\t\treject(new Error(\"Dependency check timed out\"));\n\t\t\t});\n\t\t}, timeout);\n\t\tchild.stdout.on(\"data\", (chunk: Buffer) => {\n\t\t\toutput += chunk.toString(\"utf8\");\n\t\t\tif (output.length > 64 * 1024) child.kill();\n\t\t});\n\t\tchild.stdin.on(\"error\", () => {});\n\t\tchild.on(\"error\", reject);\n\t\tchild.on(\"close\", (code) => {\n\t\t\tclearTimeout(timer);\n\t\t\tif (timedOut) return;\n\t\t\tif (code !== 0) reject(new Error(\"Dependency check failed\"));\n\t\t\telse resolve(output.trim());\n\t\t});\n\t\tchild.stdin.end(input);\n\t});\n}\n\nasync function executable(name: string): Promise<string | undefined> {\n\tconst suffixes = process.platform === \"win32\" ? [\"\", \".exe\", \".cmd\", \".bat\"] : [\"\"];\n\tconst directories = isAbsolute(name)\n\t\t? [\"\"]\n\t\t: [...(process.env.PATH ?? \"\").split(delimiter), join(homedir(), \".local\", \"bin\")];\n\tfor (const directory of directories) {\n\t\tfor (const suffix of suffixes) {\n\t\t\tconst candidate = directory ? join(directory, `${name}${suffix}`) : `${name}${suffix}`;\n\t\t\ttry {\n\t\t\t\tawait access(candidate, constants.X_OK);\n\t\t\t\treturn candidate;\n\t\t\t} catch {\n\t\t\t\t/* Next location. */\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined;\n}\n\nasync function pythonInterpreter(): Promise<string | undefined> {\n\tfor (const name of [\"python3\", \"python\"]) {\n\t\tconst path = await executable(name);\n\t\tif (!path) continue;\n\t\ttry {\n\t\t\tconst version = await run(path, [\"--version\"]);\n\t\t\tconst match = /^Python (\\d+)\\.(\\d+)/.exec(version);\n\t\t\tif (match && (Number(match[1]) > 3 || (Number(match[1]) === 3 && Number(match[2]) >= 10))) return path;\n\t\t} catch {\n\t\t\t/* Try another interpreter. */\n\t\t}\n\t}\n\treturn undefined;\n}\n\nasync function install(command: string, args: string[], interaction: AuthInteraction): Promise<void> {\n\tconst confirm = await interaction.prompt({\n\t\ttype: \"select\",\n\t\tmessage: `Run ${command} ${args.join(\" \")}? This downloads software and changes your user-level system installation.`,\n\t\toptions: [\n\t\t\t{ id: \"yes\", label: \"Install\" },\n\t\t\t{ id: \"no\", label: \"Cancel\" },\n\t\t],\n\t});\n\tif (confirm !== \"yes\") throw new Error(\"Anthropic subscription setup cancelled\");\n\tinteraction.notify({ type: \"progress\", message: \"Running the confirmed installer...\" });\n\tawait run(command, args, undefined, 300_000);\n}\n\nasync function setupProbe(python: string, command: string, type: \"status\" | \"discover\" | \"version\"): Promise<unknown> {\n\tconst requestId = randomUUID();\n\tconst line = await run(\n\t\tpython,\n\t\t[\"-s\", \"-B\", \"-u\", SETUP_WORKER],\n\t\t`${JSON.stringify({ v: 1, requestId, type, command, env: claudeCodeEnvironment(undefined, false) })}\\n`,\n\t\t55_000,\n\t);\n\tconst record: unknown = JSON.parse(line);\n\tif (\n\t\t!record ||\n\t\ttypeof record !== \"object\" ||\n\t\t!(\"v\" in record) ||\n\t\trecord.v !== 1 ||\n\t\t!(\"requestId\" in record) ||\n\t\trecord.requestId !== requestId ||\n\t\t!(\"type\" in record) ||\n\t\trecord.type !== \"result\" ||\n\t\t!(\"result\" in record)\n\t) {\n\t\tthrow new Error(\"Invalid Claude Code setup response\");\n\t}\n\treturn record.result;\n}\n\nasync function login(interaction: AuthInteraction): Promise<ExternalClaudeCodeCredential> {\n\tinteraction.notify({\n\t\ttype: \"info\",\n\t\tmessage:\n\t\t\t\"Claude Code handles subscription authentication and one generation per lunR request. lunR still owns tools, permissions, history, compaction, and subagents. Python 3.10+ and Claude Code are required. No credentials are copied into lunR.\",\n\t});\n\tlet python = await pythonInterpreter();\n\tif (!python) {\n\t\tinteraction.notify({\n\t\t\ttype: \"info\",\n\t\t\tmessage:\n\t\t\t\t\"Install Python 3.10+ from https://www.python.org/downloads/ . This is a separate operating-system installation, not part of lunR.\",\n\t\t});\n\t\tconst packageManager =\n\t\t\tprocess.platform === \"darwin\"\n\t\t\t\t? await executable(\"brew\")\n\t\t\t\t: process.platform === \"linux\"\n\t\t\t\t\t? ((await executable(\"apt-get\")) ?? (await executable(\"dnf\")))\n\t\t\t\t\t: undefined;\n\t\tconst installer =\n\t\t\tprocess.platform === \"win32\"\n\t\t\t\t? { command: \"winget\", args: [\"install\", \"--id\", \"Python.Python.3.13\", \"-e\"] }\n\t\t\t\t: packageManager?.endsWith(\"apt-get\")\n\t\t\t\t\t? { command: \"sudo\", args: [packageManager, \"install\", \"-y\", \"python3\"] }\n\t\t\t\t\t: packageManager?.endsWith(\"dnf\")\n\t\t\t\t\t\t? { command: \"sudo\", args: [packageManager, \"install\", \"-y\", \"python3\"] }\n\t\t\t\t\t\t: packageManager\n\t\t\t\t\t\t\t? { command: packageManager, args: [\"install\", \"python@3.13\"] }\n\t\t\t\t\t\t\t: undefined;\n\t\tconst choice = await interaction.prompt({\n\t\t\ttype: \"select\",\n\t\t\tmessage:\n\t\t\t\t\"Python 3.10+ is missing. A system installer may request administrator access and change your machine.\",\n\t\t\toptions: [\n\t\t\t\t...(installer\n\t\t\t\t\t? [{ id: \"install\", label: `Install through ${installer.command} ${installer.args.join(\" \")}` }]\n\t\t\t\t\t: []),\n\t\t\t\t{ id: \"cancel\", label: \"Cancel and install Python yourself\" },\n\t\t\t],\n\t\t});\n\t\tif (choice === \"install\" && installer) await install(installer.command, installer.args, interaction);\n\t\telse throw new Error(\"Install Python 3.10+ and retry /login anthropic\");\n\t\tpython = await pythonInterpreter();\n\t\tif (!python)\n\t\t\tthrow new Error(\"Python installation finished but the interpreter is not on PATH. Restart lunR and retry.\");\n\t}\n\tlet command = await executable(\"claude\");\n\tif (!command) {\n\t\tconst choice = await interaction.prompt({\n\t\t\ttype: \"select\",\n\t\t\tmessage: \"Claude Code is missing. Installation changes your user-level system and may require a new PATH.\",\n\t\t\toptions: [\n\t\t\t\t{ id: \"install\", label: \"Install Claude Code\" },\n\t\t\t\t{ id: \"existing\", label: \"Use existing executable\" },\n\t\t\t\t{ id: \"cancel\", label: \"Cancel\" },\n\t\t\t],\n\t\t});\n\t\tif (choice === \"install\") {\n\t\t\tif (process.platform === \"win32\")\n\t\t\t\tawait install(\n\t\t\t\t\t\"powershell\",\n\t\t\t\t\t[\"-NoProfile\", \"-Command\", \"irm https://claude.ai/install.ps1 | iex\"],\n\t\t\t\t\tinteraction,\n\t\t\t\t);\n\t\t\telse await install(\"sh\", [\"-c\", \"curl -fsSL https://claude.ai/install.sh | bash\"], interaction);\n\t\t\tcommand = await executable(\"claude\");\n\t\t} else if (choice === \"existing\") {\n\t\t\tconst path = await interaction.prompt({ type: \"text\", message: \"Absolute path to Claude Code executable:\" });\n\t\t\tif (!isAbsolute(path)) throw new Error(\"Claude Code path must be absolute\");\n\t\t\tcommand = await executable(path);\n\t\t} else throw new Error(\"Anthropic subscription setup cancelled\");\n\t}\n\tif (!command) throw new Error(\"Claude Code executable not found. Restart lunR after installation and retry.\");\n\tconst version = (await setupProbe(python, command, \"version\")) as string;\n\tif (!isQualifiedClaudeCodeVersion(version))\n\t\tthrow new Error(\n\t\t\t`Claude Code ${VERSION} is the only qualified version. Found ${version.slice(0, 40)}. Subscription requests are disabled until this version is qualified.`,\n\t\t);\n\tlet status = (await setupProbe(python, command, \"status\")) as {\n\t\tlogged_in?: boolean;\n\t\tplan?: string;\n\t\taccountFingerprint?: string;\n\t};\n\tif (!status.logged_in || !/Claude (Pro|Max|Team|Enterprise)/i.test(status.plan ?? \"\")) {\n\t\tif (!interaction.handoff)\n\t\t\tthrow new Error(\n\t\t\t\t`Run \"${command}\" auth login in a terminal, select a Claude subscription, then retry /login anthropic`,\n\t\t\t);\n\t\tconst choice = await interaction.prompt({\n\t\t\ttype: \"select\",\n\t\t\tmessage: \"Claude Code needs a subscription login. Hand the terminal to Claude Code now?\",\n\t\t\toptions: [\n\t\t\t\t{ id: \"login\", label: \"Run Claude Code login\" },\n\t\t\t\t{ id: \"cancel\", label: \"Cancel\" },\n\t\t\t],\n\t\t});\n\t\tif (choice !== \"login\") throw new Error(\"Anthropic subscription setup cancelled\");\n\t\tawait interaction.handoff(\n\t\t\tpython,\n\t\t\t[\"-s\", \"-B\", \"-u\", SETUP_WORKER, \"auth-login\", command],\n\t\t\tclaudeCodeEnvironment(undefined, false),\n\t\t);\n\t\tstatus = (await setupProbe(python, command, \"status\")) as typeof status;\n\t\tif (!status.logged_in || !/Claude (Pro|Max|Team|Enterprise)/i.test(status.plan ?? \"\"))\n\t\t\tthrow new Error(\"Claude Code is not signed into a Claude subscription\");\n\t}\n\tconst discovered = await setupProbe(python, command, \"discover\");\n\tif (\n\t\t!Array.isArray(discovered) ||\n\t\t!discovered.length ||\n\t\tdiscovered.some((row) => !row || typeof row.id !== \"string\" || row.upstream_requests !== 0)\n\t) {\n\t\tthrow new Error(\"Claude Code model discovery did not verify zero Messages requests. Setup not saved.\");\n\t}\n\treturn {\n\t\ttype: \"external_claude_code\",\n\t\tversion: 1,\n\t\tmanager: \"claude-code\",\n\t\tcommand,\n\t\tpython,\n\t\taccountFingerprint: status.accountFingerprint ?? randomUUID(),\n\t\troutes: discovered.map((row) => row.id),\n\t};\n}\n\nexport const anthropicOAuth: OAuthAuth = {\n\tname: \"Anthropic subscription through Claude Code\",\n\tloginLabel: \"Connect Claude Pro/Max through Claude Code\",\n\tlogin,\n\trefresh: async () => {\n\t\tthrow new Error(\"Legacy Anthropic OAuth tokens are unsupported. Run /login anthropic.\");\n\t},\n\ttoAuth: async () => {\n\t\tthrow new Error(\"Legacy Anthropic OAuth tokens are unsupported. Run /login anthropic.\");\n\t},\n};\n"]}
|