@jer-y/copilot-proxy 0.1.5 → 0.2.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/README.md +44 -1
- package/README.zh-CN.md +44 -1
- package/dist/config-D1kMGXKU.js +38 -0
- package/dist/config-D1kMGXKU.js.map +1 -0
- package/dist/config-ixm2Pm96.js +4 -0
- package/dist/darwin-BVmd1DeO.js +69 -0
- package/dist/darwin-BVmd1DeO.js.map +1 -0
- package/dist/linux-CX0xETja.js +103 -0
- package/dist/linux-CX0xETja.js.map +1 -0
- package/dist/main.js +367 -43
- package/dist/main.js.map +1 -1
- package/dist/paths-CA6OZ0WA.js +33 -0
- package/dist/paths-CA6OZ0WA.js.map +1 -0
- package/dist/pid-uKNpN4v-.js +138 -0
- package/dist/pid-uKNpN4v-.js.map +1 -0
- package/dist/start-C-0OcnXB.js +6 -0
- package/dist/start-Dcv2sypx.js +107 -0
- package/dist/start-Dcv2sypx.js.map +1 -0
- package/dist/supervisor-BbH28zwT.js +39 -0
- package/dist/supervisor-BbH28zwT.js.map +1 -0
- package/dist/win32-D1-MlKl7.js +99 -0
- package/dist/win32-D1-MlKl7.js.map +1 -0
- package/package.json +3 -3
package/dist/main.js
CHANGED
|
@@ -1,44 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { PATHS, ensurePaths } from "./paths-CA6OZ0WA.js";
|
|
3
|
+
import { loadDaemonConfig } from "./config-D1kMGXKU.js";
|
|
4
|
+
import { isDaemonRunning, isProcessRunning, readPid, removePidFile } from "./pid-uKNpN4v-.js";
|
|
5
|
+
import { daemonStart } from "./start-Dcv2sypx.js";
|
|
2
6
|
import { defineCommand, runMain } from "citty";
|
|
3
7
|
import consola from "consola";
|
|
4
8
|
import fs from "node:fs/promises";
|
|
5
9
|
import os from "node:os";
|
|
6
|
-
import path from "node:path";
|
|
7
10
|
import { randomUUID } from "node:crypto";
|
|
8
11
|
import process from "node:process";
|
|
12
|
+
import fs$1 from "node:fs";
|
|
13
|
+
import { Buffer } from "node:buffer";
|
|
14
|
+
import { execSync } from "node:child_process";
|
|
9
15
|
import clipboard from "clipboardy";
|
|
10
16
|
import { serve } from "srvx";
|
|
11
17
|
import invariant from "tiny-invariant";
|
|
12
18
|
import { getProxyForUrl } from "proxy-from-env";
|
|
13
19
|
import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
|
|
14
|
-
import { execSync } from "node:child_process";
|
|
15
20
|
import { Hono } from "hono";
|
|
16
21
|
import { cors } from "hono/cors";
|
|
17
22
|
import { logger } from "hono/logger";
|
|
18
23
|
import { streamSSE } from "hono/streaming";
|
|
19
24
|
import { events } from "fetch-event-stream";
|
|
20
25
|
|
|
21
|
-
//#region src/lib/paths.ts
|
|
22
|
-
const APP_DIR = path.join(os.homedir(), ".local", "share", "copilot-proxy");
|
|
23
|
-
const GITHUB_TOKEN_PATH = path.join(APP_DIR, "github_token");
|
|
24
|
-
const PATHS = {
|
|
25
|
-
APP_DIR,
|
|
26
|
-
GITHUB_TOKEN_PATH
|
|
27
|
-
};
|
|
28
|
-
async function ensurePaths() {
|
|
29
|
-
await fs.mkdir(PATHS.APP_DIR, { recursive: true });
|
|
30
|
-
await ensureFile(PATHS.GITHUB_TOKEN_PATH);
|
|
31
|
-
}
|
|
32
|
-
async function ensureFile(filePath) {
|
|
33
|
-
try {
|
|
34
|
-
await fs.access(filePath, fs.constants.W_OK);
|
|
35
|
-
} catch {
|
|
36
|
-
await fs.writeFile(filePath, "");
|
|
37
|
-
await fs.chmod(filePath, 384);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
//#endregion
|
|
42
26
|
//#region src/lib/state.ts
|
|
43
27
|
const state = {
|
|
44
28
|
accountType: "individual",
|
|
@@ -163,20 +147,21 @@ async function getGitHubUser() {
|
|
|
163
147
|
//#endregion
|
|
164
148
|
//#region src/services/copilot/get-models.ts
|
|
165
149
|
async function getModels() {
|
|
150
|
+
const headers = copilotHeaders(state);
|
|
151
|
+
const response = await fetch(`${copilotBaseUrl(state)}/models`, { headers });
|
|
152
|
+
if (response.ok) return await response.json();
|
|
153
|
+
consola.warn(`vscode-chat models request failed (${response.status} ${response.statusText}), falling back to copilot-developer-cli`);
|
|
166
154
|
if (state.githubToken) try {
|
|
167
155
|
const cliHeaders = copilotHeaders(state);
|
|
168
156
|
cliHeaders.Authorization = `Bearer ${state.githubToken}`;
|
|
169
157
|
cliHeaders["copilot-integration-id"] = "copilot-developer-cli";
|
|
170
|
-
const
|
|
171
|
-
if (
|
|
172
|
-
consola.warn(`copilot-developer-cli
|
|
158
|
+
const cliResponse = await fetch(`${copilotBaseUrl(state)}/models`, { headers: cliHeaders });
|
|
159
|
+
if (cliResponse.ok) return await cliResponse.json();
|
|
160
|
+
consola.warn(`copilot-developer-cli fallback also failed (${cliResponse.status} ${cliResponse.statusText})`);
|
|
173
161
|
} catch (e) {
|
|
174
|
-
consola.warn("copilot-developer-cli
|
|
162
|
+
consola.warn("copilot-developer-cli fallback error:", e);
|
|
175
163
|
}
|
|
176
|
-
|
|
177
|
-
const response = await fetch(`${copilotBaseUrl(state)}/models`, { headers });
|
|
178
|
-
if (!response.ok) throw new HTTPError("Failed to get models", response);
|
|
179
|
-
return await response.json();
|
|
164
|
+
throw new HTTPError("Failed to get models", response);
|
|
180
165
|
}
|
|
181
166
|
|
|
182
167
|
//#endregion
|
|
@@ -259,7 +244,8 @@ async function setupCopilotToken() {
|
|
|
259
244
|
state.copilotToken = token;
|
|
260
245
|
consola.debug("GitHub Copilot Token fetched successfully!");
|
|
261
246
|
if (state.showToken) consola.info("Copilot token:", token);
|
|
262
|
-
const
|
|
247
|
+
const rawInterval = (refresh_in - 60) * 1e3;
|
|
248
|
+
const refreshInterval = Number.isFinite(rawInterval) ? Math.min(Math.max(rawInterval, 6e4), 1440 * 60 * 1e3) : 6e4;
|
|
263
249
|
setInterval(async () => {
|
|
264
250
|
consola.debug("Refreshing Copilot token");
|
|
265
251
|
try {
|
|
@@ -268,8 +254,7 @@ async function setupCopilotToken() {
|
|
|
268
254
|
consola.debug("Copilot token refreshed");
|
|
269
255
|
if (state.showToken) consola.info("Refreshed Copilot token:", token$1);
|
|
270
256
|
} catch (error) {
|
|
271
|
-
consola.error("Failed to refresh Copilot token:", error);
|
|
272
|
-
throw error;
|
|
257
|
+
consola.error("Failed to refresh Copilot token, will retry next cycle:", error);
|
|
273
258
|
}
|
|
274
259
|
}, refreshInterval);
|
|
275
260
|
}
|
|
@@ -387,6 +372,228 @@ const checkUsage = defineCommand({
|
|
|
387
372
|
}
|
|
388
373
|
});
|
|
389
374
|
|
|
375
|
+
//#endregion
|
|
376
|
+
//#region src/daemon/disable.ts
|
|
377
|
+
const disable = defineCommand({
|
|
378
|
+
meta: {
|
|
379
|
+
name: "disable",
|
|
380
|
+
description: "Remove auto-start service"
|
|
381
|
+
},
|
|
382
|
+
async run() {
|
|
383
|
+
const { platform } = process;
|
|
384
|
+
let success = true;
|
|
385
|
+
if (platform === "linux") {
|
|
386
|
+
const { uninstallAutoStart } = await import("./linux-CX0xETja.js");
|
|
387
|
+
success = await uninstallAutoStart();
|
|
388
|
+
} else if (platform === "darwin") {
|
|
389
|
+
const { uninstallAutoStart } = await import("./darwin-BVmd1DeO.js");
|
|
390
|
+
success = await uninstallAutoStart();
|
|
391
|
+
} else if (platform === "win32") {
|
|
392
|
+
const { uninstallAutoStart } = await import("./win32-D1-MlKl7.js");
|
|
393
|
+
success = await uninstallAutoStart();
|
|
394
|
+
} else {
|
|
395
|
+
consola.error(`Unsupported platform: ${platform}`);
|
|
396
|
+
process.exit(1);
|
|
397
|
+
}
|
|
398
|
+
if (!success) process.exit(1);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/daemon/enable.ts
|
|
404
|
+
const enable = defineCommand({
|
|
405
|
+
meta: {
|
|
406
|
+
name: "enable",
|
|
407
|
+
description: "Register as auto-start service"
|
|
408
|
+
},
|
|
409
|
+
async run() {
|
|
410
|
+
if (!loadDaemonConfig()) {
|
|
411
|
+
consola.error("No daemon config found. Start the daemon first with `start -d`");
|
|
412
|
+
process.exit(1);
|
|
413
|
+
}
|
|
414
|
+
const execPath = process.argv[0];
|
|
415
|
+
const args = [
|
|
416
|
+
process.argv[1],
|
|
417
|
+
"start",
|
|
418
|
+
"--_supervisor"
|
|
419
|
+
];
|
|
420
|
+
let success = false;
|
|
421
|
+
const { platform } = process;
|
|
422
|
+
if (platform === "linux") {
|
|
423
|
+
const { installAutoStart } = await import("./linux-CX0xETja.js");
|
|
424
|
+
success = await installAutoStart(execPath, args);
|
|
425
|
+
} else if (platform === "darwin") {
|
|
426
|
+
const { installAutoStart } = await import("./darwin-BVmd1DeO.js");
|
|
427
|
+
success = await installAutoStart(execPath, args);
|
|
428
|
+
} else if (platform === "win32") {
|
|
429
|
+
const { installAutoStart } = await import("./win32-D1-MlKl7.js");
|
|
430
|
+
success = await installAutoStart(execPath, args);
|
|
431
|
+
} else {
|
|
432
|
+
consola.error(`Unsupported platform: ${platform}`);
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
if (!success) process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
//#endregion
|
|
440
|
+
//#region src/daemon/logs.ts
|
|
441
|
+
const logs = defineCommand({
|
|
442
|
+
meta: {
|
|
443
|
+
name: "logs",
|
|
444
|
+
description: "Show daemon logs"
|
|
445
|
+
},
|
|
446
|
+
args: {
|
|
447
|
+
follow: {
|
|
448
|
+
alias: "f",
|
|
449
|
+
type: "boolean",
|
|
450
|
+
default: false,
|
|
451
|
+
description: "Follow log output"
|
|
452
|
+
},
|
|
453
|
+
lines: {
|
|
454
|
+
alias: "n",
|
|
455
|
+
type: "string",
|
|
456
|
+
default: "50",
|
|
457
|
+
description: "Number of lines to show"
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
run({ args }) {
|
|
461
|
+
if (!fs$1.existsSync(PATHS.DAEMON_LOG)) {
|
|
462
|
+
consola.info("No log file found");
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
if (args.follow) followLogsWatch();
|
|
466
|
+
else {
|
|
467
|
+
const lines = fs$1.readFileSync(PATHS.DAEMON_LOG, "utf8").split("\n");
|
|
468
|
+
const count = Number.parseInt(args.lines, 10);
|
|
469
|
+
const output = lines.slice(-count).join("\n");
|
|
470
|
+
console.log(output);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
function followLogsWatch() {
|
|
475
|
+
const content = fs$1.readFileSync(PATHS.DAEMON_LOG, "utf8");
|
|
476
|
+
process.stdout.write(content);
|
|
477
|
+
let position = Buffer.byteLength(content);
|
|
478
|
+
let currentIno = 0;
|
|
479
|
+
try {
|
|
480
|
+
currentIno = fs$1.statSync(PATHS.DAEMON_LOG).ino;
|
|
481
|
+
} catch {}
|
|
482
|
+
setInterval(() => {
|
|
483
|
+
try {
|
|
484
|
+
const stat = fs$1.statSync(PATHS.DAEMON_LOG);
|
|
485
|
+
if (stat.ino !== currentIno) {
|
|
486
|
+
currentIno = stat.ino;
|
|
487
|
+
position = 0;
|
|
488
|
+
}
|
|
489
|
+
if (stat.size < position) position = 0;
|
|
490
|
+
if (stat.size > position) {
|
|
491
|
+
const fd = fs$1.openSync(PATHS.DAEMON_LOG, "r");
|
|
492
|
+
const buffer = Buffer.alloc(stat.size - position);
|
|
493
|
+
fs$1.readSync(fd, buffer, 0, buffer.length, position);
|
|
494
|
+
fs$1.closeSync(fd);
|
|
495
|
+
process.stdout.write(buffer);
|
|
496
|
+
position = stat.size;
|
|
497
|
+
}
|
|
498
|
+
} catch {}
|
|
499
|
+
}, 500);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
//#endregion
|
|
503
|
+
//#region src/daemon/stop.ts
|
|
504
|
+
/**
|
|
505
|
+
* Attempt to stop the daemon. Returns true if daemon was stopped or
|
|
506
|
+
* was not running. Returns false if the process could not be stopped.
|
|
507
|
+
*/
|
|
508
|
+
function stopDaemon() {
|
|
509
|
+
const daemon = isDaemonRunning();
|
|
510
|
+
if (!daemon.running) {
|
|
511
|
+
consola.info("Daemon is not running");
|
|
512
|
+
removePidFile();
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
const { pid } = daemon;
|
|
516
|
+
consola.info(`Stopping daemon (PID: ${pid})...`);
|
|
517
|
+
try {
|
|
518
|
+
process.kill(pid, "SIGTERM");
|
|
519
|
+
} catch {
|
|
520
|
+
consola.error("Failed to send SIGTERM");
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
523
|
+
const deadline = Date.now() + 1e4;
|
|
524
|
+
while (isProcessRunning(pid) && Date.now() < deadline) Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 200);
|
|
525
|
+
if (isProcessRunning(pid)) {
|
|
526
|
+
consola.warn("Process did not exit in time, sending SIGKILL");
|
|
527
|
+
try {
|
|
528
|
+
process.kill(pid, "SIGKILL");
|
|
529
|
+
} catch {}
|
|
530
|
+
const killDeadline = Date.now() + 3e3;
|
|
531
|
+
while (isProcessRunning(pid) && Date.now() < killDeadline) Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 100);
|
|
532
|
+
if (isProcessRunning(pid)) {
|
|
533
|
+
consola.error(`Failed to kill process ${pid}`);
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
removePidFile();
|
|
538
|
+
consola.success("Daemon stopped");
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
const stop = defineCommand({
|
|
542
|
+
meta: {
|
|
543
|
+
name: "stop",
|
|
544
|
+
description: "Stop the background daemon"
|
|
545
|
+
},
|
|
546
|
+
run() {
|
|
547
|
+
if (!stopDaemon()) process.exit(1);
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
//#endregion
|
|
552
|
+
//#region src/daemon/restart.ts
|
|
553
|
+
const restart = defineCommand({
|
|
554
|
+
meta: {
|
|
555
|
+
name: "restart",
|
|
556
|
+
description: "Restart the background daemon"
|
|
557
|
+
},
|
|
558
|
+
run() {
|
|
559
|
+
const config = loadDaemonConfig();
|
|
560
|
+
if (!config) {
|
|
561
|
+
consola.error("No daemon config found. Start the daemon first with `start -d`");
|
|
562
|
+
process.exit(1);
|
|
563
|
+
}
|
|
564
|
+
if (isDaemonRunning().running) {
|
|
565
|
+
if (!stopDaemon()) {
|
|
566
|
+
consola.error("Cannot restart: failed to stop existing daemon");
|
|
567
|
+
process.exit(1);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
daemonStart(config);
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
//#endregion
|
|
575
|
+
//#region src/daemon/status.ts
|
|
576
|
+
const status = defineCommand({
|
|
577
|
+
meta: {
|
|
578
|
+
name: "status",
|
|
579
|
+
description: "Show daemon status"
|
|
580
|
+
},
|
|
581
|
+
run() {
|
|
582
|
+
const daemon = isDaemonRunning();
|
|
583
|
+
if (!daemon.running) {
|
|
584
|
+
consola.info("Daemon is not running");
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const config = loadDaemonConfig();
|
|
588
|
+
const info = readPid();
|
|
589
|
+
const startedAt = info && info.startTime > 0 ? new Date(info.startTime).toLocaleString() : "unknown";
|
|
590
|
+
consola.info(`Daemon is running`);
|
|
591
|
+
consola.info(` PID: ${daemon.pid}`);
|
|
592
|
+
consola.info(` Port: ${config?.port ?? "unknown"}`);
|
|
593
|
+
consola.info(` Started: ${startedAt}`);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
|
|
390
597
|
//#endregion
|
|
391
598
|
//#region src/debug.ts
|
|
392
599
|
async function getPackageVersion() {
|
|
@@ -996,8 +1203,29 @@ function mapOpenAIStopReasonToAnthropic(finishReason) {
|
|
|
996
1203
|
|
|
997
1204
|
//#endregion
|
|
998
1205
|
//#region src/routes/messages/non-stream-translation.ts
|
|
999
|
-
|
|
1000
|
-
|
|
1206
|
+
/** Models that support variant suffixes (e.g. -fast, -1m) */
|
|
1207
|
+
const MODEL_VARIANTS = { "claude-opus-4.6": new Set(["fast", "1m"]) };
|
|
1208
|
+
/** Parse comma-separated anthropic-beta header into a Set of feature names */
|
|
1209
|
+
function parseBetaFeatures(anthropicBeta) {
|
|
1210
|
+
if (!anthropicBeta) return /* @__PURE__ */ new Set();
|
|
1211
|
+
return new Set(anthropicBeta.split(",").map((s) => s.trim()).filter(Boolean));
|
|
1212
|
+
}
|
|
1213
|
+
/** Apply model variant suffix based on speed field and beta header signals */
|
|
1214
|
+
function applyModelVariant(model, payload, anthropicBeta) {
|
|
1215
|
+
const normalizedModel = translateModelName(model);
|
|
1216
|
+
const variants = MODEL_VARIANTS[normalizedModel];
|
|
1217
|
+
if (!variants) return normalizedModel;
|
|
1218
|
+
const betaFeatures = parseBetaFeatures(anthropicBeta);
|
|
1219
|
+
if (variants.has("fast")) {
|
|
1220
|
+
if (payload.speed === "fast" || betaFeatures.has("fast-mode-2026-02-01")) return `${normalizedModel}-fast`;
|
|
1221
|
+
}
|
|
1222
|
+
if (variants.has("1m")) {
|
|
1223
|
+
if (betaFeatures.has("context-1m-2025-08-07")) return `${normalizedModel}-1m`;
|
|
1224
|
+
}
|
|
1225
|
+
return normalizedModel;
|
|
1226
|
+
}
|
|
1227
|
+
function translateToOpenAI(payload, options) {
|
|
1228
|
+
const model = applyModelVariant(payload.model, payload, options?.anthropicBeta);
|
|
1001
1229
|
const modelConfig = getModelConfig(model);
|
|
1002
1230
|
const enableCacheControl = modelConfig.enableCacheControl === true;
|
|
1003
1231
|
const messages = translateAnthropicMessagesToOpenAI(payload.messages, payload.system);
|
|
@@ -1207,14 +1435,32 @@ function getAnthropicToolUseBlocks(toolCalls) {
|
|
|
1207
1435
|
//#endregion
|
|
1208
1436
|
//#region src/routes/messages/count-tokens-handler.ts
|
|
1209
1437
|
/**
|
|
1438
|
+
* Find a model in the models list, falling back to the base model
|
|
1439
|
+
* when a variant suffix (-fast, -1m) doesn't have its own entry.
|
|
1440
|
+
*/
|
|
1441
|
+
function findModelWithFallback(modelId, models) {
|
|
1442
|
+
if (!models) return;
|
|
1443
|
+
const exact = models.find((m) => m.id === modelId);
|
|
1444
|
+
if (exact) return exact;
|
|
1445
|
+
const baseModel = modelId.replace(/-(fast|1m)$/, "");
|
|
1446
|
+
if (baseModel !== modelId) return models.find((m) => m.id === baseModel);
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Determine if the request is from Claude Code based on anthropic-beta tokens.
|
|
1450
|
+
* Order-independent: works regardless of token position in the header.
|
|
1451
|
+
*/
|
|
1452
|
+
function isClaudeCodeRequest(anthropicBeta) {
|
|
1453
|
+
return [...parseBetaFeatures(anthropicBeta)].some((f) => f.startsWith("claude-code"));
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1210
1456
|
* Handles token counting for Anthropic messages
|
|
1211
1457
|
*/
|
|
1212
1458
|
async function handleCountTokens(c) {
|
|
1213
1459
|
try {
|
|
1214
1460
|
const anthropicBeta = c.req.header("anthropic-beta");
|
|
1215
1461
|
const anthropicPayload = await c.req.json();
|
|
1216
|
-
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
1217
|
-
const selectedModel = state.models?.data
|
|
1462
|
+
const openAIPayload = translateToOpenAI(anthropicPayload, { anthropicBeta });
|
|
1463
|
+
const selectedModel = findModelWithFallback(openAIPayload.model, state.models?.data);
|
|
1218
1464
|
if (!selectedModel) {
|
|
1219
1465
|
consola.warn("Model not found, returning default token count");
|
|
1220
1466
|
return c.json({ input_tokens: 1 });
|
|
@@ -1222,7 +1468,7 @@ async function handleCountTokens(c) {
|
|
|
1222
1468
|
const tokenCount = await getTokenCount(openAIPayload, selectedModel);
|
|
1223
1469
|
if (anthropicPayload.tools && anthropicPayload.tools.length > 0) {
|
|
1224
1470
|
let mcpToolExist = false;
|
|
1225
|
-
if (anthropicBeta
|
|
1471
|
+
if (isClaudeCodeRequest(anthropicBeta)) mcpToolExist = anthropicPayload.tools.some((tool) => tool.name.startsWith("mcp__"));
|
|
1226
1472
|
if (!mcpToolExist) {
|
|
1227
1473
|
if (anthropicPayload.model.startsWith("claude")) tokenCount.input = tokenCount.input + 346;
|
|
1228
1474
|
else if (anthropicPayload.model.startsWith("grok")) tokenCount.input = tokenCount.input + 480;
|
|
@@ -1367,9 +1613,10 @@ function translateChunkToAnthropicEvents(chunk, state$1) {
|
|
|
1367
1613
|
//#region src/routes/messages/handler.ts
|
|
1368
1614
|
async function handleCompletion(c) {
|
|
1369
1615
|
await checkRateLimit(state);
|
|
1616
|
+
const anthropicBeta = c.req.header("anthropic-beta");
|
|
1370
1617
|
const anthropicPayload = await c.req.json();
|
|
1371
1618
|
consola.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
|
|
1372
|
-
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
1619
|
+
const openAIPayload = translateToOpenAI(anthropicPayload, { anthropicBeta });
|
|
1373
1620
|
consola.debug("Translated OpenAI request payload:", JSON.stringify(openAIPayload));
|
|
1374
1621
|
if (state.manualApprove) await awaitApproval();
|
|
1375
1622
|
const response = await createChatCompletions(openAIPayload);
|
|
@@ -1624,6 +1871,7 @@ async function runServer(options) {
|
|
|
1624
1871
|
fetch: server.fetch,
|
|
1625
1872
|
port: options.port
|
|
1626
1873
|
});
|
|
1874
|
+
await new Promise(() => {});
|
|
1627
1875
|
}
|
|
1628
1876
|
const start = defineCommand({
|
|
1629
1877
|
meta: {
|
|
@@ -1685,13 +1933,83 @@ const start = defineCommand({
|
|
|
1685
1933
|
type: "boolean",
|
|
1686
1934
|
default: false,
|
|
1687
1935
|
description: "Initialize proxy from environment variables"
|
|
1936
|
+
},
|
|
1937
|
+
"daemon": {
|
|
1938
|
+
alias: "d",
|
|
1939
|
+
type: "boolean",
|
|
1940
|
+
default: false,
|
|
1941
|
+
description: "Run as a background daemon"
|
|
1942
|
+
},
|
|
1943
|
+
"_supervisor": {
|
|
1944
|
+
type: "boolean",
|
|
1945
|
+
default: false,
|
|
1946
|
+
description: "Internal: run as supervisor (do not use directly)"
|
|
1688
1947
|
}
|
|
1689
1948
|
},
|
|
1690
|
-
run({ args }) {
|
|
1949
|
+
async run({ args }) {
|
|
1950
|
+
const port = Number.parseInt(args.port, 10);
|
|
1951
|
+
if (Number.isNaN(port) || port <= 0 || port > 65535 || String(port) !== args.port) {
|
|
1952
|
+
consola.error(`Invalid port: ${args.port}`);
|
|
1953
|
+
process.exit(1);
|
|
1954
|
+
}
|
|
1691
1955
|
const rateLimitRaw = args["rate-limit"];
|
|
1692
1956
|
const rateLimit = rateLimitRaw === void 0 ? void 0 : Number.parseInt(rateLimitRaw, 10);
|
|
1957
|
+
if (rateLimitRaw !== void 0 && (Number.isNaN(rateLimit) || rateLimit <= 0 || rateLimit > 86400 || String(rateLimit) !== rateLimitRaw)) {
|
|
1958
|
+
consola.error(`Invalid rate-limit: ${rateLimitRaw} (must be 1-86400)`);
|
|
1959
|
+
process.exit(1);
|
|
1960
|
+
}
|
|
1961
|
+
const validAccountTypes = [
|
|
1962
|
+
"individual",
|
|
1963
|
+
"business",
|
|
1964
|
+
"enterprise"
|
|
1965
|
+
];
|
|
1966
|
+
if (!validAccountTypes.includes(args["account-type"])) {
|
|
1967
|
+
consola.error(`Invalid account-type: ${args["account-type"]} (must be one of: ${validAccountTypes.join(", ")})`);
|
|
1968
|
+
process.exit(1);
|
|
1969
|
+
}
|
|
1970
|
+
if (args._supervisor) {
|
|
1971
|
+
const { loadDaemonConfig: loadDaemonConfig$1 } = await import("./config-ixm2Pm96.js");
|
|
1972
|
+
const config = loadDaemonConfig$1();
|
|
1973
|
+
if (!config) {
|
|
1974
|
+
consola.error("Supervisor mode: daemon config not found");
|
|
1975
|
+
process.exit(1);
|
|
1976
|
+
}
|
|
1977
|
+
const { runAsSupervisor } = await import("./supervisor-BbH28zwT.js");
|
|
1978
|
+
const options = {
|
|
1979
|
+
port: config.port,
|
|
1980
|
+
verbose: config.verbose,
|
|
1981
|
+
accountType: config.accountType,
|
|
1982
|
+
manual: config.manual,
|
|
1983
|
+
rateLimit: config.rateLimit,
|
|
1984
|
+
rateLimitWait: config.rateLimitWait,
|
|
1985
|
+
githubToken: config.githubToken,
|
|
1986
|
+
claudeCode: false,
|
|
1987
|
+
showToken: config.showToken,
|
|
1988
|
+
proxyEnv: config.proxyEnv
|
|
1989
|
+
};
|
|
1990
|
+
return runAsSupervisor(() => runServer(options));
|
|
1991
|
+
}
|
|
1992
|
+
if (args.daemon) {
|
|
1993
|
+
if (args["claude-code"]) {
|
|
1994
|
+
consola.error("Cannot use --claude-code with --daemon (interactive mode)");
|
|
1995
|
+
process.exit(1);
|
|
1996
|
+
}
|
|
1997
|
+
const { daemonStart: daemonStart$1 } = await import("./start-C-0OcnXB.js");
|
|
1998
|
+
daemonStart$1({
|
|
1999
|
+
port,
|
|
2000
|
+
verbose: args.verbose,
|
|
2001
|
+
accountType: args["account-type"],
|
|
2002
|
+
manual: args.manual,
|
|
2003
|
+
rateLimit,
|
|
2004
|
+
rateLimitWait: args.wait,
|
|
2005
|
+
githubToken: args["github-token"],
|
|
2006
|
+
showToken: args["show-token"],
|
|
2007
|
+
proxyEnv: args["proxy-env"]
|
|
2008
|
+
});
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
1693
2011
|
return runServer({
|
|
1694
|
-
port
|
|
2012
|
+
port,
|
|
1695
2013
|
verbose: args.verbose,
|
|
1696
2014
|
accountType: args["account-type"],
|
|
1697
2015
|
manual: args.manual,
|
|
@@ -1716,7 +2034,13 @@ const main = defineCommand({
|
|
|
1716
2034
|
auth,
|
|
1717
2035
|
start,
|
|
1718
2036
|
"check-usage": checkUsage,
|
|
1719
|
-
debug
|
|
2037
|
+
debug,
|
|
2038
|
+
stop,
|
|
2039
|
+
status,
|
|
2040
|
+
logs,
|
|
2041
|
+
restart,
|
|
2042
|
+
enable,
|
|
2043
|
+
disable
|
|
1720
2044
|
}
|
|
1721
2045
|
});
|
|
1722
2046
|
await runMain(main);
|