@hsupu/copilot-api 0.7.7 → 0.7.8

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 CHANGED
@@ -246,8 +246,8 @@ async function getVSCodeVersion() {
246
246
  }
247
247
  });
248
248
  if (!response.ok) return FALLBACK;
249
- const version = (await response.json()).tag_name;
250
- if (version && /^\d+\.\d+\.\d+$/.test(version)) return version;
249
+ const version$1 = (await response.json()).tag_name;
250
+ if (version$1 && /^\d+\.\d+\.\d+$/.test(version$1)) return version$1;
251
251
  return FALLBACK;
252
252
  } catch {
253
253
  return FALLBACK;
@@ -434,13 +434,13 @@ const checkUsage = defineCommand({
434
434
  const premiumUsed = premiumTotal - premium.remaining;
435
435
  const premiumPercentUsed = premiumTotal > 0 ? premiumUsed / premiumTotal * 100 : 0;
436
436
  const premiumPercentRemaining = premium.percent_remaining;
437
- function summarizeQuota(name, snap) {
438
- if (!snap) return `${name}: N/A`;
437
+ function summarizeQuota(name$1, snap) {
438
+ if (!snap) return `${name$1}: N/A`;
439
439
  const total = snap.entitlement;
440
440
  const used = total - snap.remaining;
441
441
  const percentUsed = total > 0 ? used / total * 100 : 0;
442
442
  const percentRemaining = snap.percent_remaining;
443
- return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`;
443
+ return `${name$1}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`;
444
444
  }
445
445
  const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`;
446
446
  const chatLine = summarizeQuota("Chat", usage.quota_snapshots.chat);
@@ -481,9 +481,9 @@ async function checkTokenExists() {
481
481
  }
482
482
  }
483
483
  async function getDebugInfo() {
484
- const [version, tokenExists] = await Promise.all([getPackageVersion(), checkTokenExists()]);
484
+ const [version$1, tokenExists] = await Promise.all([getPackageVersion(), checkTokenExists()]);
485
485
  return {
486
- version,
486
+ version: version$1,
487
487
  runtime: getRuntimeInfo(),
488
488
  paths: {
489
489
  APP_DIR: PATHS.APP_DIR,
@@ -571,8 +571,8 @@ const PATTERNS = {
571
571
  /**
572
572
  * Parse semver version string to comparable parts
573
573
  */
574
- function parseVersion(version) {
575
- return version.split(".").map((n) => Number.parseInt(n, 10) || 0);
574
+ function parseVersion(version$1) {
575
+ return version$1.split(".").map((n) => Number.parseInt(n, 10) || 0);
576
576
  }
577
577
  /**
578
578
  * Compare two semver versions
@@ -590,9 +590,9 @@ function compareVersions(a, b) {
590
590
  }
591
591
  return 0;
592
592
  }
593
- function getPatternTypeForVersion(version) {
594
- if (compareVersions(version, SUPPORTED_VERSIONS.v2a.min) >= 0 && compareVersions(version, SUPPORTED_VERSIONS.v2a.max) <= 0) return "func";
595
- if (compareVersions(version, SUPPORTED_VERSIONS.v2b.min) >= 0 && compareVersions(version, SUPPORTED_VERSIONS.v2b.max) <= 0) return "variable";
593
+ function getPatternTypeForVersion(version$1) {
594
+ if (compareVersions(version$1, SUPPORTED_VERSIONS.v2a.min) >= 0 && compareVersions(version$1, SUPPORTED_VERSIONS.v2a.max) <= 0) return "func";
595
+ if (compareVersions(version$1, SUPPORTED_VERSIONS.v2b.min) >= 0 && compareVersions(version$1, SUPPORTED_VERSIONS.v2b.max) <= 0) return "variable";
596
596
  return null;
597
597
  }
598
598
  /**
@@ -624,8 +624,8 @@ function findInVoltaTools(voltaHome) {
624
624
  if (existsSync(packagesPath)) paths.push(packagesPath);
625
625
  const toolsDir = join(voltaHome, "tools", "image", "node");
626
626
  if (existsSync(toolsDir)) try {
627
- for (const version of readdirSync(toolsDir)) {
628
- const claudePath = join(toolsDir, version, "lib", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
627
+ for (const version$1 of readdirSync(toolsDir)) {
628
+ const claudePath = join(toolsDir, version$1, "lib", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
629
629
  if (existsSync(claudePath)) paths.push(claudePath);
630
630
  }
631
631
  } catch {}
@@ -668,23 +668,23 @@ function getCurrentLimit(content) {
668
668
  * Check if Claude Code version is supported for patching
669
669
  */
670
670
  function checkVersionSupport(cliPath) {
671
- const version = getClaudeCodeVersion(cliPath);
672
- if (!version) return {
671
+ const version$1 = getClaudeCodeVersion(cliPath);
672
+ if (!version$1) return {
673
673
  supported: false,
674
674
  version: null,
675
675
  patternType: null,
676
676
  error: "Could not detect Claude Code version"
677
677
  };
678
- const patternType = getPatternTypeForVersion(version);
678
+ const patternType = getPatternTypeForVersion(version$1);
679
679
  if (!patternType) return {
680
680
  supported: false,
681
- version,
681
+ version: version$1,
682
682
  patternType: null,
683
- error: `Version ${version} is not supported. Supported: ${getSupportedRangeString()}`
683
+ error: `Version ${version$1} is not supported. Supported: ${getSupportedRangeString()}`
684
684
  };
685
685
  return {
686
686
  supported: true,
687
- version,
687
+ version: version$1,
688
688
  patternType
689
689
  };
690
690
  }
@@ -735,8 +735,8 @@ function restoreClaudeCode(cliPath) {
735
735
  return true;
736
736
  }
737
737
  function showStatus(cliPath, currentLimit) {
738
- const version = getClaudeCodeVersion(cliPath);
739
- if (version) consola.info(`Claude Code version: ${version}`);
738
+ const version$1 = getClaudeCodeVersion(cliPath);
739
+ if (version$1) consola.info(`Claude Code version: ${version$1}`);
740
740
  if (currentLimit === null) {
741
741
  consola.warn("Could not detect current limit - CLI may have been updated");
742
742
  consola.info("Look for the BS9 variable or HR function pattern in cli.js");
@@ -818,6 +818,86 @@ const patchClaude = defineCommand({
818
818
  }
819
819
  });
820
820
 
821
+ //#endregion
822
+ //#region package.json
823
+ var name = "@hsupu/copilot-api";
824
+ var version = "0.7.8";
825
+ var description = "Turn GitHub Copilot into OpenAI/Anthropic API compatible server. Usable with Claude Code!";
826
+ var keywords = [
827
+ "proxy",
828
+ "github-copilot",
829
+ "openai-compatible",
830
+ "anthropic-compatible"
831
+ ];
832
+ var homepage = "https://github.com/puxu-msft/copilot-api-js";
833
+ var bugs = "https://github.com/puxu-msft/copilot-api-js/issues";
834
+ var repository = {
835
+ "type": "git",
836
+ "url": "git+https://github.com/puxu-msft/copilot-api-js.git"
837
+ };
838
+ var author = "hsupu";
839
+ var type = "module";
840
+ var bin = { "copilot-api": "dist/main.js" };
841
+ var files = ["dist"];
842
+ var scripts = {
843
+ "build": "npx tsdown",
844
+ "dev": "bun run --watch ./src/main.ts",
845
+ "knip": "knip-bun",
846
+ "lint": "eslint --cache",
847
+ "lint:all": "eslint --cache .",
848
+ "prepack": "npm run build",
849
+ "prepare": "npm run build && (command -v bun >/dev/null 2>&1 && simple-git-hooks || true)",
850
+ "release": "bumpp && npm publish --access public",
851
+ "start": "NODE_ENV=production bun run ./src/main.ts",
852
+ "typecheck": "tsc"
853
+ };
854
+ var simple_git_hooks = { "pre-commit": "bun x lint-staged" };
855
+ var lint_staged = { "*": "bun run lint --fix" };
856
+ var dependencies = {
857
+ "citty": "^0.1.6",
858
+ "clipboardy": "^5.0.0",
859
+ "consola": "^3.4.2",
860
+ "fetch-event-stream": "^0.1.5",
861
+ "gpt-tokenizer": "^3.0.1",
862
+ "hono": "^4.9.9",
863
+ "picocolors": "^1.1.1",
864
+ "proxy-from-env": "^1.1.0",
865
+ "srvx": "^0.8.9",
866
+ "tiny-invariant": "^1.3.3",
867
+ "undici": "^7.16.0"
868
+ };
869
+ var devDependencies = {
870
+ "@echristian/eslint-config": "^0.0.54",
871
+ "@types/bun": "^1.2.23",
872
+ "@types/proxy-from-env": "^1.0.4",
873
+ "bumpp": "^10.2.3",
874
+ "eslint": "^9.37.0",
875
+ "knip": "^5.64.1",
876
+ "lint-staged": "^16.2.3",
877
+ "prettier-plugin-packagejson": "^2.5.19",
878
+ "simple-git-hooks": "^2.13.1",
879
+ "tsdown": "^0.15.6",
880
+ "typescript": "^5.9.3"
881
+ };
882
+ var package_default = {
883
+ name,
884
+ version,
885
+ description,
886
+ keywords,
887
+ homepage,
888
+ bugs,
889
+ repository,
890
+ author,
891
+ type,
892
+ bin,
893
+ files,
894
+ scripts,
895
+ "simple-git-hooks": simple_git_hooks,
896
+ "lint-staged": lint_staged,
897
+ dependencies,
898
+ devDependencies
899
+ };
900
+
821
901
  //#endregion
822
902
  //#region src/lib/adaptive-rate-limiter.ts
823
903
  const DEFAULT_CONFIG$1 = {
@@ -1566,8 +1646,8 @@ var ConsoleRenderer = class {
1566
1646
  /**
1567
1647
  * Get log prefix based on log type
1568
1648
  */
1569
- getLogPrefix(type) {
1570
- switch (type) {
1649
+ getLogPrefix(type$1) {
1650
+ switch (type$1) {
1571
1651
  case "error":
1572
1652
  case "fatal": return pc.red("✖");
1573
1653
  case "warn": return pc.yellow("⚠");
@@ -2183,18 +2263,40 @@ function getToolUseIds(message) {
2183
2263
  return [];
2184
2264
  }
2185
2265
  /**
2186
- * Find messages to keep from the end to stay under target tokens.
2187
- * Returns the starting index of messages to preserve.
2266
+ * Estimate the byte size of a message (for binary search).
2188
2267
  */
2189
- function findPreserveIndex(messages, targetTokens, systemTokens) {
2190
- const availableTokens = targetTokens - systemTokens - 500;
2191
- let accumulatedTokens = 0;
2268
+ function estimateMessageBytes(message) {
2269
+ return JSON.stringify(message).length;
2270
+ }
2271
+ /**
2272
+ * Find the optimal preserve index using binary search.
2273
+ * This finds the point where we keep as many messages as possible
2274
+ * while staying under both token and byte limits.
2275
+ */
2276
+ function findOptimalPreserveIndex(messages, systemMessages, targetTokens, targetBytes) {
2277
+ if (messages.length === 0) return 0;
2278
+ const systemTokens = systemMessages.reduce((sum, msg) => sum + estimateMessageTokens(msg), 0);
2279
+ const systemBytes = systemMessages.reduce((sum, msg) => sum + estimateMessageBytes(msg), 0);
2280
+ const markerOverhead = 200;
2281
+ const availableTokens = targetTokens - systemTokens - markerOverhead / 4;
2282
+ const availableBytes = targetBytes - systemBytes - markerOverhead;
2283
+ const cumulativeTokens = Array.from({ length: messages.length + 1 }, () => 0);
2284
+ const cumulativeBytes = Array.from({ length: messages.length + 1 }, () => 0);
2192
2285
  for (let i = messages.length - 1; i >= 0; i--) {
2193
- const msgTokens = estimateMessageTokens(messages[i]);
2194
- if (accumulatedTokens + msgTokens > availableTokens) return i + 1;
2195
- accumulatedTokens += msgTokens;
2286
+ const msg = messages[i];
2287
+ cumulativeTokens[i] = cumulativeTokens[i + 1] + estimateMessageTokens(msg);
2288
+ cumulativeBytes[i] = cumulativeBytes[i + 1] + estimateMessageBytes(msg);
2196
2289
  }
2197
- return 0;
2290
+ let left = 0;
2291
+ let right = messages.length;
2292
+ while (left < right) {
2293
+ const mid = Math.floor((left + right) / 2);
2294
+ const tokensFromMid = cumulativeTokens[mid];
2295
+ const bytesFromMid = cumulativeBytes[mid];
2296
+ if (tokensFromMid <= availableTokens && bytesFromMid <= availableBytes) right = mid;
2297
+ else left = mid + 1;
2298
+ }
2299
+ return left;
2198
2300
  }
2199
2301
  /**
2200
2302
  * Filter out orphaned tool_result messages that don't have a matching tool_use
@@ -2232,12 +2334,6 @@ function ensureStartsWithUser(messages) {
2232
2334
  return messages.slice(startIndex);
2233
2335
  }
2234
2336
  /**
2235
- * Calculate estimated tokens for system messages.
2236
- */
2237
- function estimateSystemTokens(systemMessages) {
2238
- return systemMessages.reduce((sum, msg) => sum + estimateMessageTokens(msg), 0);
2239
- }
2240
- /**
2241
2337
  * Create a truncation marker message.
2242
2338
  */
2243
2339
  function createTruncationMarker(removedCount) {
@@ -2248,8 +2344,9 @@ function createTruncationMarker(removedCount) {
2248
2344
  }
2249
2345
  /**
2250
2346
  * Perform auto-compaction on a payload that exceeds token or size limits.
2251
- * This uses simple truncation - no LLM calls required.
2252
- * Uses iterative approach with decreasing target tokens until under limit.
2347
+ * This uses simple truncation with binary search - no LLM calls required.
2348
+ * The algorithm finds the optimal truncation point to maximize preserved messages
2349
+ * while staying under both token and byte limits.
2253
2350
  */
2254
2351
  async function autoCompact(payload, model, config = {}) {
2255
2352
  const cfg = {
@@ -2276,58 +2373,20 @@ async function autoCompact(payload, model, config = {}) {
2276
2373
  else reason = "tokens";
2277
2374
  consola.info(`Auto-compact: Exceeds ${reason} limit (${originalTokens} tokens, ${Math.round(originalBytes / 1024)}KB), truncating...`);
2278
2375
  const { systemMessages, remainingMessages } = extractSystemMessages(payload.messages);
2279
- const systemTokens = estimateSystemTokens(systemMessages);
2280
- consola.debug(`Auto-compact: ${systemMessages.length} system messages (~${systemTokens} tokens)`);
2281
- const MAX_ITERATIONS = 5;
2282
- const MIN_TARGET = 2e4;
2283
- let currentTarget = Math.min(cfg.targetTokens, tokenLimit);
2284
- let lastResult = null;
2285
- for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
2286
- const result = await tryCompactWithTarget({
2376
+ consola.debug(`Auto-compact: ${systemMessages.length} system messages, ${remainingMessages.length} conversation messages`);
2377
+ const preserveIndex = findOptimalPreserveIndex(remainingMessages, systemMessages, tokenLimit, byteLimit);
2378
+ if (preserveIndex === 0) {
2379
+ consola.warn("Auto-compact: Cannot truncate without losing all conversation history");
2380
+ return {
2287
2381
  payload,
2288
- model,
2289
- systemMessages,
2290
- remainingMessages,
2291
- systemTokens,
2292
- targetTokens: currentTarget,
2293
- limit: tokenLimit,
2294
- originalTokens
2295
- });
2296
- if (!result.wasCompacted) return result;
2297
- lastResult = result;
2298
- const resultBytes = JSON.stringify(result.payload).length;
2299
- const underTokenLimit = result.compactedTokens <= tokenLimit;
2300
- const underByteLimit = resultBytes <= byteLimit;
2301
- if (underTokenLimit && underByteLimit) {
2302
- consola.info(`Auto-compact: ${originalTokens} → ${result.compactedTokens} tokens, ${Math.round(originalBytes / 1024)}KB → ${Math.round(resultBytes / 1024)}KB (removed ${result.removedMessageCount} messages)`);
2303
- return result;
2304
- }
2305
- const tokenStatus = underTokenLimit ? "OK" : `${result.compactedTokens} > ${tokenLimit}`;
2306
- const byteStatus = underByteLimit ? "OK" : `${Math.round(resultBytes / 1024)}KB > ${Math.round(byteLimit / 1024)}KB`;
2307
- consola.warn(`Auto-compact: Still over limit (tokens: ${tokenStatus}, size: ${byteStatus}), trying more aggressive truncation`);
2308
- currentTarget = Math.floor(currentTarget * .7);
2309
- if (currentTarget < MIN_TARGET) {
2310
- consola.error("Auto-compact: Cannot reduce further, target too low");
2311
- return result;
2312
- }
2382
+ wasCompacted: false,
2383
+ originalTokens,
2384
+ compactedTokens: originalTokens,
2385
+ removedMessageCount: 0
2386
+ };
2313
2387
  }
2314
- consola.error(`Auto-compact: Exhausted ${MAX_ITERATIONS} iterations, returning best effort`);
2315
- return lastResult ?? {
2316
- payload,
2317
- wasCompacted: false,
2318
- originalTokens,
2319
- compactedTokens: originalTokens,
2320
- removedMessageCount: 0
2321
- };
2322
- }
2323
- /**
2324
- * Helper to attempt compaction with a specific target token count.
2325
- */
2326
- async function tryCompactWithTarget(opts) {
2327
- const { payload, model, systemMessages, remainingMessages, systemTokens, targetTokens, originalTokens } = opts;
2328
- const preserveIndex = findPreserveIndex(remainingMessages, targetTokens, systemTokens);
2329
- if (preserveIndex === 0) {
2330
- consola.warn("Auto-compact: Cannot truncate further without losing all conversation history");
2388
+ if (preserveIndex >= remainingMessages.length) {
2389
+ consola.warn("Auto-compact: Would need to remove all messages, cannot compact");
2331
2390
  return {
2332
2391
  payload,
2333
2392
  wasCompacted: false,
@@ -2362,6 +2421,8 @@ async function tryCompactWithTarget(opts) {
2362
2421
  ]
2363
2422
  };
2364
2423
  const newTokenCount = await getTokenCount(newPayload, model);
2424
+ const newBytes = JSON.stringify(newPayload).length;
2425
+ consola.info(`Auto-compact: ${originalTokens} → ${newTokenCount.input} tokens, ${Math.round(originalBytes / 1024)}KB → ${Math.round(newBytes / 1024)}KB (removed ${removedMessages.length} messages)`);
2365
2426
  return {
2366
2427
  payload: newPayload,
2367
2428
  wasCompacted: true,
@@ -2633,7 +2694,7 @@ function handleNonStreamingResponse$1(c, originalResponse, ctx) {
2633
2694
  ...choice$1,
2634
2695
  message: {
2635
2696
  ...choice$1.message,
2636
- content: (choice$1.message.content ?? "") + marker
2697
+ content: marker + (choice$1.message.content ?? "")
2637
2698
  }
2638
2699
  } : choice$1)
2639
2700
  };
@@ -2694,18 +2755,13 @@ async function handleStreamingResponse$1(opts) {
2694
2755
  const { stream, response, payload, ctx } = opts;
2695
2756
  const acc = createStreamAccumulator();
2696
2757
  try {
2697
- for await (const chunk of response) {
2698
- consola.debug("Streaming chunk:", JSON.stringify(chunk));
2699
- parseStreamChunk(chunk, acc);
2700
- await stream.writeSSE(chunk);
2701
- }
2702
2758
  if (ctx.compactResult?.wasCompacted) {
2703
2759
  const marker = createCompactionMarker(ctx.compactResult);
2704
2760
  const markerChunk = {
2705
2761
  id: `compact-marker-${Date.now()}`,
2706
2762
  object: "chat.completion.chunk",
2707
2763
  created: Math.floor(Date.now() / 1e3),
2708
- model: acc.model || payload.model,
2764
+ model: payload.model,
2709
2765
  choices: [{
2710
2766
  index: 0,
2711
2767
  delta: { content: marker },
@@ -2719,6 +2775,11 @@ async function handleStreamingResponse$1(opts) {
2719
2775
  });
2720
2776
  acc.content += marker;
2721
2777
  }
2778
+ for await (const chunk of response) {
2779
+ consola.debug("Streaming chunk:", JSON.stringify(chunk));
2780
+ parseStreamChunk(chunk, acc);
2781
+ await stream.writeSSE(chunk);
2782
+ }
2722
2783
  recordStreamSuccess(acc, payload.model, ctx);
2723
2784
  completeTracking(ctx.trackingId, acc.inputTokens, acc.outputTokens, ctx.queueWaitMs);
2724
2785
  } catch (error) {
@@ -4509,7 +4570,7 @@ function handleNonStreamingResponse(opts) {
4509
4570
  consola.debug("Translated Anthropic response:", JSON.stringify(anthropicResponse));
4510
4571
  if (ctx.compactResult?.wasCompacted) {
4511
4572
  const marker = createCompactionMarker(ctx.compactResult);
4512
- anthropicResponse = appendMarkerToAnthropicResponse(anthropicResponse, marker);
4573
+ anthropicResponse = prependMarkerToAnthropicResponse(anthropicResponse, marker);
4513
4574
  }
4514
4575
  recordResponse(ctx.historyId, {
4515
4576
  success: true,
@@ -4541,16 +4602,16 @@ function handleNonStreamingResponse(opts) {
4541
4602
  });
4542
4603
  return c.json(anthropicResponse);
4543
4604
  }
4544
- function appendMarkerToAnthropicResponse(response, marker) {
4605
+ function prependMarkerToAnthropicResponse(response, marker) {
4545
4606
  const content = [...response.content];
4546
- const lastTextIndex = content.findLastIndex((block) => block.type === "text");
4547
- if (lastTextIndex !== -1) {
4548
- const textBlock = content[lastTextIndex];
4549
- if (textBlock.type === "text") content[lastTextIndex] = {
4607
+ const firstTextIndex = content.findIndex((block) => block.type === "text");
4608
+ if (firstTextIndex !== -1) {
4609
+ const textBlock = content[firstTextIndex];
4610
+ if (textBlock.type === "text") content[firstTextIndex] = {
4550
4611
  ...textBlock,
4551
- text: textBlock.text + marker
4612
+ text: marker + textBlock.text
4552
4613
  };
4553
- } else content.push({
4614
+ } else content.unshift({
4554
4615
  type: "text",
4555
4616
  text: marker
4556
4617
  });
@@ -4580,6 +4641,11 @@ async function handleStreamingResponse(opts) {
4580
4641
  };
4581
4642
  const acc = createAnthropicStreamAccumulator();
4582
4643
  try {
4644
+ if (ctx.compactResult?.wasCompacted) {
4645
+ const marker = createCompactionMarker(ctx.compactResult);
4646
+ await sendCompactionMarkerEvent(stream, streamState, marker);
4647
+ acc.content += marker;
4648
+ }
4583
4649
  await processStreamChunks({
4584
4650
  stream,
4585
4651
  response,
@@ -4587,11 +4653,6 @@ async function handleStreamingResponse(opts) {
4587
4653
  streamState,
4588
4654
  acc
4589
4655
  });
4590
- if (ctx.compactResult?.wasCompacted) {
4591
- const marker = createCompactionMarker(ctx.compactResult);
4592
- await sendCompactionMarkerEvent(stream, streamState, marker);
4593
- acc.content += marker;
4594
- }
4595
4656
  recordStreamingResponse(acc, anthropicPayload.model, ctx);
4596
4657
  completeTracking(ctx.trackingId, acc.inputTokens, acc.outputTokens, ctx.queueWaitMs);
4597
4658
  } catch (error) {
@@ -4904,6 +4965,7 @@ function formatModelInfo(model) {
4904
4965
  return ` - ${model.id.padEnd(28)} context: ${contextK.padStart(5)}, output: ${outputK.padStart(4)}${featureStr}`;
4905
4966
  }
4906
4967
  async function runServer(options) {
4968
+ consola.info(`copilot-api v${package_default.version}`);
4907
4969
  if (options.proxyEnv) initProxyFromEnv();
4908
4970
  if (options.verbose) {
4909
4971
  consola.level = 5;