github-router 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +206 -30
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -43,7 +43,9 @@ const state = {
|
|
|
43
43
|
accountType: "individual",
|
|
44
44
|
manualApprove: false,
|
|
45
45
|
rateLimitWait: false,
|
|
46
|
-
showToken: false
|
|
46
|
+
showToken: false,
|
|
47
|
+
sessionId: randomUUID(),
|
|
48
|
+
machineId: randomUUID()
|
|
47
49
|
};
|
|
48
50
|
|
|
49
51
|
//#endregion
|
|
@@ -52,7 +54,7 @@ const standardHeaders = () => ({
|
|
|
52
54
|
"content-type": "application/json",
|
|
53
55
|
accept: "application/json"
|
|
54
56
|
});
|
|
55
|
-
const COPILOT_VERSION = "0.
|
|
57
|
+
const COPILOT_VERSION = "0.38.2026021302";
|
|
56
58
|
const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
|
|
57
59
|
const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
|
|
58
60
|
const API_VERSION = "2025-05-01";
|
|
@@ -69,7 +71,9 @@ const copilotHeaders = (state$1, vision = false, integrationId = "vscode-chat")
|
|
|
69
71
|
"x-interaction-type": "conversation-panel",
|
|
70
72
|
"x-github-api-version": API_VERSION,
|
|
71
73
|
"x-request-id": randomUUID(),
|
|
72
|
-
"x-vscode-user-agent-library-version": "electron-fetch"
|
|
74
|
+
"x-vscode-user-agent-library-version": "electron-fetch",
|
|
75
|
+
"VScode-SessionId": state$1.sessionId,
|
|
76
|
+
"VScode-MachineId": state$1.machineId
|
|
73
77
|
};
|
|
74
78
|
if (vision) headers["copilot-vision-request"] = "true";
|
|
75
79
|
return headers;
|
|
@@ -198,6 +202,25 @@ const sleep = (ms) => new Promise((resolve) => {
|
|
|
198
202
|
setTimeout(resolve, ms);
|
|
199
203
|
});
|
|
200
204
|
const isNullish = (value) => value === null || value === void 0;
|
|
205
|
+
/**
|
|
206
|
+
* Beta values that VS Code Copilot Chat actually sends to the Copilot API.
|
|
207
|
+
* Only these are forwarded; everything else (e.g. context-1m-*) is stripped
|
|
208
|
+
* so our requests match what VS Code produces.
|
|
209
|
+
*/
|
|
210
|
+
const ALLOWED_BETA_PREFIXES = [
|
|
211
|
+
"interleaved-thinking-",
|
|
212
|
+
"context-management-",
|
|
213
|
+
"advanced-tool-use-",
|
|
214
|
+
"token-counting-"
|
|
215
|
+
];
|
|
216
|
+
/**
|
|
217
|
+
* Filter an `anthropic-beta` header value, keeping only beta flags that
|
|
218
|
+
* VS Code Copilot is known to send. Returns the filtered comma-separated
|
|
219
|
+
* string, or undefined if nothing remains.
|
|
220
|
+
*/
|
|
221
|
+
function filterBetaHeader(value) {
|
|
222
|
+
return value.split(",").map((v) => v.trim()).filter((v) => v && ALLOWED_BETA_PREFIXES.some((prefix) => v.startsWith(prefix))).join(",") || void 0;
|
|
223
|
+
}
|
|
201
224
|
async function cacheModels() {
|
|
202
225
|
state.models = await getModels();
|
|
203
226
|
}
|
|
@@ -794,6 +817,7 @@ const createChatCompletions = async (payload) => {
|
|
|
794
817
|
const isAgentCall = payload.messages.some((msg) => ["assistant", "tool"].includes(msg.role));
|
|
795
818
|
const headers = {
|
|
796
819
|
...copilotHeaders(state, enableVision),
|
|
820
|
+
"Openai-Organization": "github-copilot",
|
|
797
821
|
"X-Initiator": isAgentCall ? "agent" : "user"
|
|
798
822
|
};
|
|
799
823
|
const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {
|
|
@@ -928,7 +952,7 @@ async function handleCompletion$1(c) {
|
|
|
928
952
|
const isNonStreaming$1 = (response) => Object.hasOwn(response, "choices");
|
|
929
953
|
async function injectWebSearchIfNeeded$1(payload) {
|
|
930
954
|
if (!payload.tools?.some((t) => "type" in t && t.type === "web_search" || t.function?.name === "web_search")) return;
|
|
931
|
-
const query = payload.messages.some((msg) => msg.role === "tool") ? void 0 : extractUserQuery$
|
|
955
|
+
const query = payload.messages.some((msg) => msg.role === "tool") ? void 0 : extractUserQuery$2(payload.messages);
|
|
932
956
|
if (query) try {
|
|
933
957
|
const results = await searchWeb(query);
|
|
934
958
|
const searchContext = [
|
|
@@ -955,7 +979,7 @@ async function injectWebSearchIfNeeded$1(payload) {
|
|
|
955
979
|
if (toolChoiceName && !payload.tools.some((tool) => tool.function.name === toolChoiceName)) payload.tool_choice = void 0;
|
|
956
980
|
}
|
|
957
981
|
}
|
|
958
|
-
function extractUserQuery$
|
|
982
|
+
function extractUserQuery$2(messages) {
|
|
959
983
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
960
984
|
const msg = messages[i];
|
|
961
985
|
if (msg.role === "user") {
|
|
@@ -1021,23 +1045,27 @@ embeddingRoutes.post("/", async (c) => {
|
|
|
1021
1045
|
* We intentionally omit copilot-vision-request — VS Code only sends it when
|
|
1022
1046
|
* images are present, and the native /v1/messages endpoint handles vision
|
|
1023
1047
|
* without requiring the header.
|
|
1048
|
+
*
|
|
1049
|
+
* extraHeaders allows callers to forward client-supplied beta headers
|
|
1050
|
+
* (anthropic-beta) so Copilot enables extended features.
|
|
1024
1051
|
*/
|
|
1025
|
-
function buildHeaders() {
|
|
1052
|
+
function buildHeaders(extraHeaders) {
|
|
1026
1053
|
return {
|
|
1027
1054
|
...copilotHeaders(state),
|
|
1028
1055
|
"X-Initiator": "agent",
|
|
1029
1056
|
"anthropic-version": "2023-06-01",
|
|
1030
|
-
"X-Interaction-Id": randomUUID()
|
|
1057
|
+
"X-Interaction-Id": randomUUID(),
|
|
1058
|
+
...extraHeaders
|
|
1031
1059
|
};
|
|
1032
1060
|
}
|
|
1033
1061
|
/**
|
|
1034
1062
|
* Forward an Anthropic Messages API request to Copilot's native /v1/messages endpoint.
|
|
1035
1063
|
* Returns the raw Response so callers can handle streaming vs non-streaming.
|
|
1036
1064
|
*/
|
|
1037
|
-
async function createMessages(body) {
|
|
1065
|
+
async function createMessages(body, extraHeaders) {
|
|
1038
1066
|
if (!state.copilotToken) throw new Error("Copilot token not found");
|
|
1039
|
-
const headers = buildHeaders();
|
|
1040
|
-
const url = `${copilotBaseUrl(state)}/v1/messages`;
|
|
1067
|
+
const headers = buildHeaders(extraHeaders);
|
|
1068
|
+
const url = `${copilotBaseUrl(state)}/v1/messages?beta=true`;
|
|
1041
1069
|
consola.debug(`Forwarding to ${url}`);
|
|
1042
1070
|
const response = await fetch(url, {
|
|
1043
1071
|
method: "POST",
|
|
@@ -1064,10 +1092,10 @@ async function createMessages(body) {
|
|
|
1064
1092
|
* Forward an Anthropic count_tokens request to Copilot's native endpoint.
|
|
1065
1093
|
* Returns the raw Response.
|
|
1066
1094
|
*/
|
|
1067
|
-
async function countTokens(body) {
|
|
1095
|
+
async function countTokens(body, extraHeaders) {
|
|
1068
1096
|
if (!state.copilotToken) throw new Error("Copilot token not found");
|
|
1069
|
-
const headers = buildHeaders();
|
|
1070
|
-
const url = `${copilotBaseUrl(state)}/v1/messages/count_tokens`;
|
|
1097
|
+
const headers = buildHeaders(extraHeaders);
|
|
1098
|
+
const url = `${copilotBaseUrl(state)}/v1/messages/count_tokens?beta=true`;
|
|
1071
1099
|
consola.debug(`Forwarding to ${url}`);
|
|
1072
1100
|
const response = await fetch(url, {
|
|
1073
1101
|
method: "POST",
|
|
@@ -1093,25 +1121,158 @@ async function countTokens(body) {
|
|
|
1093
1121
|
|
|
1094
1122
|
//#endregion
|
|
1095
1123
|
//#region src/routes/messages/count-tokens-handler.ts
|
|
1124
|
+
const isWebSearchTool$1 = (tool) => typeof tool.type === "string" && tool.type.startsWith("web_search") || tool.name === "web_search";
|
|
1125
|
+
/**
|
|
1126
|
+
* Strip web_search tools from the request body before forwarding
|
|
1127
|
+
* to Copilot's count_tokens endpoint, which rejects unknown tool types.
|
|
1128
|
+
* Returns the original raw body if no web_search tools are present.
|
|
1129
|
+
*/
|
|
1130
|
+
function stripWebSearchFromBody(rawBody) {
|
|
1131
|
+
if (!rawBody.includes("web_search")) return rawBody;
|
|
1132
|
+
let body;
|
|
1133
|
+
try {
|
|
1134
|
+
body = JSON.parse(rawBody);
|
|
1135
|
+
} catch {
|
|
1136
|
+
return rawBody;
|
|
1137
|
+
}
|
|
1138
|
+
if (!body.tools?.some((tool) => isWebSearchTool$1(tool))) return rawBody;
|
|
1139
|
+
body.tools = body.tools.filter((tool) => !isWebSearchTool$1(tool));
|
|
1140
|
+
if (body.tools.length === 0) {
|
|
1141
|
+
body.tools = void 0;
|
|
1142
|
+
body.tool_choice = void 0;
|
|
1143
|
+
} else if (body.tool_choice && typeof body.tool_choice === "object" && body.tool_choice.type === "tool") {
|
|
1144
|
+
const choiceName = body.tool_choice.name;
|
|
1145
|
+
if (choiceName && !body.tools.some((tool) => tool.name === choiceName)) body.tool_choice = { type: "auto" };
|
|
1146
|
+
}
|
|
1147
|
+
return JSON.stringify(body);
|
|
1148
|
+
}
|
|
1096
1149
|
/**
|
|
1097
1150
|
* Passthrough handler for Anthropic token counting.
|
|
1098
|
-
*
|
|
1151
|
+
* Strips web_search tools and forwards beta headers to Copilot's
|
|
1152
|
+
* native /v1/messages/count_tokens endpoint.
|
|
1099
1153
|
*/
|
|
1100
1154
|
async function handleCountTokens(c) {
|
|
1101
|
-
const
|
|
1155
|
+
const finalBody = stripWebSearchFromBody(await c.req.text());
|
|
1156
|
+
const extraHeaders = {};
|
|
1157
|
+
const anthropicBeta = c.req.header("anthropic-beta");
|
|
1158
|
+
if (anthropicBeta) {
|
|
1159
|
+
const filtered = filterBetaHeader(anthropicBeta);
|
|
1160
|
+
if (filtered) extraHeaders["anthropic-beta"] = filtered;
|
|
1161
|
+
}
|
|
1162
|
+
const body = await (await countTokens(finalBody, extraHeaders)).json();
|
|
1102
1163
|
consola.info("Token count:", JSON.stringify(body));
|
|
1103
1164
|
return c.json(body);
|
|
1104
1165
|
}
|
|
1105
1166
|
|
|
1106
1167
|
//#endregion
|
|
1107
1168
|
//#region src/routes/messages/handler.ts
|
|
1169
|
+
const isWebSearchTool = (tool) => typeof tool.type === "string" && tool.type.startsWith("web_search") || tool.name === "web_search";
|
|
1170
|
+
/**
|
|
1171
|
+
* Extract whitelisted beta headers from the incoming request to forward
|
|
1172
|
+
* to the Copilot API. VS Code sends these to enable extended features
|
|
1173
|
+
* like thinking, context management, and advanced tool use.
|
|
1174
|
+
*/
|
|
1175
|
+
function extractBetaHeaders(c) {
|
|
1176
|
+
const headers = {};
|
|
1177
|
+
const anthropicBeta = c.req.header("anthropic-beta");
|
|
1178
|
+
if (anthropicBeta) {
|
|
1179
|
+
const filtered = filterBetaHeader(anthropicBeta);
|
|
1180
|
+
if (filtered) headers["anthropic-beta"] = filtered;
|
|
1181
|
+
}
|
|
1182
|
+
return headers;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Extract the text content from the last user message for web search.
|
|
1186
|
+
* Handles both string content and content block arrays (multimodal).
|
|
1187
|
+
*/
|
|
1188
|
+
function extractUserQuery$1(messages) {
|
|
1189
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1190
|
+
const msg = messages[i];
|
|
1191
|
+
if (msg.role === "user") {
|
|
1192
|
+
if (typeof msg.content === "string") return msg.content;
|
|
1193
|
+
if (Array.isArray(msg.content)) {
|
|
1194
|
+
const textBlock = msg.content.find((block) => block.type === "text");
|
|
1195
|
+
if (textBlock?.text) return textBlock.text;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Check if any user message contains tool_result content blocks,
|
|
1202
|
+
* indicating a follow-up turn where we should skip web search.
|
|
1203
|
+
* In Anthropic format, tool results are content blocks inside user messages,
|
|
1204
|
+
* NOT separate role: "tool" messages like in OpenAI format.
|
|
1205
|
+
*/
|
|
1206
|
+
function hasToolResultContent(messages) {
|
|
1207
|
+
return messages.some((msg) => Array.isArray(msg.content) && msg.content.some((block) => block.type === "tool_result"));
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* Inject web search results into the Anthropic system field.
|
|
1211
|
+
* Handles three cases: absent, string, or array of content blocks.
|
|
1212
|
+
* When array, prepends without cache_control to preserve existing directives.
|
|
1213
|
+
*/
|
|
1214
|
+
function injectSearchResults(body, searchContext) {
|
|
1215
|
+
if (body.system === void 0 || body.system === null) body.system = searchContext;
|
|
1216
|
+
else if (typeof body.system === "string") body.system = `${searchContext}\n\n${body.system}`;
|
|
1217
|
+
else if (Array.isArray(body.system)) body.system = [{
|
|
1218
|
+
type: "text",
|
|
1219
|
+
text: searchContext
|
|
1220
|
+
}, ...body.system];
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Strip web_search tools from the request and clean up tool_choice.
|
|
1224
|
+
* Returns the modified body object.
|
|
1225
|
+
*/
|
|
1226
|
+
function stripWebSearchTool(body) {
|
|
1227
|
+
if (!body.tools) return;
|
|
1228
|
+
body.tools = body.tools.filter((tool) => !isWebSearchTool(tool));
|
|
1229
|
+
if (body.tools.length === 0) {
|
|
1230
|
+
body.tools = void 0;
|
|
1231
|
+
body.tool_choice = void 0;
|
|
1232
|
+
} else if (body.tool_choice && typeof body.tool_choice === "object" && body.tool_choice.type === "tool") {
|
|
1233
|
+
const choiceName = body.tool_choice.name;
|
|
1234
|
+
if (choiceName && !body.tools.some((tool) => tool.name === choiceName)) body.tool_choice = { type: "auto" };
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Process web search if the request contains a web_search tool.
|
|
1239
|
+
* Performs the search, injects results into system, and strips the tool.
|
|
1240
|
+
* Returns the (possibly modified) body string to forward.
|
|
1241
|
+
*/
|
|
1242
|
+
async function processWebSearch(rawBody) {
|
|
1243
|
+
if (!rawBody.includes("web_search")) return rawBody;
|
|
1244
|
+
let body;
|
|
1245
|
+
try {
|
|
1246
|
+
body = JSON.parse(rawBody);
|
|
1247
|
+
} catch {
|
|
1248
|
+
return rawBody;
|
|
1249
|
+
}
|
|
1250
|
+
if (!body.tools?.some((tool) => isWebSearchTool(tool))) return rawBody;
|
|
1251
|
+
const query = hasToolResultContent(body.messages ?? []) ? void 0 : extractUserQuery$1(body.messages ?? []);
|
|
1252
|
+
if (query) try {
|
|
1253
|
+
const results = await searchWeb(query);
|
|
1254
|
+
const searchContext = [
|
|
1255
|
+
"[Web Search Results]",
|
|
1256
|
+
results.content,
|
|
1257
|
+
"",
|
|
1258
|
+
results.references.map((r) => `- [${r.title}](${r.url})`).join("\n"),
|
|
1259
|
+
"[End Web Search Results]"
|
|
1260
|
+
].join("\n");
|
|
1261
|
+
injectSearchResults(body, searchContext);
|
|
1262
|
+
} catch (error) {
|
|
1263
|
+
consola.warn("Web search failed, continuing without results:", error);
|
|
1264
|
+
}
|
|
1265
|
+
stripWebSearchTool(body);
|
|
1266
|
+
return JSON.stringify(body);
|
|
1267
|
+
}
|
|
1108
1268
|
async function handleCompletion(c) {
|
|
1109
1269
|
await checkRateLimit(state);
|
|
1110
1270
|
const rawBody = await c.req.text();
|
|
1111
1271
|
const debugEnabled = consola.level >= 4;
|
|
1112
1272
|
if (debugEnabled) consola.debug("Anthropic request body:", rawBody.slice(0, 2e3));
|
|
1113
1273
|
if (state.manualApprove) await awaitApproval();
|
|
1114
|
-
const
|
|
1274
|
+
const betaHeaders = extractBetaHeaders(c);
|
|
1275
|
+
const response = await createMessages(await processWebSearch(rawBody), betaHeaders);
|
|
1115
1276
|
if ((response.headers.get("content-type") ?? "").includes("text/event-stream")) {
|
|
1116
1277
|
if (debugEnabled) consola.debug("Streaming response from Copilot /v1/messages");
|
|
1117
1278
|
return new Response(response.body, {
|
|
@@ -1123,9 +1284,9 @@ async function handleCompletion(c) {
|
|
|
1123
1284
|
}
|
|
1124
1285
|
});
|
|
1125
1286
|
}
|
|
1126
|
-
const
|
|
1127
|
-
if (debugEnabled) consola.debug("Non-streaming response from Copilot /v1/messages:", JSON.stringify(
|
|
1128
|
-
return c.json(
|
|
1287
|
+
const responseBody = await response.json();
|
|
1288
|
+
if (debugEnabled) consola.debug("Non-streaming response from Copilot /v1/messages:", JSON.stringify(responseBody).slice(0, 2e3));
|
|
1289
|
+
return c.json(responseBody, response.status);
|
|
1129
1290
|
}
|
|
1130
1291
|
|
|
1131
1292
|
//#endregion
|
|
@@ -1405,18 +1566,33 @@ function filterModelsByEndpoint(models, endpoint) {
|
|
|
1405
1566
|
}
|
|
1406
1567
|
async function generateClaudeCodeCommand(serverUrl) {
|
|
1407
1568
|
invariant(state.models, "Models should be loaded by now");
|
|
1408
|
-
const
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
}
|
|
1413
|
-
const
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1569
|
+
const claudeModels = state.models.data.filter((model) => model.id.toLowerCase().startsWith("claude"));
|
|
1570
|
+
if (claudeModels.length === 0) {
|
|
1571
|
+
consola.error("No Claude models available from Copilot API");
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
const mainModel = claudeModels.find((m) => m.id.includes("opus")) ?? claudeModels.find((m) => m.id.includes("sonnet")) ?? claudeModels[0];
|
|
1575
|
+
const smallModel = claudeModels.find((m) => m.id.includes("haiku")) ?? claudeModels.find((m) => m.id.includes("sonnet")) ?? claudeModels[0];
|
|
1576
|
+
let selectedModel = mainModel.id;
|
|
1577
|
+
let selectedSmallModel = smallModel.id;
|
|
1578
|
+
if (claudeModels.length > 1) {
|
|
1579
|
+
consola.info(`Using ${mainModel.id} as main model and ${smallModel.id} as small model`);
|
|
1580
|
+
if (await consola.prompt("Override model selection?", {
|
|
1581
|
+
type: "confirm",
|
|
1582
|
+
initial: false
|
|
1583
|
+
})) {
|
|
1584
|
+
selectedModel = await consola.prompt("Select a main model for Claude Code", {
|
|
1585
|
+
type: "select",
|
|
1586
|
+
options: claudeModels.map((model) => model.id)
|
|
1587
|
+
});
|
|
1588
|
+
selectedSmallModel = await consola.prompt("Select a small/fast model for Claude Code", {
|
|
1589
|
+
type: "select",
|
|
1590
|
+
options: claudeModels.map((model) => model.id)
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1417
1594
|
printAndCopyCommand(generateEnvScript({
|
|
1418
1595
|
ANTHROPIC_BASE_URL: serverUrl,
|
|
1419
|
-
ANTHROPIC_API_KEY: "dummy",
|
|
1420
1596
|
ANTHROPIC_AUTH_TOKEN: "dummy",
|
|
1421
1597
|
ANTHROPIC_MODEL: selectedModel,
|
|
1422
1598
|
ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,
|
|
@@ -1424,7 +1600,7 @@ async function generateClaudeCodeCommand(serverUrl) {
|
|
|
1424
1600
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,
|
|
1425
1601
|
DISABLE_NON_ESSENTIAL_MODEL_CALLS: "1",
|
|
1426
1602
|
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1"
|
|
1427
|
-
}, "claude"), "Claude Code");
|
|
1603
|
+
}, "claude --dangerously-skip-permissions"), "Claude Code");
|
|
1428
1604
|
}
|
|
1429
1605
|
async function generateCodexCommand(serverUrl) {
|
|
1430
1606
|
invariant(state.models, "Models should be loaded by now");
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","names":["state: State","state","headers: Record<string, string>","errorJson: unknown","token","process","commandBlock: string","state","x","headers: Record<string, string>","searchTimestamps: Array<number>","references: Array<{ title: string; url: string }>","handleCompletion","injectWebSearchIfNeeded","isNonStreaming","extractUserQuery","handleCompletion","headers: Record<string, string>","rateLimit: number | undefined"],"sources":["../src/lib/paths.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts","../src/auth.ts","../src/services/github/get-copilot-usage.ts","../src/check-usage.ts","../src/debug.ts","../src/lib/proxy.ts","../src/lib/shell.ts","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/tokenizer.ts","../src/services/copilot/create-chat-completions.ts","../src/services/copilot/web-search.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/services/copilot/create-messages.ts","../src/routes/messages/count-tokens-handler.ts","../src/routes/messages/handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/services/copilot/create-responses.ts","../src/routes/responses/handler.ts","../src/routes/responses/route.ts","../src/routes/search/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst APP_DIR = path.join(os.homedir(), \".local\", \"share\", \"github-router\")\n\nconst GITHUB_TOKEN_PATH = path.join(APP_DIR, \"github_token\")\n\nexport const PATHS = {\n APP_DIR,\n GITHUB_TOKEN_PATH,\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}\n","import type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: string\n models?: ModelsResponse\n vsCodeVersion?: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n}\n\nexport const state: State = {\n accountType: \"individual\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.26.7\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\n\nconst API_VERSION = \"2025-05-01\"\n\nexport const copilotBaseUrl = (state: State) =>\n state.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${state.accountType}.githubcopilot.com`\nexport const copilotHeaders = (\n state: State,\n vision: boolean = false,\n integrationId: string = \"vscode-chat\",\n) => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": integrationId,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-panel\",\n \"x-interaction-type\": \"conversation-panel\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": randomUUID(),\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL = \"https://api.github.com\"\nexport const githubHeaders = (state: State) => ({\n ...standardHeaders(),\n authorization: `token ${state.githubToken}`,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"x-github-api-version\": API_VERSION,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport async function forwardError(c: Context, error: unknown) {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n const errorText = await error.response.text()\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = undefined\n }\n const message = resolveErrorMessage(errorJson, errorText)\n consola.error(\"HTTP error:\", errorJson ?? errorText)\n return c.json(\n {\n error: {\n message,\n type: \"error\",\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n error: {\n message: error instanceof Error ? error.message : String(error),\n type: \"error\",\n },\n },\n 500,\n )\n}\n\n// Extracts error message from { message } or { error: { message } } payloads.\nfunction resolveErrorMessage(errorJson: unknown, fallback: string): string {\n if (typeof errorJson !== \"object\" || errorJson === null) return fallback\n\n const errorRecord = errorJson as Record<string, unknown>\n if (errorRecord.message !== undefined) return String(errorRecord.message)\n\n if (typeof errorRecord.error === \"object\" && errorRecord.error !== null) {\n const nestedRecord = errorRecord.error as Record<string, unknown>\n if (nestedRecord.message !== undefined) return String(nestedRecord.message)\n }\n\n return fallback\n}\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotToken = async () => {\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(state),\n },\n )\n\n if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n return (await response.json()) as GetCopilotTokenResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n}\n","import {\n GITHUB_APP_SCOPES,\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n scope: GITHUB_APP_SCOPES,\n }),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\n ...standardHeaders(),\n },\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n headers: copilotHeaders(state),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n return (await response.json()) as ModelsResponse\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n}\n\ninterface ModelSupports {\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\nexport interface Model {\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n supported_endpoints?: Array<string>\n policy?: {\n state: string\n terms: string\n }\n}\n","const FALLBACK = \"1.104.3\"\n\nexport async function getVSCodeVersion() {\n const controller = new AbortController()\n const timeout = setTimeout(() => {\n controller.abort()\n }, 5000)\n\n try {\n const response = await fetch(\n \"https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin\",\n {\n signal: controller.signal,\n },\n )\n\n const pkgbuild = await response.text()\n const pkgverRegex = /pkgver=([0-9.]+)/\n const match = pkgbuild.match(pkgverRegex)\n\n if (match) {\n return match[1]\n }\n\n return FALLBACK\n } catch {\n return FALLBACK\n } finally {\n clearTimeout(timeout)\n }\n}\n\nawait getVSCodeVersion()\n","import consola from \"consola\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\nexport async function cacheModels(): Promise<void> {\n const models = await getModels()\n state.models = models\n}\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n","import consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n): Promise<string> {\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n const expiresAt = Date.now() + deviceCode.expires_in * 1000\n\n while (Date.now() < expiresAt) {\n const response = await fetch(\n `${GITHUB_BASE_URL}/login/oauth/access_token`,\n {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to poll access token:\", await response.text())\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n }\n\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n }\n\n throw new Error(\"Device code expired. Please run auth again.\")\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nexport const setupCopilotToken = async () => {\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n\n // Display the Copilot token to the screen\n consola.debug(\"GitHub Copilot Token fetched successfully!\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", token)\n }\n\n const refreshInterval = Math.max((refresh_in - 60) * 1000, 1000)\n setInterval(async () => {\n consola.debug(\"Refreshing Copilot token\")\n try {\n const { token } = await getCopilotToken()\n state.copilotToken = token\n consola.debug(\"Copilot token refreshed\")\n if (state.showToken) {\n consola.info(\"Refreshed Copilot token:\", token)\n }\n } catch (error) {\n consola.error(\"Failed to refresh Copilot token:\", error)\n }\n }, refreshInterval)\n}\n\ninterface SetupGitHubTokenOptions {\n force?: boolean\n}\n\nexport async function setupGitHubToken(\n options?: SetupGitHubTokenOptions,\n): Promise<void> {\n try {\n const githubToken = await readGithubToken()\n\n if (githubToken && !options?.force) {\n state.githubToken = githubToken\n if (state.showToken) {\n consola.info(\"GitHub token:\", githubToken)\n }\n await logUser()\n\n return\n }\n\n consola.info(\"Not logged in, getting new access token\")\n const response = await getDeviceCode()\n consola.debug(\"Device code response:\", response)\n\n consola.info(\n `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n )\n\n const token = await pollAccessToken(response)\n await writeGithubToken(token)\n state.githubToken = token\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n await logUser()\n } catch (error) {\n if (error instanceof HTTPError) {\n consola.error(\"Failed to get GitHub token:\", await error.response.json())\n throw error\n }\n\n consola.error(\"Failed to get GitHub token:\", error)\n throw error\n }\n}\n\nasync function logUser() {\n const user = await getGitHubUser()\n consola.info(`Logged in as ${user.login}`)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n verbose: boolean\n showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub auth flow without running the server\",\n },\n args: {\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub token on auth\",\n },\n },\n run({ args }) {\n return runAuth({\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n headers: githubHeaders(state),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot usage\", response)\n }\n\n return (await response.json()) as CopilotUsageResponse\n}\n\nexport interface QuotaDetail {\n entitlement: number\n overage_count: number\n overage_permitted: boolean\n percent_remaining: number\n quota_id: string\n quota_remaining: number\n remaining: number\n unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n chat: QuotaDetail\n completions: QuotaDetail\n premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n access_type_sku: string\n analytics_tracking_id: string\n assigned_date: string\n can_signup_for_limited: boolean\n chat_enabled: boolean\n copilot_plan: string\n organization_login_list: Array<unknown>\n organization_list: Array<unknown>\n quota_reset_date: string\n quota_snapshots: QuotaSnapshots\n}\n","import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n getCopilotUsage,\n type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n meta: {\n name: \"check-usage\",\n description: \"Show current GitHub Copilot usage/quota information\",\n },\n async run() {\n await ensurePaths()\n await setupGitHubToken()\n try {\n const usage = await getCopilotUsage()\n const premium = usage.quota_snapshots.premium_interactions\n const premiumTotal = premium.entitlement\n const premiumUsed = premiumTotal - premium.remaining\n const premiumPercentUsed =\n premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n const premiumPercentRemaining = premium.percent_remaining\n\n // Helper to summarize a quota snapshot\n function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n if (!snap) return `${name}: N/A`\n const total = snap.entitlement\n const used = total - snap.remaining\n const percentUsed = total > 0 ? (used / total) * 100 : 0\n const percentRemaining = snap.percent_remaining\n return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n }\n\n const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n const completionsLine = summarizeQuota(\n \"Completions\",\n usage.quota_snapshots.completions,\n )\n\n consola.box(\n `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n + `Quota resets: ${usage.quota_reset_date}\\n`\n + `\\nQuotas:\\n`\n + ` ${premiumLine}\\n`\n + ` ${chatLine}\\n`\n + ` ${completionsLine}`,\n )\n } catch (err) {\n consola.error(\"Failed to fetch Copilot usage:\", err)\n process.exit(1)\n }\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\n\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n version: string\n runtime: {\n name: string\n version: string\n platform: string\n arch: string\n }\n paths: {\n APP_DIR: string\n GITHUB_TOKEN_PATH: string\n }\n tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n try {\n const packageJsonPath = new URL(\"../package.json\", import.meta.url).pathname\n // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n // JSON.parse() can actually parse buffers\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath)) as {\n version: string\n }\n return packageJson.version\n } catch {\n return \"unknown\"\n }\n}\n\nfunction getRuntimeInfo() {\n const isBun = typeof Bun !== \"undefined\"\n\n return {\n name: isBun ? \"bun\" : \"node\",\n version: isBun ? Bun.version : process.version.slice(1),\n platform: os.platform(),\n arch: os.arch(),\n }\n}\n\nasync function checkTokenExists(): Promise<boolean> {\n try {\n const stats = await fs.stat(PATHS.GITHUB_TOKEN_PATH)\n if (!stats.isFile()) return false\n\n const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n return content.trim().length > 0\n } catch {\n return false\n }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n const [version, tokenExists] = await Promise.all([\n getPackageVersion(),\n checkTokenExists(),\n ])\n\n return {\n version,\n runtime: getRuntimeInfo(),\n paths: {\n APP_DIR: PATHS.APP_DIR,\n GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n },\n tokenExists,\n }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n consola.info(`github-router debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nToken exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n const debugInfo = await getDebugInfo()\n\n if (options.json) {\n printDebugInfoJson(debugInfo)\n } else {\n printDebugInfoPlain(debugInfo)\n }\n}\n\nexport const debug = defineCommand({\n meta: {\n name: \"debug\",\n description: \"Print debug information about the application\",\n },\n args: {\n json: {\n type: \"boolean\",\n default: false,\n description: \"Output debug information as JSON\",\n },\n },\n run({ args }) {\n return runDebug({\n json: args.json,\n })\n },\n})\n","import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nexport function initProxyFromEnv(): void {\n if (typeof Bun !== \"undefined\") return\n\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\n}\n","import process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n const { platform, env } = process\n\n if (platform === \"win32\") {\n // Git Bash / MSYS2 / Cygwin set SHELL even on Windows\n if (env.SHELL) {\n if (env.SHELL.endsWith(\"zsh\")) return \"zsh\"\n if (env.SHELL.endsWith(\"fish\")) return \"fish\"\n if (env.SHELL.endsWith(\"bash\")) return \"bash\"\n return \"sh\"\n }\n\n // Windows PowerShell 5.x sets this\n if (env.POWERSHELL_DISTRIBUTION_CHANNEL) return \"powershell\"\n\n // PowerShell (both 5.x and 7+/pwsh) adds user-scoped module paths\n // at runtime. The system-level PSModulePath in CMD lacks these paths.\n if (env.PSModulePath) {\n const lower = env.PSModulePath.toLowerCase()\n if (\n lower.includes(\"documents\\\\powershell\")\n || lower.includes(\"documents\\\\windowspowershell\")\n ) {\n return \"powershell\"\n }\n }\n\n return \"cmd\"\n }\n\n const shellPath = env.SHELL\n if (shellPath) {\n if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n if (shellPath.endsWith(\"fish\")) return \"fish\"\n if (shellPath.endsWith(\"bash\")) return \"bash\"\n }\n\n return \"sh\"\n}\n\nfunction quotePosixValue(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`\n}\n\nfunction quotePowerShellValue(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n envVars: EnvVars,\n commandToRun: string = \"\",\n): string {\n const shell = getShell()\n const filteredEnvVars = Object.entries(envVars).filter(\n ([, value]) => value !== undefined,\n ) as Array<[string, string]>\n\n let commandBlock: string\n\n switch (shell) {\n case \"powershell\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `$env:${key} = ${quotePowerShellValue(value)}`)\n .join(\"; \")\n break\n }\n case \"cmd\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set \"${key}=${value}\"`)\n .join(\" & \")\n break\n }\n case \"fish\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set -gx ${key} ${quotePosixValue(value)}`)\n .join(\"; \")\n break\n }\n default: {\n // bash, zsh, sh\n const assignments = filteredEnvVars\n .map(([key, value]) => `${key}=${quotePosixValue(value)}`)\n .join(\" \")\n commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n break\n }\n }\n\n if (commandBlock && commandToRun) {\n const separator =\n shell === \"cmd\" ? \" & \" : shell === \"powershell\" ? \"; \" : \" && \"\n return `${commandBlock}${separator}${commandToRun}`\n }\n\n return commandBlock || commandToRun\n}\n","import consola from \"consola\"\n\nimport { HTTPError } from \"./error\"\n\nexport const awaitApproval = async () => {\n const response = await consola.prompt(`Accept incoming request?`, {\n type: \"confirm\",\n })\n\n if (!response)\n throw new HTTPError(\n \"Request rejected by user\",\n Response.json({ message: \"Request rejected by user\" }, { status: 403 }),\n )\n}\n","import consola from \"consola\"\n\nimport type { State } from \"./state\"\n\nimport { HTTPError } from \"./error\"\nimport { sleep } from \"./utils\"\n\nexport async function checkRateLimit(state: State) {\n if (state.rateLimitSeconds === undefined) return\n\n const now = Date.now()\n\n if (!state.lastRequestTimestamp) {\n state.lastRequestTimestamp = now\n return\n }\n\n const elapsedSeconds = (now - state.lastRequestTimestamp) / 1000\n\n if (elapsedSeconds > state.rateLimitSeconds) {\n state.lastRequestTimestamp = now\n return\n }\n\n const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)\n\n if (!state.rateLimitWait) {\n consola.warn(\n `Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,\n )\n throw new HTTPError(\n \"Rate limit exceeded\",\n Response.json({ message: \"Rate limit exceeded\" }, { status: 429 }),\n )\n }\n\n const waitTimeMs = waitTimeSeconds * 1000\n consola.warn(\n `Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,\n )\n await sleep(waitTimeMs)\n state.lastRequestTimestamp = Date.now()\n consola.info(\"Rate limit wait completed, proceeding with request\")\n return\n}\n","import type {\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\n// Encoder type mapping\nconst ENCODING_MAP = {\n o200k_base: () => import(\"gpt-tokenizer/encoding/o200k_base\"),\n cl100k_base: () => import(\"gpt-tokenizer/encoding/cl100k_base\"),\n p50k_base: () => import(\"gpt-tokenizer/encoding/p50k_base\"),\n p50k_edit: () => import(\"gpt-tokenizer/encoding/p50k_edit\"),\n r50k_base: () => import(\"gpt-tokenizer/encoding/r50k_base\"),\n} as const\n\ntype SupportedEncoding = keyof typeof ENCODING_MAP\n\n// Define encoder interface\ninterface Encoder {\n encode: (text: string) => Array<number>\n}\n\n// Cache loaded encoders to avoid repeated imports\nconst encodingCache = new Map<string, Encoder>()\n\n/**\n * Calculate tokens for tool calls\n */\nconst calculateToolCallsTokens = (\n toolCalls: Array<ToolCall>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = 0\n for (const toolCall of toolCalls) {\n tokens += constants.funcInit\n tokens += encoder.encode(JSON.stringify(toolCall)).length\n }\n tokens += constants.funcEnd\n return tokens\n}\n\n/**\n * Calculate tokens for content parts\n */\nconst calculateContentPartsTokens = (\n contentParts: Array<ContentPart>,\n encoder: Encoder,\n): number => {\n let tokens = 0\n for (const part of contentParts) {\n if (part.type === \"image_url\") {\n tokens += encoder.encode(part.image_url.url).length + 85\n } else if (part.text) {\n tokens += encoder.encode(part.text).length\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens for a single message\n */\nconst calculateMessageTokens = (\n message: Message,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n const tokensPerMessage = 3\n const tokensPerName = 1\n let tokens = tokensPerMessage\n for (const [key, value] of Object.entries(message)) {\n if (typeof value === \"string\") {\n tokens += encoder.encode(value).length\n }\n if (key === \"name\") {\n tokens += tokensPerName\n }\n if (key === \"tool_calls\") {\n tokens += calculateToolCallsTokens(\n value as Array<ToolCall>,\n encoder,\n constants,\n )\n }\n if (key === \"content\" && Array.isArray(value)) {\n tokens += calculateContentPartsTokens(\n value as Array<ContentPart>,\n encoder,\n )\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens using custom algorithm\n */\nconst calculateTokens = (\n messages: Array<Message>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (messages.length === 0) {\n return 0\n }\n let numTokens = 0\n for (const message of messages) {\n numTokens += calculateMessageTokens(message, encoder, constants)\n }\n // every reply is primed with <|start|>assistant<|message|>\n numTokens += 3\n return numTokens\n}\n\n/**\n * Get the corresponding encoder module based on encoding type\n */\nconst getEncodeChatFunction = async (encoding: string): Promise<Encoder> => {\n if (encodingCache.has(encoding)) {\n const cached = encodingCache.get(encoding)\n if (cached) {\n return cached\n }\n }\n\n const supportedEncoding = encoding as SupportedEncoding\n if (!(supportedEncoding in ENCODING_MAP)) {\n const fallbackModule = (await ENCODING_MAP.o200k_base()) as Encoder\n encodingCache.set(encoding, fallbackModule)\n return fallbackModule\n }\n\n const encodingModule = (await ENCODING_MAP[supportedEncoding]()) as Encoder\n encodingCache.set(encoding, encodingModule)\n return encodingModule\n}\n\n/**\n * Get tokenizer type from model information\n */\nexport const getTokenizerFromModel = (model: Model): string => {\n return model.capabilities.tokenizer || \"o200k_base\"\n}\n\n/**\n * Get model-specific constants for token calculation\n */\nconst getModelConstants = (model: Model) => {\n return model.id === \"gpt-3.5-turbo\" || model.id === \"gpt-4\" ?\n {\n funcInit: 10,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n : {\n funcInit: 7,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n}\n\n/**\n * Calculate tokens for a single parameter\n */\nconst calculateParameterTokens = (\n key: string,\n prop: unknown,\n context: {\n encoder: Encoder\n constants: ReturnType<typeof getModelConstants>\n },\n): number => {\n const { encoder, constants } = context\n let tokens = constants.propKey\n\n // Early return if prop is not an object\n if (typeof prop !== \"object\" || prop === null) {\n return tokens\n }\n\n // Type assertion for parameter properties\n const param = prop as {\n type?: string\n description?: string\n enum?: Array<unknown>\n [key: string]: unknown\n }\n\n const paramName = key\n const paramType = param.type || \"string\"\n let paramDesc = param.description || \"\"\n\n // Handle enum values\n if (param.enum && Array.isArray(param.enum)) {\n tokens += constants.enumInit\n for (const item of param.enum) {\n tokens += constants.enumItem\n tokens += encoder.encode(String(item)).length\n }\n }\n\n // Clean up description\n if (paramDesc.endsWith(\".\")) {\n paramDesc = paramDesc.slice(0, -1)\n }\n\n // Encode the main parameter line\n const line = `${paramName}:${paramType}:${paramDesc}`\n tokens += encoder.encode(line).length\n\n // Handle additional properties (excluding standard ones)\n const excludedKeys = new Set([\"type\", \"description\", \"enum\"])\n for (const propertyName of Object.keys(param)) {\n if (!excludedKeys.has(propertyName)) {\n const propertyValue = param[propertyName]\n const propertyText =\n typeof propertyValue === \"string\" ? propertyValue : (\n JSON.stringify(propertyValue)\n )\n tokens += encoder.encode(`${propertyName}:${propertyText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for function parameters\n */\nconst calculateParametersTokens = (\n parameters: unknown,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (!parameters || typeof parameters !== \"object\") {\n return 0\n }\n\n const params = parameters as Record<string, unknown>\n let tokens = 0\n\n for (const [key, value] of Object.entries(params)) {\n if (key === \"properties\") {\n const properties = value as Record<string, unknown>\n if (Object.keys(properties).length > 0) {\n tokens += constants.propInit\n for (const propKey of Object.keys(properties)) {\n tokens += calculateParameterTokens(propKey, properties[propKey], {\n encoder,\n constants,\n })\n }\n }\n } else {\n const paramText =\n typeof value === \"string\" ? value : JSON.stringify(value)\n tokens += encoder.encode(`${key}:${paramText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for a single tool\n */\nconst calculateToolTokens = (\n tool: Tool,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = constants.funcInit\n const func = tool.function\n const fName = func.name\n let fDesc = func.description || \"\"\n if (fDesc.endsWith(\".\")) {\n fDesc = fDesc.slice(0, -1)\n }\n const line = fName + \":\" + fDesc\n tokens += encoder.encode(line).length\n if (\n typeof func.parameters === \"object\" \n && func.parameters !== null\n ) {\n tokens += calculateParametersTokens(func.parameters, encoder, constants)\n }\n return tokens\n}\n\n/**\n * Calculate token count for tools based on model\n */\nexport const numTokensForTools = (\n tools: Array<Tool>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let funcTokenCount = 0\n for (const tool of tools) {\n funcTokenCount += calculateToolTokens(tool, encoder, constants)\n }\n funcTokenCount += constants.funcEnd\n return funcTokenCount\n}\n\n/**\n * Calculate the token count of messages, supporting multiple GPT encoders\n */\nexport const getTokenCount = async (\n payload: ChatCompletionsPayload,\n model: Model,\n): Promise<{ input: number; output: number }> => {\n // Get tokenizer string\n const tokenizer = getTokenizerFromModel(model)\n\n // Get corresponding encoder module\n const encoder = await getEncodeChatFunction(tokenizer)\n\n const simplifiedMessages = payload.messages\n const inputMessages = simplifiedMessages.filter(\n (msg) => msg.role !== \"assistant\",\n )\n const outputMessages = simplifiedMessages.filter(\n (msg) => msg.role === \"assistant\",\n )\n\n const constants = getModelConstants(model)\n let inputTokens = calculateTokens(inputMessages, encoder, constants)\n if (payload.tools && payload.tools.length > 0) {\n inputTokens += numTokensForTools(payload.tools, encoder, constants)\n }\n const outputTokens = calculateTokens(outputMessages, encoder, constants)\n\n return {\n input: inputTokens,\n output: outputTokens,\n }\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createChatCompletions = async (\n payload: ChatCompletionsPayload,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = payload.messages.some(\n (x) =>\n typeof x.content !== \"string\"\n && x.content?.some((x) => x.type === \"image_url\"),\n )\n\n // Agent/user check for X-Initiator header\n // Determine if any message is from an agent (\"assistant\" or \"tool\")\n const isAgentCall = payload.messages.some((msg) =>\n [\"assistant\", \"tool\"].includes(msg.role),\n )\n\n // Build headers and add X-Initiator\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n const claudeModels = state.models?.data\n .filter((m) => m.id.startsWith(\"claude\"))\n .map((m) => m.id)\n .join(\", \") ?? \"(models not loaded)\"\n consola.error(\n `Copilot rejected model \"${payload.model}\": ${response.status} ${errorBody} (available Claude models: ${claudeModels})`,\n )\n // Re-create the response so downstream error handlers can still read the body\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Failed to create chat completions\", reconstructed)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n}\n\n// Streaming types\n\nexport interface ChatCompletionChunk {\n id: string\n object: \"chat.completion.chunk\"\n created: number\n model: string\n choices: Array<Choice>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n completion_tokens_details?: {\n accepted_prediction_tokens: number\n rejected_prediction_tokens: number\n }\n }\n}\n\ninterface Delta {\n content?: string | null\n role?: \"user\" | \"assistant\" | \"system\" | \"tool\"\n tool_calls?: Array<{\n index: number\n id?: string\n type?: \"function\"\n function?: {\n name?: string\n arguments?: string\n }\n }>\n}\n\ninterface Choice {\n index: number\n delta: Delta\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null\n logprobs: object | null\n}\n\n// Non-streaming types\n\nexport interface ChatCompletionResponse {\n id: string\n object: \"chat.completion\"\n created: number\n model: string\n choices: Array<ChoiceNonStreaming>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n }\n}\n\ninterface ResponseMessage {\n role: \"assistant\"\n content: string | null\n tool_calls?: Array<ToolCall>\n}\n\ninterface ChoiceNonStreaming {\n index: number\n message: ResponseMessage\n logprobs: object | null\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\"\n}\n\n// Payload types\n\nexport interface ChatCompletionsPayload {\n messages: Array<Message>\n model: string\n temperature?: number | null\n top_p?: number | null\n max_tokens?: number | null\n stop?: string | Array<string> | null\n n?: number | null\n stream?: boolean | null\n\n frequency_penalty?: number | null\n presence_penalty?: number | null\n logit_bias?: Record<string, number> | null\n logprobs?: boolean | null\n response_format?: { type: \"json_object\" } | null\n seed?: number | null\n tools?: Array<Tool> | null\n tool_choice?:\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; function: { name: string } }\n | null\n user?: string | null\n}\n\nexport interface Tool {\n type: \"function\"\n function: {\n name: string\n description?: string\n parameters: Record<string, unknown>\n }\n}\n\nexport interface Message {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\" | \"developer\"\n content: string | Array<ContentPart> | null\n\n name?: string\n tool_calls?: Array<ToolCall>\n tool_call_id?: string\n}\n\nexport interface ToolCall {\n id: string\n type: \"function\"\n function: {\n name: string\n arguments: string\n }\n}\n\nexport type ContentPart = TextPart | ImagePart\n\nexport interface TextPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImagePart {\n type: \"image_url\"\n image_url: {\n url: string\n detail?: \"low\" | \"high\" | \"auto\"\n }\n}\n","import consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { state } from \"~/lib/state\"\nimport { sleep } from \"~/lib/utils\"\n\nexport interface WebSearchResult {\n content: string\n references: Array<{ title: string; url: string }>\n}\n\ninterface ThreadsResponse {\n thread_id: string\n}\n\ninterface ThreadsMessageResponse {\n message: {\n content: string\n references: Array<{\n query?: string\n results?: Array<{\n title: string\n url: string\n reference_type: string\n }>\n }>\n }\n}\n\nconst MAX_SEARCHES_PER_SECOND = 3\nlet searchTimestamps: Array<number> = []\n\nasync function throttleSearch(): Promise<void> {\n const now = Date.now()\n searchTimestamps = searchTimestamps.filter((t) => now - t < 1000)\n if (searchTimestamps.length >= MAX_SEARCHES_PER_SECOND) {\n const waitMs = 1000 - (now - searchTimestamps[0])\n if (waitMs > 0) {\n consola.debug(`Web search rate limited, waiting ${waitMs}ms`)\n await sleep(waitMs)\n }\n }\n searchTimestamps.push(Date.now())\n}\n\nfunction threadsHeaders(): Record<string, string> {\n return copilotHeaders(state, false, \"copilot-chat\")\n}\n\nasync function createThread(): Promise<string> {\n const response = await fetch(`${copilotBaseUrl(state)}/github/chat/threads`, {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({}),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create chat thread\", response.status)\n throw new Error(`Failed to create chat thread: ${response.status}`)\n }\n\n const data = (await response.json()) as ThreadsResponse\n return data.thread_id\n}\n\nasync function sendThreadMessage(\n threadId: string,\n query: string,\n): Promise<ThreadsMessageResponse> {\n const response = await fetch(\n `${copilotBaseUrl(state)}/github/chat/threads/${threadId}/messages`,\n {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({\n content: query,\n intent: \"conversation\",\n skills: [\"web-search\"],\n references: [],\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to send thread message\", response.status)\n throw new Error(`Failed to send thread message: ${response.status}`)\n }\n\n return (await response.json()) as ThreadsMessageResponse\n}\n\nexport async function searchWeb(query: string): Promise<WebSearchResult> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n await throttleSearch()\n\n consola.info(`Web search: \"${query.slice(0, 80)}\"`)\n\n const threadId = await createThread()\n const response = await sendThreadMessage(threadId, query)\n\n const references: Array<{ title: string; url: string }> = []\n for (const ref of response.message.references ?? []) {\n if (ref.results) {\n for (const result of ref.results) {\n if (result.url && result.reference_type !== \"bing_search\") {\n references.push({ title: result.title, url: result.url })\n }\n }\n }\n }\n\n consola.debug(`Web search returned ${references.length} references`)\n\n return {\n content: response.message.content,\n references,\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE, type SSEMessage } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish } from \"~/lib/utils\"\nimport {\n createChatCompletions,\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n type Message,\n} from \"~/services/copilot/create-chat-completions\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n let payload = await c.req.json<ChatCompletionsPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n }\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n // Find the selected model\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n // Calculate and display token count\n try {\n if (selectedModel) {\n const tokenCount = await getTokenCount(payload, selectedModel)\n consola.info(\"Current token count:\", tokenCount)\n } else {\n consola.warn(\"No model selected, skipping token count calculation\")\n }\n } catch (error) {\n consola.warn(\"Failed to calculate token count:\", error)\n }\n\n if (isNullish(payload.max_tokens)) {\n payload = {\n ...payload,\n max_tokens: selectedModel?.capabilities.limits.max_output_tokens,\n }\n if (debugEnabled) {\n consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n }\n }\n\n const response = await createChatCompletions(payload)\n\n if (isNonStreaming(response)) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n consola.debug(\"Streaming response\")\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n await stream.writeSSE(chunk as SSEMessage)\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n\nasync function injectWebSearchIfNeeded(\n payload: ChatCompletionsPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some(\n (t) =>\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\",\n )\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = payload.messages.some((msg) => msg.role === \"tool\")\n const query = hasToolResult ? undefined : extractUserQuery(payload.messages)\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n // Prepend to existing system message or inject a new one\n const systemMsg = payload.messages.find((msg) => msg.role === \"system\")\n if (systemMsg) {\n const existingContent =\n typeof systemMsg.content === \"string\" ? systemMsg.content\n : Array.isArray(systemMsg.content) ?\n systemMsg.content\n .filter((p) => p.type === \"text\")\n .map((p) => (\"text\" in p ? p.text : \"\"))\n .join(\"\\n\")\n : \"\"\n systemMsg.content = `${searchContext}\\n\\n${existingContent}`\n } else {\n payload.messages.unshift({\n role: \"system\",\n content: searchContext,\n })\n }\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Remove web_search from tools before forwarding\n payload.tools = payload.tools?.filter(\n (t) =>\n !(\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\"\n ),\n ) as typeof payload.tools\n if (payload.tools?.length === 0) {\n payload.tools = undefined\n }\n if (!payload.tools) {\n payload.tool_choice = undefined\n } else if (\n payload.tool_choice\n && typeof payload.tool_choice === \"object\"\n && \"type\" in payload.tool_choice\n && payload.tool_choice.type === \"function\"\n ) {\n const toolChoiceName = payload.tool_choice.function?.name\n if (\n toolChoiceName\n && !payload.tools.some((tool) => tool.function.name === toolChoiceName)\n ) {\n payload.tool_choice = undefined\n }\n }\n}\n\nfunction extractUserQuery(messages: Array<Message>): string | undefined {\n // Find the last user message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const text = msg.content.find((p) => p.type === \"text\")\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const completionRoutes = new Hono()\n\ncompletionRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createEmbeddings = async (payload: EmbeddingRequest) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const response = await fetch(`${copilotBaseUrl(state)}/embeddings`, {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to create embeddings\", response)\n\n return (await response.json()) as EmbeddingResponse\n}\n\nexport interface EmbeddingRequest {\n input: string | Array<string>\n model: string\n}\n\nexport interface Embedding {\n object: string\n embedding: Array<number>\n index: number\n}\n\nexport interface EmbeddingResponse {\n object: string\n data: Array<Embedding>\n model: string\n usage: {\n prompt_tokens: number\n total_tokens: number\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport {\n createEmbeddings,\n type EmbeddingRequest,\n} from \"~/services/copilot/create-embeddings\"\n\nexport const embeddingRoutes = new Hono()\n\nembeddingRoutes.post(\"/\", async (c) => {\n try {\n const payload = await c.req.json<EmbeddingRequest>()\n const response = await createEmbeddings(payload)\n\n return c.json(response)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { randomUUID } from \"node:crypto\"\n\nimport consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Build headers that match what VS Code Copilot Chat sends to the Copilot API.\n *\n * copilotHeaders() provides: Authorization, content-type, copilot-integration-id,\n * editor-version, editor-plugin-version, user-agent, openai-intent,\n * x-github-api-version, x-request-id, x-vscode-user-agent-library-version.\n *\n * We add the remaining headers VS Code sends for /v1/messages:\n * - X-Initiator (VS Code sets dynamically; \"agent\" is safe for CLI use)\n * - anthropic-version (VS Code's Anthropic SDK sends this)\n * - X-Interaction-Id (VS Code sends a session-scoped UUID)\n *\n * We intentionally omit copilot-vision-request — VS Code only sends it when\n * images are present, and the native /v1/messages endpoint handles vision\n * without requiring the header.\n */\nfunction buildHeaders(): Record<string, string> {\n return {\n ...copilotHeaders(state),\n \"X-Initiator\": \"agent\",\n \"anthropic-version\": \"2023-06-01\",\n \"X-Interaction-Id\": randomUUID(),\n }\n}\n\n/**\n * Forward an Anthropic Messages API request to Copilot's native /v1/messages endpoint.\n * Returns the raw Response so callers can handle streaming vs non-streaming.\n */\nexport async function createMessages(\n body: string,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders()\n const url = `${copilotBaseUrl(state)}/v1/messages`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot /v1/messages error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot messages request failed\", reconstructed)\n }\n\n return response\n}\n\n/**\n * Forward an Anthropic count_tokens request to Copilot's native endpoint.\n * Returns the raw Response.\n */\nexport async function countTokens(\n body: string,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders()\n const url = `${copilotBaseUrl(state)}/v1/messages/count_tokens`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot count_tokens error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot count_tokens request failed\", reconstructed)\n }\n\n return response\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { countTokens } from \"~/services/copilot/create-messages\"\n\n/**\n * Passthrough handler for Anthropic token counting.\n * Forwards the request directly to Copilot's native /v1/messages/count_tokens endpoint.\n */\nexport async function handleCountTokens(c: Context) {\n const rawBody = await c.req.text()\n const response = await countTokens(rawBody)\n const body = await response.json()\n\n consola.info(\"Token count:\", JSON.stringify(body))\n\n return c.json(body)\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { createMessages } from \"~/services/copilot/create-messages\"\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n const rawBody = await c.req.text()\n\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Anthropic request body:\", rawBody.slice(0, 2000))\n }\n\n if (state.manualApprove) {\n await awaitApproval()\n }\n\n const response = await createMessages(rawBody)\n\n const contentType = response.headers.get(\"content-type\") ?? \"\"\n\n // Streaming: pipe the upstream SSE response body directly\n if (contentType.includes(\"text/event-stream\")) {\n if (debugEnabled) {\n consola.debug(\"Streaming response from Copilot /v1/messages\")\n }\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n },\n })\n }\n\n // Non-streaming: forward JSON response\n const body = await response.json()\n if (debugEnabled) {\n consola.debug(\n \"Non-streaming response from Copilot /v1/messages:\",\n JSON.stringify(body).slice(0, 2000),\n )\n }\n return c.json(body, response.status as 200)\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCountTokens } from \"./count-tokens-handler\"\nimport { handleCompletion } from \"./handler\"\n\nexport const messageRoutes = new Hono()\n\nmessageRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nmessageRoutes.post(\"/count_tokens\", async (c) => {\n try {\n return await handleCountTokens(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { cacheModels } from \"~/lib/utils\"\n\nexport const modelRoutes = new Hono()\n\nmodelRoutes.get(\"/\", async (c) => {\n try {\n if (!state.models) {\n // This should be handled by startup logic, but as a fallback.\n await cacheModels()\n }\n\n const models = state.models?.data.map((model) => ({\n id: model.id,\n object: \"model\",\n type: \"model\",\n created: 0, // No date available from source\n created_at: new Date(0).toISOString(), // No date available from source\n owned_by: model.vendor,\n display_name: model.name,\n }))\n\n return c.json({\n object: \"list\",\n data: models,\n has_more: false,\n })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createResponses = async (payload: ResponsesPayload) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = detectVision(payload.input)\n\n const isAgentCall = detectAgentCall(payload.input)\n\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const filteredPayload = filterUnsupportedTools(payload)\n\n const response = await fetch(`${copilotBaseUrl(state)}/responses`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(filteredPayload),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create responses\", response)\n throw new HTTPError(\"Failed to create responses\", response)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ResponsesApiResponse\n}\n\nfunction detectVision(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"content\" in item && Array.isArray(item.content)) {\n return item.content.some(\n (part: Record<string, unknown>) => part.type === \"input_image\",\n )\n }\n return false\n })\n}\n\nfunction detectAgentCall(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"role\" in item && item.role === \"assistant\") return true\n if (\n \"type\" in item\n && (item.type === \"function_call\" || item.type === \"function_call_output\")\n ) {\n return true\n }\n return false\n })\n}\n\nfunction filterUnsupportedTools(payload: ResponsesPayload): ResponsesPayload {\n if (!payload.tools || !Array.isArray(payload.tools)) return payload\n\n const supported = payload.tools.filter((tool) => {\n const isSupported = tool.type === \"function\"\n if (!isSupported) {\n consola.debug(`Stripping unsupported tool type: ${tool.type}`)\n }\n return isSupported\n })\n\n let toolChoice = payload.tool_choice\n if (supported.length === 0) {\n toolChoice = undefined\n } else if (\n toolChoice\n && typeof toolChoice === \"object\"\n ) {\n const supportedNames = new Set(\n supported.map((tool) => tool.name).filter(Boolean),\n )\n const toolChoiceName = getToolChoiceName(toolChoice)\n if (toolChoiceName && !supportedNames.has(toolChoiceName)) {\n toolChoice = undefined\n }\n }\n\n return {\n ...payload,\n tools: supported.length > 0 ? supported : undefined,\n tool_choice: toolChoice,\n }\n}\n\nfunction getToolChoiceName(\n toolChoice: NonNullable<ResponsesPayload[\"tool_choice\"]>,\n): string | undefined {\n if (typeof toolChoice !== \"object\") return undefined\n if (\n \"function\" in toolChoice\n && toolChoice.function\n && typeof toolChoice.function === \"object\"\n ) {\n return (toolChoice.function as { name?: string }).name\n }\n if (\"name\" in toolChoice) {\n return toolChoice.name\n }\n return undefined\n}\n\n// Types\n\nexport interface ResponsesInputItem {\n role?: \"user\" | \"assistant\" | \"system\"\n type?: \"message\" | \"function_call\" | \"function_call_output\"\n content?: string | Array<Record<string, unknown>>\n name?: string\n call_id?: string\n arguments?: string\n output?: string\n [key: string]: unknown\n}\n\nexport interface ResponsesTool {\n type: string\n name?: string\n description?: string\n parameters?: Record<string, unknown>\n [key: string]: unknown\n}\n\nexport interface ResponsesPayload {\n model: string\n input: string | Array<ResponsesInputItem>\n instructions?: string\n tools?: Array<ResponsesTool>\n tool_choice?:\n | string\n | { type: string; name?: string; function?: { name?: string } }\n max_output_tokens?: number\n temperature?: number\n top_p?: number\n stream?: boolean\n store?: boolean\n metadata?: Record<string, string>\n previous_response_id?: string\n reasoning?: { effort?: string; summary?: string }\n [key: string]: unknown\n}\n\nexport interface ResponsesApiResponse {\n id: string\n object: \"response\"\n status: string\n output: Array<unknown>\n [key: string]: unknown\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { isNullish } from \"~/lib/utils\"\nimport {\n createResponses,\n type ResponsesApiResponse,\n type ResponsesInputItem,\n type ResponsesPayload,\n} from \"~/services/copilot/create-responses\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleResponses(c: Context) {\n await checkRateLimit(state)\n\n const payload = await c.req.json<ResponsesPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\n \"Responses request payload:\",\n JSON.stringify(payload).slice(-400),\n )\n }\n\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n consola.info(\"Token counting not yet supported for /responses endpoint\")\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n if (isNullish(payload.max_output_tokens)) {\n payload.max_output_tokens =\n selectedModel?.capabilities.limits.max_output_tokens\n if (debugEnabled) {\n consola.debug(\n \"Set max_output_tokens to:\",\n JSON.stringify(payload.max_output_tokens),\n )\n }\n }\n\n const response = await createResponses(payload)\n\n if (isNonStreaming(response)) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n consola.debug(\"Streaming response\")\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n\n if (chunk.data === \"[DONE]\") {\n break\n }\n\n if (!chunk.data) {\n continue\n }\n\n await stream.writeSSE({\n data: chunk.data,\n event: chunk.event,\n id: chunk.id?.toString(),\n })\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createResponses>>,\n): response is ResponsesApiResponse => Object.hasOwn(response, \"output\")\n\nasync function injectWebSearchIfNeeded(\n payload: ResponsesPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some((t) => t.type === \"web_search\")\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (function call results)\n if (Array.isArray(payload.input)) {\n const hasFollowUp = payload.input.some(\n (item: ResponsesInputItem) => item.type === \"function_call_output\",\n )\n if (hasFollowUp) return\n }\n\n const query = extractUserQuery(payload.input)\n if (!query) return\n\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n payload.instructions =\n payload.instructions ?\n `${searchContext}\\n\\n${payload.instructions}`\n : searchContext\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n}\n\nfunction extractUserQuery(\n input: ResponsesPayload[\"input\"],\n): string | undefined {\n if (typeof input === \"string\") return input\n if (!Array.isArray(input)) return undefined\n\n // Find the last user message\n for (let i = input.length - 1; i >= 0; i--) {\n const item = input[i]\n if (\"role\" in item && item.role === \"user\") {\n if (typeof item.content === \"string\") return item.content\n if (Array.isArray(item.content)) {\n const text = item.content.find(\n (p: Record<string, unknown>) => p.type === \"input_text\",\n )\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleResponses } from \"./handler\"\n\nexport const responsesRoutes = new Hono()\n\nresponsesRoutes.post(\"/\", async (c) => {\n try {\n return await handleResponses(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport const searchRoutes = new Hono()\n\nsearchRoutes.post(\"/\", async (c) => {\n try {\n const { query } = await c.req.json<{ query: string }>()\n\n if (!query || typeof query !== \"string\") {\n return c.json(\n { error: { message: \"Missing required field: query\" } },\n 400,\n )\n }\n\n const results = await searchWeb(query)\n return c.json({ results })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n if (!state.showToken) {\n return c.json(\n { error: { message: \"Token endpoint disabled\", type: \"error\" } },\n 403,\n )\n }\n\n return c.json({\n token: state.copilotToken,\n })\n})\n","import { Hono } from \"hono\"\nimport consola from \"consola\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\n\nexport const usageRoute = new Hono()\n\nusageRoute.get(\"/\", async (c) => {\n try {\n const usage = await getCopilotUsage()\n return c.json(usage)\n } catch (error) {\n consola.error(\"Error fetching Copilot usage:\", error)\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\nimport { logger } from \"hono/logger\"\n\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { responsesRoutes } from \"./routes/responses/route\"\nimport { searchRoutes } from \"./routes/search/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\n\nexport const server = new Hono()\n\nserver.use(logger())\nserver.use(cors())\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/responses\", responsesRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/search\", searchRoutes)\nserver.route(\"/usage\", usageRoute)\nserver.route(\"/token\", tokenRoute)\n\n// Compatibility with tools that expect v1/ prefix\nserver.route(\"/v1/chat/completions\", completionRoutes)\nserver.route(\"/v1/responses\", responsesRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\nserver.route(\"/v1/search\", searchRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { initProxyFromEnv } from \"./lib/proxy\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport { setupCopilotToken, setupGitHubToken } from \"./lib/token\"\nimport { cacheModels, cacheVSCodeVersion } from \"./lib/utils\"\nimport type { Model } from \"./services/copilot/get-models\"\nimport { server } from \"./server\"\n\ninterface RunServerOptions {\n port: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n claudeCode: boolean\n codex: boolean\n showToken: boolean\n proxyEnv: boolean\n}\n\nconst allowedAccountTypes = new Set([\"individual\", \"business\", \"enterprise\"])\n\nfunction printAndCopyCommand(command: string, label: string): void {\n consola.box(`${label}\\n\\n${command}`)\n try {\n clipboard.writeSync(command)\n consola.success(`Copied ${label} command to clipboard!`)\n } catch {\n consola.warn(\"Failed to copy to clipboard. Copy the command above manually.\")\n }\n}\n\nfunction filterModelsByEndpoint(\n models: Array<Model>,\n endpoint: string,\n): Array<Model> {\n const filtered = models.filter((model) => {\n const endpoints = model.supported_endpoints\n // Some deployments omit supported_endpoints; keep those models visible.\n if (!endpoints || endpoints.length === 0) return true\n return endpoints.some((entry) => {\n const normalized = entry.replace(/^\\/?v1\\//, \"\").replace(/^\\//, \"\")\n return normalized === endpoint\n })\n })\n\n return filtered.length > 0 ? filtered : models\n}\n\nasync function generateClaudeCodeCommand(serverUrl: string) {\n invariant(state.models, \"Models should be loaded by now\")\n\n const supportedModels = filterModelsByEndpoint(\n state.models.data,\n \"v1/messages\",\n )\n\n const selectedModel = await consola.prompt(\n \"Select a model to use with Claude Code\",\n {\n type: \"select\",\n options: supportedModels.map((model) => model.id),\n },\n )\n\n const selectedSmallModel = await consola.prompt(\n \"Select a small model to use with Claude Code\",\n {\n type: \"select\",\n options: supportedModels.map((model) => model.id),\n },\n )\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_API_KEY: \"dummy\",\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: selectedModel,\n ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,\n ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n },\n \"claude\",\n )\n\n printAndCopyCommand(command, \"Claude Code\")\n}\n\nasync function generateCodexCommand(serverUrl: string) {\n invariant(state.models, \"Models should be loaded by now\")\n\n const supportedModels = filterModelsByEndpoint(\n state.models.data,\n \"responses\",\n )\n\n const defaultCodexModel = supportedModels.find(\n (model) => model.id === \"gpt5.2-codex\",\n )\n\n const selectedModel =\n defaultCodexModel ?\n defaultCodexModel.id\n : await consola.prompt(\"Select a model to use with Codex CLI\", {\n type: \"select\",\n options: supportedModels.map((model) => model.id),\n })\n\n const quotedModel = JSON.stringify(selectedModel)\n const command = generateEnvScript(\n {\n OPENAI_BASE_URL: `${serverUrl}/v1`,\n OPENAI_API_KEY: \"dummy\",\n },\n `codex -m ${quotedModel}`,\n )\n\n printAndCopyCommand(command, \"Codex CLI\")\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n if (options.proxyEnv) {\n initProxyFromEnv()\n }\n\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.accountType = options.accountType\n if (options.accountType !== \"individual\") {\n consola.info(`Using ${options.accountType} plan GitHub account`)\n }\n\n state.manualApprove = options.manual\n state.rateLimitSeconds = options.rateLimit\n state.rateLimitWait = options.rateLimitWait\n state.showToken = options.showToken\n\n await ensurePaths()\n await cacheVSCodeVersion()\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.info(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\n\n const serverUrl = `http://localhost:${options.port}`\n\n if (options.claudeCode) await generateClaudeCodeCommand(serverUrl)\n if (options.codex) await generateCodexCommand(serverUrl)\n\n consola.box(\n `🌐 Usage Viewer: https://animeshkundu.github.io/github-router/dashboard.html?endpoint=${serverUrl}/usage`,\n )\n\n serve({\n fetch: server.fetch as ServerHandler,\n hostname: \"127.0.0.1\",\n port: options.port,\n })\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the github-router server\",\n },\n args: {\n port: {\n alias: \"p\",\n type: \"string\",\n default: \"8787\",\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\",\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\",\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\",\n default: false,\n description:\n \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\n },\n \"github-token\": {\n alias: \"g\",\n type: \"string\",\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"claude-code\": {\n alias: \"c\",\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Claude Code with Copilot API config\",\n },\n codex: {\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Codex CLI with Copilot API config\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\",\n default: false,\n description: \"Initialize proxy from environment variables\",\n },\n },\n run({ args }) {\n const rateLimitRaw = args[\"rate-limit\"]\n let rateLimit: number | undefined\n if (rateLimitRaw !== undefined) {\n rateLimit = Number.parseInt(rateLimitRaw, 10)\n if (Number.isNaN(rateLimit) || rateLimit <= 0) {\n throw new Error(\"Invalid rate limit. Must be a positive integer.\")\n }\n }\n\n const port = Number.parseInt(args.port, 10)\n if (Number.isNaN(port) || port <= 0 || port > 65535) {\n throw new Error(\"Invalid port. Must be between 1 and 65535.\")\n }\n\n const accountType = args[\"account-type\"]\n if (!allowedAccountTypes.has(accountType)) {\n throw new Error(\n \"Invalid account type. Must be individual, business, or enterprise.\",\n )\n }\n\n const rateLimitWait = args.wait && rateLimit !== undefined\n if (args.wait && rateLimit === undefined) {\n consola.warn(\"Rate limit wait ignored because no rate limit was set.\")\n }\n\n const githubToken = args[\"github-token\"] ?? process.env.GH_TOKEN\n\n return runServer({\n port,\n verbose: args.verbose,\n accountType,\n manual: args.manual,\n rateLimit,\n rateLimitWait,\n githubToken,\n claudeCode: args[\"claude-code\"],\n codex: args.codex,\n showToken: args[\"show-token\"],\n proxyEnv: args[\"proxy-env\"],\n })\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from \"citty\"\n\nimport { auth } from \"./auth\"\nimport { checkUsage } from \"./check-usage\"\nimport { debug } from \"./debug\"\nimport { start } from \"./start\"\n\nconst main = defineCommand({\n meta: {\n name: \"github-router\",\n description:\n \"A reverse proxy that exposes GitHub Copilot as OpenAI and Anthropic compatible API endpoints.\",\n },\n subCommands: { auth, start, \"check-usage\": checkUsage, debug },\n})\n\nawait runMain(main)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAIA,MAAM,UAAU,KAAK,KAAK,GAAG,SAAS,EAAE,UAAU,SAAS,gBAAgB;AAE3E,MAAM,oBAAoB,KAAK,KAAK,SAAS,eAAe;AAE5D,MAAa,QAAQ;CACnB;CACA;CACD;AAED,eAAsB,cAA6B;AACjD,OAAM,GAAG,MAAM,MAAM,SAAS,EAAE,WAAW,MAAM,CAAC;AAClD,OAAM,WAAW,MAAM,kBAAkB;;AAG3C,eAAe,WAAW,UAAiC;AACzD,KAAI;AACF,QAAM,GAAG,OAAO,UAAU,GAAG,UAAU,KAAK;SACtC;AACN,QAAM,GAAG,UAAU,UAAU,GAAG;AAChC,QAAM,GAAG,MAAM,UAAU,IAAM;;;;;;ACJnC,MAAaA,QAAe;CAC1B,aAAa;CACb,eAAe;CACf,eAAe;CACf,WAAW;CACZ;;;;ACpBD,MAAa,yBAAyB;CACpC,gBAAgB;CAChB,QAAQ;CACT;AAED,MAAM,kBAAkB;AACxB,MAAM,wBAAwB,gBAAgB;AAC9C,MAAM,aAAa,qBAAqB;AAExC,MAAM,cAAc;AAEpB,MAAa,kBAAkB,YAC7BC,QAAM,gBAAgB,eACpB,kCACA,eAAeA,QAAM,YAAY;AACrC,MAAa,kBACX,SACA,SAAkB,OAClB,gBAAwB,kBACrB;CACH,MAAMC,UAAkC;EACtC,eAAe,UAAUD,QAAM;EAC/B,gBAAgB,iBAAiB,CAAC;EAClC,0BAA0B;EAC1B,kBAAkB,UAAUA,QAAM;EAClC,yBAAyB;EACzB,cAAc;EACd,iBAAiB;EACjB,sBAAsB;EACtB,wBAAwB;EACxB,gBAAgB,YAAY;EAC5B,uCAAuC;EACxC;AAED,KAAI,OAAQ,SAAQ,4BAA4B;AAEhD,QAAO;;AAGT,MAAa,sBAAsB;AACnC,MAAa,iBAAiB,aAAkB;CAC9C,GAAG,iBAAiB;CACpB,eAAe,SAASA,QAAM;CAC9B,kBAAkB,UAAUA,QAAM;CAClC,yBAAyB;CACzB,cAAc;CACd,wBAAwB;CACxB,uCAAuC;CACxC;AAED,MAAa,kBAAkB;AAC/B,MAAa,mBAAmB;AAChC,MAAa,oBAAoB,CAAC,YAAY,CAAC,KAAK,IAAI;;;;ACnDxD,IAAa,YAAb,cAA+B,MAAM;CACnC;CAEA,YAAY,SAAiB,UAAoB;AAC/C,QAAM,QAAQ;AACd,OAAK,WAAW;;;AAIpB,eAAsB,aAAa,GAAY,OAAgB;AAC7D,SAAQ,MAAM,mBAAmB,MAAM;AAEvC,KAAI,iBAAiB,WAAW;EAC9B,MAAM,YAAY,MAAM,MAAM,SAAS,MAAM;EAC7C,IAAIE;AACJ,MAAI;AACF,eAAY,KAAK,MAAM,UAAU;UAC3B;AACN,eAAY;;EAEd,MAAM,UAAU,oBAAoB,WAAW,UAAU;AACzD,UAAQ,MAAM,eAAe,aAAa,UAAU;AACpD,SAAO,EAAE,KACP,EACE,OAAO;GACL;GACA,MAAM;GACP,EACF,EACD,MAAM,SAAS,OAChB;;AAGH,QAAO,EAAE,KACP,EACE,OAAO;EACL,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;EAC/D,MAAM;EACP,EACF,EACD,IACD;;AAIH,SAAS,oBAAoB,WAAoB,UAA0B;AACzE,KAAI,OAAO,cAAc,YAAY,cAAc,KAAM,QAAO;CAEhE,MAAM,cAAc;AACpB,KAAI,YAAY,YAAY,OAAW,QAAO,OAAO,YAAY,QAAQ;AAEzE,KAAI,OAAO,YAAY,UAAU,YAAY,YAAY,UAAU,MAAM;EACvE,MAAM,eAAe,YAAY;AACjC,MAAI,aAAa,YAAY,OAAW,QAAO,OAAO,aAAa,QAAQ;;AAG7E,QAAO;;;;;ACzDT,MAAa,kBAAkB,YAAY;CACzC,MAAM,WAAW,MAAM,MACrB,GAAG,oBAAoB,6BACvB,EACE,SAAS,cAAc,MAAM,EAC9B,CACF;AAED,KAAI,CAAC,SAAS,GAAI,OAAM,IAAI,UAAU,+BAA+B,SAAS;AAE9E,QAAQ,MAAM,SAAS,MAAM;;;;;ACN/B,eAAsB,gBAA6C;CACjE,MAAM,WAAW,MAAM,MAAM,GAAG,gBAAgB,qBAAqB;EACnE,QAAQ;EACR,SAAS,iBAAiB;EAC1B,MAAM,KAAK,UAAU;GACnB,WAAW;GACX,OAAO;GACR,CAAC;EACH,CAAC;AAEF,KAAI,CAAC,SAAS,GAAI,OAAM,IAAI,UAAU,6BAA6B,SAAS;AAE5E,QAAQ,MAAM,SAAS,MAAM;;;;;AChB/B,eAAsB,gBAAgB;CACpC,MAAM,WAAW,MAAM,MAAM,GAAG,oBAAoB,QAAQ,EAC1D,SAAS;EACP,eAAe,SAAS,MAAM;EAC9B,GAAG,iBAAiB;EACrB,EACF,CAAC;AAEF,KAAI,CAAC,SAAS,GAAI,OAAM,IAAI,UAAU,6BAA6B,SAAS;AAE5E,QAAQ,MAAM,SAAS,MAAM;;;;;ACV/B,MAAa,YAAY,YAAY;CACnC,MAAM,WAAW,MAAM,MAAM,GAAG,eAAe,MAAM,CAAC,UAAU,EAC9D,SAAS,eAAe,MAAM,EAC/B,CAAC;AAEF,KAAI,CAAC,SAAS,GAAI,OAAM,IAAI,UAAU,wBAAwB,SAAS;AAEvE,QAAQ,MAAM,SAAS,MAAM;;;;;ACX/B,MAAM,WAAW;AAEjB,eAAsB,mBAAmB;CACvC,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,UAAU,iBAAiB;AAC/B,aAAW,OAAO;IACjB,IAAK;AAER,KAAI;EAUF,MAAM,SAFW,OAPA,MAAM,MACrB,kFACA,EACE,QAAQ,WAAW,QACpB,CACF,EAE+B,MAAM,EAEf,MADH,mBACqB;AAEzC,MAAI,MACF,QAAO,MAAM;AAGf,SAAO;SACD;AACN,SAAO;WACC;AACR,eAAa,QAAQ;;;AAIzB,MAAM,kBAAkB;;;;ACzBxB,MAAa,SAAS,OACpB,IAAI,SAAS,YAAY;AACvB,YAAW,SAAS,GAAG;EACvB;AAEJ,MAAa,aAAa,UACxB,UAAU,QAAQ,UAAU;AAE9B,eAAsB,cAA6B;AAEjD,OAAM,SADS,MAAM,WAAW;;AAIlC,MAAa,qBAAqB,YAAY;CAC5C,MAAM,WAAW,MAAM,kBAAkB;AACzC,OAAM,gBAAgB;AAEtB,SAAQ,KAAK,yBAAyB,WAAW;;;;;ACbnD,eAAsB,gBACpB,YACiB;CAGjB,MAAM,iBAAiB,WAAW,WAAW,KAAK;AAClD,SAAQ,MAAM,yCAAyC,cAAc,IAAI;CACzE,MAAM,YAAY,KAAK,KAAK,GAAG,WAAW,aAAa;AAEvD,QAAO,KAAK,KAAK,GAAG,WAAW;EAC7B,MAAM,WAAW,MAAM,MACrB,GAAG,gBAAgB,4BACnB;GACE,QAAQ;GACR,SAAS,iBAAiB;GAC1B,MAAM,KAAK,UAAU;IACnB,WAAW;IACX,aAAa,WAAW;IACxB,YAAY;IACb,CAAC;GACH,CACF;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,WAAQ,MAAM,gCAAgC,MAAM,SAAS,MAAM,CAAC;AACpE,OAAI,KAAK,KAAK,IAAI,UAAW;AAC7B,SAAM,MAAM,cAAc;AAC1B;;EAGF,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,UAAQ,MAAM,kCAAkC,KAAK;EAErD,MAAM,EAAE,iBAAiB;AAEzB,MAAI,aACF,QAAO;AAGT,MAAI,KAAK,KAAK,IAAI,UAAW;AAC7B,QAAM,MAAM,cAAc;;AAG5B,OAAM,IAAI,MAAM,8CAA8C;;;;;AC1ChE,MAAM,wBAAwB,GAAG,SAAS,MAAM,mBAAmB,OAAO;AAE1E,MAAM,oBAAoB,UACxB,GAAG,UAAU,MAAM,mBAAmB,MAAM;AAE9C,MAAa,oBAAoB,YAAY;CAC3C,MAAM,EAAE,OAAO,eAAe,MAAM,iBAAiB;AACrD,OAAM,eAAe;AAGrB,SAAQ,MAAM,6CAA6C;AAC3D,KAAI,MAAM,UACR,SAAQ,KAAK,kBAAkB,MAAM;CAGvC,MAAM,kBAAkB,KAAK,KAAK,aAAa,MAAM,KAAM,IAAK;AAChE,aAAY,YAAY;AACtB,UAAQ,MAAM,2BAA2B;AACzC,MAAI;GACF,MAAM,EAAE,mBAAU,MAAM,iBAAiB;AACzC,SAAM,eAAeC;AACrB,WAAQ,MAAM,0BAA0B;AACxC,OAAI,MAAM,UACR,SAAQ,KAAK,4BAA4BA,QAAM;WAE1C,OAAO;AACd,WAAQ,MAAM,oCAAoC,MAAM;;IAEzD,gBAAgB;;AAOrB,eAAsB,iBACpB,SACe;AACf,KAAI;EACF,MAAM,cAAc,MAAM,iBAAiB;AAE3C,MAAI,eAAe,CAAC,SAAS,OAAO;AAClC,SAAM,cAAc;AACpB,OAAI,MAAM,UACR,SAAQ,KAAK,iBAAiB,YAAY;AAE5C,SAAM,SAAS;AAEf;;AAGF,UAAQ,KAAK,0CAA0C;EACvD,MAAM,WAAW,MAAM,eAAe;AACtC,UAAQ,MAAM,yBAAyB,SAAS;AAEhD,UAAQ,KACN,0BAA0B,SAAS,UAAU,OAAO,SAAS,mBAC9D;EAED,MAAM,QAAQ,MAAM,gBAAgB,SAAS;AAC7C,QAAM,iBAAiB,MAAM;AAC7B,QAAM,cAAc;AAEpB,MAAI,MAAM,UACR,SAAQ,KAAK,iBAAiB,MAAM;AAEtC,QAAM,SAAS;UACR,OAAO;AACd,MAAI,iBAAiB,WAAW;AAC9B,WAAQ,MAAM,+BAA+B,MAAM,MAAM,SAAS,MAAM,CAAC;AACzE,SAAM;;AAGR,UAAQ,MAAM,+BAA+B,MAAM;AACnD,QAAM;;;AAIV,eAAe,UAAU;CACvB,MAAM,OAAO,MAAM,eAAe;AAClC,SAAQ,KAAK,gBAAgB,KAAK,QAAQ;;;;;AC9E5C,eAAsB,QAAQ,SAAwC;AACpE,KAAI,QAAQ,SAAS;AACnB,UAAQ,QAAQ;AAChB,UAAQ,KAAK,0BAA0B;;AAGzC,OAAM,YAAY,QAAQ;AAE1B,OAAM,aAAa;AACnB,OAAM,iBAAiB,EAAE,OAAO,MAAM,CAAC;AACvC,SAAQ,QAAQ,2BAA2B,MAAM,kBAAkB;;AAGrE,MAAa,OAAO,cAAc;CAChC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,SAAS;GACP,OAAO;GACP,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACD,cAAc;GACZ,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACF;CACD,IAAI,EAAE,QAAQ;AACZ,SAAO,QAAQ;GACb,SAAS,KAAK;GACd,WAAW,KAAK;GACjB,CAAC;;CAEL,CAAC;;;;AC/CF,MAAa,kBAAkB,YAA2C;CACxE,MAAM,WAAW,MAAM,MAAM,GAAG,oBAAoB,yBAAyB,EAC3E,SAAS,cAAc,MAAM,EAC9B,CAAC;AAEF,KAAI,CAAC,SAAS,GACZ,OAAM,IAAI,UAAU,+BAA+B,SAAS;AAG9D,QAAQ,MAAM,SAAS,MAAM;;;;;ACH/B,MAAa,aAAa,cAAc;CACtC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM,MAAM;AACV,QAAM,aAAa;AACnB,QAAM,kBAAkB;AACxB,MAAI;GACF,MAAM,QAAQ,MAAM,iBAAiB;GACrC,MAAM,UAAU,MAAM,gBAAgB;GACtC,MAAM,eAAe,QAAQ;GAC7B,MAAM,cAAc,eAAe,QAAQ;GAC3C,MAAM,qBACJ,eAAe,IAAK,cAAc,eAAgB,MAAM;GAC1D,MAAM,0BAA0B,QAAQ;GAGxC,SAAS,eAAe,MAAc,MAA+B;AACnE,QAAI,CAAC,KAAM,QAAO,GAAG,KAAK;IAC1B,MAAM,QAAQ,KAAK;IACnB,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,cAAc,QAAQ,IAAK,OAAO,QAAS,MAAM;IACvD,MAAM,mBAAmB,KAAK;AAC9B,WAAO,GAAG,KAAK,IAAI,KAAK,GAAG,MAAM,SAAS,YAAY,QAAQ,EAAE,CAAC,UAAU,iBAAiB,QAAQ,EAAE,CAAC;;GAGzG,MAAM,cAAc,YAAY,YAAY,GAAG,aAAa,SAAS,mBAAmB,QAAQ,EAAE,CAAC,UAAU,wBAAwB,QAAQ,EAAE,CAAC;GAChJ,MAAM,WAAW,eAAe,QAAQ,MAAM,gBAAgB,KAAK;GACnE,MAAM,kBAAkB,eACtB,eACA,MAAM,gBAAgB,YACvB;AAED,WAAQ,IACN,wBAAwB,MAAM,aAAa,mBACtB,MAAM,iBAAiB,iBAEnC,YAAY,MACZ,SAAS,MACT,kBACV;WACM,KAAK;AACZ,WAAQ,MAAM,kCAAkC,IAAI;AACpD,WAAQ,KAAK,EAAE;;;CAGpB,CAAC;;;;AC7BF,eAAe,oBAAqC;AAClD,KAAI;EACF,MAAM,kBAAkB,IAAI,IAAI,mBAAmB,OAAO,KAAK,IAAI,CAAC;AAMpE,SAHoB,KAAK,MAAM,MAAM,GAAG,SAAS,gBAAgB,CAAC,CAG/C;SACb;AACN,SAAO;;;AAIX,SAAS,iBAAiB;CACxB,MAAM,QAAQ,OAAO,QAAQ;AAE7B,QAAO;EACL,MAAM,QAAQ,QAAQ;EACtB,SAAS,QAAQ,IAAI,UAAU,QAAQ,QAAQ,MAAM,EAAE;EACvD,UAAU,GAAG,UAAU;EACvB,MAAM,GAAG,MAAM;EAChB;;AAGH,eAAe,mBAAqC;AAClD,KAAI;AAEF,MAAI,EADU,MAAM,GAAG,KAAK,MAAM,kBAAkB,EACzC,QAAQ,CAAE,QAAO;AAG5B,UADgB,MAAM,GAAG,SAAS,MAAM,mBAAmB,OAAO,EACnD,MAAM,CAAC,SAAS;SACzB;AACN,SAAO;;;AAIX,eAAe,eAAmC;CAChD,MAAM,CAAC,SAAS,eAAe,MAAM,QAAQ,IAAI,CAC/C,mBAAmB,EACnB,kBAAkB,CACnB,CAAC;AAEF,QAAO;EACL;EACA,SAAS,gBAAgB;EACzB,OAAO;GACL,SAAS,MAAM;GACf,mBAAmB,MAAM;GAC1B;EACD;EACD;;AAGH,SAAS,oBAAoB,MAAuB;AAClD,SAAQ,KAAK;;WAEJ,KAAK,QAAQ;WACb,KAAK,QAAQ,KAAK,GAAG,KAAK,QAAQ,QAAQ,IAAI,KAAK,QAAQ,SAAS,GAAG,KAAK,QAAQ,KAAK;;;aAGvF,KAAK,MAAM,QAAQ;uBACT,KAAK,MAAM,kBAAkB;;gBAEpC,KAAK,cAAc,QAAQ,OAAO;;AAGlD,SAAS,mBAAmB,MAAuB;AACjD,SAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;;AAG5C,eAAsB,SAAS,SAAyC;CACtE,MAAM,YAAY,MAAM,cAAc;AAEtC,KAAI,QAAQ,KACV,oBAAmB,UAAU;KAE7B,qBAAoB,UAAU;;AAIlC,MAAa,QAAQ,cAAc;CACjC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM,EACJ,MAAM;EACJ,MAAM;EACN,SAAS;EACT,aAAa;EACd,EACF;CACD,IAAI,EAAE,QAAQ;AACZ,SAAO,SAAS,EACd,MAAM,KAAK,MACZ,CAAC;;CAEL,CAAC;;;;AC1HF,SAAgB,mBAAyB;AACvC,KAAI,OAAO,QAAQ,YAAa;AAEhC,KAAI;EACF,MAAM,SAAS,IAAI,OAAO;EAC1B,MAAM,0BAAU,IAAI,KAAyB;AAmD7C,sBA7CmB;GACjB,SACE,SACA,SACA;AACA,QAAI;KACF,MAAM,SACJ,OAAO,QAAQ,WAAW,WACxB,IAAI,IAAI,QAAQ,OAAO,GACtB,QAAQ;KAIb,MAAM,MAHM,eAGI,OAAO,UAAU,CAAC;KAClC,MAAM,WAAW,OAAO,IAAI,SAAS,IAAI,MAAM;AAC/C,SAAI,CAAC,UAAU;AACb,cAAQ,MAAM,sBAAsB,OAAO,WAAW;AACtD,aAAQ,OAAiC,SAAS,SAAS,QAAQ;;KAErE,IAAI,QAAQ,QAAQ,IAAI,SAAS;AACjC,SAAI,CAAC,OAAO;AACV,cAAQ,IAAI,WAAW,SAAS;AAChC,cAAQ,IAAI,UAAU,MAAM;;KAE9B,IAAI,QAAQ;AACZ,SAAI;MACF,MAAM,IAAI,IAAI,IAAI,SAAS;AAC3B,cAAQ,GAAG,EAAE,SAAS,IAAI,EAAE;aACtB;AAGR,aAAQ,MAAM,qBAAqB,OAAO,SAAS,OAAO,QAAQ;AAClE,YAAQ,MAAgC,SAAS,SAAS,QAAQ;YAC5D;AACN,YAAQ,OAAiC,SAAS,SAAS,QAAQ;;;GAGvE,QAAQ;AACN,WAAO,OAAO,OAAO;;GAEvB,UAAU;AACR,WAAO,OAAO,SAAS;;GAE1B,CAEuD;AACxD,UAAQ,MAAM,mDAAmD;UAC1D,KAAK;AACZ,UAAQ,MAAM,wBAAwB,IAAI;;;;;;AC1D9C,SAAS,WAAsB;CAC7B,MAAM,EAAE,UAAU,QAAQC;AAE1B,KAAI,aAAa,SAAS;AAExB,MAAI,IAAI,OAAO;AACb,OAAI,IAAI,MAAM,SAAS,MAAM,CAAE,QAAO;AACtC,OAAI,IAAI,MAAM,SAAS,OAAO,CAAE,QAAO;AACvC,OAAI,IAAI,MAAM,SAAS,OAAO,CAAE,QAAO;AACvC,UAAO;;AAIT,MAAI,IAAI,gCAAiC,QAAO;AAIhD,MAAI,IAAI,cAAc;GACpB,MAAM,QAAQ,IAAI,aAAa,aAAa;AAC5C,OACE,MAAM,SAAS,wBAAwB,IACpC,MAAM,SAAS,+BAA+B,CAEjD,QAAO;;AAIX,SAAO;;CAGT,MAAM,YAAY,IAAI;AACtB,KAAI,WAAW;AACb,MAAI,UAAU,SAAS,MAAM,CAAE,QAAO;AACtC,MAAI,UAAU,SAAS,OAAO,CAAE,QAAO;AACvC,MAAI,UAAU,SAAS,OAAO,CAAE,QAAO;;AAGzC,QAAO;;AAGT,SAAS,gBAAgB,OAAuB;AAC9C,QAAO,IAAI,MAAM,QAAQ,MAAM,QAAQ,CAAC;;AAG1C,SAAS,qBAAqB,OAAuB;AACnD,QAAO,IAAI,MAAM,QAAQ,MAAM,KAAK,CAAC;;;;;;;;;AAUvC,SAAgB,kBACd,SACA,eAAuB,IACf;CACR,MAAM,QAAQ,UAAU;CACxB,MAAM,kBAAkB,OAAO,QAAQ,QAAQ,CAAC,QAC7C,GAAG,WAAW,UAAU,OAC1B;CAED,IAAIC;AAEJ,SAAQ,OAAR;EACE,KAAK;AACH,kBAAe,gBACZ,KAAK,CAAC,KAAK,WAAW,QAAQ,IAAI,KAAK,qBAAqB,MAAM,GAAG,CACrE,KAAK,KAAK;AACb;EAEF,KAAK;AACH,kBAAe,gBACZ,KAAK,CAAC,KAAK,WAAW,QAAQ,IAAI,GAAG,MAAM,GAAG,CAC9C,KAAK,MAAM;AACd;EAEF,KAAK;AACH,kBAAe,gBACZ,KAAK,CAAC,KAAK,WAAW,WAAW,IAAI,GAAG,gBAAgB,MAAM,GAAG,CACjE,KAAK,KAAK;AACb;EAEF,SAAS;GAEP,MAAM,cAAc,gBACjB,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,gBAAgB,MAAM,GAAG,CACzD,KAAK,IAAI;AACZ,kBAAe,gBAAgB,SAAS,IAAI,UAAU,gBAAgB;AACtE;;;AAIJ,KAAI,gBAAgB,aAGlB,QAAO,GAAG,eADR,UAAU,QAAQ,QAAQ,UAAU,eAAe,OAAO,SACvB;AAGvC,QAAO,gBAAgB;;;;;ACtGzB,MAAa,gBAAgB,YAAY;AAKvC,KAAI,CAJa,MAAM,QAAQ,OAAO,4BAA4B,EAChE,MAAM,WACP,CAAC,CAGA,OAAM,IAAI,UACR,4BACA,SAAS,KAAK,EAAE,SAAS,4BAA4B,EAAE,EAAE,QAAQ,KAAK,CAAC,CACxE;;;;;ACNL,eAAsB,eAAe,SAAc;AACjD,KAAIC,QAAM,qBAAqB,OAAW;CAE1C,MAAM,MAAM,KAAK,KAAK;AAEtB,KAAI,CAACA,QAAM,sBAAsB;AAC/B,UAAM,uBAAuB;AAC7B;;CAGF,MAAM,kBAAkB,MAAMA,QAAM,wBAAwB;AAE5D,KAAI,iBAAiBA,QAAM,kBAAkB;AAC3C,UAAM,uBAAuB;AAC7B;;CAGF,MAAM,kBAAkB,KAAK,KAAKA,QAAM,mBAAmB,eAAe;AAE1E,KAAI,CAACA,QAAM,eAAe;AACxB,UAAQ,KACN,qCAAqC,gBAAgB,gBACtD;AACD,QAAM,IAAI,UACR,uBACA,SAAS,KAAK,EAAE,SAAS,uBAAuB,EAAE,EAAE,QAAQ,KAAK,CAAC,CACnE;;CAGH,MAAM,aAAa,kBAAkB;AACrC,SAAQ,KACN,+BAA+B,gBAAgB,+BAChD;AACD,OAAM,MAAM,WAAW;AACvB,SAAM,uBAAuB,KAAK,KAAK;AACvC,SAAQ,KAAK,qDAAqD;;;;;AChCpE,MAAM,eAAe;CACnB,kBAAkB,OAAO;CACzB,mBAAmB,OAAO;CAC1B,iBAAiB,OAAO;CACxB,iBAAiB,OAAO;CACxB,iBAAiB,OAAO;CACzB;AAUD,MAAM,gCAAgB,IAAI,KAAsB;;;;AAKhD,MAAM,4BACJ,WACA,SACA,cACW;CACX,IAAI,SAAS;AACb,MAAK,MAAM,YAAY,WAAW;AAChC,YAAU,UAAU;AACpB,YAAU,QAAQ,OAAO,KAAK,UAAU,SAAS,CAAC,CAAC;;AAErD,WAAU,UAAU;AACpB,QAAO;;;;;AAMT,MAAM,+BACJ,cACA,YACW;CACX,IAAI,SAAS;AACb,MAAK,MAAM,QAAQ,aACjB,KAAI,KAAK,SAAS,YAChB,WAAU,QAAQ,OAAO,KAAK,UAAU,IAAI,CAAC,SAAS;UAC7C,KAAK,KACd,WAAU,QAAQ,OAAO,KAAK,KAAK,CAAC;AAGxC,QAAO;;;;;AAMT,MAAM,0BACJ,SACA,SACA,cACW;CACX,MAAM,mBAAmB;CACzB,MAAM,gBAAgB;CACtB,IAAI,SAAS;AACb,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE;AAClD,MAAI,OAAO,UAAU,SACnB,WAAU,QAAQ,OAAO,MAAM,CAAC;AAElC,MAAI,QAAQ,OACV,WAAU;AAEZ,MAAI,QAAQ,aACV,WAAU,yBACR,OACA,SACA,UACD;AAEH,MAAI,QAAQ,aAAa,MAAM,QAAQ,MAAM,CAC3C,WAAU,4BACR,OACA,QACD;;AAGL,QAAO;;;;;AAMT,MAAM,mBACJ,UACA,SACA,cACW;AACX,KAAI,SAAS,WAAW,EACtB,QAAO;CAET,IAAI,YAAY;AAChB,MAAK,MAAM,WAAW,SACpB,cAAa,uBAAuB,SAAS,SAAS,UAAU;AAGlE,cAAa;AACb,QAAO;;;;;AAMT,MAAM,wBAAwB,OAAO,aAAuC;AAC1E,KAAI,cAAc,IAAI,SAAS,EAAE;EAC/B,MAAM,SAAS,cAAc,IAAI,SAAS;AAC1C,MAAI,OACF,QAAO;;CAIX,MAAM,oBAAoB;AAC1B,KAAI,EAAE,qBAAqB,eAAe;EACxC,MAAM,iBAAkB,MAAM,aAAa,YAAY;AACvD,gBAAc,IAAI,UAAU,eAAe;AAC3C,SAAO;;CAGT,MAAM,iBAAkB,MAAM,aAAa,oBAAoB;AAC/D,eAAc,IAAI,UAAU,eAAe;AAC3C,QAAO;;;;;AAMT,MAAa,yBAAyB,UAAyB;AAC7D,QAAO,MAAM,aAAa,aAAa;;;;;AAMzC,MAAM,qBAAqB,UAAiB;AAC1C,QAAO,MAAM,OAAO,mBAAmB,MAAM,OAAO,UAChD;EACE,UAAU;EACV,UAAU;EACV,SAAS;EACT,UAAU;EACV,UAAU;EACV,SAAS;EACV,GACD;EACE,UAAU;EACV,UAAU;EACV,SAAS;EACT,UAAU;EACV,UAAU;EACV,SAAS;EACV;;;;;AAMP,MAAM,4BACJ,KACA,MACA,YAIW;CACX,MAAM,EAAE,SAAS,cAAc;CAC/B,IAAI,SAAS,UAAU;AAGvB,KAAI,OAAO,SAAS,YAAY,SAAS,KACvC,QAAO;CAIT,MAAM,QAAQ;CAOd,MAAM,YAAY;CAClB,MAAM,YAAY,MAAM,QAAQ;CAChC,IAAI,YAAY,MAAM,eAAe;AAGrC,KAAI,MAAM,QAAQ,MAAM,QAAQ,MAAM,KAAK,EAAE;AAC3C,YAAU,UAAU;AACpB,OAAK,MAAM,QAAQ,MAAM,MAAM;AAC7B,aAAU,UAAU;AACpB,aAAU,QAAQ,OAAO,OAAO,KAAK,CAAC,CAAC;;;AAK3C,KAAI,UAAU,SAAS,IAAI,CACzB,aAAY,UAAU,MAAM,GAAG,GAAG;CAIpC,MAAM,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG;AAC1C,WAAU,QAAQ,OAAO,KAAK,CAAC;CAG/B,MAAM,eAAe,IAAI,IAAI;EAAC;EAAQ;EAAe;EAAO,CAAC;AAC7D,MAAK,MAAM,gBAAgB,OAAO,KAAK,MAAM,CAC3C,KAAI,CAAC,aAAa,IAAI,aAAa,EAAE;EACnC,MAAM,gBAAgB,MAAM;EAC5B,MAAM,eACJ,OAAO,kBAAkB,WAAW,gBAClC,KAAK,UAAU,cAAc;AAEjC,YAAU,QAAQ,OAAO,GAAG,aAAa,GAAG,eAAe,CAAC;;AAIhE,QAAO;;;;;AAMT,MAAM,6BACJ,YACA,SACA,cACW;AACX,KAAI,CAAC,cAAc,OAAO,eAAe,SACvC,QAAO;CAGT,MAAM,SAAS;CACf,IAAI,SAAS;AAEb,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,CAC/C,KAAI,QAAQ,cAAc;EACxB,MAAM,aAAa;AACnB,MAAI,OAAO,KAAK,WAAW,CAAC,SAAS,GAAG;AACtC,aAAU,UAAU;AACpB,QAAK,MAAM,WAAW,OAAO,KAAK,WAAW,CAC3C,WAAU,yBAAyB,SAAS,WAAW,UAAU;IAC/D;IACA;IACD,CAAC;;QAGD;EACL,MAAM,YACJ,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,MAAM;AAC3D,YAAU,QAAQ,OAAO,GAAG,IAAI,GAAG,YAAY,CAAC;;AAIpD,QAAO;;;;;AAMT,MAAM,uBACJ,MACA,SACA,cACW;CACX,IAAI,SAAS,UAAU;CACvB,MAAM,OAAO,KAAK;CAClB,MAAM,QAAQ,KAAK;CACnB,IAAI,QAAQ,KAAK,eAAe;AAChC,KAAI,MAAM,SAAS,IAAI,CACrB,SAAQ,MAAM,MAAM,GAAG,GAAG;CAE5B,MAAM,OAAO,QAAQ,MAAM;AAC3B,WAAU,QAAQ,OAAO,KAAK,CAAC;AAC/B,KACE,OAAO,KAAK,eAAe,YACxB,KAAK,eAAe,KAEvB,WAAU,0BAA0B,KAAK,YAAY,SAAS,UAAU;AAE1E,QAAO;;;;;AAMT,MAAa,qBACX,OACA,SACA,cACW;CACX,IAAI,iBAAiB;AACrB,MAAK,MAAM,QAAQ,MACjB,mBAAkB,oBAAoB,MAAM,SAAS,UAAU;AAEjE,mBAAkB,UAAU;AAC5B,QAAO;;;;;AAMT,MAAa,gBAAgB,OAC3B,SACA,UAC+C;CAK/C,MAAM,UAAU,MAAM,sBAHJ,sBAAsB,MAAM,CAGQ;CAEtD,MAAM,qBAAqB,QAAQ;CACnC,MAAM,gBAAgB,mBAAmB,QACtC,QAAQ,IAAI,SAAS,YACvB;CACD,MAAM,iBAAiB,mBAAmB,QACvC,QAAQ,IAAI,SAAS,YACvB;CAED,MAAM,YAAY,kBAAkB,MAAM;CAC1C,IAAI,cAAc,gBAAgB,eAAe,SAAS,UAAU;AACpE,KAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,EAC1C,gBAAe,kBAAkB,QAAQ,OAAO,SAAS,UAAU;CAErE,MAAM,eAAe,gBAAgB,gBAAgB,SAAS,UAAU;AAExE,QAAO;EACL,OAAO;EACP,QAAQ;EACT;;;;;ACnVH,MAAa,wBAAwB,OACnC,YACG;AACH,KAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM,0BAA0B;CAEnE,MAAM,eAAe,QAAQ,SAAS,MACnC,MACC,OAAO,EAAE,YAAY,YAClB,EAAE,SAAS,MAAM,QAAMC,IAAE,SAAS,YAAY,CACpD;CAID,MAAM,cAAc,QAAQ,SAAS,MAAM,QACzC,CAAC,aAAa,OAAO,CAAC,SAAS,IAAI,KAAK,CACzC;CAGD,MAAMC,UAAkC;EACtC,GAAG,eAAe,OAAO,aAAa;EACtC,eAAe,cAAc,UAAU;EACxC;CAED,MAAM,WAAW,MAAM,MAAM,GAAG,eAAe,MAAM,CAAC,oBAAoB;EACxE,QAAQ;EACR;EACA,MAAM,KAAK,UAAU,QAAQ;EAC9B,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,IAAI,YAAY;AAChB,MAAI;AACF,eAAY,MAAM,SAAS,MAAM;UAC3B;AACN,eAAY;;EAEd,MAAM,eAAe,MAAM,QAAQ,KAChC,QAAQ,MAAM,EAAE,GAAG,WAAW,SAAS,CAAC,CACxC,KAAK,MAAM,EAAE,GAAG,CAChB,KAAK,KAAK,IAAI;AACjB,UAAQ,MACN,2BAA2B,QAAQ,MAAM,KAAK,SAAS,OAAO,GAAG,UAAU,6BAA6B,aAAa,GACtH;AAOD,QAAM,IAAI,UAAU,qCALE,IAAI,SAAS,WAAW;GAC5C,QAAQ,SAAS;GACjB,YAAY,SAAS;GACrB,SAAS,SAAS;GACnB,CAAC,CACqE;;AAGzE,KAAI,QAAQ,OACV,QAAO,OAAO,SAAS;AAGzB,QAAQ,MAAM,SAAS,MAAM;;;;;AClC/B,MAAM,0BAA0B;AAChC,IAAIC,mBAAkC,EAAE;AAExC,eAAe,iBAAgC;CAC7C,MAAM,MAAM,KAAK,KAAK;AACtB,oBAAmB,iBAAiB,QAAQ,MAAM,MAAM,IAAI,IAAK;AACjE,KAAI,iBAAiB,UAAU,yBAAyB;EACtD,MAAM,SAAS,OAAQ,MAAM,iBAAiB;AAC9C,MAAI,SAAS,GAAG;AACd,WAAQ,MAAM,oCAAoC,OAAO,IAAI;AAC7D,SAAM,MAAM,OAAO;;;AAGvB,kBAAiB,KAAK,KAAK,KAAK,CAAC;;AAGnC,SAAS,iBAAyC;AAChD,QAAO,eAAe,OAAO,OAAO,eAAe;;AAGrD,eAAe,eAAgC;CAC7C,MAAM,WAAW,MAAM,MAAM,GAAG,eAAe,MAAM,CAAC,uBAAuB;EAC3E,QAAQ;EACR,SAAS,gBAAgB;EACzB,MAAM,KAAK,UAAU,EAAE,CAAC;EACzB,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;AAChB,UAAQ,MAAM,gCAAgC,SAAS,OAAO;AAC9D,QAAM,IAAI,MAAM,iCAAiC,SAAS,SAAS;;AAIrE,SADc,MAAM,SAAS,MAAM,EACvB;;AAGd,eAAe,kBACb,UACA,OACiC;CACjC,MAAM,WAAW,MAAM,MACrB,GAAG,eAAe,MAAM,CAAC,uBAAuB,SAAS,YACzD;EACE,QAAQ;EACR,SAAS,gBAAgB;EACzB,MAAM,KAAK,UAAU;GACnB,SAAS;GACT,QAAQ;GACR,QAAQ,CAAC,aAAa;GACtB,YAAY,EAAE;GACf,CAAC;EACH,CACF;AAED,KAAI,CAAC,SAAS,IAAI;AAChB,UAAQ,MAAM,iCAAiC,SAAS,OAAO;AAC/D,QAAM,IAAI,MAAM,kCAAkC,SAAS,SAAS;;AAGtE,QAAQ,MAAM,SAAS,MAAM;;AAG/B,eAAsB,UAAU,OAAyC;AACvE,KAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM,0BAA0B;AAEnE,OAAM,gBAAgB;AAEtB,SAAQ,KAAK,gBAAgB,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG;CAGnD,MAAM,WAAW,MAAM,kBADN,MAAM,cAAc,EACc,MAAM;CAEzD,MAAMC,aAAoD,EAAE;AAC5D,MAAK,MAAM,OAAO,SAAS,QAAQ,cAAc,EAAE,CACjD,KAAI,IAAI,SACN;OAAK,MAAM,UAAU,IAAI,QACvB,KAAI,OAAO,OAAO,OAAO,mBAAmB,cAC1C,YAAW,KAAK;GAAE,OAAO,OAAO;GAAO,KAAK,OAAO;GAAK,CAAC;;AAMjE,SAAQ,MAAM,uBAAuB,WAAW,OAAO,aAAa;AAEpE,QAAO;EACL,SAAS,SAAS,QAAQ;EAC1B;EACD;;;;;ACnGH,eAAsBC,mBAAiB,GAAY;AACjD,OAAM,eAAe,MAAM;CAE3B,IAAI,UAAU,MAAM,EAAE,IAAI,MAA8B;CACxD,MAAM,eAAe,QAAQ,SAAS;AACtC,KAAI,aACF,SAAQ,MAAM,oBAAoB,KAAK,UAAU,QAAQ,CAAC,MAAM,KAAK,CAAC;AAGxE,KAAI,MAAM,cAAe,OAAM,eAAe;AAE9C,OAAMC,0BAAwB,QAAQ;CAGtC,MAAM,gBAAgB,MAAM,QAAQ,KAAK,MACtC,UAAU,MAAM,OAAO,QAAQ,MACjC;AAGD,KAAI;AACF,MAAI,eAAe;GACjB,MAAM,aAAa,MAAM,cAAc,SAAS,cAAc;AAC9D,WAAQ,KAAK,wBAAwB,WAAW;QAEhD,SAAQ,KAAK,sDAAsD;UAE9D,OAAO;AACd,UAAQ,KAAK,oCAAoC,MAAM;;AAGzD,KAAI,UAAU,QAAQ,WAAW,EAAE;AACjC,YAAU;GACR,GAAG;GACH,YAAY,eAAe,aAAa,OAAO;GAChD;AACD,MAAI,aACF,SAAQ,MAAM,sBAAsB,KAAK,UAAU,QAAQ,WAAW,CAAC;;CAI3E,MAAM,WAAW,MAAM,sBAAsB,QAAQ;AAErD,KAAIC,iBAAe,SAAS,EAAE;AAC5B,MAAI,aACF,SAAQ,MAAM,2BAA2B,KAAK,UAAU,SAAS,CAAC;AAEpE,SAAO,EAAE,KAAK,SAAS;;AAGzB,SAAQ,MAAM,qBAAqB;AACnC,QAAO,UAAU,GAAG,OAAO,WAAW;AACpC,aAAW,MAAM,SAAS,UAAU;AAClC,OAAI,aACF,SAAQ,MAAM,oBAAoB,KAAK,UAAU,MAAM,CAAC;AAE1D,SAAM,OAAO,SAAS,MAAoB;;GAE5C;;AAGJ,MAAMA,oBACJ,aACuC,OAAO,OAAO,UAAU,UAAU;AAE3E,eAAeD,0BACb,SACe;AAMf,KAAI,CALiB,QAAQ,OAAO,MACjC,MACE,UAAU,KAAM,EAAyC,SAAS,gBAChE,EAAE,UAAU,SAAS,aAC3B,CACkB;CAInB,MAAM,QADgB,QAAQ,SAAS,MAAM,QAAQ,IAAI,SAAS,OAAO,GAC3C,SAAYE,mBAAiB,QAAQ,SAAS;AAE5E,KAAI,MACF,KAAI;EACF,MAAM,UAAU,MAAM,UAAU,MAAM;EACtC,MAAM,gBAAgB;GACpB;GACA,QAAQ;GACR;GACA,QAAQ,WAAW,KAAK,MAAM,MAAM,EAAE,MAAM,IAAI,EAAE,IAAI,GAAG,CAAC,KAAK,KAAK;GACpE;GACD,CAAC,KAAK,KAAK;EAGZ,MAAM,YAAY,QAAQ,SAAS,MAAM,QAAQ,IAAI,SAAS,SAAS;AACvE,MAAI,UASF,WAAU,UAAU,GAAG,cAAc,MAPnC,OAAO,UAAU,YAAY,WAAW,UAAU,UAChD,MAAM,QAAQ,UAAU,QAAQ,GAChC,UAAU,QACP,QAAQ,MAAM,EAAE,SAAS,OAAO,CAChC,KAAK,MAAO,UAAU,IAAI,EAAE,OAAO,GAAI,CACvC,KAAK,KAAK,GACb;MAGJ,SAAQ,SAAS,QAAQ;GACvB,MAAM;GACN,SAAS;GACV,CAAC;UAEG,OAAO;AACd,UAAQ,KAAK,kDAAkD,MAAM;;AAKzE,SAAQ,QAAQ,QAAQ,OAAO,QAC5B,MACC,EACG,UAAU,KAAM,EAAyC,SAAS,gBAChE,EAAE,UAAU,SAAS,cAE7B;AACD,KAAI,QAAQ,OAAO,WAAW,EAC5B,SAAQ,QAAQ;AAElB,KAAI,CAAC,QAAQ,MACX,SAAQ,cAAc;UAEtB,QAAQ,eACL,OAAO,QAAQ,gBAAgB,YAC/B,UAAU,QAAQ,eAClB,QAAQ,YAAY,SAAS,YAChC;EACA,MAAM,iBAAiB,QAAQ,YAAY,UAAU;AACrD,MACE,kBACG,CAAC,QAAQ,MAAM,MAAM,SAAS,KAAK,SAAS,SAAS,eAAe,CAEvE,SAAQ,cAAc;;;AAK5B,SAASA,mBAAiB,UAA8C;AAEtE,MAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;EAC7C,MAAM,MAAM,SAAS;AACrB,MAAI,IAAI,SAAS,QAAQ;AACvB,OAAI,OAAO,IAAI,YAAY,SAAU,QAAO,IAAI;AAChD,OAAI,MAAM,QAAQ,IAAI,QAAQ,EAAE;IAC9B,MAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,EAAE,SAAS,OAAO;AACvD,QAAI,QAAQ,UAAU,KAAM,QAAO,KAAK;;;;;;;;ACjKhD,MAAa,mBAAmB,IAAI,MAAM;AAE1C,iBAAiB,KAAK,KAAK,OAAO,MAAM;AACtC,KAAI;AACF,SAAO,MAAMC,mBAAiB,EAAE;UACzB,OAAO;AACd,SAAO,MAAM,aAAa,GAAG,MAAM;;EAErC;;;;ACVF,MAAa,mBAAmB,OAAO,YAA8B;AACnE,KAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM,0BAA0B;CAEnE,MAAM,WAAW,MAAM,MAAM,GAAG,eAAe,MAAM,CAAC,cAAc;EAClE,QAAQ;EACR,SAAS,eAAe,MAAM;EAC9B,MAAM,KAAK,UAAU,QAAQ;EAC9B,CAAC;AAEF,KAAI,CAAC,SAAS,GAAI,OAAM,IAAI,UAAU,+BAA+B,SAAS;AAE9E,QAAQ,MAAM,SAAS,MAAM;;;;;ACP/B,MAAa,kBAAkB,IAAI,MAAM;AAEzC,gBAAgB,KAAK,KAAK,OAAO,MAAM;AACrC,KAAI;EAEF,MAAM,WAAW,MAAM,iBADP,MAAM,EAAE,IAAI,MAAwB,CACJ;AAEhD,SAAO,EAAE,KAAK,SAAS;UAChB,OAAO;AACd,SAAO,MAAM,aAAa,GAAG,MAAM;;EAErC;;;;;;;;;;;;;;;;;;;;ACKF,SAAS,eAAuC;AAC9C,QAAO;EACL,GAAG,eAAe,MAAM;EACxB,eAAe;EACf,qBAAqB;EACrB,oBAAoB,YAAY;EACjC;;;;;;AAOH,eAAsB,eACpB,MACmB;AACnB,KAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM,0BAA0B;CAEnE,MAAM,UAAU,cAAc;CAC9B,MAAM,MAAM,GAAG,eAAe,MAAM,CAAC;AACrC,SAAQ,MAAM,iBAAiB,MAAM;CAErC,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC,QAAQ;EACR;EACA;EACD,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,IAAI,YAAY;AAChB,MAAI;AACF,eAAY,MAAM,SAAS,MAAM;UAC3B;AACN,eAAY;;AAEd,UAAQ,MACN,+BAA+B,SAAS,OAAO,GAAG,YACnD;AAMD,QAAM,IAAI,UAAU,mCALE,IAAI,SAAS,WAAW;GAC5C,QAAQ,SAAS;GACjB,YAAY,SAAS;GACrB,SAAS,SAAS;GACnB,CAAC,CACmE;;AAGvE,QAAO;;;;;;AAOT,eAAsB,YACpB,MACmB;AACnB,KAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM,0BAA0B;CAEnE,MAAM,UAAU,cAAc;CAC9B,MAAM,MAAM,GAAG,eAAe,MAAM,CAAC;AACrC,SAAQ,MAAM,iBAAiB,MAAM;CAErC,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC,QAAQ;EACR;EACA;EACD,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,IAAI,YAAY;AAChB,MAAI;AACF,eAAY,MAAM,SAAS,MAAM;UAC3B;AACN,eAAY;;AAEd,UAAQ,MACN,+BAA+B,SAAS,OAAO,GAAG,YACnD;AAMD,QAAM,IAAI,UAAU,uCALE,IAAI,SAAS,WAAW;GAC5C,QAAQ,SAAS;GACjB,YAAY,SAAS;GACrB,SAAS,SAAS;GACnB,CAAC,CACuE;;AAG3E,QAAO;;;;;;;;;ACpGT,eAAsB,kBAAkB,GAAY;CAGlD,MAAM,OAAO,OADI,MAAM,YADP,MAAM,EAAE,IAAI,MAAM,CACS,EACf,MAAM;AAElC,SAAQ,KAAK,gBAAgB,KAAK,UAAU,KAAK,CAAC;AAElD,QAAO,EAAE,KAAK,KAAK;;;;;ACRrB,eAAsB,iBAAiB,GAAY;AACjD,OAAM,eAAe,MAAM;CAE3B,MAAM,UAAU,MAAM,EAAE,IAAI,MAAM;CAElC,MAAM,eAAe,QAAQ,SAAS;AACtC,KAAI,aACF,SAAQ,MAAM,2BAA2B,QAAQ,MAAM,GAAG,IAAK,CAAC;AAGlE,KAAI,MAAM,cACR,OAAM,eAAe;CAGvB,MAAM,WAAW,MAAM,eAAe,QAAQ;AAK9C,MAHoB,SAAS,QAAQ,IAAI,eAAe,IAAI,IAG5C,SAAS,oBAAoB,EAAE;AAC7C,MAAI,aACF,SAAQ,MAAM,+CAA+C;AAE/D,SAAO,IAAI,SAAS,SAAS,MAAM;GACjC,QAAQ,SAAS;GACjB,SAAS;IACP,gBAAgB;IAChB,iBAAiB;IACjB,YAAY;IACb;GACF,CAAC;;CAIJ,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,KAAI,aACF,SAAQ,MACN,qDACA,KAAK,UAAU,KAAK,CAAC,MAAM,GAAG,IAAK,CACpC;AAEH,QAAO,EAAE,KAAK,MAAM,SAAS,OAAc;;;;;AC3C7C,MAAa,gBAAgB,IAAI,MAAM;AAEvC,cAAc,KAAK,KAAK,OAAO,MAAM;AACnC,KAAI;AACF,SAAO,MAAM,iBAAiB,EAAE;UACzB,OAAO;AACd,SAAO,MAAM,aAAa,GAAG,MAAM;;EAErC;AAEF,cAAc,KAAK,iBAAiB,OAAO,MAAM;AAC/C,KAAI;AACF,SAAO,MAAM,kBAAkB,EAAE;UAC1B,OAAO;AACd,SAAO,MAAM,aAAa,GAAG,MAAM;;EAErC;;;;ACjBF,MAAa,cAAc,IAAI,MAAM;AAErC,YAAY,IAAI,KAAK,OAAO,MAAM;AAChC,KAAI;AACF,MAAI,CAAC,MAAM,OAET,OAAM,aAAa;EAGrB,MAAM,SAAS,MAAM,QAAQ,KAAK,KAAK,WAAW;GAChD,IAAI,MAAM;GACV,QAAQ;GACR,MAAM;GACN,SAAS;GACT,6BAAY,IAAI,KAAK,EAAE,EAAC,aAAa;GACrC,UAAU,MAAM;GAChB,cAAc,MAAM;GACrB,EAAE;AAEH,SAAO,EAAE,KAAK;GACZ,QAAQ;GACR,MAAM;GACN,UAAU;GACX,CAAC;UACK,OAAO;AACd,SAAO,MAAM,aAAa,GAAG,MAAM;;EAErC;;;;AC1BF,MAAa,kBAAkB,OAAO,YAA8B;AAClE,KAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM,0BAA0B;CAEnE,MAAM,eAAe,aAAa,QAAQ,MAAM;CAEhD,MAAM,cAAc,gBAAgB,QAAQ,MAAM;CAElD,MAAMC,UAAkC;EACtC,GAAG,eAAe,OAAO,aAAa;EACtC,eAAe,cAAc,UAAU;EACxC;CAED,MAAM,kBAAkB,uBAAuB,QAAQ;CAEvD,MAAM,WAAW,MAAM,MAAM,GAAG,eAAe,MAAM,CAAC,aAAa;EACjE,QAAQ;EACR;EACA,MAAM,KAAK,UAAU,gBAAgB;EACtC,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;AAChB,UAAQ,MAAM,8BAA8B,SAAS;AACrD,QAAM,IAAI,UAAU,8BAA8B,SAAS;;AAG7D,KAAI,QAAQ,OACV,QAAO,OAAO,SAAS;AAGzB,QAAQ,MAAM,SAAS,MAAM;;AAG/B,SAAS,aAAa,OAA2C;AAC/D,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,CAAC,MAAM,QAAQ,MAAM,CAAE,QAAO;AAElC,QAAO,MAAM,MAAM,SAAS;AAC1B,MAAI,aAAa,QAAQ,MAAM,QAAQ,KAAK,QAAQ,CAClD,QAAO,KAAK,QAAQ,MACjB,SAAkC,KAAK,SAAS,cAClD;AAEH,SAAO;GACP;;AAGJ,SAAS,gBAAgB,OAA2C;AAClE,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,CAAC,MAAM,QAAQ,MAAM,CAAE,QAAO;AAElC,QAAO,MAAM,MAAM,SAAS;AAC1B,MAAI,UAAU,QAAQ,KAAK,SAAS,YAAa,QAAO;AACxD,MACE,UAAU,SACN,KAAK,SAAS,mBAAmB,KAAK,SAAS,wBAEnD,QAAO;AAET,SAAO;GACP;;AAGJ,SAAS,uBAAuB,SAA6C;AAC3E,KAAI,CAAC,QAAQ,SAAS,CAAC,MAAM,QAAQ,QAAQ,MAAM,CAAE,QAAO;CAE5D,MAAM,YAAY,QAAQ,MAAM,QAAQ,SAAS;EAC/C,MAAM,cAAc,KAAK,SAAS;AAClC,MAAI,CAAC,YACH,SAAQ,MAAM,oCAAoC,KAAK,OAAO;AAEhE,SAAO;GACP;CAEF,IAAI,aAAa,QAAQ;AACzB,KAAI,UAAU,WAAW,EACvB,cAAa;UAEb,cACG,OAAO,eAAe,UACzB;EACA,MAAM,iBAAiB,IAAI,IACzB,UAAU,KAAK,SAAS,KAAK,KAAK,CAAC,OAAO,QAAQ,CACnD;EACD,MAAM,iBAAiB,kBAAkB,WAAW;AACpD,MAAI,kBAAkB,CAAC,eAAe,IAAI,eAAe,CACvD,cAAa;;AAIjB,QAAO;EACL,GAAG;EACH,OAAO,UAAU,SAAS,IAAI,YAAY;EAC1C,aAAa;EACd;;AAGH,SAAS,kBACP,YACoB;AACpB,KAAI,OAAO,eAAe,SAAU,QAAO;AAC3C,KACE,cAAc,cACX,WAAW,YACX,OAAO,WAAW,aAAa,SAElC,QAAQ,WAAW,SAA+B;AAEpD,KAAI,UAAU,WACZ,QAAO,WAAW;;;;;AClGtB,eAAsB,gBAAgB,GAAY;AAChD,OAAM,eAAe,MAAM;CAE3B,MAAM,UAAU,MAAM,EAAE,IAAI,MAAwB;CACpD,MAAM,eAAe,QAAQ,SAAS;AACtC,KAAI,aACF,SAAQ,MACN,8BACA,KAAK,UAAU,QAAQ,CAAC,MAAM,KAAK,CACpC;CAGH,MAAM,gBAAgB,MAAM,QAAQ,KAAK,MACtC,UAAU,MAAM,OAAO,QAAQ,MACjC;AAED,SAAQ,KAAK,2DAA2D;AAExE,KAAI,MAAM,cAAe,OAAM,eAAe;AAE9C,OAAM,wBAAwB,QAAQ;AAEtC,KAAI,UAAU,QAAQ,kBAAkB,EAAE;AACxC,UAAQ,oBACN,eAAe,aAAa,OAAO;AACrC,MAAI,aACF,SAAQ,MACN,6BACA,KAAK,UAAU,QAAQ,kBAAkB,CAC1C;;CAIL,MAAM,WAAW,MAAM,gBAAgB,QAAQ;AAE/C,KAAI,eAAe,SAAS,EAAE;AAC5B,MAAI,aACF,SAAQ,MAAM,2BAA2B,KAAK,UAAU,SAAS,CAAC;AAEpE,SAAO,EAAE,KAAK,SAAS;;AAGzB,SAAQ,MAAM,qBAAqB;AACnC,QAAO,UAAU,GAAG,OAAO,WAAW;AACpC,aAAW,MAAM,SAAS,UAAU;AAClC,OAAI,aACF,SAAQ,MAAM,oBAAoB,KAAK,UAAU,MAAM,CAAC;AAG1D,OAAI,MAAM,SAAS,SACjB;AAGF,OAAI,CAAC,MAAM,KACT;AAGF,SAAM,OAAO,SAAS;IACpB,MAAM,MAAM;IACZ,OAAO,MAAM;IACb,IAAI,MAAM,IAAI,UAAU;IACzB,CAAC;;GAEJ;;AAGJ,MAAM,kBACJ,aACqC,OAAO,OAAO,UAAU,SAAS;AAExE,eAAe,wBACb,SACe;AAEf,KAAI,CADiB,QAAQ,OAAO,MAAM,MAAM,EAAE,SAAS,aAAa,CACrD;AAGnB,KAAI,MAAM,QAAQ,QAAQ,MAAM,EAI9B;MAHoB,QAAQ,MAAM,MAC/B,SAA6B,KAAK,SAAS,uBAC7C,CACgB;;CAGnB,MAAM,QAAQ,iBAAiB,QAAQ,MAAM;AAC7C,KAAI,CAAC,MAAO;AAEZ,KAAI;EACF,MAAM,UAAU,MAAM,UAAU,MAAM;EACtC,MAAM,gBAAgB;GACpB;GACA,QAAQ;GACR;GACA,QAAQ,WAAW,KAAK,MAAM,MAAM,EAAE,MAAM,IAAI,EAAE,IAAI,GAAG,CAAC,KAAK,KAAK;GACpE;GACD,CAAC,KAAK,KAAK;AAEZ,UAAQ,eACN,QAAQ,eACN,GAAG,cAAc,MAAM,QAAQ,iBAC/B;UACG,OAAO;AACd,UAAQ,KAAK,kDAAkD,MAAM;;;AAIzE,SAAS,iBACP,OACoB;AACpB,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,CAAC,MAAM,QAAQ,MAAM,CAAE,QAAO;AAGlC,MAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;EAC1C,MAAM,OAAO,MAAM;AACnB,MAAI,UAAU,QAAQ,KAAK,SAAS,QAAQ;AAC1C,OAAI,OAAO,KAAK,YAAY,SAAU,QAAO,KAAK;AAClD,OAAI,MAAM,QAAQ,KAAK,QAAQ,EAAE;IAC/B,MAAM,OAAO,KAAK,QAAQ,MACvB,MAA+B,EAAE,SAAS,aAC5C;AACD,QAAI,QAAQ,UAAU,KAAM,QAAO,KAAK;;;;;;;;ACpIhD,MAAa,kBAAkB,IAAI,MAAM;AAEzC,gBAAgB,KAAK,KAAK,OAAO,MAAM;AACrC,KAAI;AACF,SAAO,MAAM,gBAAgB,EAAE;UACxB,OAAO;AACd,SAAO,MAAM,aAAa,GAAG,MAAM;;EAErC;;;;ACTF,MAAa,eAAe,IAAI,MAAM;AAEtC,aAAa,KAAK,KAAK,OAAO,MAAM;AAClC,KAAI;EACF,MAAM,EAAE,UAAU,MAAM,EAAE,IAAI,MAAyB;AAEvD,MAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO,EAAE,KACP,EAAE,OAAO,EAAE,SAAS,iCAAiC,EAAE,EACvD,IACD;EAGH,MAAM,UAAU,MAAM,UAAU,MAAM;AACtC,SAAO,EAAE,KAAK,EAAE,SAAS,CAAC;UACnB,OAAO;AACd,SAAO,MAAM,aAAa,GAAG,MAAM;;EAErC;;;;ACnBF,MAAa,aAAa,IAAI,MAAM;AAEpC,WAAW,IAAI,MAAM,MAAM;AACzB,KAAI,CAAC,MAAM,UACT,QAAO,EAAE,KACP,EAAE,OAAO;EAAE,SAAS;EAA2B,MAAM;EAAS,EAAE,EAChE,IACD;AAGH,QAAO,EAAE,KAAK,EACZ,OAAO,MAAM,cACd,CAAC;EACF;;;;ACXF,MAAa,aAAa,IAAI,MAAM;AAEpC,WAAW,IAAI,KAAK,OAAO,MAAM;AAC/B,KAAI;EACF,MAAM,QAAQ,MAAM,iBAAiB;AACrC,SAAO,EAAE,KAAK,MAAM;UACb,OAAO;AACd,UAAQ,MAAM,iCAAiC,MAAM;AACrD,SAAO,MAAM,aAAa,GAAG,MAAM;;EAErC;;;;ACHF,MAAa,SAAS,IAAI,MAAM;AAEhC,OAAO,IAAI,QAAQ,CAAC;AACpB,OAAO,IAAI,MAAM,CAAC;AAElB,OAAO,IAAI,MAAM,MAAM,EAAE,KAAK,iBAAiB,CAAC;AAEhD,OAAO,MAAM,qBAAqB,iBAAiB;AACnD,OAAO,MAAM,cAAc,gBAAgB;AAC3C,OAAO,MAAM,WAAW,YAAY;AACpC,OAAO,MAAM,eAAe,gBAAgB;AAC5C,OAAO,MAAM,WAAW,aAAa;AACrC,OAAO,MAAM,UAAU,WAAW;AAClC,OAAO,MAAM,UAAU,WAAW;AAGlC,OAAO,MAAM,wBAAwB,iBAAiB;AACtD,OAAO,MAAM,iBAAiB,gBAAgB;AAC9C,OAAO,MAAM,cAAc,YAAY;AACvC,OAAO,MAAM,kBAAkB,gBAAgB;AAC/C,OAAO,MAAM,cAAc,aAAa;AAGxC,OAAO,MAAM,gBAAgB,cAAc;;;;ACL3C,MAAM,sBAAsB,IAAI,IAAI;CAAC;CAAc;CAAY;CAAa,CAAC;AAE7E,SAAS,oBAAoB,SAAiB,OAAqB;AACjE,SAAQ,IAAI,GAAG,MAAM,MAAM,UAAU;AACrC,KAAI;AACF,YAAU,UAAU,QAAQ;AAC5B,UAAQ,QAAQ,UAAU,MAAM,wBAAwB;SAClD;AACN,UAAQ,KAAK,gEAAgE;;;AAIjF,SAAS,uBACP,QACA,UACc;CACd,MAAM,WAAW,OAAO,QAAQ,UAAU;EACxC,MAAM,YAAY,MAAM;AAExB,MAAI,CAAC,aAAa,UAAU,WAAW,EAAG,QAAO;AACjD,SAAO,UAAU,MAAM,UAAU;AAE/B,UADmB,MAAM,QAAQ,YAAY,GAAG,CAAC,QAAQ,OAAO,GAAG,KAC7C;IACtB;GACF;AAEF,QAAO,SAAS,SAAS,IAAI,WAAW;;AAG1C,eAAe,0BAA0B,WAAmB;AAC1D,WAAU,MAAM,QAAQ,iCAAiC;CAEzD,MAAM,kBAAkB,uBACtB,MAAM,OAAO,MACb,cACD;CAED,MAAM,gBAAgB,MAAM,QAAQ,OAClC,0CACA;EACE,MAAM;EACN,SAAS,gBAAgB,KAAK,UAAU,MAAM,GAAG;EAClD,CACF;CAED,MAAM,qBAAqB,MAAM,QAAQ,OACvC,gDACA;EACE,MAAM;EACN,SAAS,gBAAgB,KAAK,UAAU,MAAM,GAAG;EAClD,CACF;AAiBD,qBAfgB,kBACd;EACE,oBAAoB;EACpB,mBAAmB;EACnB,sBAAsB;EACtB,iBAAiB;EACjB,gCAAgC;EAChC,4BAA4B;EAC5B,+BAA+B;EAC/B,mCAAmC;EACnC,0CAA0C;EAC3C,EACD,SACD,EAE4B,cAAc;;AAG7C,eAAe,qBAAqB,WAAmB;AACrD,WAAU,MAAM,QAAQ,iCAAiC;CAEzD,MAAM,kBAAkB,uBACtB,MAAM,OAAO,MACb,YACD;CAED,MAAM,oBAAoB,gBAAgB,MACvC,UAAU,MAAM,OAAO,eACzB;CAED,MAAM,gBACJ,oBACE,kBAAkB,KAClB,MAAM,QAAQ,OAAO,wCAAwC;EAC3D,MAAM;EACN,SAAS,gBAAgB,KAAK,UAAU,MAAM,GAAG;EAClD,CAAC;CAEN,MAAM,cAAc,KAAK,UAAU,cAAc;AASjD,qBARgB,kBACd;EACE,iBAAiB,GAAG,UAAU;EAC9B,gBAAgB;EACjB,EACD,YAAY,cACb,EAE4B,YAAY;;AAG3C,eAAsB,UAAU,SAA0C;AACxE,KAAI,QAAQ,SACV,mBAAkB;AAGpB,KAAI,QAAQ,SAAS;AACnB,UAAQ,QAAQ;AAChB,UAAQ,KAAK,0BAA0B;;AAGzC,OAAM,cAAc,QAAQ;AAC5B,KAAI,QAAQ,gBAAgB,aAC1B,SAAQ,KAAK,SAAS,QAAQ,YAAY,sBAAsB;AAGlE,OAAM,gBAAgB,QAAQ;AAC9B,OAAM,mBAAmB,QAAQ;AACjC,OAAM,gBAAgB,QAAQ;AAC9B,OAAM,YAAY,QAAQ;AAE1B,OAAM,aAAa;AACnB,OAAM,oBAAoB;AAE1B,KAAI,QAAQ,aAAa;AACvB,QAAM,cAAc,QAAQ;AAC5B,UAAQ,KAAK,8BAA8B;OAE3C,OAAM,kBAAkB;AAG1B,OAAM,mBAAmB;AACzB,OAAM,aAAa;AAEnB,SAAQ,KACN,uBAAuB,MAAM,QAAQ,KAAK,KAAK,UAAU,KAAK,MAAM,KAAK,CAAC,KAAK,KAAK,GACrF;CAED,MAAM,YAAY,oBAAoB,QAAQ;AAE9C,KAAI,QAAQ,WAAY,OAAM,0BAA0B,UAAU;AAClE,KAAI,QAAQ,MAAO,OAAM,qBAAqB,UAAU;AAExD,SAAQ,IACN,yFAAyF,UAAU,QACpG;AAED,OAAM;EACJ,OAAO,OAAO;EACd,UAAU;EACV,MAAM,QAAQ;EACf,CAAC;;AAGJ,MAAa,QAAQ,cAAc;CACjC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,MAAM;GACJ,OAAO;GACP,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACD,SAAS;GACP,OAAO;GACP,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACD,gBAAgB;GACd,OAAO;GACP,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACD,QAAQ;GACN,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACD,cAAc;GACZ,OAAO;GACP,MAAM;GACN,aAAa;GACd;EACD,MAAM;GACJ,OAAO;GACP,MAAM;GACN,SAAS;GACT,aACE;GACH;EACD,gBAAgB;GACd,OAAO;GACP,MAAM;GACN,aACE;GACH;EACD,eAAe;GACb,OAAO;GACP,MAAM;GACN,SAAS;GACT,aACE;GACH;EACD,OAAO;GACL,MAAM;GACN,SAAS;GACT,aACE;GACH;EACD,cAAc;GACZ,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACD,aAAa;GACX,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACF;CACD,IAAI,EAAE,QAAQ;EACZ,MAAM,eAAe,KAAK;EAC1B,IAAIC;AACJ,MAAI,iBAAiB,QAAW;AAC9B,eAAY,OAAO,SAAS,cAAc,GAAG;AAC7C,OAAI,OAAO,MAAM,UAAU,IAAI,aAAa,EAC1C,OAAM,IAAI,MAAM,kDAAkD;;EAItE,MAAM,OAAO,OAAO,SAAS,KAAK,MAAM,GAAG;AAC3C,MAAI,OAAO,MAAM,KAAK,IAAI,QAAQ,KAAK,OAAO,MAC5C,OAAM,IAAI,MAAM,6CAA6C;EAG/D,MAAM,cAAc,KAAK;AACzB,MAAI,CAAC,oBAAoB,IAAI,YAAY,CACvC,OAAM,IAAI,MACR,qEACD;EAGH,MAAM,gBAAgB,KAAK,QAAQ,cAAc;AACjD,MAAI,KAAK,QAAQ,cAAc,OAC7B,SAAQ,KAAK,yDAAyD;EAGxE,MAAM,cAAc,KAAK,mBAAmB,QAAQ,IAAI;AAExD,SAAO,UAAU;GACf;GACA,SAAS,KAAK;GACd;GACA,QAAQ,KAAK;GACb;GACA;GACA;GACA,YAAY,KAAK;GACjB,OAAO,KAAK;GACZ,WAAW,KAAK;GAChB,UAAU,KAAK;GAChB,CAAC;;CAEL,CAAC;;;;AC3RF,MAAM,QATO,cAAc;CACzB,MAAM;EACJ,MAAM;EACN,aACE;EACH;CACD,aAAa;EAAE;EAAM;EAAO,eAAe;EAAY;EAAO;CAC/D,CAAC,CAEiB"}
|
|
1
|
+
{"version":3,"file":"main.js","names":["state: State","state","headers: Record<string, string>","errorJson: unknown","token","process","commandBlock: string","state","x","headers: Record<string, string>","searchTimestamps: Array<number>","references: Array<{ title: string; url: string }>","handleCompletion","injectWebSearchIfNeeded","isNonStreaming","extractUserQuery","handleCompletion","isWebSearchTool","body: AnyRecord","extraHeaders: Record<string, string>","headers: Record<string, string>","extractUserQuery","body: AnyRecord","headers: Record<string, string>","rateLimit: number | undefined"],"sources":["../src/lib/paths.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts","../src/auth.ts","../src/services/github/get-copilot-usage.ts","../src/check-usage.ts","../src/debug.ts","../src/lib/proxy.ts","../src/lib/shell.ts","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/tokenizer.ts","../src/services/copilot/create-chat-completions.ts","../src/services/copilot/web-search.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/services/copilot/create-messages.ts","../src/routes/messages/count-tokens-handler.ts","../src/routes/messages/handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/services/copilot/create-responses.ts","../src/routes/responses/handler.ts","../src/routes/responses/route.ts","../src/routes/search/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst APP_DIR = path.join(os.homedir(), \".local\", \"share\", \"github-router\")\n\nconst GITHUB_TOKEN_PATH = path.join(APP_DIR, \"github_token\")\n\nexport const PATHS = {\n APP_DIR,\n GITHUB_TOKEN_PATH,\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: string\n models?: ModelsResponse\n vsCodeVersion?: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n\n // Persistent session identifiers to match VS Code fingerprint\n sessionId: string\n machineId: string\n}\n\nexport const state: State = {\n accountType: \"individual\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n sessionId: randomUUID(),\n machineId: randomUUID(),\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.38.2026021302\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\n\nconst API_VERSION = \"2025-05-01\"\n\nexport const copilotBaseUrl = (state: State) =>\n state.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${state.accountType}.githubcopilot.com`\nexport const copilotHeaders = (\n state: State,\n vision: boolean = false,\n integrationId: string = \"vscode-chat\",\n) => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": integrationId,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-panel\",\n \"x-interaction-type\": \"conversation-panel\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": randomUUID(),\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n \"VScode-SessionId\": state.sessionId,\n \"VScode-MachineId\": state.machineId,\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL = \"https://api.github.com\"\nexport const githubHeaders = (state: State) => ({\n ...standardHeaders(),\n authorization: `token ${state.githubToken}`,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"x-github-api-version\": API_VERSION,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport async function forwardError(c: Context, error: unknown) {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n const errorText = await error.response.text()\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = undefined\n }\n const message = resolveErrorMessage(errorJson, errorText)\n consola.error(\"HTTP error:\", errorJson ?? errorText)\n return c.json(\n {\n error: {\n message,\n type: \"error\",\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n error: {\n message: error instanceof Error ? error.message : String(error),\n type: \"error\",\n },\n },\n 500,\n )\n}\n\n// Extracts error message from { message } or { error: { message } } payloads.\nfunction resolveErrorMessage(errorJson: unknown, fallback: string): string {\n if (typeof errorJson !== \"object\" || errorJson === null) return fallback\n\n const errorRecord = errorJson as Record<string, unknown>\n if (errorRecord.message !== undefined) return String(errorRecord.message)\n\n if (typeof errorRecord.error === \"object\" && errorRecord.error !== null) {\n const nestedRecord = errorRecord.error as Record<string, unknown>\n if (nestedRecord.message !== undefined) return String(nestedRecord.message)\n }\n\n return fallback\n}\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotToken = async () => {\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(state),\n },\n )\n\n if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n return (await response.json()) as GetCopilotTokenResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n}\n","import {\n GITHUB_APP_SCOPES,\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n scope: GITHUB_APP_SCOPES,\n }),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\n ...standardHeaders(),\n },\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n headers: copilotHeaders(state),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n return (await response.json()) as ModelsResponse\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n}\n\ninterface ModelSupports {\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\nexport interface Model {\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n supported_endpoints?: Array<string>\n policy?: {\n state: string\n terms: string\n }\n}\n","const FALLBACK = \"1.104.3\"\n\nexport async function getVSCodeVersion() {\n const controller = new AbortController()\n const timeout = setTimeout(() => {\n controller.abort()\n }, 5000)\n\n try {\n const response = await fetch(\n \"https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin\",\n {\n signal: controller.signal,\n },\n )\n\n const pkgbuild = await response.text()\n const pkgverRegex = /pkgver=([0-9.]+)/\n const match = pkgbuild.match(pkgverRegex)\n\n if (match) {\n return match[1]\n }\n\n return FALLBACK\n } catch {\n return FALLBACK\n } finally {\n clearTimeout(timeout)\n }\n}\n\nawait getVSCodeVersion()\n","import consola from \"consola\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\n/**\n * Beta values that VS Code Copilot Chat actually sends to the Copilot API.\n * Only these are forwarded; everything else (e.g. context-1m-*) is stripped\n * so our requests match what VS Code produces.\n */\nconst ALLOWED_BETA_PREFIXES = [\n \"interleaved-thinking-\",\n \"context-management-\",\n \"advanced-tool-use-\",\n \"token-counting-\",\n]\n\n/**\n * Filter an `anthropic-beta` header value, keeping only beta flags that\n * VS Code Copilot is known to send. Returns the filtered comma-separated\n * string, or undefined if nothing remains.\n */\nexport function filterBetaHeader(value: string): string | undefined {\n const filtered = value\n .split(\",\")\n .map((v) => v.trim())\n .filter(\n (v) =>\n v && ALLOWED_BETA_PREFIXES.some((prefix) => v.startsWith(prefix)),\n )\n .join(\",\")\n return filtered || undefined\n}\n\nexport async function cacheModels(): Promise<void> {\n const models = await getModels()\n state.models = models\n}\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n","import consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n): Promise<string> {\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n const expiresAt = Date.now() + deviceCode.expires_in * 1000\n\n while (Date.now() < expiresAt) {\n const response = await fetch(\n `${GITHUB_BASE_URL}/login/oauth/access_token`,\n {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to poll access token:\", await response.text())\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n }\n\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n }\n\n throw new Error(\"Device code expired. Please run auth again.\")\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nexport const setupCopilotToken = async () => {\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n\n // Display the Copilot token to the screen\n consola.debug(\"GitHub Copilot Token fetched successfully!\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", token)\n }\n\n const refreshInterval = Math.max((refresh_in - 60) * 1000, 1000)\n setInterval(async () => {\n consola.debug(\"Refreshing Copilot token\")\n try {\n const { token } = await getCopilotToken()\n state.copilotToken = token\n consola.debug(\"Copilot token refreshed\")\n if (state.showToken) {\n consola.info(\"Refreshed Copilot token:\", token)\n }\n } catch (error) {\n consola.error(\"Failed to refresh Copilot token:\", error)\n }\n }, refreshInterval)\n}\n\ninterface SetupGitHubTokenOptions {\n force?: boolean\n}\n\nexport async function setupGitHubToken(\n options?: SetupGitHubTokenOptions,\n): Promise<void> {\n try {\n const githubToken = await readGithubToken()\n\n if (githubToken && !options?.force) {\n state.githubToken = githubToken\n if (state.showToken) {\n consola.info(\"GitHub token:\", githubToken)\n }\n await logUser()\n\n return\n }\n\n consola.info(\"Not logged in, getting new access token\")\n const response = await getDeviceCode()\n consola.debug(\"Device code response:\", response)\n\n consola.info(\n `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n )\n\n const token = await pollAccessToken(response)\n await writeGithubToken(token)\n state.githubToken = token\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n await logUser()\n } catch (error) {\n if (error instanceof HTTPError) {\n consola.error(\"Failed to get GitHub token:\", await error.response.json())\n throw error\n }\n\n consola.error(\"Failed to get GitHub token:\", error)\n throw error\n }\n}\n\nasync function logUser() {\n const user = await getGitHubUser()\n consola.info(`Logged in as ${user.login}`)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n verbose: boolean\n showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub auth flow without running the server\",\n },\n args: {\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub token on auth\",\n },\n },\n run({ args }) {\n return runAuth({\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n headers: githubHeaders(state),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot usage\", response)\n }\n\n return (await response.json()) as CopilotUsageResponse\n}\n\nexport interface QuotaDetail {\n entitlement: number\n overage_count: number\n overage_permitted: boolean\n percent_remaining: number\n quota_id: string\n quota_remaining: number\n remaining: number\n unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n chat: QuotaDetail\n completions: QuotaDetail\n premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n access_type_sku: string\n analytics_tracking_id: string\n assigned_date: string\n can_signup_for_limited: boolean\n chat_enabled: boolean\n copilot_plan: string\n organization_login_list: Array<unknown>\n organization_list: Array<unknown>\n quota_reset_date: string\n quota_snapshots: QuotaSnapshots\n}\n","import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n getCopilotUsage,\n type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n meta: {\n name: \"check-usage\",\n description: \"Show current GitHub Copilot usage/quota information\",\n },\n async run() {\n await ensurePaths()\n await setupGitHubToken()\n try {\n const usage = await getCopilotUsage()\n const premium = usage.quota_snapshots.premium_interactions\n const premiumTotal = premium.entitlement\n const premiumUsed = premiumTotal - premium.remaining\n const premiumPercentUsed =\n premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n const premiumPercentRemaining = premium.percent_remaining\n\n // Helper to summarize a quota snapshot\n function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n if (!snap) return `${name}: N/A`\n const total = snap.entitlement\n const used = total - snap.remaining\n const percentUsed = total > 0 ? (used / total) * 100 : 0\n const percentRemaining = snap.percent_remaining\n return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n }\n\n const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n const completionsLine = summarizeQuota(\n \"Completions\",\n usage.quota_snapshots.completions,\n )\n\n consola.box(\n `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n + `Quota resets: ${usage.quota_reset_date}\\n`\n + `\\nQuotas:\\n`\n + ` ${premiumLine}\\n`\n + ` ${chatLine}\\n`\n + ` ${completionsLine}`,\n )\n } catch (err) {\n consola.error(\"Failed to fetch Copilot usage:\", err)\n process.exit(1)\n }\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\n\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n version: string\n runtime: {\n name: string\n version: string\n platform: string\n arch: string\n }\n paths: {\n APP_DIR: string\n GITHUB_TOKEN_PATH: string\n }\n tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n try {\n const packageJsonPath = new URL(\"../package.json\", import.meta.url).pathname\n // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n // JSON.parse() can actually parse buffers\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath)) as {\n version: string\n }\n return packageJson.version\n } catch {\n return \"unknown\"\n }\n}\n\nfunction getRuntimeInfo() {\n const isBun = typeof Bun !== \"undefined\"\n\n return {\n name: isBun ? \"bun\" : \"node\",\n version: isBun ? Bun.version : process.version.slice(1),\n platform: os.platform(),\n arch: os.arch(),\n }\n}\n\nasync function checkTokenExists(): Promise<boolean> {\n try {\n const stats = await fs.stat(PATHS.GITHUB_TOKEN_PATH)\n if (!stats.isFile()) return false\n\n const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n return content.trim().length > 0\n } catch {\n return false\n }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n const [version, tokenExists] = await Promise.all([\n getPackageVersion(),\n checkTokenExists(),\n ])\n\n return {\n version,\n runtime: getRuntimeInfo(),\n paths: {\n APP_DIR: PATHS.APP_DIR,\n GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n },\n tokenExists,\n }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n consola.info(`github-router debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nToken exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n const debugInfo = await getDebugInfo()\n\n if (options.json) {\n printDebugInfoJson(debugInfo)\n } else {\n printDebugInfoPlain(debugInfo)\n }\n}\n\nexport const debug = defineCommand({\n meta: {\n name: \"debug\",\n description: \"Print debug information about the application\",\n },\n args: {\n json: {\n type: \"boolean\",\n default: false,\n description: \"Output debug information as JSON\",\n },\n },\n run({ args }) {\n return runDebug({\n json: args.json,\n })\n },\n})\n","import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nexport function initProxyFromEnv(): void {\n if (typeof Bun !== \"undefined\") return\n\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\n}\n","import process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n const { platform, env } = process\n\n if (platform === \"win32\") {\n // Git Bash / MSYS2 / Cygwin set SHELL even on Windows\n if (env.SHELL) {\n if (env.SHELL.endsWith(\"zsh\")) return \"zsh\"\n if (env.SHELL.endsWith(\"fish\")) return \"fish\"\n if (env.SHELL.endsWith(\"bash\")) return \"bash\"\n return \"sh\"\n }\n\n // Windows PowerShell 5.x sets this\n if (env.POWERSHELL_DISTRIBUTION_CHANNEL) return \"powershell\"\n\n // PowerShell (both 5.x and 7+/pwsh) adds user-scoped module paths\n // at runtime. The system-level PSModulePath in CMD lacks these paths.\n if (env.PSModulePath) {\n const lower = env.PSModulePath.toLowerCase()\n if (\n lower.includes(\"documents\\\\powershell\")\n || lower.includes(\"documents\\\\windowspowershell\")\n ) {\n return \"powershell\"\n }\n }\n\n return \"cmd\"\n }\n\n const shellPath = env.SHELL\n if (shellPath) {\n if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n if (shellPath.endsWith(\"fish\")) return \"fish\"\n if (shellPath.endsWith(\"bash\")) return \"bash\"\n }\n\n return \"sh\"\n}\n\nfunction quotePosixValue(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`\n}\n\nfunction quotePowerShellValue(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n envVars: EnvVars,\n commandToRun: string = \"\",\n): string {\n const shell = getShell()\n const filteredEnvVars = Object.entries(envVars).filter(\n ([, value]) => value !== undefined,\n ) as Array<[string, string]>\n\n let commandBlock: string\n\n switch (shell) {\n case \"powershell\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `$env:${key} = ${quotePowerShellValue(value)}`)\n .join(\"; \")\n break\n }\n case \"cmd\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set \"${key}=${value}\"`)\n .join(\" & \")\n break\n }\n case \"fish\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set -gx ${key} ${quotePosixValue(value)}`)\n .join(\"; \")\n break\n }\n default: {\n // bash, zsh, sh\n const assignments = filteredEnvVars\n .map(([key, value]) => `${key}=${quotePosixValue(value)}`)\n .join(\" \")\n commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n break\n }\n }\n\n if (commandBlock && commandToRun) {\n const separator =\n shell === \"cmd\" ? \" & \" : shell === \"powershell\" ? \"; \" : \" && \"\n return `${commandBlock}${separator}${commandToRun}`\n }\n\n return commandBlock || commandToRun\n}\n","import consola from \"consola\"\n\nimport { HTTPError } from \"./error\"\n\nexport const awaitApproval = async () => {\n const response = await consola.prompt(`Accept incoming request?`, {\n type: \"confirm\",\n })\n\n if (!response)\n throw new HTTPError(\n \"Request rejected by user\",\n Response.json({ message: \"Request rejected by user\" }, { status: 403 }),\n )\n}\n","import consola from \"consola\"\n\nimport type { State } from \"./state\"\n\nimport { HTTPError } from \"./error\"\nimport { sleep } from \"./utils\"\n\nexport async function checkRateLimit(state: State) {\n if (state.rateLimitSeconds === undefined) return\n\n const now = Date.now()\n\n if (!state.lastRequestTimestamp) {\n state.lastRequestTimestamp = now\n return\n }\n\n const elapsedSeconds = (now - state.lastRequestTimestamp) / 1000\n\n if (elapsedSeconds > state.rateLimitSeconds) {\n state.lastRequestTimestamp = now\n return\n }\n\n const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)\n\n if (!state.rateLimitWait) {\n consola.warn(\n `Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,\n )\n throw new HTTPError(\n \"Rate limit exceeded\",\n Response.json({ message: \"Rate limit exceeded\" }, { status: 429 }),\n )\n }\n\n const waitTimeMs = waitTimeSeconds * 1000\n consola.warn(\n `Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,\n )\n await sleep(waitTimeMs)\n state.lastRequestTimestamp = Date.now()\n consola.info(\"Rate limit wait completed, proceeding with request\")\n return\n}\n","import type {\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\n// Encoder type mapping\nconst ENCODING_MAP = {\n o200k_base: () => import(\"gpt-tokenizer/encoding/o200k_base\"),\n cl100k_base: () => import(\"gpt-tokenizer/encoding/cl100k_base\"),\n p50k_base: () => import(\"gpt-tokenizer/encoding/p50k_base\"),\n p50k_edit: () => import(\"gpt-tokenizer/encoding/p50k_edit\"),\n r50k_base: () => import(\"gpt-tokenizer/encoding/r50k_base\"),\n} as const\n\ntype SupportedEncoding = keyof typeof ENCODING_MAP\n\n// Define encoder interface\ninterface Encoder {\n encode: (text: string) => Array<number>\n}\n\n// Cache loaded encoders to avoid repeated imports\nconst encodingCache = new Map<string, Encoder>()\n\n/**\n * Calculate tokens for tool calls\n */\nconst calculateToolCallsTokens = (\n toolCalls: Array<ToolCall>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = 0\n for (const toolCall of toolCalls) {\n tokens += constants.funcInit\n tokens += encoder.encode(JSON.stringify(toolCall)).length\n }\n tokens += constants.funcEnd\n return tokens\n}\n\n/**\n * Calculate tokens for content parts\n */\nconst calculateContentPartsTokens = (\n contentParts: Array<ContentPart>,\n encoder: Encoder,\n): number => {\n let tokens = 0\n for (const part of contentParts) {\n if (part.type === \"image_url\") {\n tokens += encoder.encode(part.image_url.url).length + 85\n } else if (part.text) {\n tokens += encoder.encode(part.text).length\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens for a single message\n */\nconst calculateMessageTokens = (\n message: Message,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n const tokensPerMessage = 3\n const tokensPerName = 1\n let tokens = tokensPerMessage\n for (const [key, value] of Object.entries(message)) {\n if (typeof value === \"string\") {\n tokens += encoder.encode(value).length\n }\n if (key === \"name\") {\n tokens += tokensPerName\n }\n if (key === \"tool_calls\") {\n tokens += calculateToolCallsTokens(\n value as Array<ToolCall>,\n encoder,\n constants,\n )\n }\n if (key === \"content\" && Array.isArray(value)) {\n tokens += calculateContentPartsTokens(\n value as Array<ContentPart>,\n encoder,\n )\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens using custom algorithm\n */\nconst calculateTokens = (\n messages: Array<Message>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (messages.length === 0) {\n return 0\n }\n let numTokens = 0\n for (const message of messages) {\n numTokens += calculateMessageTokens(message, encoder, constants)\n }\n // every reply is primed with <|start|>assistant<|message|>\n numTokens += 3\n return numTokens\n}\n\n/**\n * Get the corresponding encoder module based on encoding type\n */\nconst getEncodeChatFunction = async (encoding: string): Promise<Encoder> => {\n if (encodingCache.has(encoding)) {\n const cached = encodingCache.get(encoding)\n if (cached) {\n return cached\n }\n }\n\n const supportedEncoding = encoding as SupportedEncoding\n if (!(supportedEncoding in ENCODING_MAP)) {\n const fallbackModule = (await ENCODING_MAP.o200k_base()) as Encoder\n encodingCache.set(encoding, fallbackModule)\n return fallbackModule\n }\n\n const encodingModule = (await ENCODING_MAP[supportedEncoding]()) as Encoder\n encodingCache.set(encoding, encodingModule)\n return encodingModule\n}\n\n/**\n * Get tokenizer type from model information\n */\nexport const getTokenizerFromModel = (model: Model): string => {\n return model.capabilities.tokenizer || \"o200k_base\"\n}\n\n/**\n * Get model-specific constants for token calculation\n */\nconst getModelConstants = (model: Model) => {\n return model.id === \"gpt-3.5-turbo\" || model.id === \"gpt-4\" ?\n {\n funcInit: 10,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n : {\n funcInit: 7,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n}\n\n/**\n * Calculate tokens for a single parameter\n */\nconst calculateParameterTokens = (\n key: string,\n prop: unknown,\n context: {\n encoder: Encoder\n constants: ReturnType<typeof getModelConstants>\n },\n): number => {\n const { encoder, constants } = context\n let tokens = constants.propKey\n\n // Early return if prop is not an object\n if (typeof prop !== \"object\" || prop === null) {\n return tokens\n }\n\n // Type assertion for parameter properties\n const param = prop as {\n type?: string\n description?: string\n enum?: Array<unknown>\n [key: string]: unknown\n }\n\n const paramName = key\n const paramType = param.type || \"string\"\n let paramDesc = param.description || \"\"\n\n // Handle enum values\n if (param.enum && Array.isArray(param.enum)) {\n tokens += constants.enumInit\n for (const item of param.enum) {\n tokens += constants.enumItem\n tokens += encoder.encode(String(item)).length\n }\n }\n\n // Clean up description\n if (paramDesc.endsWith(\".\")) {\n paramDesc = paramDesc.slice(0, -1)\n }\n\n // Encode the main parameter line\n const line = `${paramName}:${paramType}:${paramDesc}`\n tokens += encoder.encode(line).length\n\n // Handle additional properties (excluding standard ones)\n const excludedKeys = new Set([\"type\", \"description\", \"enum\"])\n for (const propertyName of Object.keys(param)) {\n if (!excludedKeys.has(propertyName)) {\n const propertyValue = param[propertyName]\n const propertyText =\n typeof propertyValue === \"string\" ? propertyValue : (\n JSON.stringify(propertyValue)\n )\n tokens += encoder.encode(`${propertyName}:${propertyText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for function parameters\n */\nconst calculateParametersTokens = (\n parameters: unknown,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (!parameters || typeof parameters !== \"object\") {\n return 0\n }\n\n const params = parameters as Record<string, unknown>\n let tokens = 0\n\n for (const [key, value] of Object.entries(params)) {\n if (key === \"properties\") {\n const properties = value as Record<string, unknown>\n if (Object.keys(properties).length > 0) {\n tokens += constants.propInit\n for (const propKey of Object.keys(properties)) {\n tokens += calculateParameterTokens(propKey, properties[propKey], {\n encoder,\n constants,\n })\n }\n }\n } else {\n const paramText =\n typeof value === \"string\" ? value : JSON.stringify(value)\n tokens += encoder.encode(`${key}:${paramText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for a single tool\n */\nconst calculateToolTokens = (\n tool: Tool,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = constants.funcInit\n const func = tool.function\n const fName = func.name\n let fDesc = func.description || \"\"\n if (fDesc.endsWith(\".\")) {\n fDesc = fDesc.slice(0, -1)\n }\n const line = fName + \":\" + fDesc\n tokens += encoder.encode(line).length\n if (\n typeof func.parameters === \"object\" \n && func.parameters !== null\n ) {\n tokens += calculateParametersTokens(func.parameters, encoder, constants)\n }\n return tokens\n}\n\n/**\n * Calculate token count for tools based on model\n */\nexport const numTokensForTools = (\n tools: Array<Tool>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let funcTokenCount = 0\n for (const tool of tools) {\n funcTokenCount += calculateToolTokens(tool, encoder, constants)\n }\n funcTokenCount += constants.funcEnd\n return funcTokenCount\n}\n\n/**\n * Calculate the token count of messages, supporting multiple GPT encoders\n */\nexport const getTokenCount = async (\n payload: ChatCompletionsPayload,\n model: Model,\n): Promise<{ input: number; output: number }> => {\n // Get tokenizer string\n const tokenizer = getTokenizerFromModel(model)\n\n // Get corresponding encoder module\n const encoder = await getEncodeChatFunction(tokenizer)\n\n const simplifiedMessages = payload.messages\n const inputMessages = simplifiedMessages.filter(\n (msg) => msg.role !== \"assistant\",\n )\n const outputMessages = simplifiedMessages.filter(\n (msg) => msg.role === \"assistant\",\n )\n\n const constants = getModelConstants(model)\n let inputTokens = calculateTokens(inputMessages, encoder, constants)\n if (payload.tools && payload.tools.length > 0) {\n inputTokens += numTokensForTools(payload.tools, encoder, constants)\n }\n const outputTokens = calculateTokens(outputMessages, encoder, constants)\n\n return {\n input: inputTokens,\n output: outputTokens,\n }\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createChatCompletions = async (\n payload: ChatCompletionsPayload,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = payload.messages.some(\n (x) =>\n typeof x.content !== \"string\"\n && x.content?.some((x) => x.type === \"image_url\"),\n )\n\n // Agent/user check for X-Initiator header\n // Determine if any message is from an agent (\"assistant\" or \"tool\")\n const isAgentCall = payload.messages.some((msg) =>\n [\"assistant\", \"tool\"].includes(msg.role),\n )\n\n // Build headers and add X-Initiator\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"Openai-Organization\": \"github-copilot\",\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n const claudeModels = state.models?.data\n .filter((m) => m.id.startsWith(\"claude\"))\n .map((m) => m.id)\n .join(\", \") ?? \"(models not loaded)\"\n consola.error(\n `Copilot rejected model \"${payload.model}\": ${response.status} ${errorBody} (available Claude models: ${claudeModels})`,\n )\n // Re-create the response so downstream error handlers can still read the body\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Failed to create chat completions\", reconstructed)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n}\n\n// Streaming types\n\nexport interface ChatCompletionChunk {\n id: string\n object: \"chat.completion.chunk\"\n created: number\n model: string\n choices: Array<Choice>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n completion_tokens_details?: {\n accepted_prediction_tokens: number\n rejected_prediction_tokens: number\n }\n }\n}\n\ninterface Delta {\n content?: string | null\n role?: \"user\" | \"assistant\" | \"system\" | \"tool\"\n tool_calls?: Array<{\n index: number\n id?: string\n type?: \"function\"\n function?: {\n name?: string\n arguments?: string\n }\n }>\n}\n\ninterface Choice {\n index: number\n delta: Delta\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null\n logprobs: object | null\n}\n\n// Non-streaming types\n\nexport interface ChatCompletionResponse {\n id: string\n object: \"chat.completion\"\n created: number\n model: string\n choices: Array<ChoiceNonStreaming>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n }\n}\n\ninterface ResponseMessage {\n role: \"assistant\"\n content: string | null\n tool_calls?: Array<ToolCall>\n}\n\ninterface ChoiceNonStreaming {\n index: number\n message: ResponseMessage\n logprobs: object | null\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\"\n}\n\n// Payload types\n\nexport interface ChatCompletionsPayload {\n messages: Array<Message>\n model: string\n temperature?: number | null\n top_p?: number | null\n max_tokens?: number | null\n stop?: string | Array<string> | null\n n?: number | null\n stream?: boolean | null\n\n frequency_penalty?: number | null\n presence_penalty?: number | null\n logit_bias?: Record<string, number> | null\n logprobs?: boolean | null\n response_format?: { type: \"json_object\" } | null\n seed?: number | null\n tools?: Array<Tool> | null\n tool_choice?:\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; function: { name: string } }\n | null\n user?: string | null\n}\n\nexport interface Tool {\n type: \"function\"\n function: {\n name: string\n description?: string\n parameters: Record<string, unknown>\n }\n}\n\nexport interface Message {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\" | \"developer\"\n content: string | Array<ContentPart> | null\n\n name?: string\n tool_calls?: Array<ToolCall>\n tool_call_id?: string\n}\n\nexport interface ToolCall {\n id: string\n type: \"function\"\n function: {\n name: string\n arguments: string\n }\n}\n\nexport type ContentPart = TextPart | ImagePart\n\nexport interface TextPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImagePart {\n type: \"image_url\"\n image_url: {\n url: string\n detail?: \"low\" | \"high\" | \"auto\"\n }\n}\n","import consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { state } from \"~/lib/state\"\nimport { sleep } from \"~/lib/utils\"\n\nexport interface WebSearchResult {\n content: string\n references: Array<{ title: string; url: string }>\n}\n\ninterface ThreadsResponse {\n thread_id: string\n}\n\ninterface ThreadsMessageResponse {\n message: {\n content: string\n references: Array<{\n query?: string\n results?: Array<{\n title: string\n url: string\n reference_type: string\n }>\n }>\n }\n}\n\nconst MAX_SEARCHES_PER_SECOND = 3\nlet searchTimestamps: Array<number> = []\n\nasync function throttleSearch(): Promise<void> {\n const now = Date.now()\n searchTimestamps = searchTimestamps.filter((t) => now - t < 1000)\n if (searchTimestamps.length >= MAX_SEARCHES_PER_SECOND) {\n const waitMs = 1000 - (now - searchTimestamps[0])\n if (waitMs > 0) {\n consola.debug(`Web search rate limited, waiting ${waitMs}ms`)\n await sleep(waitMs)\n }\n }\n searchTimestamps.push(Date.now())\n}\n\nfunction threadsHeaders(): Record<string, string> {\n return copilotHeaders(state, false, \"copilot-chat\")\n}\n\nasync function createThread(): Promise<string> {\n const response = await fetch(`${copilotBaseUrl(state)}/github/chat/threads`, {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({}),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create chat thread\", response.status)\n throw new Error(`Failed to create chat thread: ${response.status}`)\n }\n\n const data = (await response.json()) as ThreadsResponse\n return data.thread_id\n}\n\nasync function sendThreadMessage(\n threadId: string,\n query: string,\n): Promise<ThreadsMessageResponse> {\n const response = await fetch(\n `${copilotBaseUrl(state)}/github/chat/threads/${threadId}/messages`,\n {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({\n content: query,\n intent: \"conversation\",\n skills: [\"web-search\"],\n references: [],\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to send thread message\", response.status)\n throw new Error(`Failed to send thread message: ${response.status}`)\n }\n\n return (await response.json()) as ThreadsMessageResponse\n}\n\nexport async function searchWeb(query: string): Promise<WebSearchResult> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n await throttleSearch()\n\n consola.info(`Web search: \"${query.slice(0, 80)}\"`)\n\n const threadId = await createThread()\n const response = await sendThreadMessage(threadId, query)\n\n const references: Array<{ title: string; url: string }> = []\n for (const ref of response.message.references ?? []) {\n if (ref.results) {\n for (const result of ref.results) {\n if (result.url && result.reference_type !== \"bing_search\") {\n references.push({ title: result.title, url: result.url })\n }\n }\n }\n }\n\n consola.debug(`Web search returned ${references.length} references`)\n\n return {\n content: response.message.content,\n references,\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE, type SSEMessage } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish } from \"~/lib/utils\"\nimport {\n createChatCompletions,\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n type Message,\n} from \"~/services/copilot/create-chat-completions\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n let payload = await c.req.json<ChatCompletionsPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n }\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n // Find the selected model\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n // Calculate and display token count\n try {\n if (selectedModel) {\n const tokenCount = await getTokenCount(payload, selectedModel)\n consola.info(\"Current token count:\", tokenCount)\n } else {\n consola.warn(\"No model selected, skipping token count calculation\")\n }\n } catch (error) {\n consola.warn(\"Failed to calculate token count:\", error)\n }\n\n if (isNullish(payload.max_tokens)) {\n payload = {\n ...payload,\n max_tokens: selectedModel?.capabilities.limits.max_output_tokens,\n }\n if (debugEnabled) {\n consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n }\n }\n\n const response = await createChatCompletions(payload)\n\n if (isNonStreaming(response)) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n consola.debug(\"Streaming response\")\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n await stream.writeSSE(chunk as SSEMessage)\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n\nasync function injectWebSearchIfNeeded(\n payload: ChatCompletionsPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some(\n (t) =>\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\",\n )\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = payload.messages.some((msg) => msg.role === \"tool\")\n const query = hasToolResult ? undefined : extractUserQuery(payload.messages)\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n // Prepend to existing system message or inject a new one\n const systemMsg = payload.messages.find((msg) => msg.role === \"system\")\n if (systemMsg) {\n const existingContent =\n typeof systemMsg.content === \"string\" ? systemMsg.content\n : Array.isArray(systemMsg.content) ?\n systemMsg.content\n .filter((p) => p.type === \"text\")\n .map((p) => (\"text\" in p ? p.text : \"\"))\n .join(\"\\n\")\n : \"\"\n systemMsg.content = `${searchContext}\\n\\n${existingContent}`\n } else {\n payload.messages.unshift({\n role: \"system\",\n content: searchContext,\n })\n }\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Remove web_search from tools before forwarding\n payload.tools = payload.tools?.filter(\n (t) =>\n !(\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\"\n ),\n ) as typeof payload.tools\n if (payload.tools?.length === 0) {\n payload.tools = undefined\n }\n if (!payload.tools) {\n payload.tool_choice = undefined\n } else if (\n payload.tool_choice\n && typeof payload.tool_choice === \"object\"\n && \"type\" in payload.tool_choice\n && payload.tool_choice.type === \"function\"\n ) {\n const toolChoiceName = payload.tool_choice.function?.name\n if (\n toolChoiceName\n && !payload.tools.some((tool) => tool.function.name === toolChoiceName)\n ) {\n payload.tool_choice = undefined\n }\n }\n}\n\nfunction extractUserQuery(messages: Array<Message>): string | undefined {\n // Find the last user message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const text = msg.content.find((p) => p.type === \"text\")\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const completionRoutes = new Hono()\n\ncompletionRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createEmbeddings = async (payload: EmbeddingRequest) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const response = await fetch(`${copilotBaseUrl(state)}/embeddings`, {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to create embeddings\", response)\n\n return (await response.json()) as EmbeddingResponse\n}\n\nexport interface EmbeddingRequest {\n input: string | Array<string>\n model: string\n}\n\nexport interface Embedding {\n object: string\n embedding: Array<number>\n index: number\n}\n\nexport interface EmbeddingResponse {\n object: string\n data: Array<Embedding>\n model: string\n usage: {\n prompt_tokens: number\n total_tokens: number\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport {\n createEmbeddings,\n type EmbeddingRequest,\n} from \"~/services/copilot/create-embeddings\"\n\nexport const embeddingRoutes = new Hono()\n\nembeddingRoutes.post(\"/\", async (c) => {\n try {\n const payload = await c.req.json<EmbeddingRequest>()\n const response = await createEmbeddings(payload)\n\n return c.json(response)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { randomUUID } from \"node:crypto\"\n\nimport consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Build headers that match what VS Code Copilot Chat sends to the Copilot API.\n *\n * copilotHeaders() provides: Authorization, content-type, copilot-integration-id,\n * editor-version, editor-plugin-version, user-agent, openai-intent,\n * x-github-api-version, x-request-id, x-vscode-user-agent-library-version.\n *\n * We add the remaining headers VS Code sends for /v1/messages:\n * - X-Initiator (VS Code sets dynamically; \"agent\" is safe for CLI use)\n * - anthropic-version (VS Code's Anthropic SDK sends this)\n * - X-Interaction-Id (VS Code sends a session-scoped UUID)\n *\n * We intentionally omit copilot-vision-request — VS Code only sends it when\n * images are present, and the native /v1/messages endpoint handles vision\n * without requiring the header.\n *\n * extraHeaders allows callers to forward client-supplied beta headers\n * (anthropic-beta) so Copilot enables extended features.\n */\nfunction buildHeaders(\n extraHeaders?: Record<string, string>,\n): Record<string, string> {\n return {\n ...copilotHeaders(state),\n \"X-Initiator\": \"agent\",\n \"anthropic-version\": \"2023-06-01\",\n \"X-Interaction-Id\": randomUUID(),\n ...extraHeaders,\n }\n}\n\n/**\n * Forward an Anthropic Messages API request to Copilot's native /v1/messages endpoint.\n * Returns the raw Response so callers can handle streaming vs non-streaming.\n */\nexport async function createMessages(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot /v1/messages error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot messages request failed\", reconstructed)\n }\n\n return response\n}\n\n/**\n * Forward an Anthropic count_tokens request to Copilot's native endpoint.\n * Returns the raw Response.\n */\nexport async function countTokens(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages/count_tokens?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot count_tokens error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot count_tokens request failed\", reconstructed)\n }\n\n return response\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { filterBetaHeader } from \"~/lib/utils\"\nimport { countTokens } from \"~/services/copilot/create-messages\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Strip web_search tools from the request body before forwarding\n * to Copilot's count_tokens endpoint, which rejects unknown tool types.\n * Returns the original raw body if no web_search tools are present.\n */\nfunction stripWebSearchFromBody(rawBody: string): string {\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n\n return JSON.stringify(body)\n}\n\n/**\n * Passthrough handler for Anthropic token counting.\n * Strips web_search tools and forwards beta headers to Copilot's\n * native /v1/messages/count_tokens endpoint.\n */\nexport async function handleCountTokens(c: Context) {\n const rawBody = await c.req.text()\n const finalBody = stripWebSearchFromBody(rawBody)\n\n const extraHeaders: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) extraHeaders[\"anthropic-beta\"] = filtered\n }\n\n const response = await countTokens(finalBody, extraHeaders)\n const body = await response.json()\n\n consola.info(\"Token count:\", JSON.stringify(body))\n\n return c.json(body)\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { filterBetaHeader } from \"~/lib/utils\"\nimport { createMessages } from \"~/services/copilot/create-messages\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Extract whitelisted beta headers from the incoming request to forward\n * to the Copilot API. VS Code sends these to enable extended features\n * like thinking, context management, and advanced tool use.\n */\nfunction extractBetaHeaders(c: Context): Record<string, string> {\n const headers: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) headers[\"anthropic-beta\"] = filtered\n }\n return headers\n}\n\n/**\n * Extract the text content from the last user message for web search.\n * Handles both string content and content block arrays (multimodal).\n */\nfunction extractUserQuery(\n messages: Array<AnyRecord>,\n): string | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const textBlock = msg.content.find(\n (block: AnyRecord) => block.type === \"text\",\n )\n if (textBlock?.text) return textBlock.text as string\n }\n }\n }\n return undefined\n}\n\n/**\n * Check if any user message contains tool_result content blocks,\n * indicating a follow-up turn where we should skip web search.\n * In Anthropic format, tool results are content blocks inside user messages,\n * NOT separate role: \"tool\" messages like in OpenAI format.\n */\nfunction hasToolResultContent(messages: Array<AnyRecord>): boolean {\n return messages.some(\n (msg) =>\n Array.isArray(msg.content) &&\n msg.content.some(\n (block: AnyRecord) => block.type === \"tool_result\",\n ),\n )\n}\n\n/**\n * Inject web search results into the Anthropic system field.\n * Handles three cases: absent, string, or array of content blocks.\n * When array, prepends without cache_control to preserve existing directives.\n */\nfunction injectSearchResults(\n body: AnyRecord,\n searchContext: string,\n): void {\n if (body.system === undefined || body.system === null) {\n body.system = searchContext\n } else if (typeof body.system === \"string\") {\n body.system = `${searchContext}\\n\\n${body.system}`\n } else if (Array.isArray(body.system)) {\n body.system = [\n { type: \"text\", text: searchContext },\n ...body.system,\n ]\n }\n}\n\n/**\n * Strip web_search tools from the request and clean up tool_choice.\n * Returns the modified body object.\n */\nfunction stripWebSearchTool(body: AnyRecord): void {\n if (!body.tools) return\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n // If tool_choice forced the removed web_search tool, fall back to auto\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n}\n\n/**\n * Process web search if the request contains a web_search tool.\n * Performs the search, injects results into system, and strips the tool.\n * Returns the (possibly modified) body string to forward.\n */\nasync function processWebSearch(rawBody: string): Promise<string> {\n // Fast path: skip parsing if no web_search tool present\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = hasToolResultContent(body.messages ?? [])\n const query = hasToolResult ? undefined : extractUserQuery(body.messages ?? [])\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n injectSearchResults(body, searchContext)\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Always strip web_search tool regardless of whether search succeeded\n stripWebSearchTool(body)\n\n return JSON.stringify(body)\n}\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n const rawBody = await c.req.text()\n\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Anthropic request body:\", rawBody.slice(0, 2000))\n }\n\n if (state.manualApprove) {\n await awaitApproval()\n }\n\n const betaHeaders = extractBetaHeaders(c)\n const finalBody = await processWebSearch(rawBody)\n\n const response = await createMessages(finalBody, betaHeaders)\n\n const contentType = response.headers.get(\"content-type\") ?? \"\"\n\n // Streaming: pipe the upstream SSE response body directly\n if (contentType.includes(\"text/event-stream\")) {\n if (debugEnabled) {\n consola.debug(\"Streaming response from Copilot /v1/messages\")\n }\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n },\n })\n }\n\n // Non-streaming: forward JSON response\n const responseBody = await response.json()\n if (debugEnabled) {\n consola.debug(\n \"Non-streaming response from Copilot /v1/messages:\",\n JSON.stringify(responseBody).slice(0, 2000),\n )\n }\n return c.json(responseBody, response.status as 200)\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCountTokens } from \"./count-tokens-handler\"\nimport { handleCompletion } from \"./handler\"\n\nexport const messageRoutes = new Hono()\n\nmessageRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nmessageRoutes.post(\"/count_tokens\", async (c) => {\n try {\n return await handleCountTokens(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { cacheModels } from \"~/lib/utils\"\n\nexport const modelRoutes = new Hono()\n\nmodelRoutes.get(\"/\", async (c) => {\n try {\n if (!state.models) {\n // This should be handled by startup logic, but as a fallback.\n await cacheModels()\n }\n\n const models = state.models?.data.map((model) => ({\n id: model.id,\n object: \"model\",\n type: \"model\",\n created: 0, // No date available from source\n created_at: new Date(0).toISOString(), // No date available from source\n owned_by: model.vendor,\n display_name: model.name,\n }))\n\n return c.json({\n object: \"list\",\n data: models,\n has_more: false,\n })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createResponses = async (payload: ResponsesPayload) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = detectVision(payload.input)\n\n const isAgentCall = detectAgentCall(payload.input)\n\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const filteredPayload = filterUnsupportedTools(payload)\n\n const response = await fetch(`${copilotBaseUrl(state)}/responses`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(filteredPayload),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create responses\", response)\n throw new HTTPError(\"Failed to create responses\", response)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ResponsesApiResponse\n}\n\nfunction detectVision(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"content\" in item && Array.isArray(item.content)) {\n return item.content.some(\n (part: Record<string, unknown>) => part.type === \"input_image\",\n )\n }\n return false\n })\n}\n\nfunction detectAgentCall(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"role\" in item && item.role === \"assistant\") return true\n if (\n \"type\" in item\n && (item.type === \"function_call\" || item.type === \"function_call_output\")\n ) {\n return true\n }\n return false\n })\n}\n\nfunction filterUnsupportedTools(payload: ResponsesPayload): ResponsesPayload {\n if (!payload.tools || !Array.isArray(payload.tools)) return payload\n\n const supported = payload.tools.filter((tool) => {\n const isSupported = tool.type === \"function\"\n if (!isSupported) {\n consola.debug(`Stripping unsupported tool type: ${tool.type}`)\n }\n return isSupported\n })\n\n let toolChoice = payload.tool_choice\n if (supported.length === 0) {\n toolChoice = undefined\n } else if (\n toolChoice\n && typeof toolChoice === \"object\"\n ) {\n const supportedNames = new Set(\n supported.map((tool) => tool.name).filter(Boolean),\n )\n const toolChoiceName = getToolChoiceName(toolChoice)\n if (toolChoiceName && !supportedNames.has(toolChoiceName)) {\n toolChoice = undefined\n }\n }\n\n return {\n ...payload,\n tools: supported.length > 0 ? supported : undefined,\n tool_choice: toolChoice,\n }\n}\n\nfunction getToolChoiceName(\n toolChoice: NonNullable<ResponsesPayload[\"tool_choice\"]>,\n): string | undefined {\n if (typeof toolChoice !== \"object\") return undefined\n if (\n \"function\" in toolChoice\n && toolChoice.function\n && typeof toolChoice.function === \"object\"\n ) {\n return (toolChoice.function as { name?: string }).name\n }\n if (\"name\" in toolChoice) {\n return toolChoice.name\n }\n return undefined\n}\n\n// Types\n\nexport interface ResponsesInputItem {\n role?: \"user\" | \"assistant\" | \"system\"\n type?: \"message\" | \"function_call\" | \"function_call_output\"\n content?: string | Array<Record<string, unknown>>\n name?: string\n call_id?: string\n arguments?: string\n output?: string\n [key: string]: unknown\n}\n\nexport interface ResponsesTool {\n type: string\n name?: string\n description?: string\n parameters?: Record<string, unknown>\n [key: string]: unknown\n}\n\nexport interface ResponsesPayload {\n model: string\n input: string | Array<ResponsesInputItem>\n instructions?: string\n tools?: Array<ResponsesTool>\n tool_choice?:\n | string\n | { type: string; name?: string; function?: { name?: string } }\n max_output_tokens?: number\n temperature?: number\n top_p?: number\n stream?: boolean\n store?: boolean\n metadata?: Record<string, string>\n previous_response_id?: string\n reasoning?: { effort?: string; summary?: string }\n [key: string]: unknown\n}\n\nexport interface ResponsesApiResponse {\n id: string\n object: \"response\"\n status: string\n output: Array<unknown>\n [key: string]: unknown\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { isNullish } from \"~/lib/utils\"\nimport {\n createResponses,\n type ResponsesApiResponse,\n type ResponsesInputItem,\n type ResponsesPayload,\n} from \"~/services/copilot/create-responses\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleResponses(c: Context) {\n await checkRateLimit(state)\n\n const payload = await c.req.json<ResponsesPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\n \"Responses request payload:\",\n JSON.stringify(payload).slice(-400),\n )\n }\n\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n consola.info(\"Token counting not yet supported for /responses endpoint\")\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n if (isNullish(payload.max_output_tokens)) {\n payload.max_output_tokens =\n selectedModel?.capabilities.limits.max_output_tokens\n if (debugEnabled) {\n consola.debug(\n \"Set max_output_tokens to:\",\n JSON.stringify(payload.max_output_tokens),\n )\n }\n }\n\n const response = await createResponses(payload)\n\n if (isNonStreaming(response)) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n consola.debug(\"Streaming response\")\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n\n if (chunk.data === \"[DONE]\") {\n break\n }\n\n if (!chunk.data) {\n continue\n }\n\n await stream.writeSSE({\n data: chunk.data,\n event: chunk.event,\n id: chunk.id?.toString(),\n })\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createResponses>>,\n): response is ResponsesApiResponse => Object.hasOwn(response, \"output\")\n\nasync function injectWebSearchIfNeeded(\n payload: ResponsesPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some((t) => t.type === \"web_search\")\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (function call results)\n if (Array.isArray(payload.input)) {\n const hasFollowUp = payload.input.some(\n (item: ResponsesInputItem) => item.type === \"function_call_output\",\n )\n if (hasFollowUp) return\n }\n\n const query = extractUserQuery(payload.input)\n if (!query) return\n\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n payload.instructions =\n payload.instructions ?\n `${searchContext}\\n\\n${payload.instructions}`\n : searchContext\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n}\n\nfunction extractUserQuery(\n input: ResponsesPayload[\"input\"],\n): string | undefined {\n if (typeof input === \"string\") return input\n if (!Array.isArray(input)) return undefined\n\n // Find the last user message\n for (let i = input.length - 1; i >= 0; i--) {\n const item = input[i]\n if (\"role\" in item && item.role === \"user\") {\n if (typeof item.content === \"string\") return item.content\n if (Array.isArray(item.content)) {\n const text = item.content.find(\n (p: Record<string, unknown>) => p.type === \"input_text\",\n )\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleResponses } from \"./handler\"\n\nexport const responsesRoutes = new Hono()\n\nresponsesRoutes.post(\"/\", async (c) => {\n try {\n return await handleResponses(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport const searchRoutes = new Hono()\n\nsearchRoutes.post(\"/\", async (c) => {\n try {\n const { query } = await c.req.json<{ query: string }>()\n\n if (!query || typeof query !== \"string\") {\n return c.json(\n { error: { message: \"Missing required field: query\" } },\n 400,\n )\n }\n\n const results = await searchWeb(query)\n return c.json({ results })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n if (!state.showToken) {\n return c.json(\n { error: { message: \"Token endpoint disabled\", type: \"error\" } },\n 403,\n )\n }\n\n return c.json({\n token: state.copilotToken,\n })\n})\n","import { Hono } from \"hono\"\nimport consola from \"consola\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\n\nexport const usageRoute = new Hono()\n\nusageRoute.get(\"/\", async (c) => {\n try {\n const usage = await getCopilotUsage()\n return c.json(usage)\n } catch (error) {\n consola.error(\"Error fetching Copilot usage:\", error)\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\nimport { logger } from \"hono/logger\"\n\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { responsesRoutes } from \"./routes/responses/route\"\nimport { searchRoutes } from \"./routes/search/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\n\nexport const server = new Hono()\n\nserver.use(logger())\nserver.use(cors())\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/responses\", responsesRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/search\", searchRoutes)\nserver.route(\"/usage\", usageRoute)\nserver.route(\"/token\", tokenRoute)\n\n// Compatibility with tools that expect v1/ prefix\nserver.route(\"/v1/chat/completions\", completionRoutes)\nserver.route(\"/v1/responses\", responsesRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\nserver.route(\"/v1/search\", searchRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { initProxyFromEnv } from \"./lib/proxy\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport { setupCopilotToken, setupGitHubToken } from \"./lib/token\"\nimport { cacheModels, cacheVSCodeVersion } from \"./lib/utils\"\nimport type { Model } from \"./services/copilot/get-models\"\nimport { server } from \"./server\"\n\ninterface RunServerOptions {\n port: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n claudeCode: boolean\n codex: boolean\n showToken: boolean\n proxyEnv: boolean\n}\n\nconst allowedAccountTypes = new Set([\"individual\", \"business\", \"enterprise\"])\n\nfunction printAndCopyCommand(command: string, label: string): void {\n consola.box(`${label}\\n\\n${command}`)\n try {\n clipboard.writeSync(command)\n consola.success(`Copied ${label} command to clipboard!`)\n } catch {\n consola.warn(\"Failed to copy to clipboard. Copy the command above manually.\")\n }\n}\n\nfunction filterModelsByEndpoint(\n models: Array<Model>,\n endpoint: string,\n): Array<Model> {\n const filtered = models.filter((model) => {\n const endpoints = model.supported_endpoints\n // Some deployments omit supported_endpoints; keep those models visible.\n if (!endpoints || endpoints.length === 0) return true\n return endpoints.some((entry) => {\n const normalized = entry.replace(/^\\/?v1\\//, \"\").replace(/^\\//, \"\")\n return normalized === endpoint\n })\n })\n\n return filtered.length > 0 ? filtered : models\n}\n\nasync function generateClaudeCodeCommand(serverUrl: string) {\n invariant(state.models, \"Models should be loaded by now\")\n\n const claudeModels = state.models.data.filter((model) =>\n model.id.toLowerCase().startsWith(\"claude\"),\n )\n\n if (claudeModels.length === 0) {\n consola.error(\"No Claude models available from Copilot API\")\n return\n }\n\n // Pick the best main model: prefer opus, then sonnet, then first available\n const mainModel =\n claudeModels.find((m) => m.id.includes(\"opus\")) ??\n claudeModels.find((m) => m.id.includes(\"sonnet\")) ??\n claudeModels[0]\n\n // Pick the best small model: prefer haiku, then sonnet, then first available\n const smallModel =\n claudeModels.find((m) => m.id.includes(\"haiku\")) ??\n claudeModels.find((m) => m.id.includes(\"sonnet\")) ??\n claudeModels[0]\n\n // Only prompt if there are multiple options and the user might want to override\n let selectedModel = mainModel.id\n let selectedSmallModel = smallModel.id\n\n if (claudeModels.length > 1) {\n consola.info(\n `Using ${mainModel.id} as main model and ${smallModel.id} as small model`,\n )\n const override = await consola.prompt(\"Override model selection?\", {\n type: \"confirm\",\n initial: false,\n })\n\n if (override) {\n selectedModel = await consola.prompt(\n \"Select a main model for Claude Code\",\n {\n type: \"select\",\n options: claudeModels.map((model) => model.id),\n },\n )\n selectedSmallModel = await consola.prompt(\n \"Select a small/fast model for Claude Code\",\n {\n type: \"select\",\n options: claudeModels.map((model) => model.id),\n },\n )\n }\n }\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: selectedModel,\n ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,\n ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n },\n \"claude --dangerously-skip-permissions\",\n )\n\n printAndCopyCommand(command, \"Claude Code\")\n}\n\nasync function generateCodexCommand(serverUrl: string) {\n invariant(state.models, \"Models should be loaded by now\")\n\n const supportedModels = filterModelsByEndpoint(\n state.models.data,\n \"responses\",\n )\n\n const defaultCodexModel = supportedModels.find(\n (model) => model.id === \"gpt5.2-codex\",\n )\n\n const selectedModel =\n defaultCodexModel ?\n defaultCodexModel.id\n : await consola.prompt(\"Select a model to use with Codex CLI\", {\n type: \"select\",\n options: supportedModels.map((model) => model.id),\n })\n\n const quotedModel = JSON.stringify(selectedModel)\n const command = generateEnvScript(\n {\n OPENAI_BASE_URL: `${serverUrl}/v1`,\n OPENAI_API_KEY: \"dummy\",\n },\n `codex -m ${quotedModel}`,\n )\n\n printAndCopyCommand(command, \"Codex CLI\")\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n if (options.proxyEnv) {\n initProxyFromEnv()\n }\n\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.accountType = options.accountType\n if (options.accountType !== \"individual\") {\n consola.info(`Using ${options.accountType} plan GitHub account`)\n }\n\n state.manualApprove = options.manual\n state.rateLimitSeconds = options.rateLimit\n state.rateLimitWait = options.rateLimitWait\n state.showToken = options.showToken\n\n await ensurePaths()\n await cacheVSCodeVersion()\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.info(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\n\n const serverUrl = `http://localhost:${options.port}`\n\n if (options.claudeCode) await generateClaudeCodeCommand(serverUrl)\n if (options.codex) await generateCodexCommand(serverUrl)\n\n consola.box(\n `🌐 Usage Viewer: https://animeshkundu.github.io/github-router/dashboard.html?endpoint=${serverUrl}/usage`,\n )\n\n serve({\n fetch: server.fetch as ServerHandler,\n hostname: \"127.0.0.1\",\n port: options.port,\n })\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the github-router server\",\n },\n args: {\n port: {\n alias: \"p\",\n type: \"string\",\n default: \"8787\",\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\",\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\",\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\",\n default: false,\n description:\n \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\n },\n \"github-token\": {\n alias: \"g\",\n type: \"string\",\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"claude-code\": {\n alias: \"c\",\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Claude Code with Copilot API config\",\n },\n codex: {\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Codex CLI with Copilot API config\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\",\n default: false,\n description: \"Initialize proxy from environment variables\",\n },\n },\n run({ args }) {\n const rateLimitRaw = args[\"rate-limit\"]\n let rateLimit: number | undefined\n if (rateLimitRaw !== undefined) {\n rateLimit = Number.parseInt(rateLimitRaw, 10)\n if (Number.isNaN(rateLimit) || rateLimit <= 0) {\n throw new Error(\"Invalid rate limit. Must be a positive integer.\")\n }\n }\n\n const port = Number.parseInt(args.port, 10)\n if (Number.isNaN(port) || port <= 0 || port > 65535) {\n throw new Error(\"Invalid port. Must be between 1 and 65535.\")\n }\n\n const accountType = args[\"account-type\"]\n if (!allowedAccountTypes.has(accountType)) {\n throw new Error(\n \"Invalid account type. Must be individual, business, or enterprise.\",\n )\n }\n\n const rateLimitWait = args.wait && rateLimit !== undefined\n if (args.wait && rateLimit === undefined) {\n consola.warn(\"Rate limit wait ignored because no rate limit was set.\")\n }\n\n const githubToken = args[\"github-token\"] ?? process.env.GH_TOKEN\n\n return runServer({\n port,\n verbose: args.verbose,\n accountType,\n manual: args.manual,\n rateLimit,\n rateLimitWait,\n githubToken,\n claudeCode: args[\"claude-code\"],\n codex: args.codex,\n showToken: args[\"show-token\"],\n proxyEnv: args[\"proxy-env\"],\n })\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from \"citty\"\n\nimport { auth } from \"./auth\"\nimport { checkUsage } from \"./check-usage\"\nimport { debug } from \"./debug\"\nimport { start } from \"./start\"\n\nconst main = defineCommand({\n meta: {\n name: \"github-router\",\n description:\n \"A reverse proxy that exposes GitHub Copilot as OpenAI and Anthropic compatible API endpoints.\",\n },\n subCommands: { auth, start, \"check-usage\": checkUsage, debug },\n})\n\nawait runMain(main)\n"],"mappings":"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"}
|