codexui-android 0.1.82 → 0.1.85
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 +10 -1
- package/dist/assets/{ReviewPane-CxVyabn_.js → ReviewPane-BYXF27M-.js} +2 -2
- package/dist/assets/{ReviewPane-CxVyabn_.js.map → ReviewPane-BYXF27M-.js.map} +1 -1
- package/dist/assets/{SkillsHub-BXlwzycZ.js → SkillsHub-GpJ2Lrm3.js} +2 -2
- package/dist/assets/{SkillsHub-BXlwzycZ.js.map → SkillsHub-GpJ2Lrm3.js.map} +1 -1
- package/dist/assets/{ThreadConversation-Dl_rx6II.js → ThreadConversation-BNp42k0F.js} +2 -2
- package/dist/assets/{ThreadConversation-Dl_rx6II.js.map → ThreadConversation-BNp42k0F.js.map} +1 -1
- package/dist/assets/index-CWwHJTfC.js +92 -0
- package/dist/assets/index-CWwHJTfC.js.map +1 -0
- package/dist/assets/index-iN-aqOuT.css +1 -0
- package/dist/index.html +2 -2
- package/dist-cli/{chunk-UUZOL7SL.js → chunk-JQMCS7KJ.js} +8 -7
- package/dist-cli/chunk-JQMCS7KJ.js.map +1 -0
- package/dist-cli/index.js +461 -13
- package/dist-cli/index.js.map +1 -1
- package/dist-cli/instrument.js +1 -1
- package/package.json +1 -1
- package/dist/assets/index-B2j_CnU5.js +0 -89
- package/dist/assets/index-B2j_CnU5.js.map +0 -1
- package/dist/assets/index-H9Lygcy8.css +0 -1
- package/dist-cli/chunk-UUZOL7SL.js.map +0 -1
package/dist-cli/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-JQMCS7KJ.js";
|
|
3
3
|
|
|
4
4
|
// src/cli/index.ts
|
|
5
5
|
import { createServer as createServer2 } from "http";
|
|
@@ -227,7 +227,7 @@ import * as Sentry4 from "@sentry/node";
|
|
|
227
227
|
import { spawn as spawn4 } from "child_process";
|
|
228
228
|
import { createHash as createHash2, randomBytes } from "crypto";
|
|
229
229
|
import { mkdtemp as mkdtemp3, readFile as readFile3, rm as rm4, mkdir as mkdir4, stat as stat4 } from "fs/promises";
|
|
230
|
-
import { createReadStream } from "fs";
|
|
230
|
+
import { createReadStream, readFileSync } from "fs";
|
|
231
231
|
import { request as httpRequest } from "http";
|
|
232
232
|
import { request as httpsRequest } from "https";
|
|
233
233
|
import { homedir as homedir4 } from "os";
|
|
@@ -480,6 +480,22 @@ async function validateSwitchedAccount(appServer) {
|
|
|
480
480
|
quotaSnapshot: pickCodexRateLimitSnapshot(quotaPayload)
|
|
481
481
|
};
|
|
482
482
|
}
|
|
483
|
+
async function validateSwitchedAccountWithTimeout(appServer) {
|
|
484
|
+
let timeoutHandle = null;
|
|
485
|
+
try {
|
|
486
|
+
return await Promise.race([
|
|
487
|
+
validateSwitchedAccount(appServer),
|
|
488
|
+
new Promise((_, reject) => {
|
|
489
|
+
timeoutHandle = setTimeout(() => {
|
|
490
|
+
reject(new Error(`Account switch validation timed out after ${ACCOUNT_INSPECTION_TIMEOUT_MS}ms`));
|
|
491
|
+
}, ACCOUNT_INSPECTION_TIMEOUT_MS);
|
|
492
|
+
timeoutHandle.unref?.();
|
|
493
|
+
})
|
|
494
|
+
]);
|
|
495
|
+
} finally {
|
|
496
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
483
499
|
async function restoreActiveAuth(raw) {
|
|
484
500
|
const path = getActiveAuthPath();
|
|
485
501
|
if (raw === null) {
|
|
@@ -794,7 +810,7 @@ async function handleAccountRoutes(req, res, url, context) {
|
|
|
794
810
|
const imported = await importAccountFromAuthPath(getActiveAuthPath());
|
|
795
811
|
try {
|
|
796
812
|
appServer.dispose();
|
|
797
|
-
const inspection = await
|
|
813
|
+
const inspection = await validateSwitchedAccountWithTimeout(appServer);
|
|
798
814
|
const state = await readStoredAccountsState();
|
|
799
815
|
const importedAccountId = imported.importedAccountId;
|
|
800
816
|
const target = state.accounts.find((entry) => entry.accountId === importedAccountId) ?? null;
|
|
@@ -893,7 +909,7 @@ async function handleAccountRoutes(req, res, url, context) {
|
|
|
893
909
|
await writeFile(getActiveAuthPath(), targetRaw, { encoding: "utf8", mode: 384 });
|
|
894
910
|
try {
|
|
895
911
|
appServer.dispose();
|
|
896
|
-
const inspection = await
|
|
912
|
+
const inspection = await validateSwitchedAccountWithTimeout(appServer);
|
|
897
913
|
const nextEntry = {
|
|
898
914
|
...target,
|
|
899
915
|
email: inspection.metadata.email ?? target.email,
|
|
@@ -1034,7 +1050,7 @@ async function handleAccountRoutes(req, res, url, context) {
|
|
|
1034
1050
|
await writeFile(getActiveAuthPath(), replacementRaw, { encoding: "utf8", mode: 384 });
|
|
1035
1051
|
try {
|
|
1036
1052
|
appServer.dispose();
|
|
1037
|
-
const inspection = await
|
|
1053
|
+
const inspection = await validateSwitchedAccountWithTimeout(appServer);
|
|
1038
1054
|
const activatedReplacement = {
|
|
1039
1055
|
...replacement,
|
|
1040
1056
|
email: inspection.metadata.email ?? replacement.email,
|
|
@@ -3141,8 +3157,27 @@ function getErrorMessage4(payload, fallback) {
|
|
|
3141
3157
|
}
|
|
3142
3158
|
return fallback;
|
|
3143
3159
|
}
|
|
3160
|
+
function normalizeTelegramAllowlist(values) {
|
|
3161
|
+
const rawValues = Array.isArray(values) ? values : [];
|
|
3162
|
+
const allowAllUsers = rawValues.some((value) => typeof value === "string" && value.trim() === "*");
|
|
3163
|
+
const allowedUserIds = Array.from(new Set(rawValues.map((value) => {
|
|
3164
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
3165
|
+
return Math.trunc(value);
|
|
3166
|
+
}
|
|
3167
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
3168
|
+
const normalized = value.trim().replace(/^(telegram|tg):/i, "").trim();
|
|
3169
|
+
if (/^-?\d+$/.test(normalized)) {
|
|
3170
|
+
return Number.parseInt(normalized, 10);
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
return Number.NaN;
|
|
3174
|
+
}).filter((value) => Number.isFinite(value)))).slice(0, 100);
|
|
3175
|
+
return { allowAllUsers, allowedUserIds };
|
|
3176
|
+
}
|
|
3144
3177
|
var TelegramThreadBridge = class {
|
|
3145
3178
|
constructor(appServer, options = {}) {
|
|
3179
|
+
this.allowAllUsers = false;
|
|
3180
|
+
this.allowedUserIds = /* @__PURE__ */ new Set();
|
|
3146
3181
|
this.threadIdByChatId = /* @__PURE__ */ new Map();
|
|
3147
3182
|
this.chatIdsByThreadId = /* @__PURE__ */ new Map();
|
|
3148
3183
|
this.lastForwardedTurnByThreadId = /* @__PURE__ */ new Map();
|
|
@@ -3153,6 +3188,9 @@ var TelegramThreadBridge = class {
|
|
|
3153
3188
|
this.appServer = appServer;
|
|
3154
3189
|
this.token = process.env.TELEGRAM_BOT_TOKEN?.trim() ?? "";
|
|
3155
3190
|
this.defaultCwd = process.env.TELEGRAM_DEFAULT_CWD?.trim() ?? process.cwd();
|
|
3191
|
+
this.configureAllowedUserIds(
|
|
3192
|
+
(process.env.TELEGRAM_ALLOWED_USER_IDS ?? "").split(",").map((value) => value.trim()).filter(Boolean)
|
|
3193
|
+
);
|
|
3156
3194
|
this.onChatSeen = options.onChatSeen;
|
|
3157
3195
|
}
|
|
3158
3196
|
start() {
|
|
@@ -3220,9 +3258,16 @@ var TelegramThreadBridge = class {
|
|
|
3220
3258
|
active: this.active,
|
|
3221
3259
|
mappedChats: this.threadIdByChatId.size,
|
|
3222
3260
|
mappedThreads: this.chatIdsByThreadId.size,
|
|
3261
|
+
allowedUsers: this.allowedUserIds.size,
|
|
3262
|
+
allowAllUsers: this.allowAllUsers,
|
|
3223
3263
|
lastError: this.lastError
|
|
3224
3264
|
};
|
|
3225
3265
|
}
|
|
3266
|
+
configureAllowedUserIds(allowedUserIds) {
|
|
3267
|
+
const normalized = normalizeTelegramAllowlist(allowedUserIds);
|
|
3268
|
+
this.allowAllUsers = normalized.allowAllUsers;
|
|
3269
|
+
this.allowedUserIds = new Set(normalized.allowedUserIds);
|
|
3270
|
+
}
|
|
3226
3271
|
connectThread(threadId, chatId, token) {
|
|
3227
3272
|
const normalizedThreadId = threadId.trim();
|
|
3228
3273
|
if (!normalizedThreadId) {
|
|
@@ -3276,8 +3321,13 @@ var TelegramThreadBridge = class {
|
|
|
3276
3321
|
}
|
|
3277
3322
|
const message = update.message;
|
|
3278
3323
|
const chatId = message?.chat?.id;
|
|
3324
|
+
const senderId = message?.from?.id;
|
|
3279
3325
|
const text = message?.text?.trim();
|
|
3280
3326
|
if (typeof chatId !== "number" || !text) return;
|
|
3327
|
+
if (!this.isAllowedSender(senderId)) {
|
|
3328
|
+
await this.sendTelegramMessage(chatId, this.unauthorizedMessage(senderId));
|
|
3329
|
+
return;
|
|
3330
|
+
}
|
|
3281
3331
|
this.markChatSeen(chatId);
|
|
3282
3332
|
if (text === "/start") {
|
|
3283
3333
|
await this.sendThreadPicker(chatId);
|
|
@@ -3310,6 +3360,16 @@ var TelegramThreadBridge = class {
|
|
|
3310
3360
|
const callbackId = typeof callbackQuery.id === "string" ? callbackQuery.id : "";
|
|
3311
3361
|
const data = typeof callbackQuery.data === "string" ? callbackQuery.data : "";
|
|
3312
3362
|
const chatId = callbackQuery.message?.chat?.id;
|
|
3363
|
+
const senderId = callbackQuery.from?.id;
|
|
3364
|
+
if (!this.isAllowedSender(senderId)) {
|
|
3365
|
+
if (callbackId) {
|
|
3366
|
+
await this.answerCallbackQuery(callbackId, this.unauthorizedCallbackMessage(senderId));
|
|
3367
|
+
}
|
|
3368
|
+
if (typeof chatId === "number") {
|
|
3369
|
+
await this.sendTelegramMessage(chatId, this.unauthorizedMessage(senderId));
|
|
3370
|
+
}
|
|
3371
|
+
return;
|
|
3372
|
+
}
|
|
3313
3373
|
if (typeof chatId === "number") {
|
|
3314
3374
|
this.markChatSeen(chatId);
|
|
3315
3375
|
}
|
|
@@ -3331,6 +3391,25 @@ var TelegramThreadBridge = class {
|
|
|
3331
3391
|
await this.sendTelegramMessage(chatId, history);
|
|
3332
3392
|
}
|
|
3333
3393
|
}
|
|
3394
|
+
isAllowedSender(senderId) {
|
|
3395
|
+
if (this.allowAllUsers) {
|
|
3396
|
+
return typeof senderId === "number" && Number.isFinite(senderId);
|
|
3397
|
+
}
|
|
3398
|
+
return typeof senderId === "number" && Number.isFinite(senderId) && this.allowedUserIds.has(Math.trunc(senderId));
|
|
3399
|
+
}
|
|
3400
|
+
unauthorizedMessage(senderId) {
|
|
3401
|
+
const normalizedSenderId = typeof senderId === "number" && Number.isFinite(senderId) ? String(Math.trunc(senderId)) : "unknown";
|
|
3402
|
+
return `Unauthorized sender.
|
|
3403
|
+
|
|
3404
|
+
Your Telegram user ID: ${normalizedSenderId}
|
|
3405
|
+
Add this ID to the bot allowlist before using the bridge.`;
|
|
3406
|
+
}
|
|
3407
|
+
unauthorizedCallbackMessage(senderId) {
|
|
3408
|
+
if (typeof senderId === "number" && Number.isFinite(senderId)) {
|
|
3409
|
+
return `Unauthorized: ${String(Math.trunc(senderId))}`;
|
|
3410
|
+
}
|
|
3411
|
+
return "Unauthorized sender";
|
|
3412
|
+
}
|
|
3334
3413
|
async answerCallbackQuery(callbackQueryId, text) {
|
|
3335
3414
|
await fetch(this.apiUrl("answerCallbackQuery"), {
|
|
3336
3415
|
method: "POST",
|
|
@@ -3499,6 +3578,163 @@ ${summary}`;
|
|
|
3499
3578
|
}
|
|
3500
3579
|
};
|
|
3501
3580
|
|
|
3581
|
+
// src/server/freeMode.ts
|
|
3582
|
+
var ENCRYPTED_KEYS = [
|
|
3583
|
+
"FhkYWwEZE0MYBhAGUEADDBYFBEoDBxIHVUpUVRIMVUYDAkEHVRYNAxABUUAEAUMDV0pUDEQAU0ZTDEQCVERQVkoBVhAEBBBXAQ==",
|
|
3584
|
+
"FhkYWwEZE0MYVkIGUkNUUkpVXUsBBUUAVEYHUEIMBhQCVxZWBBcHVkoNUENRAxAMA0MHARBXBkVUAUVQXBAFAUVXVxFWBUtWBw==",
|
|
3585
|
+
"FhkYWwEZE0MYVhFWAUJUUBEMURMHAUoEAUcABRAEURRXARBRU0ZUBBFVB0YAAUNVVUYBDBBSABRUAhdVXUUBUhANV0IMBBABBA==",
|
|
3586
|
+
"FhkYWwEZE0MYUBIDABMBVkMHURcGDRVSXRMFBUUCBBQBVhUBUBEGDBAAVkpTVUoGUBYMBhJXB0ANABUEARBQB0RRXUBRBUNQBw==",
|
|
3587
|
+
"FhkYWwEZE0MYVhcFBhMFARJXVBMADRdWVxYHBkQNA0cBBEsGVEBRAkYCXEFXURBXABZQDEZSXBQHAkJSAUABVxIMA0NWAEcMUA==",
|
|
3588
|
+
"FhkYWwEZE0MYAEQAXEZQURUGARFRBkRWVENWDUYFBkQHBEJWU0dQUkdWBhZXARYMAERXURcBUUQNDUAGAEoEB0ABV0NTUkQDBw==",
|
|
3589
|
+
"FhkYWwEZE0MYABdRURBXVkYDURZWUUIAUEcMBEcMUUpXVxEGVhEMBktVXBBWAEFQBBBRVhECUEQEBkFQUUpRVRUMV0dRA0QGUw==",
|
|
3590
|
+
"FhkYWwEZE0MYVUMCUUIHAUFRVksFVhYMARRRBBIAVBMBDEFVAxMAAUpRXUsEBkMHVhAHBUdSVxECABJSVRdRBkMEURANAEdXVA==",
|
|
3591
|
+
"FhkYWwEZE0MYUkEFVEVUBEoMVkINDUFQUENQAkBSAEVQVhcEAEsDBxVWUkBWAkRSA0ANV0FVBkYMVxcBXUQEUEQCARYDDEpWXA==",
|
|
3592
|
+
"FhkYWwEZE0MYDBcCXBANBRdVU0YEAEsMAUoNUkoMUBYDABcHVEBQBkRVUxdWBUUAAURUVxUGB0oDVxIHABRUAhJRAEUDUkECXQ==",
|
|
3593
|
+
"FhkYWwEZE0MYVhUHVBEBURFQA0EBVRcNUUZXAhVXVkpQAEUHBhNTDUQMXRAGA0JQA0BRBRUHVRQMURVWXUoBVxcEBEYEAEACUQ==",
|
|
3594
|
+
"FhkYWwEZE0MYA0UCB0ZTABUNBhRTAUYAUENQUEANBEMCARdQBkRRBRYDUhdWVhACXBcGBhIDVBFRBRJQUREGDRAAUhQHUhUBAA==",
|
|
3595
|
+
"FhkYWwEZE0MYAUsMARACBBYGVxQHARVQVxRRBRcNUkAFUUQCXBEAUkcBXEMBBEYCXRENBUsBVRYABUJXU0FUAEYBUUpWABEGUw==",
|
|
3596
|
+
"FhkYWwEZE0MYAEdSUBcNAUoFUERUAkcFAEQAB0IBUxcFDUIMBEpQVktWUxdUB0MBXUEBBhIMXRQEUBFQXEMFAEBQXUEMVkoBUQ==",
|
|
3597
|
+
"FhkYWwEZE0MYDBYNUUVUA0ECUREMVhUEBkoCVxJSXEtRUENQVxAMBBcMAxACVkVVBEEDUEYDAURWA0oDXUYAAEEEVxQABUANVg==",
|
|
3598
|
+
"FhkYWwEZE0MYVhcHBhcFV0EBUEdWVxdSU0sMABFSUEIHA0EAU0dWBkcFXEZRBENXAUEDV0AFUkEABBAEXBdXAhZRBEAAUUBSVg==",
|
|
3599
|
+
"FhkYWwEZE0MYV0MHAxYBDUsHB0oFVRJWAUoABEQGAUEHDRdRUBQHBREFUkpQVUYHVkVTDBcDXUYHBkJXUhENVUIAVUtTDRcMVA==",
|
|
3600
|
+
"FhkYWwEZE0MYBxVXBEsAUkYBA0EEAUIGBkRQA0MNABZRVkcHA0JTUEdWUkNRBBUEXUFUB0oFB0QGDBdWUUsEV0NXBBQBVRUEVg==",
|
|
3601
|
+
"FhkYWwEZE0MYVxcCVBYHAEsNVBEADEENUkMAUhFWXBNUVxdWBxNWURYAVEEAUUdSURAHDUsAUkEABBJSVRZQV0YNVRBRDUVSBw==",
|
|
3602
|
+
"FhkYWwEZE0MYAEQEV0YGVxcMVkRQUEsGUEBRUEADAEYEV0NRBBRWBUpXV0oMA0NRXBBRAkAMXUZWURBSXEZRB0EEVBQNVxYBXQ==",
|
|
3603
|
+
"FhkYWwEZE0MYA0IBUhADUERXB0MNB0MHVUtUDRUNBEpXVkEGUBMABkZVUENUAkBVXRAEDEAHBkJWABAEURNWDEcEABQCVUdVVA==",
|
|
3604
|
+
"FhkYWwEZE0MYUhcEBBYCAUFSXUAEAEEBV0sDDRAFV0YDV0NVBENXB0QNVxdUAkYMXUQGA0tRV0tWVUoDAxcGUUVVVUQHDBEDBA==",
|
|
3605
|
+
"FhkYWwEZE0MYA0QBBEIAB0INXUtTBxYFVBFXABJSBkYEAxIAVEAGVkZSB0tQUEoHBkcGBBUHVENWAUNRUEYCAhJSXRcNUEQGUA==",
|
|
3606
|
+
"FhkYWwEZE0MYUBJQUEIFUkBXARBUBUIDAxBQVhJVVkUMVhEDAEYNVxEGBhRUVkJWURYDAUAAAUUMARVRBhYAUkAEUkUEAhYCVg==",
|
|
3607
|
+
"FhkYWwEZE0MYVUYGVBcEDEAFVhACVkFWXBFTAxAMUUpQURENARYBVhABAEINAEQCAUECDEsCBEUBVxBXBxRUVxdQBBRXVkcCUA==",
|
|
3608
|
+
"FhkYWwEZE0MYV0YMVxBTVUNQBERRURVSUxQGUUVWB0MGVUMHV0cHUkMEAEMDDUMCVEcGVkNVB0oDURdVAUFQBkIAURYDBhAHAA==",
|
|
3609
|
+
"FhkYWwEZE0MYUhYCXEsNVUAEURFXBkcHABFQBxcFUENWVkpVAxZWAhEBAxMBBkRRVUtQDEZWXEoBBxUNVkYBBhJQUBBQUUoDBw==",
|
|
3610
|
+
"FhkYWwEZE0MYB0YGXUIGDRIHVRZQVUJSV0UNB0oNAxQADRUMVUcEBhdQV0AHDUZXAEtQVkVQUhBRBUBSUEQCVkRSBEUDUkQEVQ==",
|
|
3611
|
+
"FhkYWwEZE0MYB0MGAUEADERVV0RXDUJSUUMAUEdRAUMCBxZSBktQDUMEBkIBBkIDAEMNURdRXUoFB0RWVEZRDUFXAEJTVRVWVg==",
|
|
3612
|
+
"FhkYWwEZE0MYAkQDAxcFBEpXVEIEDUJSB0tXBhVXUkIDAEEMBBBXDUdRVRcNBURVAxZXUUENARYNBkMAUBBTDUsGVUFWDEcAVQ==",
|
|
3613
|
+
"FhkYWwEZE0MYDRFQVUsCBRIMXBEFBEYEBEMBAUAMVkoCDUoABEcNV0YMU0pWABJXURcAAEIEUBcGVxcGUhZWBUIAVUQCUkVVAA==",
|
|
3614
|
+
"FhkYWwEZE0MYUhcDVURUDBBSVkVWAEYCBkoMUEVVU0cEAxcFVhcDVUEBAEpXUhIAXEUNBUQBAxYGUhFXVUUHBBUAVkpRURAAVQ==",
|
|
3615
|
+
"FhkYWwEZE0MYUEtVV0BQV0tXB0dXVkNRVRRQBUADABFTURYDVBdXUEFSXEpXB0dQVBQEA0oAVUpTBEYEVBMNDEMDU0BUBUINUg==",
|
|
3616
|
+
"FhkYWwEZE0MYUEpQBxZTBkFXXEZWAkEEBxEHB0RXVktQUEMDARRRABEFAUIABEAMARRRDUACBBAMUEMMUxcEUUEEAEoAURBQBg==",
|
|
3617
|
+
"FhkYWwEZE0MYUEINARRQAhcCUEJRUBIFBEIHBkJQB0tWVhINXRBUUBdVBkcMBUZVUxNTAUsMU0cFAEtSXUJXDRJSBkVUAUoBVA==",
|
|
3618
|
+
"FhkYWwEZE0MYUEBWAUtXBxEHUhNTBRZVB0UEB0MDA0sCBEAABkNUAUQCBxYAAEVQUEYDVkoDVxAFVUFVVUcMAUECBkoGUUsCUA==",
|
|
3619
|
+
"FhkYWwEZE0MYBBUBUEFTBUIDAxAGBUcFARBWBRJXUUJTAkUGURQBUUUEB0EFBBBVVURQBEEAUBMAVhINVUEBVUcMA0sNVUNQVg==",
|
|
3620
|
+
"FhkYWwEZE0MYDUMDA0MNA0oAV0BQUEEFBEUBAkpQXBAMBUsCVRZXVkIAXBMEAktXBhYABkcAUhMAUhYBA0BTAURVURMBA0ACXA==",
|
|
3621
|
+
"FhkYWwEZE0MYUhdXUUMDAEQNBhZTAEdWXUYHBxEHXUQCDBYCBkEBBEIDAEBQBkEAUkUBBREMUEUNAEUMBENUBhZXVkVQV0NWBw==",
|
|
3622
|
+
"FhkYWwEZE0MYUBdVU0VXVkpQUkEEBkFSVhZRDEQMXBdQA0QDXUIHUEtWBEABAERXBEoMAxEDUxYMDUVRXUJTUBcFBhQCVkcAVQ==",
|
|
3623
|
+
"FhkYWwEZE0MYDRcBUBYCUEpRABQNVRcHBkQABkZXUkBWURFVU0sMBxINURQMAREHUUcHAUYDB0QBAUNVVUAAARUGUEoAABYGXA==",
|
|
3624
|
+
"FhkYWwEZE0MYAhUCUktQV0oEBxcCVUoCB0pTAUJQXUJTARYAXUsNDRUDUkVQARIHUUJUBEMEVxMFBhEAUUUCBRIAXBMBVUAHAA==",
|
|
3625
|
+
"FhkYWwEZE0MYARcCAUMDVxFQBEZXUEcCAEYDVksNVUpQB0MEB0EEAhVWXRcEUUBQXEoGA0BSAEVWBhdXVUACUUZSUEZXBUZRVg==",
|
|
3626
|
+
"FhkYWwEZE0MYA0oBUhEHABYCBkcMUUcGXRdUDRZXVBZTARUHVkQGV0UAAUoDBxJRVRQBA0oFAUEGBERSVhMGBEBWBEpRAUMGVg==",
|
|
3627
|
+
"FhkYWwEZE0MYVhANVBFXDEoAXEoMBhYMUxMNUEECVEoMAkQFVxANVRcFABdRDRVWXUACBBYHVURUUBACXUNUV0IMAUcCAUIHBw==",
|
|
3628
|
+
"FhkYWwEZE0MYUEUCB0UNDBEFVhQGBhJSBkYHBEMNBhAGUkAFA0AMBUAGUEYDAUZQVUdWUhcHUEcAUhEFB0FQV0VQAUtXBEcDBw==",
|
|
3629
|
+
"FhkYWwEZE0MYAUNSURNTBRANUkRWVxYHXEYMAUYBB0cCBksCAEUHUkVSVUdRURIEBxADBhECVxNRUEcFUxQMUEMMA0MFBEENBA==",
|
|
3630
|
+
"FhkYWwEZE0MYBxBWVkZQAkENVhYNBBUDXBADAUANUkBRVkICBEtRVxEEAEFUDUIDUkNXAxEDAUcHARIAVEJTA0oNVkANB0EGXA==",
|
|
3631
|
+
"FhkYWwEZE0MYV0IGAREGUhZVUEFXVkJVVUECDBcFARcNUhZQXBEFAkMBU0sDUEIFBhcCV0cCXUBTVRADV0YEA0ZQUxACUUsEXA==",
|
|
3632
|
+
"FhkYWwEZE0MYVUoNVUNQURVQUREDAxJSB0AAAkMCABQDAUMGVBYABBJWBxADBENRVEsAVxcAAEdTARUDBBEFUhZSUEQDDRcAXA==",
|
|
3633
|
+
"FhkYWwEZE0MYBhdRVUQBVhcGBhENV0QEAEIGVxcBUxQNUUcAVxZWBEEEVUBTARYGAUFUAUUHBEQEDUsDVEJXDEQNU0sCV0YMAA==",
|
|
3634
|
+
"FhkYWwEZE0MYVktRAENWAkEBXUsGUUEDUkMHB0FXB0cCAhEHARZUBxJWB0IDBERRUkUAAxYDUkYBUkYDV0QDVUcHVxAGA0INVA==",
|
|
3635
|
+
"FhkYWwEZE0MYBkIAVBABVUINV0NTVxYGAUYFVUMBUxYMURAGBksAVUJVBkoHUUQMA0cMAUdQVkUGBUpSAEZTVRANUBYEUEQBVA==",
|
|
3636
|
+
"FhkYWwEZE0MYDEMDA0oCVURRUBZWUkANUEQBAkBSXBBRB0BSVBYGVkAFVRAGDEYDVkMEDBBSBkQHV0JRA0JUBRcFXURTDRZRUw==",
|
|
3637
|
+
"FhkYWwEZE0MYUBJSVEUNUhcGBkYGAhYDUEcAUEsEBxdUUBZSXEcGDEINXEoDBxcFUkdWBEBRVxYNDUYAUBMBVkcCUBcHUUsAXA==",
|
|
3638
|
+
"FhkYWwEZE0MYA0QNUEtWAUMEAEoBUEoAAREDVRYHVkoEV0ZQBEEEUkEAAUIEAUcCVhEHUBUDB0FRVktVVEFXARIHA0NWBUpXBg==",
|
|
3639
|
+
"FhkYWwEZE0MYV0oCAxFXV0YMUxFQAUAAUEVWA0cEB0pUUBAFXUIHDRdQAEQAUkMGU0AEVxEDBBEBAhBRV0QEAxVWU0NQBxECBw==",
|
|
3640
|
+
"FhkYWwEZE0MYUkoCBBMEUkYDBhYFB0IFVkQMVUpSBksMUUcFUxEEDRZVVkUADEoCVhcHUkEHUxACUUJXBBdTVUQDAEFRBxUGAw==",
|
|
3641
|
+
"FhkYWwEZE0MYV0BXBEUCURUNXUYABUpQURYBBUYFVENXBhYCXRBWDUsHA0NRB0oGUREHDRYGUxMBAksEUkINVkNVBEIBAxdWUA==",
|
|
3642
|
+
"FhkYWwEZE0MYBEoCA0MNDEUAXUNUAxYHXBRRURACUEFQBxYDB0dUBksDA0QFVksMAxQFAEZRAxNTA0cMVUENVxEEAUFRBUAHBA==",
|
|
3643
|
+
"FhkYWwEZE0MYB0ENVkAABxEFXEZQAUYHBhMFBBJQBkMCUUZRBERTAkBRBhADVxYEXEADB0RSUUtRUREBXRdXBkAGBEUNBEQCUg==",
|
|
3644
|
+
"FhkYWwEZE0MYVhFVXBAFDBYFBkFTAhIGB0ZRBEJVXURTBBFWBxNUVkBXBEMMBkIHURcDAksAVEMEV0dSUhdXBBJWUkJWAxBRVg==",
|
|
3645
|
+
"FhkYWwEZE0MYBRFRXUoBBUcGBhZUAUBVABYEVkICVkNXDUcMABYFVxdXU0sEBkcFXEYBURUFVUYFABJSA0dTABdRVBRQVRENVg==",
|
|
3646
|
+
"FhkYWwEZE0MYV0VQVhEHVkVVAEFQAhcHBEMMUUANVxNUBUJWVRcEVUoEBBcDUkcNBkoCUUVVVBcDVRZQBBBUVRYNXBZWBUMAAQ==",
|
|
3647
|
+
"FhkYWwEZE0MYAhIHARYBVxIABhYBVxVWUkVXV0ICXUUADBZQAUYBBEUBUEsFBRcFARcGUEtVXEoGABYAUkEGDEBRVUMBB0IFXQ==",
|
|
3648
|
+
"FhkYWwEZE0MYBBUCXEEFBEJVVxZQBEICUxFRBUUNBksHBhFXUUANVhUCV0EMB0QDVURWDBFSVkYDAxYAABdXBhIEUEQMBEUCUg==",
|
|
3649
|
+
"FhkYWwEZE0MYDUsDBEoNAEECURBTAUJXUEpWVUdSBEAMDRBVUkYAUUoDAxFTDEpVVxEHAUYNVUMGVkYAA0cBBRJWBBAHUUIMVw==",
|
|
3650
|
+
"FhkYWwEZE0MYUUUFXUBTUEYHUkoHBBIFBEpRV0NWVRcBAktWBkADBxAMVUZUBhJSBEAEB0MDVkpTABUMUUVUUEABUkJUVkIHAA=="
|
|
3651
|
+
];
|
|
3652
|
+
var DECRYPT_KEY = "er54s4";
|
|
3653
|
+
function xorDecrypt(b64, secret) {
|
|
3654
|
+
const buf = Buffer.from(b64, "base64");
|
|
3655
|
+
const keyBuf = Buffer.from(secret, "utf8");
|
|
3656
|
+
const out = Buffer.alloc(buf.length);
|
|
3657
|
+
for (let i = 0; i < buf.length; i++) {
|
|
3658
|
+
out[i] = buf[i] ^ keyBuf[i % keyBuf.length];
|
|
3659
|
+
}
|
|
3660
|
+
return out.toString("utf8");
|
|
3661
|
+
}
|
|
3662
|
+
function getRandomFreeKey() {
|
|
3663
|
+
if (ENCRYPTED_KEYS.length === 0) return null;
|
|
3664
|
+
const idx = Math.floor(Math.random() * ENCRYPTED_KEYS.length);
|
|
3665
|
+
return xorDecrypt(ENCRYPTED_KEYS[idx], DECRYPT_KEY);
|
|
3666
|
+
}
|
|
3667
|
+
function getFreeKeyCount() {
|
|
3668
|
+
return ENCRYPTED_KEYS.length;
|
|
3669
|
+
}
|
|
3670
|
+
var FREE_MODE_PROVIDER_ID = "openrouter-free";
|
|
3671
|
+
var FREE_MODE_BASE_URL = "https://openrouter.ai/api/v1";
|
|
3672
|
+
var FALLBACK_FREE_MODELS = [
|
|
3673
|
+
"openrouter/free",
|
|
3674
|
+
"google/gemma-4-26b-a4b-it:free",
|
|
3675
|
+
"google/gemma-3-27b-it:free",
|
|
3676
|
+
"meta-llama/llama-3.3-70b-instruct:free",
|
|
3677
|
+
"qwen/qwen3-coder:free"
|
|
3678
|
+
];
|
|
3679
|
+
var cachedFreeModels = null;
|
|
3680
|
+
var cacheTimestamp = 0;
|
|
3681
|
+
var CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
3682
|
+
async function fetchFreeModelsFromOpenRouter() {
|
|
3683
|
+
try {
|
|
3684
|
+
const resp = await fetch("https://openrouter.ai/api/v1/models");
|
|
3685
|
+
if (!resp.ok) return cachedFreeModels ?? FALLBACK_FREE_MODELS;
|
|
3686
|
+
const json = await resp.json();
|
|
3687
|
+
const ids = json.data.filter((m) => m.id.endsWith(":free") || m.id === "openrouter/free").map((m) => m.id);
|
|
3688
|
+
if (ids.length === 0) return cachedFreeModels ?? FALLBACK_FREE_MODELS;
|
|
3689
|
+
const sorted = ["openrouter/free", ...ids.filter((id) => id !== "openrouter/free")];
|
|
3690
|
+
cachedFreeModels = sorted;
|
|
3691
|
+
cacheTimestamp = Date.now();
|
|
3692
|
+
return sorted;
|
|
3693
|
+
} catch {
|
|
3694
|
+
return cachedFreeModels ?? FALLBACK_FREE_MODELS;
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
async function getFreeModels() {
|
|
3698
|
+
if (cachedFreeModels && Date.now() - cacheTimestamp < CACHE_TTL_MS) {
|
|
3699
|
+
return cachedFreeModels;
|
|
3700
|
+
}
|
|
3701
|
+
return fetchFreeModelsFromOpenRouter();
|
|
3702
|
+
}
|
|
3703
|
+
var FREE_MODE_DEFAULT_MODEL = "openrouter/free";
|
|
3704
|
+
var FREE_MODE_STATE_FILE = "webui-free-mode.json";
|
|
3705
|
+
var CUSTOM_PROVIDER_ID = "custom-endpoint";
|
|
3706
|
+
function getFreeModeConfigArgs(state) {
|
|
3707
|
+
if (!state.enabled || !state.apiKey) return [];
|
|
3708
|
+
if (state.provider === "custom" && state.customBaseUrl) {
|
|
3709
|
+
return [
|
|
3710
|
+
"-c",
|
|
3711
|
+
`model_provider="${CUSTOM_PROVIDER_ID}"`,
|
|
3712
|
+
"-c",
|
|
3713
|
+
`model_providers.${CUSTOM_PROVIDER_ID}.name="Custom Endpoint"`,
|
|
3714
|
+
"-c",
|
|
3715
|
+
`model_providers.${CUSTOM_PROVIDER_ID}.base_url="${state.customBaseUrl}"`,
|
|
3716
|
+
"-c",
|
|
3717
|
+
`model_providers.${CUSTOM_PROVIDER_ID}.wire_api="responses"`,
|
|
3718
|
+
"-c",
|
|
3719
|
+
`model_providers.${CUSTOM_PROVIDER_ID}.experimental_bearer_token="${state.apiKey}"`
|
|
3720
|
+
];
|
|
3721
|
+
}
|
|
3722
|
+
return [
|
|
3723
|
+
"-c",
|
|
3724
|
+
`model="${state.model}"`,
|
|
3725
|
+
"-c",
|
|
3726
|
+
`model_provider="${FREE_MODE_PROVIDER_ID}"`,
|
|
3727
|
+
"-c",
|
|
3728
|
+
`model_providers.${FREE_MODE_PROVIDER_ID}.name="OpenRouter Free"`,
|
|
3729
|
+
"-c",
|
|
3730
|
+
`model_providers.${FREE_MODE_PROVIDER_ID}.base_url="${FREE_MODE_BASE_URL}"`,
|
|
3731
|
+
"-c",
|
|
3732
|
+
`model_providers.${FREE_MODE_PROVIDER_ID}.wire_api="responses"`,
|
|
3733
|
+
"-c",
|
|
3734
|
+
`model_providers.${FREE_MODE_PROVIDER_ID}.experimental_bearer_token="${state.apiKey}"`
|
|
3735
|
+
];
|
|
3736
|
+
}
|
|
3737
|
+
|
|
3502
3738
|
// src/utils/commandInvocation.ts
|
|
3503
3739
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
3504
3740
|
import { basename as basename2, extname } from "path";
|
|
@@ -4979,11 +5215,24 @@ async function writeWorkspaceRootsState(nextState) {
|
|
|
4979
5215
|
}
|
|
4980
5216
|
function normalizeTelegramBridgeConfig(value) {
|
|
4981
5217
|
const record = asRecord5(value);
|
|
4982
|
-
if (!record) return { botToken: "", chatIds: [] };
|
|
5218
|
+
if (!record) return { botToken: "", chatIds: [], allowedUserIds: [] };
|
|
4983
5219
|
const botToken = typeof record.botToken === "string" ? record.botToken.trim() : "";
|
|
4984
5220
|
const rawChatIds = Array.isArray(record.chatIds) ? record.chatIds : [];
|
|
4985
5221
|
const chatIds = Array.from(new Set(rawChatIds.filter((value2) => typeof value2 === "number" && Number.isFinite(value2)).map((value2) => Math.trunc(value2)))).slice(0, 50);
|
|
4986
|
-
|
|
5222
|
+
const rawAllowedUserIds = Array.isArray(record.allowedUserIds) ? record.allowedUserIds : [];
|
|
5223
|
+
const allowAllUsers = rawAllowedUserIds.some((value2) => typeof value2 === "string" && value2.trim() === "*");
|
|
5224
|
+
const normalizedAllowedUserIds = Array.from(new Set(rawAllowedUserIds.map((value2) => {
|
|
5225
|
+
if (typeof value2 === "number" && Number.isFinite(value2)) return Math.trunc(value2);
|
|
5226
|
+
if (typeof value2 === "string") {
|
|
5227
|
+
const normalized = value2.trim().replace(/^(telegram|tg):/i, "").trim();
|
|
5228
|
+
if (/^-?\d+$/.test(normalized)) {
|
|
5229
|
+
return Number.parseInt(normalized, 10);
|
|
5230
|
+
}
|
|
5231
|
+
}
|
|
5232
|
+
return Number.NaN;
|
|
5233
|
+
}).filter((value2) => Number.isFinite(value2)))).slice(0, 100);
|
|
5234
|
+
const allowedUserIds = allowAllUsers ? ["*", ...normalizedAllowedUserIds] : normalizedAllowedUserIds;
|
|
5235
|
+
return { botToken, chatIds, allowedUserIds };
|
|
4987
5236
|
}
|
|
4988
5237
|
async function readTelegramBridgeConfig() {
|
|
4989
5238
|
const telegramConfigPath = getTelegramBridgeConfigPath();
|
|
@@ -4992,7 +5241,7 @@ async function readTelegramBridgeConfig() {
|
|
|
4992
5241
|
const payload = asRecord5(JSON.parse(raw)) ?? {};
|
|
4993
5242
|
return normalizeTelegramBridgeConfig(payload);
|
|
4994
5243
|
} catch {
|
|
4995
|
-
return { botToken: "", chatIds: [] };
|
|
5244
|
+
return { botToken: "", chatIds: [], allowedUserIds: [] };
|
|
4996
5245
|
}
|
|
4997
5246
|
}
|
|
4998
5247
|
async function writeTelegramBridgeConfig(nextState) {
|
|
@@ -5000,7 +5249,8 @@ async function writeTelegramBridgeConfig(nextState) {
|
|
|
5000
5249
|
const telegramConfigPath = getTelegramBridgeConfigPath();
|
|
5001
5250
|
await writeFile4(telegramConfigPath, JSON.stringify({
|
|
5002
5251
|
botToken: normalized.botToken,
|
|
5003
|
-
chatIds: normalized.chatIds
|
|
5252
|
+
chatIds: normalized.chatIds,
|
|
5253
|
+
allowedUserIds: normalized.allowedUserIds
|
|
5004
5254
|
}), "utf8");
|
|
5005
5255
|
}
|
|
5006
5256
|
var telegramBridgeConfigMutation = Promise.resolve();
|
|
@@ -5206,10 +5456,27 @@ var AppServerProcess = class {
|
|
|
5206
5456
|
}
|
|
5207
5457
|
return codexCommand;
|
|
5208
5458
|
}
|
|
5459
|
+
buildAppServerArgs() {
|
|
5460
|
+
const args = [
|
|
5461
|
+
"app-server",
|
|
5462
|
+
"-c",
|
|
5463
|
+
'approval_policy="never"',
|
|
5464
|
+
"-c",
|
|
5465
|
+
'sandbox_mode="danger-full-access"'
|
|
5466
|
+
];
|
|
5467
|
+
const statePath = join5(getCodexHomeDir3(), FREE_MODE_STATE_FILE);
|
|
5468
|
+
try {
|
|
5469
|
+
const raw = readFileSync(statePath, "utf8");
|
|
5470
|
+
const state = JSON.parse(raw);
|
|
5471
|
+
args.push(...getFreeModeConfigArgs(state));
|
|
5472
|
+
} catch {
|
|
5473
|
+
}
|
|
5474
|
+
return args;
|
|
5475
|
+
}
|
|
5209
5476
|
start() {
|
|
5210
5477
|
if (this.process) return;
|
|
5211
5478
|
this.stopping = false;
|
|
5212
|
-
const invocation = getSpawnInvocation(this.getCodexCommand(), this.
|
|
5479
|
+
const invocation = getSpawnInvocation(this.getCodexCommand(), this.buildAppServerArgs());
|
|
5213
5480
|
const proc = spawn4(invocation.command, invocation.args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
5214
5481
|
this.process = proc;
|
|
5215
5482
|
proc.stdout.setEncoding("utf8");
|
|
@@ -5758,6 +6025,7 @@ function createCodexBridgeMiddleware() {
|
|
|
5758
6025
|
void readTelegramBridgeConfig().then((config) => {
|
|
5759
6026
|
if (!config.botToken) return;
|
|
5760
6027
|
telegramBridge.configureToken(config.botToken);
|
|
6028
|
+
telegramBridge.configureAllowedUserIds(config.allowedUserIds);
|
|
5761
6029
|
telegramBridge.start();
|
|
5762
6030
|
}).catch(() => {
|
|
5763
6031
|
});
|
|
@@ -5768,6 +6036,135 @@ function createCodexBridgeMiddleware() {
|
|
|
5768
6036
|
return;
|
|
5769
6037
|
}
|
|
5770
6038
|
const url = new URL(req.url, "http://localhost");
|
|
6039
|
+
if (url.pathname.startsWith("/codex-api/free-mode")) {
|
|
6040
|
+
let readFreeModeState2 = function() {
|
|
6041
|
+
try {
|
|
6042
|
+
return JSON.parse(readFileSync(statePath, "utf8"));
|
|
6043
|
+
} catch {
|
|
6044
|
+
return { enabled: false, apiKey: null, model: FREE_MODE_DEFAULT_MODEL };
|
|
6045
|
+
}
|
|
6046
|
+
};
|
|
6047
|
+
var readFreeModeState = readFreeModeState2;
|
|
6048
|
+
const statePath = join5(getCodexHomeDir3(), FREE_MODE_STATE_FILE);
|
|
6049
|
+
if (req.method === "POST" && url.pathname === "/codex-api/free-mode") {
|
|
6050
|
+
try {
|
|
6051
|
+
const body = await readJsonBody(req);
|
|
6052
|
+
const enable = Boolean(body?.enable);
|
|
6053
|
+
if (enable) {
|
|
6054
|
+
const apiKey = getRandomFreeKey();
|
|
6055
|
+
if (!apiKey) {
|
|
6056
|
+
setJson4(res, 500, { error: "No free keys available" });
|
|
6057
|
+
return;
|
|
6058
|
+
}
|
|
6059
|
+
const state = { enabled: true, apiKey, model: FREE_MODE_DEFAULT_MODEL, provider: "openrouter" };
|
|
6060
|
+
await writeFile4(statePath, JSON.stringify(state), "utf8");
|
|
6061
|
+
appServer.dispose();
|
|
6062
|
+
const freeModels = await getFreeModels();
|
|
6063
|
+
setJson4(res, 200, {
|
|
6064
|
+
ok: true,
|
|
6065
|
+
enabled: true,
|
|
6066
|
+
model: FREE_MODE_DEFAULT_MODEL,
|
|
6067
|
+
keyCount: getFreeKeyCount(),
|
|
6068
|
+
models: freeModels
|
|
6069
|
+
});
|
|
6070
|
+
} else {
|
|
6071
|
+
const state = { enabled: false, apiKey: null, model: FREE_MODE_DEFAULT_MODEL };
|
|
6072
|
+
await writeFile4(statePath, JSON.stringify(state), "utf8");
|
|
6073
|
+
appServer.dispose();
|
|
6074
|
+
setJson4(res, 200, { ok: true, enabled: false });
|
|
6075
|
+
}
|
|
6076
|
+
} catch (error) {
|
|
6077
|
+
setJson4(res, 500, { error: getErrorMessage5(error, "Failed to toggle free mode") });
|
|
6078
|
+
}
|
|
6079
|
+
return;
|
|
6080
|
+
}
|
|
6081
|
+
if (req.method === "GET" && url.pathname === "/codex-api/free-mode/status") {
|
|
6082
|
+
try {
|
|
6083
|
+
const state = readFreeModeState2();
|
|
6084
|
+
const freeModels = await getFreeModels();
|
|
6085
|
+
const maskedKey = state.apiKey && state.customKey ? state.apiKey.substring(0, 12) + "..." + state.apiKey.substring(state.apiKey.length - 4) : null;
|
|
6086
|
+
setJson4(res, 200, {
|
|
6087
|
+
enabled: state.enabled,
|
|
6088
|
+
keyCount: getFreeKeyCount(),
|
|
6089
|
+
models: freeModels,
|
|
6090
|
+
currentModel: state.enabled ? state.model : null,
|
|
6091
|
+
customKey: Boolean(state.customKey),
|
|
6092
|
+
maskedKey,
|
|
6093
|
+
provider: state.provider ?? "openrouter",
|
|
6094
|
+
customBaseUrl: state.customBaseUrl ?? null
|
|
6095
|
+
});
|
|
6096
|
+
} catch (error) {
|
|
6097
|
+
setJson4(res, 500, { error: getErrorMessage5(error, "Failed to read free mode status") });
|
|
6098
|
+
}
|
|
6099
|
+
return;
|
|
6100
|
+
}
|
|
6101
|
+
if (req.method === "POST" && url.pathname === "/codex-api/free-mode/rotate-key") {
|
|
6102
|
+
try {
|
|
6103
|
+
const apiKey = getRandomFreeKey();
|
|
6104
|
+
if (!apiKey) {
|
|
6105
|
+
setJson4(res, 500, { error: "No free keys available" });
|
|
6106
|
+
return;
|
|
6107
|
+
}
|
|
6108
|
+
const current = readFreeModeState2();
|
|
6109
|
+
const state = { ...current, apiKey, customKey: false };
|
|
6110
|
+
await writeFile4(statePath, JSON.stringify(state), "utf8");
|
|
6111
|
+
appServer.dispose();
|
|
6112
|
+
setJson4(res, 200, { ok: true });
|
|
6113
|
+
} catch (error) {
|
|
6114
|
+
setJson4(res, 500, { error: getErrorMessage5(error, "Failed to rotate key") });
|
|
6115
|
+
}
|
|
6116
|
+
return;
|
|
6117
|
+
}
|
|
6118
|
+
if (req.method === "POST" && url.pathname === "/codex-api/free-mode/custom-key") {
|
|
6119
|
+
try {
|
|
6120
|
+
const body = await readJsonBody(req);
|
|
6121
|
+
const key = typeof body?.key === "string" ? body.key.trim() : "";
|
|
6122
|
+
const current = readFreeModeState2();
|
|
6123
|
+
if (key.length > 0) {
|
|
6124
|
+
const state = { ...current, enabled: true, apiKey: key, customKey: true, provider: "openrouter" };
|
|
6125
|
+
await writeFile4(statePath, JSON.stringify(state), "utf8");
|
|
6126
|
+
appServer.dispose();
|
|
6127
|
+
setJson4(res, 200, { ok: true, customKey: true });
|
|
6128
|
+
} else {
|
|
6129
|
+
const communityKey = getRandomFreeKey();
|
|
6130
|
+
const state = { ...current, apiKey: communityKey, customKey: false, provider: "openrouter" };
|
|
6131
|
+
await writeFile4(statePath, JSON.stringify(state), "utf8");
|
|
6132
|
+
appServer.dispose();
|
|
6133
|
+
setJson4(res, 200, { ok: true, customKey: false });
|
|
6134
|
+
}
|
|
6135
|
+
} catch (error) {
|
|
6136
|
+
setJson4(res, 500, { error: getErrorMessage5(error, "Failed to set custom key") });
|
|
6137
|
+
}
|
|
6138
|
+
return;
|
|
6139
|
+
}
|
|
6140
|
+
if (req.method === "POST" && url.pathname === "/codex-api/free-mode/custom-provider") {
|
|
6141
|
+
try {
|
|
6142
|
+
const body = await readJsonBody(req);
|
|
6143
|
+
const baseUrl = typeof body?.baseUrl === "string" ? body.baseUrl.trim() : "";
|
|
6144
|
+
const apiKey = typeof body?.apiKey === "string" ? body.apiKey.trim() : "";
|
|
6145
|
+
if (!baseUrl) {
|
|
6146
|
+
setJson4(res, 400, { error: "baseUrl is required" });
|
|
6147
|
+
return;
|
|
6148
|
+
}
|
|
6149
|
+
const state = {
|
|
6150
|
+
enabled: true,
|
|
6151
|
+
apiKey: apiKey || "dummy",
|
|
6152
|
+
model: "",
|
|
6153
|
+
customKey: true,
|
|
6154
|
+
provider: "custom",
|
|
6155
|
+
customBaseUrl: baseUrl
|
|
6156
|
+
};
|
|
6157
|
+
await writeFile4(statePath, JSON.stringify(state), "utf8");
|
|
6158
|
+
appServer.dispose();
|
|
6159
|
+
setJson4(res, 200, { ok: true });
|
|
6160
|
+
} catch (error) {
|
|
6161
|
+
setJson4(res, 500, { error: getErrorMessage5(error, "Failed to set custom provider") });
|
|
6162
|
+
}
|
|
6163
|
+
return;
|
|
6164
|
+
}
|
|
6165
|
+
next();
|
|
6166
|
+
return;
|
|
6167
|
+
}
|
|
5771
6168
|
if (!url.pathname.startsWith("/codex-api/")) {
|
|
5772
6169
|
next();
|
|
5773
6170
|
return;
|
|
@@ -6038,6 +6435,34 @@ function createCodexBridgeMiddleware() {
|
|
|
6038
6435
|
return;
|
|
6039
6436
|
}
|
|
6040
6437
|
if (req.method === "GET" && url.pathname === "/codex-api/provider-models") {
|
|
6438
|
+
try {
|
|
6439
|
+
const fmState = JSON.parse(readFileSync(join5(getCodexHomeDir3(), FREE_MODE_STATE_FILE), "utf8"));
|
|
6440
|
+
if (fmState.enabled) {
|
|
6441
|
+
if (fmState.provider === "custom" && fmState.customBaseUrl) {
|
|
6442
|
+
try {
|
|
6443
|
+
const modelsUrl = fmState.customBaseUrl.replace(/\/+$/, "") + "/models";
|
|
6444
|
+
const headers = {};
|
|
6445
|
+
if (fmState.apiKey && fmState.apiKey !== "dummy") {
|
|
6446
|
+
headers["Authorization"] = `Bearer ${fmState.apiKey}`;
|
|
6447
|
+
}
|
|
6448
|
+
const resp = await fetch(modelsUrl, { headers, signal: AbortSignal.timeout(8e3) });
|
|
6449
|
+
if (resp.ok) {
|
|
6450
|
+
const json = await resp.json();
|
|
6451
|
+
const ids = (json.data ?? []).map((m) => m.id).filter(Boolean);
|
|
6452
|
+
setJson4(res, 200, { data: ids, exclusive: true, source: "custom" });
|
|
6453
|
+
return;
|
|
6454
|
+
}
|
|
6455
|
+
} catch {
|
|
6456
|
+
}
|
|
6457
|
+
setJson4(res, 200, { data: [], exclusive: true, source: "custom" });
|
|
6458
|
+
return;
|
|
6459
|
+
}
|
|
6460
|
+
const freeModels = await getFreeModels();
|
|
6461
|
+
setJson4(res, 200, { data: freeModels, exclusive: true });
|
|
6462
|
+
return;
|
|
6463
|
+
}
|
|
6464
|
+
} catch {
|
|
6465
|
+
}
|
|
6041
6466
|
const data = await readProviderBackedModelIds(appServer);
|
|
6042
6467
|
setJson4(res, 200, data);
|
|
6043
6468
|
return;
|
|
@@ -6495,20 +6920,41 @@ function createCodexBridgeMiddleware() {
|
|
|
6495
6920
|
if (req.method === "POST" && url.pathname === "/codex-api/telegram/configure-bot") {
|
|
6496
6921
|
const payload = asRecord5(await readJsonBody(req));
|
|
6497
6922
|
const botToken = typeof payload?.botToken === "string" ? payload.botToken.trim() : "";
|
|
6923
|
+
const rawAllowedUserIds = Array.isArray(payload?.allowedUserIds) ? payload.allowedUserIds : [];
|
|
6498
6924
|
if (!botToken) {
|
|
6499
6925
|
setJson4(res, 400, { error: "Missing botToken" });
|
|
6500
6926
|
return;
|
|
6501
6927
|
}
|
|
6502
|
-
|
|
6928
|
+
const config = normalizeTelegramBridgeConfig({
|
|
6929
|
+
botToken,
|
|
6930
|
+
allowedUserIds: rawAllowedUserIds
|
|
6931
|
+
});
|
|
6932
|
+
if (config.allowedUserIds.length === 0) {
|
|
6933
|
+
setJson4(res, 400, { error: "At least one allowed Telegram user ID is required" });
|
|
6934
|
+
return;
|
|
6935
|
+
}
|
|
6936
|
+
telegramBridge.configureToken(config.botToken);
|
|
6937
|
+
telegramBridge.configureAllowedUserIds(config.allowedUserIds);
|
|
6503
6938
|
telegramBridge.start();
|
|
6504
6939
|
const existingConfig = await readTelegramBridgeConfig();
|
|
6505
6940
|
await writeTelegramBridgeConfig({
|
|
6506
|
-
botToken,
|
|
6507
|
-
chatIds: existingConfig.chatIds
|
|
6941
|
+
botToken: config.botToken,
|
|
6942
|
+
chatIds: existingConfig.chatIds,
|
|
6943
|
+
allowedUserIds: config.allowedUserIds
|
|
6508
6944
|
});
|
|
6509
6945
|
setJson4(res, 200, { ok: true });
|
|
6510
6946
|
return;
|
|
6511
6947
|
}
|
|
6948
|
+
if (req.method === "GET" && url.pathname === "/codex-api/telegram/config") {
|
|
6949
|
+
const config = await readTelegramBridgeConfig();
|
|
6950
|
+
setJson4(res, 200, {
|
|
6951
|
+
data: {
|
|
6952
|
+
botToken: config.botToken,
|
|
6953
|
+
allowedUserIds: config.allowedUserIds
|
|
6954
|
+
}
|
|
6955
|
+
});
|
|
6956
|
+
return;
|
|
6957
|
+
}
|
|
6512
6958
|
if (req.method === "GET" && url.pathname === "/codex-api/telegram/status") {
|
|
6513
6959
|
setJson4(res, 200, { data: telegramBridge.getStatus() });
|
|
6514
6960
|
return;
|
|
@@ -7776,6 +8222,8 @@ async function startServer(options) {
|
|
|
7776
8222
|
if (options.login && !hasCodexAuth() && codexCommand) {
|
|
7777
8223
|
console.log("\nCodex is not logged in. Starting `codex login`...\n");
|
|
7778
8224
|
runOrFail(codexCommand, ["login"], "Codex login");
|
|
8225
|
+
} else if (options.login && !hasCodexAuth()) {
|
|
8226
|
+
console.log("\nCodex is not logged in. You can log in later via settings or run `codexui login`.\n");
|
|
7779
8227
|
}
|
|
7780
8228
|
const requestedPort = parseInt(options.port, 10);
|
|
7781
8229
|
const password = resolvePassword(options.password);
|