ghc-proxy 0.10.1 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,32 +9,44 @@ A proxy that turns your GitHub Copilot subscription into an OpenAI and Anthropic
9
9
  > [!WARNING]
10
10
  > Reverse-engineered, unofficial, may break at any time. Excessive use can trigger GitHub abuse detection. **Use at your own risk.**
11
11
 
12
- **TL;DR** — Install [Bun](https://bun.com/docs/installation), then run:
13
-
14
- ```bash
15
- bunx ghc-proxy@latest start
16
- ```
12
+ **TL;DR** — Choose either supported runtime:
13
+
14
+ ```bash
15
+ # Bun >= 1.4
16
+ bunx --bun ghc-proxy@latest start
17
+
18
+ # Node.js >= 24
19
+ npx ghc-proxy@latest start
20
+ ```
17
21
 
18
22
  ## Prerequisites
19
23
 
20
24
  Before you start, make sure you have:
21
25
 
22
- 1. **Bun** (>= 1.3) -- a fast JavaScript runtime used to run the proxy
23
- - **Windows:** `winget install --id Oven-sh.Bun`
24
- - **Other platforms:** see the [official installation guide](https://bun.com/docs/installation)
25
- 2. **A GitHub Copilot subscription** -- individual, business, or enterprise
26
+ 1. **One supported JavaScript runtime:**
27
+ - **Bun >= 1.4:** `winget install --id Oven-sh.Bun` on Windows, or see the [official installation guide](https://bun.com/docs/installation)
28
+ - **Node.js >= 24:** install the latest LTS release from the [official Node.js download page](https://nodejs.org/en/download)
29
+ 2. **A GitHub Copilot subscription** -- individual, business, or enterprise
26
30
 
27
31
  ## Quick Start
28
32
 
29
- 1. Start the proxy:
30
-
31
- bunx ghc-proxy@latest start
33
+ 1. Start the proxy with your chosen runtime:
34
+
35
+ ```bash
36
+ # Bun
37
+ bunx --bun ghc-proxy@latest start
38
+
39
+ # Node.js
40
+ npx ghc-proxy@latest start
41
+ ```
32
42
 
33
43
  2. On the first run, you will be guided through GitHub's device-code authentication flow. Follow the prompts to authorize the proxy.
34
44
 
35
45
  3. Once authenticated, the proxy starts on **`http://localhost:4141`** and is ready to accept requests.
36
46
 
37
- That's it. Any tool that supports the OpenAI or Anthropic API can now point to `http://localhost:4141`.
47
+ That's it. Any tool that supports the OpenAI or Anthropic API can now point to `http://localhost:4141`.
48
+
49
+ The examples below use `bunx --bun`. If you chose Node.js, replace `bunx --bun` with `npx`; the published CLI and commands are the same.
38
50
 
39
51
  > **Tip:** If you set `--rate-limit`, add `--wait` to queue requests instead of rejecting them with 429 when the cooldown has not elapsed yet. See [Rate Limiting](#rate-limiting) for details.
40
52
 
@@ -45,7 +57,7 @@ This is the most common use case. There are two ways to set it up:
45
57
  ### Option A: One-command launch
46
58
 
47
59
  ```bash
48
- bunx ghc-proxy@latest start --claude-code
60
+ bunx --bun ghc-proxy@latest start --claude-code
49
61
  ```
50
62
 
51
63
  This starts the proxy, opens an interactive model picker, and prints a ready-to-paste environment command. Run that command in another terminal to launch Claude Code with the correct configuration.
@@ -73,7 +85,7 @@ Create or edit `~/.claude/settings.json` (this applies globally to all projects)
73
85
  Then simply start the proxy and use Claude Code as usual:
74
86
 
75
87
  ```bash
76
- bunx ghc-proxy@latest start
88
+ bunx --bun ghc-proxy@latest start
77
89
  ```
78
90
 
79
91
  **What each environment variable does:**
@@ -96,11 +108,11 @@ See the [Claude Code settings docs](https://docs.anthropic.com/en/docs/claude-co
96
108
  ghc-proxy uses a subcommand structure:
97
109
 
98
110
  ```bash
99
- bunx ghc-proxy@latest start # Start the proxy server
100
- bunx ghc-proxy@latest auth # Run GitHub auth flow without starting the server
101
- bunx ghc-proxy@latest check-usage # Show your Copilot usage/quota in the terminal
102
- bunx ghc-proxy@latest debug # Print diagnostic info (version, paths, token status)
103
- bunx ghc-proxy@latest selfcheck # Probe tokenizer chunks and Bun/Node runtime contracts in the packaged bundle
111
+ bunx --bun ghc-proxy@latest start # Start the proxy server
112
+ bunx --bun ghc-proxy@latest auth # Run GitHub auth flow without starting the server
113
+ bunx --bun ghc-proxy@latest check-usage # Show your Copilot usage/quota in the terminal
114
+ bunx --bun ghc-proxy@latest debug # Print diagnostic info (version, paths, token status)
115
+ bunx --bun ghc-proxy@latest selfcheck # Probe tokenizer chunks and Bun/Node runtime contracts in the packaged bundle
104
116
  ```
105
117
 
106
118
  ### `start` Options
@@ -133,13 +145,13 @@ If you want to throttle how often the proxy forwards requests:
133
145
 
134
146
  ```bash
135
147
  # Enforce a 30-second cooldown between requests
136
- bunx ghc-proxy@latest start --rate-limit 30
148
+ bunx --bun ghc-proxy@latest start --rate-limit 30
137
149
 
138
150
  # Same, but queue requests instead of returning 429
139
- bunx ghc-proxy@latest start --rate-limit 30 --wait
151
+ bunx --bun ghc-proxy@latest start --rate-limit 30 --wait
140
152
 
141
153
  # Manually approve every request (useful for debugging)
142
- bunx ghc-proxy@latest start --manual
154
+ bunx --bun ghc-proxy@latest start --manual
143
155
  ```
144
156
 
145
157
  `--wait` only takes effect when `--rate-limit` is also set. Without `--rate-limit`, there is no cooldown to wait on and `--wait` has no effect.
@@ -149,8 +161,8 @@ bunx ghc-proxy@latest start --manual
149
161
  If you have a GitHub Business or Enterprise Copilot plan, pass `--account-type`:
150
162
 
151
163
  ```bash
152
- bunx ghc-proxy@latest start --account-type business
153
- bunx ghc-proxy@latest start --account-type enterprise
164
+ bunx --bun ghc-proxy@latest start --account-type business
165
+ bunx --bun ghc-proxy@latest start --account-type enterprise
154
166
  ```
155
167
 
156
168
  This routes requests to the correct Copilot API endpoint for your plan. See the [GitHub docs on network routing](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 details.
@@ -160,17 +172,17 @@ This routes requests to the correct Copilot API endpoint for your plan. See the
160
172
  If your organization uses GitHub Enterprise Cloud (`*.ghe.com`), the standard GitHub device login URL differs from `github.com`. Pass your company's GHE domain on first auth:
161
173
 
162
174
  ```bash
163
- bunx ghc-proxy@latest start --account-type enterprise --ghe-domain company.ghe.com
175
+ bunx --bun ghc-proxy@latest start --account-type enterprise --ghe-domain company.ghe.com
164
176
  ```
165
177
 
166
178
  Or authenticate first, then start without the flag on subsequent runs:
167
179
 
168
180
  ```bash
169
181
  # First run (authenticates and persists the domain)
170
- bunx ghc-proxy@latest auth --ghe-domain company.ghe.com
182
+ bunx --bun ghc-proxy@latest auth --ghe-domain company.ghe.com
171
183
 
172
184
  # Later runs (domain is read from persisted config)
173
- bunx ghc-proxy@latest start --account-type enterprise
185
+ bunx --bun ghc-proxy@latest start --account-type enterprise
174
186
  ```
175
187
 
176
188
  The proxy normalizes and persists the GHE domain automatically after a successful authentication, so you only need to pass `--ghe-domain` on the first run or when switching tenants.
@@ -428,7 +440,7 @@ This keeps the existing chat pipeline stable while allowing newer Copilot models
428
440
 
429
441
  Dashboard routes are restricted to local access and return `403` when the peer, request host, or supplied `Origin` fails the loopback/same-origin checks. They are excluded from request history and access logging. See [Dashboard Observability](./docs/design/dashboard-observability.md) for the projection and security contract.
430
442
 
431
- > **Note:** The `/v1/` prefix is optional for OpenAI-compatible endpoints (`/chat/completions`, `/responses`, `/models`, `/embeddings`). Anthropic endpoints (`/v1/messages`, `/v1/messages/count_tokens`) require the `/v1` prefix. The utility and Dashboard endpoints are root-only and not exposed under `/v1`.
443
+ > **Note:** The `/v1/` prefix is optional for OpenAI-compatible endpoints (`/chat/completions`, `/responses` and its resource routes, `/models`, `/embeddings`). Anthropic endpoints (`/v1/messages`, `/v1/messages/count_tokens`) require the `/v1` prefix. The utility and Dashboard endpoints are root-only and not exposed under `/v1`.
432
444
 
433
445
  ## Responses Compatibility
434
446
 
@@ -488,51 +500,76 @@ Stripped parameters are removed entirely (never sent as `null`), because upstrea
488
500
 
489
501
  ## Docker
490
502
 
491
- Pre-built images are available on GHCR:
492
-
493
- ```bash
494
- docker pull ghcr.io/wxxb789/ghc-proxy
495
- docker run -p 4141:4141 ghcr.io/wxxb789/ghc-proxy
496
- ```
497
-
498
- Or build locally:
499
-
500
- ```bash
501
- docker build -t ghc-proxy .
502
- mkdir -p ./copilot-data
503
- docker run -p 4141:4141 -v $(pwd)/copilot-data:/root/.local/share/ghc-proxy ghc-proxy
504
- ```
505
-
506
- Authentication and settings are persisted in `copilot-data/config.json` so they survive container restarts.
507
-
508
- You can also pass a GitHub token via environment variable. The container [entrypoint](entrypoint.sh) forwards `GH_TOKEN` to `start --github-token`, so this is Docker-specific — the proxy binary itself does not read `GH_TOKEN` from the environment (outside Docker, use the `--github-token` flag or a persisted `config.json`):
509
-
510
- ```bash
511
- docker run -p 4141:4141 -e GH_TOKEN=your_token ghcr.io/wxxb789/ghc-proxy
512
- ```
513
-
514
- To run the one-time device-code auth flow inside the container instead (writes the token into the mounted data volume):
515
-
516
- ```bash
517
- docker run -it -v $(pwd)/copilot-data:/root/.local/share/ghc-proxy ghc-proxy --auth
518
- ```
519
-
520
- Docker Compose:
503
+ Pre-built images are available on GHCR:
504
+
505
+ ```bash
506
+ docker pull ghcr.io/wxxb789/ghc-proxy
507
+ docker volume create ghc-proxy-data
508
+ docker run --rm -p 127.0.0.1:4141:4141 \
509
+ -v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
510
+ ghcr.io/wxxb789/ghc-proxy
511
+ ```
512
+
513
+ Or build locally:
514
+
515
+ ```bash
516
+ docker build -t ghc-proxy .
517
+ docker volume create ghc-proxy-data
518
+ docker run --rm -p 127.0.0.1:4141:4141 \
519
+ -v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
520
+ ghc-proxy
521
+ ```
522
+
523
+ Authentication and settings are persisted in the `ghc-proxy-data` volume so they survive container restarts. The proxy does not provide API authentication. Keep the port bound to loopback as shown; any non-loopback deployment needs an authenticated TLS reverse proxy or a firewall that restricts access.
524
+
525
+ Run the device-code authentication flow once against the same volume:
526
+
527
+ ```bash
528
+ docker run --rm -it \
529
+ -v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
530
+ ghcr.io/wxxb789/ghc-proxy auth
531
+ ```
532
+
533
+ The legacy `--auth` container argument remains supported, but `auth` is the standard CLI subcommand:
534
+
535
+ ```bash
536
+ docker run --rm -it \
537
+ -v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
538
+ ghcr.io/wxxb789/ghc-proxy --auth
539
+ ```
540
+
541
+ You can also pass a GitHub token via `GH_TOKEN`. The container [entrypoint](entrypoint.sh) forwards a non-empty value only when starting the proxy, as `start --github-token`:
542
+
543
+ ```bash
544
+ docker run --rm -p 127.0.0.1:4141:4141 \
545
+ -v ghc-proxy-data:/home/bun/.local/share/ghc-proxy \
546
+ -e GH_TOKEN=your_token \
547
+ ghcr.io/wxxb789/ghc-proxy
548
+ ```
549
+
550
+ Docker Compose:
521
551
 
522
552
  ```yaml
523
553
  services:
524
- ghc-proxy:
525
- image: ghcr.io/wxxb789/ghc-proxy
526
- ports:
527
- - '4141:4141'
528
- environment:
529
- - GH_TOKEN=your_token_here
530
- restart: unless-stopped
531
- ```
532
-
533
- ## Running from Source
554
+ ghc-proxy:
555
+ image: ghcr.io/wxxb789/ghc-proxy
556
+ ports:
557
+ - '127.0.0.1:4141:4141'
558
+ volumes:
559
+ - ghc-proxy-data:/home/bun/.local/share/ghc-proxy
560
+ environment:
561
+ - GH_TOKEN=your_token_here
562
+ restart: unless-stopped
563
+
564
+ volumes:
565
+ ghc-proxy-data:
566
+ ```
534
567
 
535
- ```bash
568
+ ## Running from Source
569
+
570
+ Repository development uses Bun >= 1.4 even if you run the published package with Node.js.
571
+
572
+ ```bash
536
573
  git clone https://github.com/wxxb789/ghc-proxy.git
537
574
  cd ghc-proxy
538
575
  bun install
@@ -76,7 +76,7 @@ function getSpecialTokenRegex(tokens) {
76
76
  }
77
77
  //#endregion
78
78
  //#region node_modules/gpt-tokenizer/esm/BytePairEncodingCore.js
79
- const emptyBuffer = new Uint8Array(0);
79
+ const emptyBuffer = /* @__PURE__ */ new Uint8Array(0);
80
80
  const decoder = new TextDecoder("utf8");
81
81
  var BytePairEncodingCore = class {
82
82
  mergeableBytePairRankCount;
@@ -674,7 +674,7 @@ function Cl100KBase(bytePairRankDecoder) {
674
674
  return {
675
675
  tokenSplitRegex: CL100K_TOKEN_SPLIT_REGEX,
676
676
  bytePairRankDecoder,
677
- specialTokensEncoder: new Map([
677
+ specialTokensEncoder: /* @__PURE__ */ new Map([
678
678
  [EndOfText, 100257],
679
679
  [FimPrefix, 100258],
680
680
  [FimMiddle, 100259],
@@ -745,7 +745,7 @@ function P50KBase(bytePairRankDecoder) {
745
745
  expectedVocabularySize: 50281,
746
746
  tokenSplitRegex: R50K_TOKEN_SPLIT_REGEX,
747
747
  bytePairRankDecoder,
748
- specialTokensEncoder: new Map([[EndOfText, 50256]])
748
+ specialTokensEncoder: /* @__PURE__ */ new Map([[EndOfText, 50256]])
749
749
  };
750
750
  }
751
751
  //#endregion
@@ -754,7 +754,7 @@ function P50KEdit(bytePairRankDecoder) {
754
754
  return {
755
755
  tokenSplitRegex: R50K_TOKEN_SPLIT_REGEX,
756
756
  bytePairRankDecoder,
757
- specialTokensEncoder: new Map([
757
+ specialTokensEncoder: /* @__PURE__ */ new Map([
758
758
  [EndOfText, 50256],
759
759
  [FimPrefix, 50281],
760
760
  [FimMiddle, 50282],
@@ -769,7 +769,7 @@ function R50KBase(bytePairRankDecoder) {
769
769
  expectedVocabularySize: 50257,
770
770
  tokenSplitRegex: R50K_TOKEN_SPLIT_REGEX,
771
771
  bytePairRankDecoder,
772
- specialTokensEncoder: new Map([[EndOfText, 50256]])
772
+ specialTokensEncoder: /* @__PURE__ */ new Map([[EndOfText, 50256]])
773
773
  };
774
774
  }
775
775
  //#endregion
@@ -883,11 +883,13 @@ var GptEncoding = class GptEncoding {
883
883
  }
884
884
  }
885
885
  static getEncodingApi(encodingName, getMergeableRanks) {
886
- return new GptEncoding(getEncodingParams(encodingName, getMergeableRanks));
886
+ const modelParams = getEncodingParams(encodingName, getMergeableRanks);
887
+ return new GptEncoding(modelParams);
887
888
  }
888
889
  static getEncodingApiForModel(modelName, getMergeableRanks, modelSpec) {
890
+ const modelParams = getEncodingParams(modelToEncodingMap[modelName] ?? "o200k_base", getMergeableRanks);
889
891
  return new GptEncoding({
890
- ...getEncodingParams(modelToEncodingMap[modelName] ?? "o200k_base", getMergeableRanks),
892
+ ...modelParams,
891
893
  modelName,
892
894
  modelSpec
893
895
  });
@@ -950,7 +952,7 @@ var GptEncoding = class GptEncoding {
950
952
  const chatStartToken = this.specialTokensEncoder.get(ImStart);
951
953
  const chatEndToken = this.specialTokensEncoder.get(ImEnd);
952
954
  if (chatStartToken === void 0 || chatEndToken === void 0) throw new Error(`Model '${model}' does not support chat.`);
953
- const allowedSpecial = new Set([ImSep]);
955
+ const allowedSpecial = /* @__PURE__ */ new Set([ImSep]);
954
956
  const { messageSeparator, roleSeparator } = params;
955
957
  const encodedMessageSeparator = messageSeparator.length > 0 ? this.encode(messageSeparator) : [];
956
958
  const encodedRoleSeparator = roleSeparator.length > 0 ? this.encode(roleSeparator, { allowedSpecial }) : [];
@@ -1098,4 +1100,4 @@ var GptEncoding = class GptEncoding {
1098
1100
  //#endregion
1099
1101
  export { ImStart as _, FimPrefix as a, HarmonyChannel as c, HarmonyMessage as d, HarmonyReturn as f, ImSep as g, ImEnd as h, FimMiddle as i, HarmonyConstrain as l, HarmonyStartOfText as m, EndOfPrompt as n, FimSuffix as o, HarmonyStart as p, EndOfText as r, HarmonyCall as s, GptEncoding as t, HarmonyEnd as u, ALL_SPECIAL_TOKENS as v, DEFAULT_MERGE_CACHE_SIZE as y };
1100
1102
 
1101
- //# sourceMappingURL=GptEncoding-DdY2evDX.mjs.map
1103
+ //# sourceMappingURL=GptEncoding-DGbju5p-.mjs.map
@@ -1,4 +1,4 @@
1
- import { _ as ImStart, a as FimPrefix, c as HarmonyChannel, d as HarmonyMessage, f as HarmonyReturn, g as ImSep, h as ImEnd, i as FimMiddle, l as HarmonyConstrain, m as HarmonyStartOfText, n as EndOfPrompt, o as FimSuffix, p as HarmonyStart, r as EndOfText, s as HarmonyCall, t as GptEncoding, u as HarmonyEnd, v as ALL_SPECIAL_TOKENS, y as DEFAULT_MERGE_CACHE_SIZE } from "./GptEncoding-DdY2evDX.mjs";
1
+ import { _ as ImStart, a as FimPrefix, c as HarmonyChannel, d as HarmonyMessage, f as HarmonyReturn, g as ImSep, h as ImEnd, i as FimMiddle, l as HarmonyConstrain, m as HarmonyStartOfText, n as EndOfPrompt, o as FimSuffix, p as HarmonyStart, r as EndOfText, s as HarmonyCall, t as GptEncoding, u as HarmonyEnd, v as ALL_SPECIAL_TOKENS, y as DEFAULT_MERGE_CACHE_SIZE } from "./GptEncoding-DGbju5p-.mjs";
2
2
  //#region node_modules/gpt-tokenizer/esm/bpeRanks/cl100k_base.js
3
3
  const c0 = [
4
4
  "!",
@@ -101368,4 +101368,4 @@ const { decode, decodeAsyncGenerator, decodeGenerator, encode, encodeGenerator,
101368
101368
  //#endregion
101369
101369
  export { ALL_SPECIAL_TOKENS, DEFAULT_MERGE_CACHE_SIZE, EndOfPrompt, EndOfText, FimMiddle, FimPrefix, FimSuffix, HarmonyCall, HarmonyChannel, HarmonyConstrain, HarmonyEnd, HarmonyMessage, HarmonyReturn, HarmonyStart, HarmonyStartOfText, ImEnd, ImSep, ImStart, clearMergeCache, countTokens, decode, decodeAsyncGenerator, decodeGenerator, api as default, encode, encodeChat, encodeChatGenerator, encodeGenerator, estimateCost, isWithinTokenLimit, setMergeCacheSize, vocabularySize };
101370
101370
 
101371
- //# sourceMappingURL=cl100k_base-ChJqEXhP.mjs.map
101371
+ //# sourceMappingURL=cl100k_base-CR_-ZzWY.mjs.map