@kenkaiiii/gg-core 5.92.0 → 5.94.0
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/NOTICE +1 -1
- package/README.md +52 -36
- package/dist/{chunk-2X5L6U4Z.js → chunk-GXOFTHM5.js} +4 -2
- package/dist/chunk-GXOFTHM5.js.map +1 -0
- package/dist/{chunk-SDUIKPGO.js → chunk-JLEBGMG4.js} +649 -164
- package/dist/chunk-JLEBGMG4.js.map +1 -0
- package/dist/index.cjs +826 -228
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +180 -37
- package/dist/index.d.ts +180 -37
- package/dist/index.js +170 -57
- package/dist/index.js.map +1 -1
- package/dist/model-registry.cjs +53 -16
- package/dist/model-registry.cjs.map +1 -1
- package/dist/model-registry.js +2 -2
- package/dist/paths.cjs +3 -1
- package/dist/paths.cjs.map +1 -1
- package/dist/paths.d.cts +4 -0
- package/dist/paths.d.ts +4 -0
- package/dist/paths.js +1 -1
- package/package.json +17 -4
- package/dist/chunk-2X5L6U4Z.js.map +0 -1
- package/dist/chunk-SDUIKPGO.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getAppPaths
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GXOFTHM5.js";
|
|
4
4
|
|
|
5
5
|
// src/oauth/kimi.ts
|
|
6
6
|
import { execFileSync } from "child_process";
|
|
@@ -230,141 +230,539 @@ async function refreshKimiToken(refreshToken) {
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
// src/auth-storage.ts
|
|
233
|
-
import
|
|
233
|
+
import fs5 from "fs/promises";
|
|
234
234
|
import { readFileSync as readFileSync2 } from "fs";
|
|
235
235
|
import crypto5 from "crypto";
|
|
236
236
|
|
|
237
|
-
// src/
|
|
237
|
+
// src/claude-code/runtime.ts
|
|
238
|
+
import { spawn } from "child_process";
|
|
238
239
|
import crypto2 from "crypto";
|
|
240
|
+
import fs2 from "fs";
|
|
241
|
+
import fsp2 from "fs/promises";
|
|
242
|
+
import path2 from "path";
|
|
239
243
|
|
|
240
|
-
// src/
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
244
|
+
// src/claude-code/tar.ts
|
|
245
|
+
import fs from "fs";
|
|
246
|
+
import fsp from "fs/promises";
|
|
247
|
+
import zlib from "zlib";
|
|
248
|
+
var BLOCK = 512;
|
|
249
|
+
function readString(buf, offset, length) {
|
|
250
|
+
const end = buf.indexOf(0, offset);
|
|
251
|
+
return buf.toString("utf8", offset, end === -1 || end > offset + length ? offset + length : end);
|
|
252
|
+
}
|
|
253
|
+
function readSize(buf, offset) {
|
|
254
|
+
if (buf[offset] & 128) {
|
|
255
|
+
let value = buf[offset] & 127;
|
|
256
|
+
for (let i = 1; i < 12; i++) value = value * 256 + buf[offset + i];
|
|
257
|
+
return value;
|
|
258
|
+
}
|
|
259
|
+
const text = readString(buf, offset, 12).trim();
|
|
260
|
+
return text ? parseInt(text, 8) : 0;
|
|
261
|
+
}
|
|
262
|
+
function paxPath(data) {
|
|
263
|
+
let pos = 0;
|
|
264
|
+
while (pos < data.length) {
|
|
265
|
+
const space = data.indexOf(32, pos);
|
|
266
|
+
if (space === -1) break;
|
|
267
|
+
const len = parseInt(data.toString("utf8", pos, space), 10);
|
|
268
|
+
if (!Number.isFinite(len) || len <= 0) break;
|
|
269
|
+
const record = data.toString("utf8", space + 1, pos + len - 1);
|
|
270
|
+
const eq = record.indexOf("=");
|
|
271
|
+
if (eq !== -1 && record.slice(0, eq) === "path") return record.slice(eq + 1);
|
|
272
|
+
pos += len;
|
|
245
273
|
}
|
|
246
|
-
return
|
|
274
|
+
return void 0;
|
|
247
275
|
}
|
|
248
|
-
async function
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
276
|
+
async function extractFileFromTarGz(tgzPath, entryName, destPath) {
|
|
277
|
+
const input = fs.createReadStream(tgzPath).pipe(zlib.createGunzip());
|
|
278
|
+
let pending = Buffer.alloc(0);
|
|
279
|
+
let remaining = 0;
|
|
280
|
+
let padding = 0;
|
|
281
|
+
let kind = "skip";
|
|
282
|
+
let meta = [];
|
|
283
|
+
let overridePath;
|
|
284
|
+
let out;
|
|
285
|
+
let found = false;
|
|
286
|
+
try {
|
|
287
|
+
for await (const chunk of input) {
|
|
288
|
+
pending = pending.length ? Buffer.concat([pending, chunk]) : chunk;
|
|
289
|
+
let pos = 0;
|
|
290
|
+
while (pos < pending.length) {
|
|
291
|
+
if (remaining > 0) {
|
|
292
|
+
const take = Math.min(remaining, pending.length - pos);
|
|
293
|
+
const slice = pending.subarray(pos, pos + take);
|
|
294
|
+
if (kind === "target") await out.write(slice);
|
|
295
|
+
else if (kind === "pax" || kind === "longname") meta.push(Buffer.from(slice));
|
|
296
|
+
pos += take;
|
|
297
|
+
remaining -= take;
|
|
298
|
+
if (remaining === 0) {
|
|
299
|
+
if (kind === "target") {
|
|
300
|
+
await out.close();
|
|
301
|
+
out = void 0;
|
|
302
|
+
found = true;
|
|
303
|
+
} else if (kind === "pax") {
|
|
304
|
+
overridePath = paxPath(Buffer.concat(meta)) ?? overridePath;
|
|
305
|
+
} else if (kind === "longname") {
|
|
306
|
+
overridePath = readString(Buffer.concat(meta), 0, Number.MAX_SAFE_INTEGER);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (padding > 0) {
|
|
312
|
+
const skip = Math.min(padding, pending.length - pos);
|
|
313
|
+
pos += skip;
|
|
314
|
+
padding -= skip;
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (found) break;
|
|
318
|
+
if (pending.length - pos < BLOCK) break;
|
|
319
|
+
const header = pending.subarray(pos, pos + BLOCK);
|
|
320
|
+
pos += BLOCK;
|
|
321
|
+
if (header.every((b) => b === 0)) continue;
|
|
322
|
+
const size = readSize(header, 124);
|
|
323
|
+
const type2 = String.fromCharCode(header[156] || 48);
|
|
324
|
+
let name = readString(header, 0, 100);
|
|
325
|
+
if (readString(header, 257, 6) === "ustar") {
|
|
326
|
+
const prefix = readString(header, 345, 155);
|
|
327
|
+
if (prefix) name = `${prefix}/${name}`;
|
|
328
|
+
}
|
|
329
|
+
remaining = size;
|
|
330
|
+
padding = (BLOCK - size % BLOCK) % BLOCK;
|
|
331
|
+
meta = [];
|
|
332
|
+
if (type2 === "x") kind = "pax";
|
|
333
|
+
else if (type2 === "L") kind = "longname";
|
|
334
|
+
else {
|
|
335
|
+
const path4 = overridePath ?? name;
|
|
336
|
+
overridePath = void 0;
|
|
337
|
+
if ((type2 === "0" || type2 === "\0" || type2 === "7") && path4 === entryName) {
|
|
338
|
+
kind = "target";
|
|
339
|
+
out = await fsp.open(destPath, "w", 493);
|
|
340
|
+
if (size === 0) {
|
|
341
|
+
await out.close();
|
|
342
|
+
out = void 0;
|
|
343
|
+
found = true;
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
kind = "skip";
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
pending = pos < pending.length ? Buffer.from(pending.subarray(pos)) : Buffer.alloc(0);
|
|
351
|
+
if (found) break;
|
|
352
|
+
}
|
|
353
|
+
if (!found && out) throw new Error(`Archive ended inside ${entryName}`);
|
|
354
|
+
return found;
|
|
355
|
+
} finally {
|
|
356
|
+
if (out) await out.close().catch(() => {
|
|
357
|
+
});
|
|
358
|
+
input.destroy();
|
|
359
|
+
}
|
|
256
360
|
}
|
|
257
361
|
|
|
258
|
-
// src/claude-code
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
362
|
+
// src/claude-code/manifest.json
|
|
363
|
+
var manifest_default = {
|
|
364
|
+
sdkVersion: "0.3.318",
|
|
365
|
+
claudeCodeVersion: "2.1.318",
|
|
366
|
+
platforms: {
|
|
367
|
+
"darwin-arm64": {
|
|
368
|
+
url: "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.318.tgz",
|
|
369
|
+
integrity: "sha512-AWoXeDXzAMD3RaA21lWuHvCrKd8xmbTTmKjovninn4j07jheoVSMzFbCFjpp4kk5TdhT36JtWPkAxvjNMbcO8w==",
|
|
370
|
+
bin: "claude"
|
|
371
|
+
},
|
|
372
|
+
"darwin-x64": {
|
|
373
|
+
url: "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.318.tgz",
|
|
374
|
+
integrity: "sha512-6CkZ5PCdebSY/LePp16sf/HYRtM6zVuxtn8qYICFS5KUZFsjccJJ9swVsOdHXNHi4SWZcSmIFTwoUbfFCzisRw==",
|
|
375
|
+
bin: "claude"
|
|
376
|
+
},
|
|
377
|
+
"linux-arm64": {
|
|
378
|
+
url: "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.318.tgz",
|
|
379
|
+
integrity: "sha512-mBm4su17aMitLBBCQj3bHdejyUDY6z/ormGih+HG24N689RSbdKECjGjkT87tDBIR/4jyoqmuSeHqM1DI8TJlg==",
|
|
380
|
+
bin: "claude"
|
|
381
|
+
},
|
|
382
|
+
"linux-arm64-musl": {
|
|
383
|
+
url: "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.318.tgz",
|
|
384
|
+
integrity: "sha512-l4LSYFOrvlYCrUImGfxMTQ0wg+T3s9CBhrBvPF/0oJGKZg+QnxHHU8jUVm9e9/xYmDRTtqFIrr4id/5AfH4XGw==",
|
|
385
|
+
bin: "claude"
|
|
386
|
+
},
|
|
387
|
+
"linux-x64": {
|
|
388
|
+
url: "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.318.tgz",
|
|
389
|
+
integrity: "sha512-+mE+ueBD3oRFdaG16rd0h+LMjdeivGxL0pr/+FZK7JeLWVu+yPSw/f/X02b9oK36/DWykiFTu2G6HnJ9/+YO6w==",
|
|
390
|
+
bin: "claude"
|
|
391
|
+
},
|
|
392
|
+
"linux-x64-musl": {
|
|
393
|
+
url: "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.318.tgz",
|
|
394
|
+
integrity: "sha512-SAF3lj/2OzTU84p+OOA13QEKA9+5fYAw0M9E7AJjdnRmVFGqQfbV7Do1i1f9Sj0mIubB3rLTRphGRw8O4HZjgA==",
|
|
395
|
+
bin: "claude"
|
|
396
|
+
},
|
|
397
|
+
"win32-arm64": {
|
|
398
|
+
url: "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.318.tgz",
|
|
399
|
+
integrity: "sha512-19iVSZ4379QbZU1XnGUtfFvhKS1WzS8H1sbU/DbrzqbJ5Kq1eB1drj+obB1fCxTh6m26tRPj0zMJmdeu/jk3Gw==",
|
|
400
|
+
bin: "claude.exe"
|
|
401
|
+
},
|
|
402
|
+
"win32-x64": {
|
|
403
|
+
url: "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.318.tgz",
|
|
404
|
+
integrity: "sha512-ZdKVWpyVNVt0cXrOf8sUBaxcxLEAP+oGMdQDLBWr/BqOxTWLy7TBWOj1kzw+wVg/9WIkjkgQWeJzGXPWulR1sA==",
|
|
405
|
+
bin: "claude.exe"
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
};
|
|
264
409
|
|
|
265
|
-
// src/
|
|
266
|
-
var
|
|
267
|
-
var
|
|
268
|
-
var
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
410
|
+
// src/claude-code/runtime.ts
|
|
411
|
+
var CLAUDE_CODE_MANIFEST = manifest_default;
|
|
412
|
+
var CLAUDE_CODE_AUTH_KEY = "anthropic-claude-code";
|
|
413
|
+
var CLAUDE_CODE_AUTH_MARKER = { via: "claude-code" };
|
|
414
|
+
function isClaudeCodeAuthMarker(value) {
|
|
415
|
+
return value?.via === CLAUDE_CODE_AUTH_MARKER.via;
|
|
416
|
+
}
|
|
417
|
+
function isLegacyClaudeOAuth(value) {
|
|
418
|
+
const token = value?.accessToken;
|
|
419
|
+
return typeof token === "string" && token.startsWith("sk-ant-oat");
|
|
420
|
+
}
|
|
421
|
+
function isMusl() {
|
|
422
|
+
if (process.platform !== "linux") return false;
|
|
423
|
+
const report = typeof process.report?.getReport === "function" ? process.report.getReport() : null;
|
|
424
|
+
return report != null && report.header?.glibcVersionRuntime === void 0;
|
|
425
|
+
}
|
|
426
|
+
function claudeCodePlatformKey(info = { platform: process.platform, arch: process.arch, musl: isMusl() }) {
|
|
427
|
+
const arch2 = info.arch === "arm64" || info.arch === "x64" ? info.arch : null;
|
|
428
|
+
if (!arch2) return null;
|
|
429
|
+
if (info.platform === "darwin" || info.platform === "win32") return `${info.platform}-${arch2}`;
|
|
430
|
+
if (info.platform === "linux") return `linux-${arch2}${info.musl ? "-musl" : ""}`;
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
function resolveAsset(opts) {
|
|
434
|
+
const manifest = opts.manifest ?? CLAUDE_CODE_MANIFEST;
|
|
435
|
+
const key = opts.platformKey ?? claudeCodePlatformKey();
|
|
436
|
+
const asset = key ? manifest.platforms[key] : void 0;
|
|
437
|
+
if (!asset) {
|
|
438
|
+
throw new Error(
|
|
439
|
+
`Claude Code isn't available for ${process.platform}-${process.arch}. Use an Anthropic API key instead.`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
return { manifest, asset };
|
|
443
|
+
}
|
|
444
|
+
function claudeCodeHome(opts = {}) {
|
|
445
|
+
return opts.home ?? getAppPaths().claudeCodeDir;
|
|
446
|
+
}
|
|
447
|
+
function claudeCodeConfigDir(opts = {}) {
|
|
448
|
+
return opts.home ? path2.join(opts.home, "config") : getAppPaths().claudeCodeConfigDir;
|
|
449
|
+
}
|
|
450
|
+
function claudeCodeBinaryPath(opts = {}) {
|
|
451
|
+
const { manifest, asset } = resolveAsset(opts);
|
|
452
|
+
return path2.join(claudeCodeHome(opts), manifest.claudeCodeVersion, asset.bin);
|
|
453
|
+
}
|
|
454
|
+
function resolveClaudeCodeBinary(opts = {}) {
|
|
455
|
+
let binary;
|
|
456
|
+
try {
|
|
457
|
+
binary = claudeCodeBinaryPath(opts);
|
|
458
|
+
} catch {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
try {
|
|
462
|
+
return fs2.statSync(binary).isFile() ? binary : null;
|
|
463
|
+
} catch {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
var installs = /* @__PURE__ */ new Map();
|
|
468
|
+
async function ensureClaudeCodeBinary(opts = {}) {
|
|
469
|
+
const existing = resolveClaudeCodeBinary(opts);
|
|
470
|
+
if (existing) return existing;
|
|
471
|
+
const target = claudeCodeBinaryPath(opts);
|
|
472
|
+
let install = installs.get(target);
|
|
473
|
+
if (!install) {
|
|
474
|
+
install = installClaudeCode(opts).finally(() => installs.delete(target));
|
|
475
|
+
installs.set(target, install);
|
|
476
|
+
}
|
|
477
|
+
return install;
|
|
478
|
+
}
|
|
479
|
+
async function installClaudeCode(opts) {
|
|
480
|
+
const { manifest, asset } = resolveAsset(opts);
|
|
481
|
+
const home = claudeCodeHome(opts);
|
|
482
|
+
const versionDir = path2.join(home, manifest.claudeCodeVersion);
|
|
483
|
+
const binary = path2.join(versionDir, asset.bin);
|
|
484
|
+
await fsp2.mkdir(home, { recursive: true });
|
|
485
|
+
const tag = `${process.pid}-${crypto2.randomBytes(4).toString("hex")}`;
|
|
486
|
+
const tarball = path2.join(home, `.download-${tag}.tgz`);
|
|
487
|
+
const staging = path2.join(home, `.staging-${tag}`);
|
|
488
|
+
try {
|
|
489
|
+
await download(asset, tarball, opts);
|
|
490
|
+
opts.onProgress?.({ phase: "extract" });
|
|
491
|
+
await fsp2.mkdir(staging, { recursive: true });
|
|
492
|
+
const found = await extractFileFromTarGz(
|
|
493
|
+
tarball,
|
|
494
|
+
`package/${asset.bin}`,
|
|
495
|
+
path2.join(staging, asset.bin)
|
|
496
|
+
);
|
|
497
|
+
if (!found) throw new Error(`The Claude Code download has no ${asset.bin} binary.`);
|
|
498
|
+
await fsp2.chmod(path2.join(staging, asset.bin), 493);
|
|
284
499
|
try {
|
|
285
|
-
|
|
286
|
-
method: "POST",
|
|
287
|
-
headers,
|
|
288
|
-
body: encoded,
|
|
289
|
-
signal: oauthRequestSignal()
|
|
290
|
-
});
|
|
500
|
+
await fsp2.rename(staging, versionDir);
|
|
291
501
|
} catch (err) {
|
|
292
|
-
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
if (response.ok) {
|
|
296
|
-
return await response.json();
|
|
502
|
+
if (!fs2.existsSync(binary)) throw err;
|
|
297
503
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
504
|
+
await removeOldVersions(home, manifest.claudeCodeVersion);
|
|
505
|
+
return binary;
|
|
506
|
+
} finally {
|
|
507
|
+
await fsp2.rm(tarball, { force: true }).catch(() => {
|
|
508
|
+
});
|
|
509
|
+
await fsp2.rm(staging, { recursive: true, force: true }).catch(() => {
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
async function download(asset, dest, opts) {
|
|
514
|
+
const doFetch = opts.fetch ?? fetch;
|
|
515
|
+
const res = await doFetch(asset.url, { signal: opts.signal });
|
|
516
|
+
if (!res.ok || !res.body) {
|
|
517
|
+
throw new Error(`Claude Code download failed (HTTP ${res.status}).`);
|
|
518
|
+
}
|
|
519
|
+
const totalBytes = Number(res.headers.get("content-length")) || void 0;
|
|
520
|
+
const hash = crypto2.createHash("sha512");
|
|
521
|
+
const out = await fsp2.open(dest, "w");
|
|
522
|
+
let receivedBytes = 0;
|
|
523
|
+
let lastReported = -1;
|
|
524
|
+
try {
|
|
525
|
+
opts.onProgress?.({ phase: "download", receivedBytes, totalBytes });
|
|
526
|
+
for await (const chunk of res.body) {
|
|
527
|
+
if (opts.signal?.aborted) throw opts.signal.reason ?? new Error("Download cancelled.");
|
|
528
|
+
hash.update(chunk);
|
|
529
|
+
await out.write(chunk);
|
|
530
|
+
receivedBytes += chunk.byteLength;
|
|
531
|
+
const step = totalBytes ? Math.floor(receivedBytes / totalBytes * 100) : Math.floor(receivedBytes / 4194304);
|
|
532
|
+
if (step !== lastReported) {
|
|
533
|
+
lastReported = step;
|
|
534
|
+
opts.onProgress?.({ phase: "download", receivedBytes, totalBytes });
|
|
535
|
+
}
|
|
301
536
|
}
|
|
302
|
-
|
|
537
|
+
} finally {
|
|
538
|
+
await out.close();
|
|
539
|
+
}
|
|
540
|
+
opts.onProgress?.({ phase: "verify" });
|
|
541
|
+
const expected = asset.integrity.replace(/^sha512-/, "");
|
|
542
|
+
if (hash.digest("base64") !== expected) {
|
|
543
|
+
throw new Error(
|
|
544
|
+
"The Claude Code download didn't match its pinned checksum, so it was discarded."
|
|
545
|
+
);
|
|
303
546
|
}
|
|
304
|
-
throw lastError ?? new Error(`Anthropic ${label} failed: all endpoints unreachable`);
|
|
305
547
|
}
|
|
306
|
-
function
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
548
|
+
async function removeOldVersions(home, keep) {
|
|
549
|
+
let entries;
|
|
550
|
+
try {
|
|
551
|
+
entries = await fsp2.readdir(home, { withFileTypes: true });
|
|
552
|
+
} catch {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
for (const entry of entries) {
|
|
556
|
+
if (!entry.isDirectory() || entry.name === keep || entry.name === "config") continue;
|
|
557
|
+
if (!/^\d+\.\d+\.\d+/.test(entry.name)) continue;
|
|
558
|
+
await fsp2.rm(path2.join(home, entry.name), { recursive: true, force: true }).catch(() => {
|
|
559
|
+
});
|
|
560
|
+
}
|
|
312
561
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
562
|
+
function formatClaudeCodeInstallProgress(progress) {
|
|
563
|
+
if (progress.phase === "verify") return "Checking the Claude Code download\u2026";
|
|
564
|
+
if (progress.phase === "extract") return "Unpacking Claude Code\u2026";
|
|
565
|
+
const mb = (bytes) => Math.round(bytes / 1048576);
|
|
566
|
+
if (!progress.totalBytes) return `Downloading Claude Code\u2026 ${mb(progress.receivedBytes)} MB`;
|
|
567
|
+
const pct = Math.floor(progress.receivedBytes / progress.totalBytes * 100);
|
|
568
|
+
return `Downloading Claude Code\u2026 ${pct}% (${mb(progress.receivedBytes)} of ${mb(progress.totalBytes)} MB)`;
|
|
569
|
+
}
|
|
570
|
+
var STRIPPED_ENV = [
|
|
571
|
+
"ANTHROPIC_API_KEY",
|
|
572
|
+
"ANTHROPIC_AUTH_TOKEN",
|
|
573
|
+
"ANTHROPIC_BASE_URL",
|
|
574
|
+
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
575
|
+
"CLAUDE_CODE_OAUTH_REFRESH_TOKEN",
|
|
576
|
+
"CLAUDE_CODE_USE_BEDROCK",
|
|
577
|
+
"CLAUDE_CODE_USE_VERTEX",
|
|
578
|
+
"CLAUDE_CODE_USE_FOUNDRY",
|
|
579
|
+
"NODE_OPTIONS"
|
|
580
|
+
];
|
|
581
|
+
function claudeCodeEnv(opts = {}, base = process.env) {
|
|
582
|
+
const env = {};
|
|
583
|
+
for (const [key, value] of Object.entries(base)) {
|
|
584
|
+
if (value !== void 0 && !STRIPPED_ENV.includes(key)) env[key] = value;
|
|
585
|
+
}
|
|
586
|
+
env.CLAUDE_CONFIG_DIR = claudeCodeConfigDir(opts);
|
|
587
|
+
env.DISABLE_AUTOUPDATER = "1";
|
|
588
|
+
return env;
|
|
589
|
+
}
|
|
590
|
+
function runCommand(opts) {
|
|
591
|
+
if (opts.binary) return { command: opts.binary, prefix: opts.binaryArgs ?? [] };
|
|
592
|
+
const binary = resolveClaudeCodeBinary(opts);
|
|
593
|
+
if (!binary) throw new Error("Claude Code isn't installed yet. Sign in with Claude first.");
|
|
594
|
+
return { command: binary, prefix: [] };
|
|
595
|
+
}
|
|
596
|
+
function runClaude(args, opts) {
|
|
597
|
+
const { command, prefix } = runCommand(opts);
|
|
598
|
+
return new Promise((resolve, reject) => {
|
|
599
|
+
const child = spawn(command, [...prefix, ...args], {
|
|
600
|
+
env: claudeCodeEnv(opts),
|
|
601
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
602
|
+
windowsHide: true,
|
|
603
|
+
signal: opts.signal
|
|
604
|
+
});
|
|
605
|
+
let stdout = "";
|
|
606
|
+
let stderr = "";
|
|
607
|
+
child.stdout.on("data", (d) => stdout += d.toString());
|
|
608
|
+
child.stderr.on("data", (d) => stderr += d.toString());
|
|
609
|
+
child.on("error", reject);
|
|
610
|
+
child.on("close", (code) => resolve({ code, stdout, stderr }));
|
|
325
611
|
});
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
612
|
+
}
|
|
613
|
+
async function claudeCodeAuthStatus(opts = {}) {
|
|
614
|
+
if (!opts.binary && !resolveClaudeCodeBinary(opts)) return { loggedIn: false };
|
|
615
|
+
const { stdout } = await runClaude(["auth", "status", "--json"], opts);
|
|
616
|
+
try {
|
|
617
|
+
const parsed = JSON.parse(stdout);
|
|
618
|
+
return {
|
|
619
|
+
loggedIn: parsed.loggedIn === true,
|
|
620
|
+
...typeof parsed.authMethod === "string" ? { authMethod: parsed.authMethod } : {},
|
|
621
|
+
...typeof parsed.email === "string" ? { email: parsed.email } : {},
|
|
622
|
+
...typeof parsed.subscriptionType === "string" ? { subscriptionType: parsed.subscriptionType } : {}
|
|
623
|
+
};
|
|
624
|
+
} catch {
|
|
625
|
+
return { loggedIn: false };
|
|
332
626
|
}
|
|
333
|
-
return exchangeAnthropicCode(parts[0], parts[1], verifier);
|
|
334
627
|
}
|
|
335
|
-
async function
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
client_id: CLIENT_ID2,
|
|
340
|
-
code,
|
|
341
|
-
state,
|
|
342
|
-
redirect_uri: REDIRECT_URI,
|
|
343
|
-
code_verifier: verifier
|
|
344
|
-
},
|
|
345
|
-
"token exchange"
|
|
346
|
-
);
|
|
347
|
-
return toCredentials(data);
|
|
628
|
+
async function logoutClaudeCode(opts = {}) {
|
|
629
|
+
if (!opts.binary && !resolveClaudeCodeBinary(opts)) return;
|
|
630
|
+
const { code, stderr } = await runClaude(["auth", "logout"], opts);
|
|
631
|
+
if (code !== 0) throw new Error(stderr.trim() || `claude auth logout exited with ${code}`);
|
|
348
632
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return
|
|
633
|
+
var OPEN_URL_HOOK = `const arg = String(process.argv[1] || "");
|
|
634
|
+
const file = process.env.GG_CLAUDE_CODE_URL_FILE;
|
|
635
|
+
if (file && /https?:/.test(arg)) {
|
|
636
|
+
require("node:fs").appendFileSync(file, arg + "\\n");
|
|
637
|
+
process.exit(0);
|
|
638
|
+
}
|
|
639
|
+
`;
|
|
640
|
+
var CAPTURE_WAIT_MS = 3e3;
|
|
641
|
+
function stripAnsi(text) {
|
|
642
|
+
return text.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[[0-9;?]*[A-Za-z]/g, "");
|
|
643
|
+
}
|
|
644
|
+
function claudeCodeCallbackUrl(manualUrl, captured) {
|
|
645
|
+
const port = /localhost(?::|%3A)(\d{2,5})(?:\/|%2F)callback/i.exec(captured)?.[1];
|
|
646
|
+
if (!port) return null;
|
|
647
|
+
try {
|
|
648
|
+
const url = new URL(manualUrl);
|
|
649
|
+
url.searchParams.set("redirect_uri", `http://localhost:${port}/callback`);
|
|
650
|
+
return url.toString();
|
|
651
|
+
} catch {
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
async function loginClaudeCode(callbacks, opts = {}) {
|
|
656
|
+
const { command, prefix } = runCommand(opts);
|
|
657
|
+
const home = claudeCodeHome(opts);
|
|
658
|
+
await fsp2.mkdir(claudeCodeConfigDir(opts), { recursive: true });
|
|
659
|
+
const tag = `${process.pid}-${crypto2.randomBytes(4).toString("hex")}`;
|
|
660
|
+
const hookFile = path2.join(home, `.open-url-${tag}.cjs`);
|
|
661
|
+
const urlFile = path2.join(home, `.open-url-${tag}.txt`);
|
|
662
|
+
await fsp2.writeFile(hookFile, OPEN_URL_HOOK);
|
|
663
|
+
const env = {
|
|
664
|
+
...claudeCodeEnv(opts),
|
|
665
|
+
BROWSER: process.execPath,
|
|
666
|
+
NODE_OPTIONS: `--require ${JSON.stringify(hookFile)}`,
|
|
667
|
+
GG_CLAUDE_CODE_URL_FILE: urlFile
|
|
668
|
+
};
|
|
669
|
+
const promptAbort = new AbortController();
|
|
670
|
+
let timer;
|
|
671
|
+
try {
|
|
672
|
+
await new Promise((resolve, reject) => {
|
|
673
|
+
const child = spawn(command, [...prefix, "auth", "login", "--claudeai"], {
|
|
674
|
+
env,
|
|
675
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
676
|
+
windowsHide: true
|
|
677
|
+
});
|
|
678
|
+
let stdout = "";
|
|
679
|
+
let stderr = "";
|
|
680
|
+
let manualUrl = null;
|
|
681
|
+
let opened = false;
|
|
682
|
+
const onAbort = () => child.kill();
|
|
683
|
+
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
684
|
+
const open = (url, needsCode) => {
|
|
685
|
+
if (opened) return;
|
|
686
|
+
opened = true;
|
|
687
|
+
clearInterval(timer);
|
|
688
|
+
callbacks.onOpenUrl(url);
|
|
689
|
+
callbacks.onStatus("Finish signing in to Claude in your browser\u2026");
|
|
690
|
+
if (!needsCode) return;
|
|
691
|
+
void callbacks.onPromptCode("Paste the code shown after signing in to Claude:", promptAbort.signal).then((code) => {
|
|
692
|
+
const trimmed = code.trim();
|
|
693
|
+
if (trimmed && !child.stdin.destroyed) child.stdin.write(`${trimmed}
|
|
694
|
+
`);
|
|
695
|
+
}).catch(() => {
|
|
696
|
+
});
|
|
697
|
+
};
|
|
698
|
+
child.stdout.on("data", (d) => {
|
|
699
|
+
stdout += d.toString();
|
|
700
|
+
if (manualUrl) return;
|
|
701
|
+
const match = /visit:\s*(https:\/\/\S+)/.exec(stripAnsi(stdout));
|
|
702
|
+
if (!match) return;
|
|
703
|
+
manualUrl = match[1];
|
|
704
|
+
const started = Date.now();
|
|
705
|
+
timer = setInterval(() => {
|
|
706
|
+
let captured = "";
|
|
707
|
+
try {
|
|
708
|
+
captured = fs2.readFileSync(urlFile, "utf8");
|
|
709
|
+
} catch {
|
|
710
|
+
}
|
|
711
|
+
const callbackUrl = captured ? claudeCodeCallbackUrl(manualUrl, captured) : null;
|
|
712
|
+
if (callbackUrl) open(callbackUrl, false);
|
|
713
|
+
else if (Date.now() - started > (opts.browserWaitMs ?? CAPTURE_WAIT_MS))
|
|
714
|
+
open(manualUrl, true);
|
|
715
|
+
}, 100);
|
|
716
|
+
});
|
|
717
|
+
child.stderr.on("data", (d) => stderr += d.toString());
|
|
718
|
+
child.on("error", reject);
|
|
719
|
+
child.on("close", (code) => {
|
|
720
|
+
opts.signal?.removeEventListener("abort", onAbort);
|
|
721
|
+
if (opts.signal?.aborted) reject(new Error("Sign-in cancelled."));
|
|
722
|
+
else if (code === 0) resolve();
|
|
723
|
+
else {
|
|
724
|
+
const detail = stripAnsi(stderr).trim().split("\n").pop()?.trim();
|
|
725
|
+
reject(new Error(detail || `Claude sign-in failed (exit ${code}).`));
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
});
|
|
729
|
+
} finally {
|
|
730
|
+
clearInterval(timer);
|
|
731
|
+
promptAbort.abort();
|
|
732
|
+
await fsp2.rm(hookFile, { force: true }).catch(() => {
|
|
733
|
+
});
|
|
734
|
+
await fsp2.rm(urlFile, { force: true }).catch(() => {
|
|
735
|
+
});
|
|
736
|
+
}
|
|
359
737
|
}
|
|
360
738
|
|
|
361
739
|
// src/oauth/openai.ts
|
|
362
740
|
import http from "http";
|
|
363
741
|
import crypto3 from "crypto";
|
|
364
|
-
|
|
365
|
-
|
|
742
|
+
|
|
743
|
+
// src/oauth/pkce.ts
|
|
744
|
+
function base64urlEncode(bytes) {
|
|
745
|
+
let binary = "";
|
|
746
|
+
for (const byte of bytes) {
|
|
747
|
+
binary += String.fromCharCode(byte);
|
|
748
|
+
}
|
|
749
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
750
|
+
}
|
|
751
|
+
async function generatePKCE() {
|
|
752
|
+
const verifierBytes = new Uint8Array(32);
|
|
753
|
+
crypto.getRandomValues(verifierBytes);
|
|
754
|
+
const verifier = base64urlEncode(verifierBytes);
|
|
755
|
+
const data = new TextEncoder().encode(verifier);
|
|
756
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
757
|
+
const challenge = base64urlEncode(new Uint8Array(hashBuffer));
|
|
758
|
+
return { verifier, challenge };
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// src/oauth/openai.ts
|
|
762
|
+
var CLIENT_ID2 = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
763
|
+
var AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize";
|
|
366
764
|
var TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
367
|
-
var
|
|
765
|
+
var REDIRECT_URI = "http://localhost:1455/auth/callback";
|
|
368
766
|
var SCOPE = "openid profile email offline_access api.connectors.read api.connectors.invoke";
|
|
369
767
|
var JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
370
768
|
var CALLBACK_TIMEOUT_MS = 12e4;
|
|
@@ -373,10 +771,10 @@ var MIN_RAW_CODE_LENGTH = 10;
|
|
|
373
771
|
async function loginOpenAI(callbacks) {
|
|
374
772
|
const { verifier, challenge } = await generatePKCE();
|
|
375
773
|
const state = crypto3.randomBytes(16).toString("hex");
|
|
376
|
-
const url = new URL(
|
|
774
|
+
const url = new URL(AUTHORIZE_URL);
|
|
377
775
|
url.searchParams.set("response_type", "code");
|
|
378
|
-
url.searchParams.set("client_id",
|
|
379
|
-
url.searchParams.set("redirect_uri",
|
|
776
|
+
url.searchParams.set("client_id", CLIENT_ID2);
|
|
777
|
+
url.searchParams.set("redirect_uri", REDIRECT_URI);
|
|
380
778
|
url.searchParams.set("scope", SCOPE);
|
|
381
779
|
url.searchParams.set("code_challenge", challenge);
|
|
382
780
|
url.searchParams.set("code_challenge_method", "S256");
|
|
@@ -532,9 +930,9 @@ async function exchangeOpenAICode(code, verifier) {
|
|
|
532
930
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
533
931
|
body: new URLSearchParams({
|
|
534
932
|
grant_type: "authorization_code",
|
|
535
|
-
client_id:
|
|
933
|
+
client_id: CLIENT_ID2,
|
|
536
934
|
code,
|
|
537
|
-
redirect_uri:
|
|
935
|
+
redirect_uri: REDIRECT_URI,
|
|
538
936
|
code_verifier: verifier
|
|
539
937
|
}),
|
|
540
938
|
signal: oauthRequestSignal()
|
|
@@ -557,7 +955,7 @@ async function refreshOpenAIToken(refreshToken) {
|
|
|
557
955
|
body: new URLSearchParams({
|
|
558
956
|
grant_type: "refresh_token",
|
|
559
957
|
refresh_token: refreshToken,
|
|
560
|
-
client_id:
|
|
958
|
+
client_id: CLIENT_ID2
|
|
561
959
|
}),
|
|
562
960
|
signal: oauthRequestSignal()
|
|
563
961
|
});
|
|
@@ -585,7 +983,7 @@ var CLIENT_ID_ENV = "GGCODER_GEMINI_OAUTH_CLIENT_ID";
|
|
|
585
983
|
var CLIENT_SECRET_ENV = "GGCODER_GEMINI_OAUTH_CLIENT_SECRET";
|
|
586
984
|
var DEFAULT_CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com";
|
|
587
985
|
var DEFAULT_CLIENT_SECRET = "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";
|
|
588
|
-
var
|
|
986
|
+
var AUTHORIZE_URL2 = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
589
987
|
var TOKEN_URL2 = "https://oauth2.googleapis.com/token";
|
|
590
988
|
var CODE_ASSIST_BASE_URL = "https://cloudcode-pa.googleapis.com";
|
|
591
989
|
var CODE_ASSIST_API_VERSION = "v1internal";
|
|
@@ -616,7 +1014,7 @@ async function loginGemini(callbacks) {
|
|
|
616
1014
|
const { verifier, challenge } = await generatePKCE();
|
|
617
1015
|
const state = crypto4.randomBytes(32).toString("hex");
|
|
618
1016
|
const redirectUri = await getLoopbackRedirectUri();
|
|
619
|
-
const url = new URL(
|
|
1017
|
+
const url = new URL(AUTHORIZE_URL2);
|
|
620
1018
|
url.searchParams.set("response_type", "code");
|
|
621
1019
|
url.searchParams.set("client_id", clientId2);
|
|
622
1020
|
url.searchParams.set("redirect_uri", redirectUri);
|
|
@@ -653,7 +1051,7 @@ async function loginGemini(callbacks) {
|
|
|
653
1051
|
}
|
|
654
1052
|
async function refreshGeminiToken(refreshToken) {
|
|
655
1053
|
const { clientId: clientId2, clientSecret } = getGeminiOAuthClientCredentials();
|
|
656
|
-
const data = await
|
|
1054
|
+
const data = await postTokenRequest({
|
|
657
1055
|
grant_type: "refresh_token",
|
|
658
1056
|
refresh_token: refreshToken,
|
|
659
1057
|
client_id: clientId2,
|
|
@@ -748,7 +1146,7 @@ async function loginWithServer(authUrl, redirectUri, expectedState, callbacks) {
|
|
|
748
1146
|
});
|
|
749
1147
|
}
|
|
750
1148
|
async function exchangeGeminiCode(code, verifier, redirectUri, clientId2, clientSecret) {
|
|
751
|
-
const data = await
|
|
1149
|
+
const data = await postTokenRequest({
|
|
752
1150
|
grant_type: "authorization_code",
|
|
753
1151
|
client_id: clientId2,
|
|
754
1152
|
client_secret: clientSecret,
|
|
@@ -765,7 +1163,7 @@ async function exchangeGeminiCode(code, verifier, redirectUri, clientId2, client
|
|
|
765
1163
|
expiresAt: Date.now() + data.expires_in * 1e3 - 5 * 60 * 1e3
|
|
766
1164
|
};
|
|
767
1165
|
}
|
|
768
|
-
async function
|
|
1166
|
+
async function postTokenRequest(body) {
|
|
769
1167
|
const response = await fetch(TOKEN_URL2, {
|
|
770
1168
|
method: "POST",
|
|
771
1169
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
@@ -1143,7 +1541,7 @@ async function refreshXaiToken(refreshToken) {
|
|
|
1143
1541
|
}
|
|
1144
1542
|
|
|
1145
1543
|
// src/file-lock.ts
|
|
1146
|
-
import
|
|
1544
|
+
import fs3 from "fs/promises";
|
|
1147
1545
|
import { setTimeout as setTimeout2 } from "timers/promises";
|
|
1148
1546
|
var STALE_TIMEOUT_MS = 1e4;
|
|
1149
1547
|
var RETRY_INTERVAL_MS = 50;
|
|
@@ -1164,7 +1562,7 @@ async function acquireLock(lockPath) {
|
|
|
1164
1562
|
while (true) {
|
|
1165
1563
|
try {
|
|
1166
1564
|
const info = { pid: process.pid, timestamp: Date.now() };
|
|
1167
|
-
await
|
|
1565
|
+
await fs3.writeFile(lockPath, JSON.stringify(info), { flag: "wx" });
|
|
1168
1566
|
return;
|
|
1169
1567
|
} catch (err) {
|
|
1170
1568
|
const code = err.code;
|
|
@@ -1177,26 +1575,26 @@ async function acquireLock(lockPath) {
|
|
|
1177
1575
|
continue;
|
|
1178
1576
|
}
|
|
1179
1577
|
try {
|
|
1180
|
-
const content = await
|
|
1578
|
+
const content = await fs3.readFile(lockPath, "utf-8");
|
|
1181
1579
|
const info = JSON.parse(content);
|
|
1182
1580
|
const isProcessAlive = isAlive(info.pid);
|
|
1183
1581
|
const isStale = Date.now() - info.timestamp > STALE_TIMEOUT_MS;
|
|
1184
1582
|
if (!isProcessAlive || isStale) {
|
|
1185
|
-
await
|
|
1583
|
+
await fs3.unlink(lockPath).catch(() => {
|
|
1186
1584
|
});
|
|
1187
1585
|
continue;
|
|
1188
1586
|
}
|
|
1189
1587
|
} catch {
|
|
1190
|
-
const stat = await
|
|
1588
|
+
const stat = await fs3.stat(lockPath).catch(() => null);
|
|
1191
1589
|
if (!stat) continue;
|
|
1192
1590
|
if (Date.now() - stat.mtimeMs > STALE_TIMEOUT_MS) {
|
|
1193
|
-
await
|
|
1591
|
+
await fs3.unlink(lockPath).catch(() => {
|
|
1194
1592
|
});
|
|
1195
1593
|
continue;
|
|
1196
1594
|
}
|
|
1197
1595
|
}
|
|
1198
1596
|
if (Date.now() - startTime > MAX_WAIT_MS) {
|
|
1199
|
-
await
|
|
1597
|
+
await fs3.unlink(lockPath).catch(() => {
|
|
1200
1598
|
});
|
|
1201
1599
|
continue;
|
|
1202
1600
|
}
|
|
@@ -1206,14 +1604,14 @@ async function acquireLock(lockPath) {
|
|
|
1206
1604
|
}
|
|
1207
1605
|
async function lockFileExists(lockPath) {
|
|
1208
1606
|
try {
|
|
1209
|
-
await
|
|
1607
|
+
await fs3.stat(lockPath);
|
|
1210
1608
|
return true;
|
|
1211
1609
|
} catch (err) {
|
|
1212
1610
|
return err.code !== "ENOENT";
|
|
1213
1611
|
}
|
|
1214
1612
|
}
|
|
1215
1613
|
async function releaseLock(lockPath) {
|
|
1216
|
-
await
|
|
1614
|
+
await fs3.unlink(lockPath).catch(() => {
|
|
1217
1615
|
});
|
|
1218
1616
|
}
|
|
1219
1617
|
function isAlive(pid) {
|
|
@@ -1227,8 +1625,8 @@ function isAlive(pid) {
|
|
|
1227
1625
|
}
|
|
1228
1626
|
|
|
1229
1627
|
// src/logger.ts
|
|
1230
|
-
import
|
|
1231
|
-
import
|
|
1628
|
+
import fs4 from "fs";
|
|
1629
|
+
import path3 from "path";
|
|
1232
1630
|
import { randomBytes } from "crypto";
|
|
1233
1631
|
import { environmentSecrets, redactText, redactValue } from "@kenkaiiii/gg-ai";
|
|
1234
1632
|
var MAX_BYTES = 10 * 1024 * 1024;
|
|
@@ -1245,14 +1643,14 @@ var cleanups = [];
|
|
|
1245
1643
|
var exactSecrets = [];
|
|
1246
1644
|
function rotateIfNeeded(filePath, force = false) {
|
|
1247
1645
|
try {
|
|
1248
|
-
const st =
|
|
1646
|
+
const st = fs4.statSync(filePath);
|
|
1249
1647
|
if (!force && st.size <= MAX_BYTES - MIN_HEADROOM_BYTES) return;
|
|
1250
1648
|
const rotated = `${filePath}.1`;
|
|
1251
1649
|
try {
|
|
1252
|
-
|
|
1650
|
+
fs4.unlinkSync(rotated);
|
|
1253
1651
|
} catch {
|
|
1254
1652
|
}
|
|
1255
|
-
|
|
1653
|
+
fs4.renameSync(filePath, rotated);
|
|
1256
1654
|
} catch {
|
|
1257
1655
|
}
|
|
1258
1656
|
}
|
|
@@ -1260,18 +1658,18 @@ function rotateOpenLog() {
|
|
|
1260
1658
|
if (fd === null || logPath === null) return false;
|
|
1261
1659
|
const sizeBefore = fileBytes;
|
|
1262
1660
|
try {
|
|
1263
|
-
|
|
1661
|
+
fs4.closeSync(fd);
|
|
1264
1662
|
} catch {
|
|
1265
1663
|
}
|
|
1266
1664
|
fd = null;
|
|
1267
1665
|
rotateIfNeeded(logPath, true);
|
|
1268
1666
|
try {
|
|
1269
|
-
fd =
|
|
1270
|
-
fileBytes =
|
|
1667
|
+
fd = fs4.openSync(logPath, "a");
|
|
1668
|
+
fileBytes = fs4.fstatSync(fd).size;
|
|
1271
1669
|
} catch {
|
|
1272
1670
|
if (fd !== null) {
|
|
1273
1671
|
try {
|
|
1274
|
-
|
|
1672
|
+
fs4.closeSync(fd);
|
|
1275
1673
|
} catch {
|
|
1276
1674
|
}
|
|
1277
1675
|
}
|
|
@@ -1287,22 +1685,22 @@ function openLog(filePath, name) {
|
|
|
1287
1685
|
appName = name;
|
|
1288
1686
|
exactSecrets = environmentSecrets(process.env);
|
|
1289
1687
|
try {
|
|
1290
|
-
|
|
1688
|
+
fs4.mkdirSync(path3.dirname(filePath), { recursive: true, mode: 448 });
|
|
1291
1689
|
} catch {
|
|
1292
1690
|
}
|
|
1293
1691
|
rotateIfNeeded(filePath);
|
|
1294
1692
|
try {
|
|
1295
|
-
fd =
|
|
1693
|
+
fd = fs4.openSync(filePath, "a");
|
|
1296
1694
|
} catch {
|
|
1297
1695
|
fd = null;
|
|
1298
1696
|
fileBytes = 0;
|
|
1299
1697
|
return false;
|
|
1300
1698
|
}
|
|
1301
1699
|
try {
|
|
1302
|
-
fileBytes =
|
|
1700
|
+
fileBytes = fs4.fstatSync(fd).size;
|
|
1303
1701
|
} catch {
|
|
1304
1702
|
try {
|
|
1305
|
-
|
|
1703
|
+
fs4.closeSync(fd);
|
|
1306
1704
|
} catch {
|
|
1307
1705
|
}
|
|
1308
1706
|
fd = null;
|
|
@@ -1315,7 +1713,7 @@ function openLog(filePath, name) {
|
|
|
1315
1713
|
sessionId = randomBytes(4).toString("hex");
|
|
1316
1714
|
try {
|
|
1317
1715
|
if (fileBytes < MAX_BYTES) {
|
|
1318
|
-
const written =
|
|
1716
|
+
const written = fs4.writeSync(fd, "\n");
|
|
1319
1717
|
fileBytes += written;
|
|
1320
1718
|
processBytes += written;
|
|
1321
1719
|
}
|
|
@@ -1350,9 +1748,9 @@ function log(level, category, message, data) {
|
|
|
1350
1748
|
`;
|
|
1351
1749
|
try {
|
|
1352
1750
|
if (fileBytes + Buffer.byteLength(capLine) <= MAX_BYTES) {
|
|
1353
|
-
fileBytes +=
|
|
1751
|
+
fileBytes += fs4.writeSync(fd, capLine);
|
|
1354
1752
|
}
|
|
1355
|
-
|
|
1753
|
+
fs4.closeSync(fd);
|
|
1356
1754
|
} catch {
|
|
1357
1755
|
}
|
|
1358
1756
|
fd = null;
|
|
@@ -1362,7 +1760,7 @@ function log(level, category, message, data) {
|
|
|
1362
1760
|
if (fileBytes + lineBytes > MAX_BYTES && !rotationFailed && !rotateOpenLog()) return;
|
|
1363
1761
|
if (fd === null) return;
|
|
1364
1762
|
try {
|
|
1365
|
-
const written =
|
|
1763
|
+
const written = fs4.writeSync(fd, line);
|
|
1366
1764
|
fileBytes += written;
|
|
1367
1765
|
processBytes += written;
|
|
1368
1766
|
} catch {
|
|
@@ -1375,7 +1773,7 @@ function closeLogger(opts) {
|
|
|
1375
1773
|
if (fd !== null) {
|
|
1376
1774
|
if (opts?.shutdownLine !== false) log("INFO", "shutdown", `${appName} shutting down`);
|
|
1377
1775
|
try {
|
|
1378
|
-
if (fd !== null)
|
|
1776
|
+
if (fd !== null) fs4.closeSync(fd);
|
|
1379
1777
|
} catch {
|
|
1380
1778
|
}
|
|
1381
1779
|
}
|
|
@@ -1556,6 +1954,8 @@ function refreshThresholdMs(creds) {
|
|
|
1556
1954
|
}
|
|
1557
1955
|
var USAGE_EXHAUSTED_DEFAULT_MS = 15 * 60 * 1e3;
|
|
1558
1956
|
var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
|
|
1957
|
+
// Anthropic is API-key only; Claude subscriptions run through Claude Code.
|
|
1958
|
+
"anthropic",
|
|
1559
1959
|
"glm",
|
|
1560
1960
|
"moonshot",
|
|
1561
1961
|
"xiaomi",
|
|
@@ -1636,11 +2036,44 @@ var AuthStorage = class {
|
|
|
1636
2036
|
if (provider === "gemini") {
|
|
1637
2037
|
return Boolean(this.data["gemini"] || this.data[GEMINI_API_KEY]);
|
|
1638
2038
|
}
|
|
2039
|
+
if (provider === "anthropic") {
|
|
2040
|
+
return Boolean(this.data.anthropic) && !isLegacyClaudeOAuth(this.data.anthropic) || isClaudeCodeAuthMarker(this.data[CLAUDE_CODE_AUTH_KEY]);
|
|
2041
|
+
}
|
|
1639
2042
|
if (provider === "local") {
|
|
1640
2043
|
return Object.keys(this.data).some((key) => key.startsWith(LOCAL_AUTH_KEY_PREFIX));
|
|
1641
2044
|
}
|
|
1642
2045
|
return Boolean(this.data[provider]);
|
|
1643
2046
|
}
|
|
2047
|
+
/** True when the user signed in with Claude through Claude Code (marker only, no token). */
|
|
2048
|
+
async hasClaudeCodeLogin() {
|
|
2049
|
+
await this.ensureFresh();
|
|
2050
|
+
return isClaudeCodeAuthMarker(this.data[CLAUDE_CODE_AUTH_KEY]);
|
|
2051
|
+
}
|
|
2052
|
+
/** Record a Claude Code sign-in. Claude Code keeps the token; auth.json gets only the marker. */
|
|
2053
|
+
async setClaudeCodeLogin() {
|
|
2054
|
+
await this.mutateLatest((latest) => {
|
|
2055
|
+
latest[CLAUDE_CODE_AUTH_KEY] = { ...CLAUDE_CODE_AUTH_MARKER };
|
|
2056
|
+
if (isLegacyClaudeOAuth(latest.anthropic)) delete latest.anthropic;
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Remove an old GG Claude sign-in token (`sk-ant-oat…`), if any. True when one
|
|
2061
|
+
* was removed, so the caller can tell the user once to sign in with Claude again.
|
|
2062
|
+
*/
|
|
2063
|
+
async takeLegacyClaudeSignIn() {
|
|
2064
|
+
await this.ensureFresh();
|
|
2065
|
+
if (!isLegacyClaudeOAuth(this.data.anthropic)) return false;
|
|
2066
|
+
let removed = false;
|
|
2067
|
+
await this.mutateLatest((latest) => {
|
|
2068
|
+
if (!isLegacyClaudeOAuth(latest.anthropic)) return;
|
|
2069
|
+
delete latest.anthropic;
|
|
2070
|
+
removed = true;
|
|
2071
|
+
});
|
|
2072
|
+
return removed;
|
|
2073
|
+
}
|
|
2074
|
+
async clearClaudeCodeLogin() {
|
|
2075
|
+
await this.clearCredentials(CLAUDE_CODE_AUTH_KEY);
|
|
2076
|
+
}
|
|
1644
2077
|
/** Endpoint ids that currently have a `local:<id>` credential stored. */
|
|
1645
2078
|
async listLocalEndpointIds() {
|
|
1646
2079
|
await this.ensureLoaded();
|
|
@@ -1694,7 +2127,7 @@ var AuthStorage = class {
|
|
|
1694
2127
|
const first = !this.loaded;
|
|
1695
2128
|
await withFileLock(this.filePath, async () => {
|
|
1696
2129
|
try {
|
|
1697
|
-
const content = await
|
|
2130
|
+
const content = await fs5.readFile(this.filePath, "utf-8");
|
|
1698
2131
|
this.data = JSON.parse(content);
|
|
1699
2132
|
if (first) {
|
|
1700
2133
|
log("INFO", "auth", `Loaded credentials from ${this.filePath}`, {
|
|
@@ -1740,7 +2173,7 @@ var AuthStorage = class {
|
|
|
1740
2173
|
}
|
|
1741
2174
|
let changed;
|
|
1742
2175
|
try {
|
|
1743
|
-
const stat = await
|
|
2176
|
+
const stat = await fs5.stat(this.filePath);
|
|
1744
2177
|
changed = stat.ino !== this.snapshotIno || stat.mtimeMs !== this.snapshotMtimeMs || stat.size !== this.snapshotSize;
|
|
1745
2178
|
} catch {
|
|
1746
2179
|
changed = this.snapshotSize !== -1;
|
|
@@ -1753,7 +2186,7 @@ var AuthStorage = class {
|
|
|
1753
2186
|
*/
|
|
1754
2187
|
async rememberSnapshot() {
|
|
1755
2188
|
try {
|
|
1756
|
-
const stat = await
|
|
2189
|
+
const stat = await fs5.stat(this.filePath);
|
|
1757
2190
|
this.snapshotMtimeMs = stat.mtimeMs;
|
|
1758
2191
|
this.snapshotSize = stat.size;
|
|
1759
2192
|
this.snapshotIno = stat.ino;
|
|
@@ -1894,7 +2327,7 @@ var AuthStorage = class {
|
|
|
1894
2327
|
await this.ensureFresh();
|
|
1895
2328
|
}
|
|
1896
2329
|
const directStorageKeys = opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider) ? opts.storageKeys : providerStorageKeys(provider);
|
|
1897
|
-
if (!directStorageKeys.some((key) => Boolean(this.data[key]))) {
|
|
2330
|
+
if (!directStorageKeys.some((key) => Boolean(this.data[key])) && !(provider === "anthropic" && this.data[CLAUDE_CODE_AUTH_KEY])) {
|
|
1898
2331
|
await this.reloadLatest();
|
|
1899
2332
|
}
|
|
1900
2333
|
if (opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider)) {
|
|
@@ -1917,6 +2350,12 @@ var AuthStorage = class {
|
|
|
1917
2350
|
}
|
|
1918
2351
|
throw new NotLoggedInError(provider);
|
|
1919
2352
|
}
|
|
2353
|
+
if (provider === "anthropic" && (!this.data.anthropic || isLegacyClaudeOAuth(this.data.anthropic))) {
|
|
2354
|
+
if (isClaudeCodeAuthMarker(this.data[CLAUDE_CODE_AUTH_KEY])) {
|
|
2355
|
+
return { accessToken: "", refreshToken: "", expiresAt: Number.MAX_SAFE_INTEGER };
|
|
2356
|
+
}
|
|
2357
|
+
if (this.data.anthropic) throw new NotLoggedInError(provider);
|
|
2358
|
+
}
|
|
1920
2359
|
const dual = dualAuthProvider(provider);
|
|
1921
2360
|
const dualOAuthCreds = dual ? this.data[dual.oauthKey] : void 0;
|
|
1922
2361
|
if (dual && dualOAuthCreds) {
|
|
@@ -1979,7 +2418,7 @@ var AuthStorage = class {
|
|
|
1979
2418
|
this.data = latest;
|
|
1980
2419
|
return latestCreds;
|
|
1981
2420
|
}
|
|
1982
|
-
const refreshFn = provider === "
|
|
2421
|
+
const refreshFn = provider === "gemini" ? refreshGeminiToken : provider === MOONSHOT_OAUTH_KEY ? refreshKimiToken : provider === XAI_OAUTH_KEY ? refreshXaiToken : refreshOpenAIToken;
|
|
1983
2422
|
let refreshed;
|
|
1984
2423
|
try {
|
|
1985
2424
|
refreshed = await refreshFn(latestCreds.refreshToken);
|
|
@@ -2038,7 +2477,7 @@ var AuthStorage = class {
|
|
|
2038
2477
|
};
|
|
2039
2478
|
async function readAuthData(filePath) {
|
|
2040
2479
|
try {
|
|
2041
|
-
const content = await
|
|
2480
|
+
const content = await fs5.readFile(filePath, "utf-8");
|
|
2042
2481
|
return JSON.parse(content);
|
|
2043
2482
|
} catch (error) {
|
|
2044
2483
|
if (error.code === "ENOENT") return {};
|
|
@@ -2048,10 +2487,10 @@ async function readAuthData(filePath) {
|
|
|
2048
2487
|
async function atomicWriteFile(filePath, content) {
|
|
2049
2488
|
const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${crypto5.randomUUID().slice(0, 8)}.tmp`;
|
|
2050
2489
|
try {
|
|
2051
|
-
await
|
|
2052
|
-
await
|
|
2490
|
+
await fs5.writeFile(tmpPath, content, { encoding: "utf-8", mode: 384 });
|
|
2491
|
+
await fs5.rename(tmpPath, filePath);
|
|
2053
2492
|
} catch (err) {
|
|
2054
|
-
await
|
|
2493
|
+
await fs5.unlink(tmpPath).catch(() => {
|
|
2055
2494
|
});
|
|
2056
2495
|
throw err;
|
|
2057
2496
|
}
|
|
@@ -2254,9 +2693,9 @@ var MODELS = [
|
|
|
2254
2693
|
billing: CODEX_FAST_BILLING
|
|
2255
2694
|
},
|
|
2256
2695
|
// GPT-6 Sol + Luna — released 2026-09-22 below Astra, replacing the whole
|
|
2257
|
-
// GPT-5.6 family (Sol/Terra/Luna; there
|
|
2696
|
+
// GPT-5.6 family (Sol/Terra/Luna; there was no GPT-6 Terra — OpenAI's Codex
|
|
2258
2697
|
// catalog upgrades 5.6 Terra to 6 Sol). GPT-6.1 Sol (2026-09-29) then replaced
|
|
2259
|
-
// GPT-6 Sol. Same window split as Astra: 1.05M on the public Responses API,
|
|
2698
|
+
// GPT-6 Sol, and GPT-6.1 Terra (2026-10-26) sits between Sol and Luna. Same window split as Astra: 1.05M on the public Responses API,
|
|
2260
2699
|
// 272K on the Codex route; 128K output, text+image input, freeform
|
|
2261
2700
|
// apply_patch, responses-lite transport. The GPT-5.6 ids and `gpt-6-sol` are
|
|
2262
2701
|
// retired — a saved session on one falls back to the provider default on
|
|
@@ -2298,6 +2737,40 @@ var MODELS = [
|
|
|
2298
2737
|
maxThinkingLevel: "ultra",
|
|
2299
2738
|
billing: CODEX_FAST_BILLING
|
|
2300
2739
|
},
|
|
2740
|
+
{
|
|
2741
|
+
// GPT-6.1 Terra (Codex priority 7, default low, client >= 0.153.0). $1/$5
|
|
2742
|
+
// MTok, cached input $0.05. Unlike Sol/Astra the Codex route gets a 500K
|
|
2743
|
+
// window (catalog `context_window`). Same ladder and Ultra preset as Sol.
|
|
2744
|
+
id: "gpt-6.1-terra",
|
|
2745
|
+
name: "GPT-6.1 Terra",
|
|
2746
|
+
provider: "openai",
|
|
2747
|
+
contextWindow: 105e4,
|
|
2748
|
+
codexContextWindow: 5e5,
|
|
2749
|
+
maxOutputTokens: 128e3,
|
|
2750
|
+
supportsThinking: true,
|
|
2751
|
+
defaultThinkingLevel: "low",
|
|
2752
|
+
supportsImages: true,
|
|
2753
|
+
supportsVideo: false,
|
|
2754
|
+
costTier: "medium",
|
|
2755
|
+
maxThinkingLevel: "ultra"
|
|
2756
|
+
},
|
|
2757
|
+
{
|
|
2758
|
+
// Codex Fast mode for 6.1 Terra ("1.5x speed") — see `gpt-6-astra-fast`
|
|
2759
|
+
// for the wire mapping and billing.
|
|
2760
|
+
id: "gpt-6.1-terra-fast",
|
|
2761
|
+
name: "GPT-6.1 Terra Fast",
|
|
2762
|
+
provider: "openai",
|
|
2763
|
+
contextWindow: 105e4,
|
|
2764
|
+
codexContextWindow: 5e5,
|
|
2765
|
+
maxOutputTokens: 128e3,
|
|
2766
|
+
supportsThinking: true,
|
|
2767
|
+
defaultThinkingLevel: "low",
|
|
2768
|
+
supportsImages: true,
|
|
2769
|
+
supportsVideo: false,
|
|
2770
|
+
costTier: "medium",
|
|
2771
|
+
maxThinkingLevel: "ultra",
|
|
2772
|
+
billing: CODEX_FAST_BILLING
|
|
2773
|
+
},
|
|
2301
2774
|
{
|
|
2302
2775
|
// Luna — "Fast and affordable model for easier tasks." (Codex priority 4,
|
|
2303
2776
|
// default medium, needs a Codex client >= 0.155.0). $0.10/$0.50 MTok.
|
|
@@ -2974,12 +3447,24 @@ export {
|
|
|
2974
3447
|
isKimiCodingEndpoint,
|
|
2975
3448
|
loginKimi,
|
|
2976
3449
|
refreshKimiToken,
|
|
3450
|
+
CLAUDE_CODE_MANIFEST,
|
|
3451
|
+
CLAUDE_CODE_AUTH_KEY,
|
|
3452
|
+
CLAUDE_CODE_AUTH_MARKER,
|
|
3453
|
+
isClaudeCodeAuthMarker,
|
|
3454
|
+
isLegacyClaudeOAuth,
|
|
3455
|
+
claudeCodePlatformKey,
|
|
3456
|
+
claudeCodeHome,
|
|
3457
|
+
claudeCodeConfigDir,
|
|
3458
|
+
claudeCodeBinaryPath,
|
|
3459
|
+
resolveClaudeCodeBinary,
|
|
3460
|
+
ensureClaudeCodeBinary,
|
|
3461
|
+
formatClaudeCodeInstallProgress,
|
|
3462
|
+
claudeCodeEnv,
|
|
3463
|
+
claudeCodeAuthStatus,
|
|
3464
|
+
logoutClaudeCode,
|
|
3465
|
+
claudeCodeCallbackUrl,
|
|
3466
|
+
loginClaudeCode,
|
|
2977
3467
|
generatePKCE,
|
|
2978
|
-
getClaudeCodeVersion,
|
|
2979
|
-
getClaudeCliUserAgent,
|
|
2980
|
-
pendingClaudeCodeVersionRefresh,
|
|
2981
|
-
loginAnthropic,
|
|
2982
|
-
refreshAnthropicToken,
|
|
2983
3468
|
loginOpenAI,
|
|
2984
3469
|
refreshOpenAIToken,
|
|
2985
3470
|
loginGemini,
|
|
@@ -3039,4 +3524,4 @@ export {
|
|
|
3039
3524
|
getDefaultThinkingLevel,
|
|
3040
3525
|
getSummaryModel
|
|
3041
3526
|
};
|
|
3042
|
-
//# sourceMappingURL=chunk-
|
|
3527
|
+
//# sourceMappingURL=chunk-JLEBGMG4.js.map
|