From f38fe7ea15d4fd902407ff9bc52e5cf37b5c5776 Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 29 Jul 2026 16:26:18 +0800 Subject: [PATCH 1/7] test: reproduce trailing assistant prefill rejection --- tests/anthropic-request.test.ts | 65 +++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/anthropic-request.test.ts b/tests/anthropic-request.test.ts index 06c663778..ae26da2f6 100644 --- a/tests/anthropic-request.test.ts +++ b/tests/anthropic-request.test.ts @@ -140,6 +140,7 @@ describe("Anthropic to OpenAI translation logic", () => { { type: "text", text: "2+2 equals 4." }, ], }, + { role: "user", content: "Thanks! And what is 3+3?" }, ], max_tokens: 100, } @@ -197,6 +198,70 @@ describe("Anthropic to OpenAI translation logic", () => { expect(assistantMessage?.tool_calls).toHaveLength(1) expect(assistantMessage?.tool_calls?.[0].function.name).toBe("get_weather") }) + + test("should rewrite a trailing assistant prefill into a user message", () => { + const anthropicPayload: AnthropicMessagesPayload = { + model: "claude-3-5-sonnet-20241022", + messages: [ + { role: "user", content: "Give me a JSON object for the sky color." }, + { role: "assistant", content: '{"color": "' }, + ], + max_tokens: 100, + } + const openAIPayload = translateToOpenAI(anthropicPayload) + + // Upstream rejects a request ending with an assistant message, so the + // conversation must end with a user message. + const lastMessage = openAIPayload.messages.at(-1) + expect(lastMessage?.role).toBe("user") + expect(openAIPayload.messages.some((m) => m.role === "assistant")).toBe( + false, + ) + // The prefill text is preserved inside the injected user instruction. + expect(lastMessage?.content).toContain('{"color": "') + }) + + test("should rewrite an empty trailing assistant prefill", () => { + const anthropicPayload: AnthropicMessagesPayload = { + model: "claude-3-5-sonnet-20241022", + messages: [ + { role: "user", content: "Hello" }, + { role: "assistant", content: "" }, + ], + max_tokens: 100, + } + const openAIPayload = translateToOpenAI(anthropicPayload) + + const lastMessage = openAIPayload.messages.at(-1) + expect(lastMessage?.role).toBe("user") + expect(lastMessage?.content).toBe("Continue.") + }) + + test("should not treat a trailing assistant tool call as a prefill", () => { + const anthropicPayload: AnthropicMessagesPayload = { + model: "claude-3-5-sonnet-20241022", + messages: [ + { role: "user", content: "What's the weather?" }, + { + role: "assistant", + content: [ + { + type: "tool_use", + id: "call_123", + name: "get_weather", + input: { location: "New York" }, + }, + ], + }, + ], + max_tokens: 100, + } + const openAIPayload = translateToOpenAI(anthropicPayload) + + const lastMessage = openAIPayload.messages.at(-1) + expect(lastMessage?.role).toBe("assistant") + expect(lastMessage?.tool_calls).toHaveLength(1) + }) }) describe("OpenAI Chat Completion v1 Request Payload Validation with Zod", () => { From a1fcc788e6b142a88ccc36e15ef941223d3e289d Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 29 Jul 2026 16:27:04 +0800 Subject: [PATCH 2/7] fix: rewrite unsupported trailing assistant prefill --- src/routes/messages/non-stream-translation.ts | 71 ++++++++++++++++--- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/src/routes/messages/non-stream-translation.ts b/src/routes/messages/non-stream-translation.ts index dc41e6382..66170c4da 100644 --- a/src/routes/messages/non-stream-translation.ts +++ b/src/routes/messages/non-stream-translation.ts @@ -29,12 +29,14 @@ import { mapOpenAIStopReasonToAnthropic } from "./utils" export function translateToOpenAI( payload: AnthropicMessagesPayload, ): ChatCompletionsPayload { + const messages = translateAnthropicMessagesToOpenAI( + payload.messages, + payload.system, + ) + fixTrailingAssistantPrefill(messages) return { model: translateModelName(payload.model), - messages: translateAnthropicMessagesToOpenAI( - payload.messages, - payload.system, - ), + messages, max_tokens: payload.max_tokens, stop: payload.stop_sequences, stream: payload.stream, @@ -46,14 +48,61 @@ export function translateToOpenAI( } } -function translateModelName(model: string): string { - // Subagent requests use a specific model number which Copilot doesn't support - if (model.startsWith("claude-sonnet-4-")) { - return model.replace(/^claude-sonnet-4-.*/, "claude-sonnet-4") - } else if (model.startsWith("claude-opus-")) { - return model.replace(/^claude-opus-4-.*/, "claude-opus-4") +// Some Copilot upstream models reject a request whose message list ends with +// an assistant turn ("assistant message prefill"), responding with a 400: +// "This model does not support assistant message prefill. The conversation +// must end with a user message." +// Anthropic clients (e.g. Claude Code) legitimately use prefill to constrain a +// reply. To stay compatible we drop the trailing assistant prefill and re-add +// it as a user instruction asking the model to emit only the continuation, +// reproducing Anthropic's prefill contract (the response excludes the prefill). +function fixTrailingAssistantPrefill(messages: Array): void { + const last = messages.at(-1) + if (!last || last.role !== "assistant") { + return + } + // A trailing tool call is part of an in-flight tool exchange, not a prefill. + if ("tool_calls" in last && last.tool_calls && last.tool_calls.length > 0) { + return + } + + const prefill = extractAssistantText(last.content) + + messages.pop() + + if (prefill.trim().length === 0) { + messages.push({ role: "user", content: "Continue." }) + return } - return model + + messages.push({ + role: "user", + content: + "You have already begun your reply with the text below. Do not repeat" + + " it and do not add any preamble: output only the text that continues" + + ` seamlessly from it.\n\n--- Your reply so far ---\n${prefill}`, + }) +} + +function extractAssistantText(content: Message["content"]): string { + if (typeof content === "string") { + return content + } + if (Array.isArray(content)) { + return content + .filter((part): part is TextPart => part.type === "text") + .map((part) => part.text) + .join("") + } + return "" +} + +function translateModelName(model: string): string { + // Copilot exposes Claude models with dotted minor versions (e.g. + // "claude-opus-4.8"), while Anthropic clients (Claude Code) send dashed IDs + // ("claude-opus-4-8"). Rewrite the trailing "-N" minor version to ".N" so the + // requested model resolves. Mirrors upstream copilot-api normalization. + return model.replace(/^(claude-(?:opus|sonnet|haiku)-\d+)-(\d+)/, "$1.$2") } function translateAnthropicMessagesToOpenAI( From 58efcdf9a2d87ab1bbafe087c6d0fdada51ac472 Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 29 Jul 2026 16:30:14 +0800 Subject: [PATCH 3/7] test: protect Opus 5 and dated model normalization --- tests/anthropic-request.test.ts | 37 +++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/anthropic-request.test.ts b/tests/anthropic-request.test.ts index ae26da2f6..ff310cbf6 100644 --- a/tests/anthropic-request.test.ts +++ b/tests/anthropic-request.test.ts @@ -62,6 +62,27 @@ function isValidChatCompletionRequest(payload: unknown): boolean { return result.success } +describe("Claude model ID normalization", () => { + test.each([ + ["claude-opus-5", "claude-opus-5"], + ["claude-opus-4-8", "claude-opus-4.8"], + ["claude-opus-4.8", "claude-opus-4.8"], + ["claude-sonnet-4-20250514", "claude-sonnet-4"], + ["claude-opus-4-1-20250805", "claude-opus-4"], + ["gpt-4o", "gpt-4o"], + ])("should safely normalize model ID %s", (model, expected) => { + const anthropicPayload: AnthropicMessagesPayload = { + model, + messages: [{ role: "user", content: "Hello!" }], + max_tokens: 100, + } + + const openAIPayload = translateToOpenAI(anthropicPayload) + + expect(openAIPayload.model).toBe(expected) + }) +}) + describe("Anthropic to OpenAI translation logic", () => { test("should translate minimal Anthropic payload to valid OpenAI payload", () => { const anthropicPayload: AnthropicMessagesPayload = { @@ -259,8 +280,20 @@ describe("Anthropic to OpenAI translation logic", () => { const openAIPayload = translateToOpenAI(anthropicPayload) const lastMessage = openAIPayload.messages.at(-1) - expect(lastMessage?.role).toBe("assistant") - expect(lastMessage?.tool_calls).toHaveLength(1) + expect(lastMessage).toEqual({ + role: "assistant", + content: null, + tool_calls: [ + { + id: "call_123", + type: "function", + function: { + name: "get_weather", + arguments: '{"location":"New York"}', + }, + }, + ], + }) }) }) From bd7ed2f262367222bf89df0b41cc02398321a240 Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 29 Jul 2026 16:30:38 +0800 Subject: [PATCH 4/7] fix: preserve dated Claude model identifiers --- src/routes/messages/non-stream-translation.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/routes/messages/non-stream-translation.ts b/src/routes/messages/non-stream-translation.ts index 66170c4da..b022e9d8b 100644 --- a/src/routes/messages/non-stream-translation.ts +++ b/src/routes/messages/non-stream-translation.ts @@ -98,11 +98,22 @@ function extractAssistantText(content: Message["content"]): string { } function translateModelName(model: string): string { + const datedModel = model.match( + /^(claude-(?:opus|sonnet|haiku)-\d+)(?:-\d+)?-\d{8}$/, + ) + if (datedModel) { + return datedModel[1] + } + // Copilot exposes Claude models with dotted minor versions (e.g. // "claude-opus-4.8"), while Anthropic clients (Claude Code) send dashed IDs // ("claude-opus-4-8"). Rewrite the trailing "-N" minor version to ".N" so the - // requested model resolves. Mirrors upstream copilot-api normalization. - return model.replace(/^(claude-(?:opus|sonnet|haiku)-\d+)-(\d+)/, "$1.$2") + // requested model resolves. The exact match prevents an eight-digit release + // date from being mistaken for a minor version. + return model.replace( + /^(claude-(?:opus|sonnet|haiku)-\d+)-(\d{1,2})$/, + "$1.$2", + ) } function translateAnthropicMessagesToOpenAI( From 3036055ae335bcbb8a5f679b30851a6060d90d9d Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 29 Jul 2026 16:32:44 +0800 Subject: [PATCH 5/7] docs: record local Opus 5 TDD evidence --- docs/testing/local-opus5-prefill.tdd.md | 47 +++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/testing/local-opus5-prefill.tdd.md diff --git a/docs/testing/local-opus5-prefill.tdd.md b/docs/testing/local-opus5-prefill.tdd.md new file mode 100644 index 000000000..f23338013 --- /dev/null +++ b/docs/testing/local-opus5-prefill.tdd.md @@ -0,0 +1,47 @@ +# Local Opus 5 prefill compatibility — TDD evidence + +## Source and user journey + +No external plan file was supplied. The journey was derived from the local +service request: + +> As a Claude Code user routed through cc-switch and copilot-api, I want +> `claude-opus-5` requests that contain an assistant prefill to remain valid, so +> the local proxy continues serving requests after GitHub enables the model. + +The implementation starts from official `ericc-ch/copilot-api` `v0.7.0` +(`0ea08febdd7e3e055b03dd298bf57e669500b5c1`) and incorporates the behavior +proposed by upstream PR #261, with an additional dated-model normalization +guard found during local review. + +## RED/GREEN evidence + +| Guarantee | Test/command | Type | Result | Evidence | +|---|---|---|---|---| +| Official v0.7.0 reproduces the trailing assistant prefill defect | `bun test tests/anthropic-request.test.ts` at `f38fe7e^` with the test file from `f38fe7e` | Regression | RED | 20 passed, 2 failed; final role was `assistant`, expected `user` | +| Text and empty prefills are rewritten, while a trailing tool call remains intact | `bun test tests/anthropic-request.test.ts` | Unit/integration translation | PASS | 28 passed, 0 failed | +| `claude-opus-5` is unchanged, dashed minor IDs are dotted, and dated IDs are not corrupted | `bun test tests/anthropic-request.test.ts` | Unit/integration translation | RED then PASS | Dated-ID tests failed at `58efcdf`, then passed after `bd7ed2f` | +| No translation/response regressions exist in the repository suite | `bun test` | Regression | PASS | 35 passed, 0 failed | +| TypeScript contracts remain valid | `bun x --bun tsc --noEmit` | Static | PASS | Exit 0 | +| Changed source and tests meet lint rules | `bun x --bun eslint --cache src/routes/messages/non-stream-translation.ts tests/anthropic-request.test.ts` | Static | PASS | Exit 0 | +| The production artifact builds | `/opt/codex-desktop/resources/node-runtime/bin/node node_modules/tsdown/dist/run.mjs` | Build | PASS | `dist/main.js` SHA-256 `cf73067276e2711df1502486c592e96cd8b968243edd121a21f6af215ea20b29` | +| The restarted service exposes Opus 5 and continues handling requests | systemd status, `GET /`, `GET /v1/models`, and journal inspection | Operational | PASS | New PID `696958`; service active/enabled; Opus 5 present; post-restart request returned HTTP 200 | + +## Checkpoints + +- `f38fe7e` — RED prefill regression tests +- `a1fcc78` — GREEN upstream prefill rewrite +- `58efcdf` — RED Opus 5/date/tool-call review tests +- `bd7ed2f` — GREEN dated-model guard + +Two-axis Codex review was rerun after the review fixes and returned CLEAN for +both Standards and Spec. + +## Coverage and known gap + +`bun test --coverage` passes all 35 tests and reports 77.06% line coverage and +69.11% function coverage for the repository's current three-test suite. This is +below the generic 80% project-wide target because unrelated error/response +translation paths remain uncovered. The changed prefill branches, exact Opus 5 +mapping, dashed/dotted variants, dated variants, and full tool-call exception +are covered explicitly. No project coverage threshold is configured. From 9f9ba74ddf00d407505b6a37065514aff2c1b77a Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 29 Jul 2026 17:16:23 +0800 Subject: [PATCH 6/7] fix: extend streaming idle timeout --- src/start.ts | 22 +++++++++++++++++----- tests/server-options.test.ts | 13 +++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tests/server-options.test.ts diff --git a/src/start.ts b/src/start.ts index 14abbbdff..dd82048f7 100644 --- a/src/start.ts +++ b/src/start.ts @@ -3,7 +3,7 @@ import { defineCommand } from "citty" import clipboard from "clipboardy" import consola from "consola" -import { serve, type ServerHandler } from "srvx" +import { serve, type ServerHandler, type ServerOptions } from "srvx" import invariant from "tiny-invariant" import { ensurePaths } from "./lib/paths" @@ -27,6 +27,21 @@ interface RunServerOptions { proxyEnv: boolean } +export const HTTP_IDLE_TIMEOUT_SECONDS = 255 + +export function createServeOptions( + fetch: ServerHandler, + port: number, +): ServerOptions { + return { + fetch, + port, + bun: { + idleTimeout: HTTP_IDLE_TIMEOUT_SECONDS, + }, + } +} + export async function runServer(options: RunServerOptions): Promise { if (options.proxyEnv) { initProxyFromEnv() @@ -114,10 +129,7 @@ export async function runServer(options: RunServerOptions): Promise { `🌐 Usage Viewer: https://ericc-ch.github.io/copilot-api?endpoint=${serverUrl}/usage`, ) - serve({ - fetch: server.fetch as ServerHandler, - port: options.port, - }) + serve(createServeOptions(server.fetch as ServerHandler, options.port)) } export const start = defineCommand({ diff --git a/tests/server-options.test.ts b/tests/server-options.test.ts new file mode 100644 index 000000000..fcfc5d7ee --- /dev/null +++ b/tests/server-options.test.ts @@ -0,0 +1,13 @@ +import { describe, expect, test } from "bun:test" + +import { createServeOptions } from "~/start" + +const fetch = () => new Response("ok") + +describe("HTTP server options", () => { + test("allows long pauses between streaming response chunks", () => { + const options = createServeOptions(fetch, 4141) + + expect(options.bun?.idleTimeout).toBe(255) + }) +}) From bc8e58effd4cb1cff126560bff20d43e1d86b9bc Mon Sep 17 00:00:00 2001 From: momo Date: Wed, 29 Jul 2026 17:24:10 +0800 Subject: [PATCH 7/7] docs: establish maintained Mizoreww fork --- CHANGELOG.md | 30 +++++++++++++++++ README.md | 92 ++++++++++++++++++++++++++++++++++++++-------------- bun.lock | 34 +------------------ package.json | 11 +++---- 4 files changed, 104 insertions(+), 63 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..58b4097c8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,30 @@ +# Changelog + +## [0.7.0-mizore.1] - 2026-07-29 + +### Features + +- Added a maintained compatibility baseline for direct Claude Code usage with + GitHub Copilot Business. +- Documented the tested direct-mode configuration for Claude Opus 5. + +### Design Rationale + +- Preserve upstream `v0.7.0` behavior while carrying only the compatibility and + reliability fixes required by current clients. +- Keep the fork installable from source without publishing or claiming ownership + of the upstream npm package. + +### Fixes + +- Rewrite unsupported trailing assistant prefills before forwarding requests. +- Keep exact Opus 5 IDs unchanged, convert dashed minor versions to Copilot's + dotted form, and reduce dated IDs to their supported base model. +- Raise Bun's streaming idle timeout from its 10-second default to 255 seconds. + +### Notes & Caveats + +- This project reverse-engineers GitHub Copilot endpoints and is not supported + by GitHub. +- GitHub may change model availability or request contracts without notice. +- Use responsibly and comply with GitHub's terms and acceptable-use policies. diff --git a/README.md b/README.md index 0d36c13c9..3d0a28021 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,19 @@ # Copilot API Proxy +> [!NOTE] +> **Maintained fork:** This repository is the `Mizoreww` compatibility fork +> based on upstream `v0.7.0`. It keeps the locally verified fixes required for +> current Claude Code usage: +> +> - Exact Opus 5 IDs remain unchanged, dashed minor versions are converted to +> Copilot's dotted form, and dated IDs fall back to their supported base model. +> - Unsupported trailing assistant prefills are rewritten compatibly. +> - Quiet streaming responses no longer reset after Bun's default 10-second +> idle timeout. +> +> Upstream remains available at +> [`ericc-ch/copilot-api`](https://github.com/ericc-ch/copilot-api). + > [!WARNING] > This is a reverse-engineered proxy of GitHub Copilot API. It is not supported by GitHub, and may break unexpectedly. Use at your own risk. @@ -57,6 +71,31 @@ To install dependencies, run: bun install ``` +### Install this maintained fork + +```sh +git clone https://github.com/Mizoreww/copilot-api.git +cd copilot-api +bun install --frozen-lockfile +bun run build +bun dist/main.js start --account-type business --port 4141 +``` + +For Claude Code direct mode, keep CC Switch routing disabled and use: + +```json +{ + "model": "opus", + "env": { + "ANTHROPIC_BASE_URL": "http://localhost:4141", + "ANTHROPIC_AUTH_TOKEN": "dummy", + "ANTHROPIC_MODEL": "claude-opus-5", + "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-5[1M]", + "ANTHROPIC_DEFAULT_OPUS_MODEL_NAME": "claude-opus-5" + } +} +``` + ## Using with Docker Build image @@ -116,26 +155,31 @@ The Docker image includes: - Health check for container monitoring - Pinned base image version for reproducible builds -## Using with npx +## Running this fork -You can run the project directly using npx: +This fork is not published to npm. Run the source-built executable so the local +compatibility fixes are included: ```sh -npx copilot-api@latest start +bun dist/main.js start ``` With options: ```sh -npx copilot-api@latest start --port 8080 +bun dist/main.js start --port 8080 ``` For authentication only: ```sh -npx copilot-api@latest auth +bun dist/main.js auth ``` +> [!CAUTION] +> `npx copilot-api@latest` installs the upstream npm release and does not include +> this fork's fixes. + ## Command Structure Copilot API now uses a subcommand structure with these main commands: @@ -211,59 +255,59 @@ New endpoints for monitoring your Copilot usage and quotas. ## Example Usage -Using with npx: +Run these examples from a built checkout of this fork: ```sh # Basic usage with start command -npx copilot-api@latest start +bun dist/main.js start # Run on custom port with verbose logging -npx copilot-api@latest start --port 8080 --verbose +bun dist/main.js start --port 8080 --verbose # Use with a business plan GitHub account -npx copilot-api@latest start --account-type business +bun dist/main.js start --account-type business # Use with an enterprise plan GitHub account -npx copilot-api@latest start --account-type enterprise +bun dist/main.js start --account-type enterprise # Enable manual approval for each request -npx copilot-api@latest start --manual +bun dist/main.js start --manual # Set rate limit to 30 seconds between requests -npx copilot-api@latest start --rate-limit 30 +bun dist/main.js start --rate-limit 30 # Wait instead of error when rate limit is hit -npx copilot-api@latest start --rate-limit 30 --wait +bun dist/main.js start --rate-limit 30 --wait # Provide GitHub token directly -npx copilot-api@latest start --github-token ghp_YOUR_TOKEN_HERE +bun dist/main.js start --github-token ghp_YOUR_TOKEN_HERE # Run only the auth flow -npx copilot-api@latest auth +bun dist/main.js auth # Run auth flow with verbose logging -npx copilot-api@latest auth --verbose +bun dist/main.js auth --verbose # Show your Copilot usage/quota in the terminal (no server needed) -npx copilot-api@latest check-usage +bun dist/main.js check-usage # Display debug information for troubleshooting -npx copilot-api@latest debug +bun dist/main.js debug # Display debug information in JSON format -npx copilot-api@latest debug --json +bun dist/main.js debug --json # Initialize proxy from environment variables (HTTP_PROXY, HTTPS_PROXY, etc.) -npx copilot-api@latest start --proxy-env +bun dist/main.js start --proxy-env ``` ## Using the Usage Viewer After starting the server, a URL to the Copilot Usage Dashboard will be displayed in your console. This dashboard is a web interface for monitoring your API usage. -1. Start the server. For example, using npx: +1. Start the source-built server: ```sh - npx copilot-api@latest start + bun dist/main.js start ``` 2. The server will output a URL to the usage viewer. Copy and paste this URL into your browser. It will look something like this: `https://ericc-ch.github.io/copilot-api?endpoint=http://localhost:4141/usage` @@ -289,7 +333,7 @@ There are two ways to configure Claude Code to use this proxy: To get started, run the `start` command with the `--claude-code` flag: ```sh -npx copilot-api@latest start --claude-code +bun dist/main.js start --claude-code ``` You will be prompted to select a primary model and a "small, fast" model for background tasks. After selecting the models, a command will be copied to your clipboard. This command sets the necessary environment variables for Claude Code to use the proxy. @@ -346,6 +390,6 @@ bun run start - To avoid hitting GitHub Copilot's rate limits, you can use the following flags: - `--manual`: Enables manual approval for each request, giving you full control over when requests are sent. - - `--rate-limit `: Enforces a minimum time interval between requests. For example, `copilot-api start --rate-limit 30` will ensure there's at least a 30-second gap between requests. + - `--rate-limit `: Enforces a minimum time interval between requests. For example, `bun dist/main.js start --rate-limit 30` will ensure there's at least a 30-second gap between requests. - `--wait`: Use this with `--rate-limit`. It makes the server wait for the cooldown period to end instead of rejecting the request with an error. This is useful for clients that don't automatically retry on rate limit errors. - If you have a GitHub business or enterprise plan account with Copilot, use the `--account-type` flag (e.g., `--account-type business`). See the [official documentation](https://docs.github.com/en/enterprise-cloud@latest/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/managing-github-copilot-access-to-your-organizations-network#configuring-copilot-subscription-based-network-routing-for-your-enterprise-or-organization) for more details. diff --git a/bun.lock b/bun.lock index 20e895e7f..bf769d93c 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "copilot-api", @@ -20,7 +21,6 @@ "@echristian/eslint-config": "^0.0.54", "@types/bun": "^1.2.23", "@types/proxy-from-env": "^1.0.4", - "bumpp": "^10.2.3", "eslint": "^9.37.0", "knip": "^5.64.1", "lint-staged": "^16.2.3", @@ -244,8 +244,6 @@ "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - "args-tokenizer": ["args-tokenizer@0.3.0", "", {}, "sha512-xXAd7G2Mll5W8uo37GETpQ2VrE84M181Z7ugHFGQnJZ50M2mbOv0osSZ9VsSgPfJQ+LVG0prSi0th+ELMsno7Q=="], - "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], @@ -286,12 +284,8 @@ "builtin-modules": ["builtin-modules@5.0.0", "", {}, "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg=="], - "bumpp": ["bumpp@10.2.3", "", { "dependencies": { "ansis": "^4.1.0", "args-tokenizer": "^0.3.0", "c12": "^3.2.0", "cac": "^6.7.14", "escalade": "^3.2.0", "jsonc-parser": "^3.3.1", "package-manager-detector": "^1.3.0", "semver": "^7.7.2", "tinyexec": "^1.0.1", "tinyglobby": "^0.2.14", "yaml": "^2.8.1" }, "bin": { "bumpp": "bin/bumpp.mjs" } }, "sha512-nsFBZACxuBVu6yzDSaZZaWpX5hTQ+++9WtYkmO+0Bd3cpSq0Mzvqw5V83n+fOyRj3dYuZRFCQf5Z9NNfZj+Rnw=="], - "bun-types": ["bun-types@1.2.23", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-R9f0hKAZXgFU3mlrA0YpE/fiDvwV0FT9rORApt2aQVWSuJDzZOyB5QLc0N/4HF57CS8IXJ6+L5E4W1bW6NS2Aw=="], - "c12": ["c12@3.3.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.2", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.5.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-K9ZkuyeJQeqLEyqldbYLG3wjqwpw4BVaAqvmxq3GYKK0b1A/yYQdIcJxkzAOWcNVWhJpRXAPfZFueekiY/L8Dw=="], - "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], @@ -338,8 +332,6 @@ "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], @@ -368,16 +360,12 @@ "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], - "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], - "detect-indent": ["detect-indent@7.0.2", "", {}, "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A=="], "detect-newline": ["detect-newline@4.0.1", "", {}, "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog=="], "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], - "dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], - "dts-resolver": ["dts-resolver@2.1.2", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-xeXHBQkn2ISSXxbJWD828PFjtyg+/UrMDo7W4Ffcs7+YWCquxU8YjV1KoxuiL+eJ5pg3ll+bC6flVv61L3LKZg=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], @@ -464,8 +452,6 @@ "execa": ["execa@9.6.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw=="], - "exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="], - "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="], @@ -524,8 +510,6 @@ "get-tsconfig": ["get-tsconfig@4.10.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ=="], - "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], - "git-hooks-list": ["git-hooks-list@4.1.1", "", {}, "sha512-cmP497iLq54AZnv4YRAEMnEyQ1eIn4tGKbmswqwmFV4GBnAqE8NLtWxxdXa++AalfgL5EBH4IxTPyquEuGY/jA=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], @@ -660,8 +644,6 @@ "jsonc-eslint-parser": ["jsonc-eslint-parser@2.4.1", "", { "dependencies": { "acorn": "^8.5.0", "eslint-visitor-keys": "^3.0.0", "espree": "^9.0.0", "semver": "^7.3.5" } }, "sha512-uuPNLJkKN8NXAlZlQ6kmUF9qO+T6Kyd7oV4+/7yy8Jz6+MZNyhPq8EdLpdfnPVzUC8qSf1b4j1azKaGnFsjmsw=="], - "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], - "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], @@ -706,14 +688,10 @@ "natural-orderby": ["natural-orderby@5.0.0", "", {}, "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg=="], - "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], - "node-releases": ["node-releases@2.0.23", "", {}, "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg=="], "npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="], - "nypm": ["nypm@0.6.2", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g=="], - "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], @@ -724,8 +702,6 @@ "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], @@ -740,8 +716,6 @@ "package-json-validator": ["package-json-validator@0.30.0", "", { "dependencies": { "semver": "^7.7.2", "validate-npm-package-license": "^3.0.4", "yargs": "~18.0.0" }, "bin": { "pjv": "lib/bin/pjv.js" } }, "sha512-gOLW+BBye32t+IB2trIALIcL3DZBy3s4G4ZV6dAgDM+qLs/7jUNOV7iO7PwXqyf+3izI12qHBwtS4kOSJp5Tdg=="], - "package-manager-detector": ["package-manager-detector@1.3.0", "", {}, "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ=="], - "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], @@ -752,16 +726,12 @@ "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "perfect-debounce": ["perfect-debounce@2.0.0", "", {}, "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow=="], - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], "pidtree": ["pidtree@0.6.0", "", { "bin": { "pidtree": "bin/pidtree.js" } }, "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g=="], - "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "pluralize": ["pluralize@8.0.0", "", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="], "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], @@ -784,8 +754,6 @@ "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], - "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], "refa": ["refa@0.12.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.8.0" } }, "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g=="], diff --git a/package.json b/package.json index a5adbb8e7..6357b5c78 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,18 @@ { "name": "copilot-api", - "version": "0.7.0", + "version": "0.7.0-mizore.1", + "private": true, "description": "Turn GitHub Copilot into OpenAI/Anthropic API compatible server. Usable with Claude Code!", "keywords": [ "proxy", "github-copilot", "openai-compatible" ], - "homepage": "https://github.com/ericc-ch/copilot-api", - "bugs": "https://github.com/ericc-ch/copilot-api/issues", + "homepage": "https://github.com/Mizoreww/copilot-api", + "bugs": "https://github.com/Mizoreww/copilot-api/issues", "repository": { "type": "git", - "url": "git+https://github.com/ericc-ch/copilot-api.git" + "url": "git+https://github.com/Mizoreww/copilot-api.git" }, "author": "Erick Christian ", "type": "module", @@ -29,7 +30,6 @@ "lint:all": "eslint --cache .", "prepack": "bun run build", "prepare": "simple-git-hooks", - "release": "bumpp && bun publish --access public", "start": "NODE_ENV=production bun run ./src/main.ts", "typecheck": "tsc" }, @@ -56,7 +56,6 @@ "@echristian/eslint-config": "^0.0.54", "@types/bun": "^1.2.23", "@types/proxy-from-env": "^1.0.4", - "bumpp": "^10.2.3", "eslint": "^9.37.0", "knip": "^5.64.1", "lint-staged": "^16.2.3",