useclaudeproxy 1.0.0

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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/app.d.ts +2 -0
  4. package/dist/app.d.ts.map +1 -0
  5. package/dist/app.js +47 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/args.d.ts +17 -0
  8. package/dist/args.d.ts.map +1 -0
  9. package/dist/args.js +37 -0
  10. package/dist/args.js.map +1 -0
  11. package/dist/config-yaml.d.ts +5 -0
  12. package/dist/config-yaml.d.ts.map +1 -0
  13. package/dist/config-yaml.js +26 -0
  14. package/dist/config-yaml.js.map +1 -0
  15. package/dist/config.d.ts +9 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +29 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/http-client.d.ts +10 -0
  20. package/dist/http-client.d.ts.map +1 -0
  21. package/dist/http-client.js +33 -0
  22. package/dist/http-client.js.map +1 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +27 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/install-cli-proxy.d.ts +2 -0
  28. package/dist/install-cli-proxy.d.ts.map +1 -0
  29. package/dist/install-cli-proxy.js +140 -0
  30. package/dist/install-cli-proxy.js.map +1 -0
  31. package/dist/providers/hermes.d.ts +15 -0
  32. package/dist/providers/hermes.d.ts.map +1 -0
  33. package/dist/providers/hermes.js +210 -0
  34. package/dist/providers/hermes.js.map +1 -0
  35. package/dist/providers/index.d.ts +5 -0
  36. package/dist/providers/index.d.ts.map +1 -0
  37. package/dist/providers/index.js +11 -0
  38. package/dist/providers/index.js.map +1 -0
  39. package/dist/providers/types.d.ts +7 -0
  40. package/dist/providers/types.d.ts.map +1 -0
  41. package/dist/providers/types.js +2 -0
  42. package/dist/providers/types.js.map +1 -0
  43. package/dist/run-cli-proxy.d.ts +2 -0
  44. package/dist/run-cli-proxy.d.ts.map +1 -0
  45. package/dist/run-cli-proxy.js +22 -0
  46. package/dist/run-cli-proxy.js.map +1 -0
  47. package/dist/types.d.ts +31 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +23 -0
  50. package/dist/types.js.map +1 -0
  51. package/dist/yaml.example.d.ts +2 -0
  52. package/dist/yaml.example.d.ts.map +1 -0
  53. package/dist/yaml.example.js +141 -0
  54. package/dist/yaml.example.js.map +1 -0
  55. package/package.json +96 -0
@@ -0,0 +1,210 @@
1
+ import Debug from "debug";
2
+ import fs from "node:fs";
3
+ import open from "open";
4
+ import { args } from "../args.js";
5
+ import { readConfig, writeConfig } from "../config-yaml.js";
6
+ import { TOKENS_PATH } from "../config.js";
7
+ import { createOAuthHttpClient } from "../http-client.js";
8
+ import { AccessDeniedError, DeviceCodeExpiredError, OAuthHttpError, } from "../types.js";
9
+ const log = Debug("useclaudeproxy:oauth");
10
+ const errorLog = Debug("useclaudeproxy:oauth:error");
11
+ const POLL_INTERVAL_MS = 7000;
12
+ const FORM_HEADERS = {
13
+ "Content-Type": "application/x-www-form-urlencoded",
14
+ Accept: "application/json",
15
+ };
16
+ const OAUTH = {
17
+ baseUrl: "https://portal.nousresearch.com/api/oauth",
18
+ clientId: "hermes-cli",
19
+ scope: "inference:invoke",
20
+ grantType: "urn:ietf:params:oauth:grant-type:device_code",
21
+ refreshTokenHeader: "X-Nous-Refresh-Token",
22
+ };
23
+ // Device flow client — Hermes-specific (endpoints, headers, error mapping).
24
+ class HermesDeviceFlowClient {
25
+ http;
26
+ constructor(http = createOAuthHttpClient()) {
27
+ this.http = http;
28
+ }
29
+ async requestDeviceCode() {
30
+ log("Requesting device code");
31
+ const response = await this.http.post(`${OAUTH.baseUrl}/device/code`, {
32
+ headers: FORM_HEADERS,
33
+ body: `client_id=${OAUTH.clientId}&scope=${encodeURIComponent(OAUTH.scope)}`,
34
+ });
35
+ return this.parseOrThrow(response, "Failed to get device code");
36
+ }
37
+ async pollForToken(deviceCode) {
38
+ log("Polling for token");
39
+ while (true) {
40
+ await sleep(POLL_INTERVAL_MS);
41
+ const response = await this.http.post(`${OAUTH.baseUrl}/token`, {
42
+ headers: FORM_HEADERS,
43
+ body: `grant_type=${OAUTH.grantType}&client_id=${OAUTH.clientId}&device_code=${deviceCode}`,
44
+ });
45
+ if (response.statusCode === 200)
46
+ return parseBody(response);
47
+ if (response.statusCode === 400) {
48
+ this.handlePollingError(parseBody(response));
49
+ continue;
50
+ }
51
+ throw new OAuthHttpError(`Unexpected status during polling: ${response.statusCode}`, response.statusCode, response.body);
52
+ }
53
+ }
54
+ async refreshToken(refreshToken) {
55
+ log("Refreshing access token");
56
+ const response = await this.http.post(`${OAUTH.baseUrl}/token`, {
57
+ headers: { ...FORM_HEADERS, [OAUTH.refreshTokenHeader]: refreshToken },
58
+ body: `grant_type=refresh_token&client_id=${OAUTH.clientId}`,
59
+ });
60
+ return this.parseOrThrow(response, "Failed to refresh token");
61
+ }
62
+ async fetchAccountInfo(accessToken) {
63
+ log("Fetching account information");
64
+ const response = await this.http.get(`${OAUTH.baseUrl}/account`, {
65
+ headers: {
66
+ Authorization: `Bearer ${accessToken}`,
67
+ Accept: "application/json",
68
+ },
69
+ });
70
+ return this.parseOrThrow(response, "Failed to fetch account info");
71
+ }
72
+ handlePollingError(error) {
73
+ switch (error.error) {
74
+ case "authorization_pending":
75
+ case "slow_down":
76
+ return;
77
+ case "expired_token":
78
+ throw new DeviceCodeExpiredError();
79
+ case "access_denied":
80
+ throw new AccessDeniedError();
81
+ default:
82
+ throw new OAuthHttpError(`Unexpected polling error: ${error.error}`, 400, error);
83
+ }
84
+ }
85
+ parseOrThrow(response, failureMessage) {
86
+ if (response.statusCode !== 200) {
87
+ throw new OAuthHttpError(failureMessage, response.statusCode, response.body);
88
+ }
89
+ return parseBody(response);
90
+ }
91
+ }
92
+ function parseBody(response) {
93
+ return typeof response.body === "string"
94
+ ? JSON.parse(response.body)
95
+ : response.body;
96
+ }
97
+ function sleep(ms) {
98
+ return new Promise((resolve) => setTimeout(resolve, ms));
99
+ }
100
+ export class HermesProvider {
101
+ name = "hermes";
102
+ client = new HermesDeviceFlowClient();
103
+ async getValidToken() {
104
+ const stored = this.readStoredToken();
105
+ if (stored) {
106
+ try {
107
+ await this.client.fetchAccountInfo(stored.access_token);
108
+ log("Stored token valid");
109
+ return stored;
110
+ }
111
+ catch (err) {
112
+ errorLog("Stored Access-Token invalid: %o", err);
113
+ }
114
+ if (stored.refresh_token) {
115
+ try {
116
+ log("Refreshing stored token");
117
+ const refreshed = await this.client.refreshToken(stored.refresh_token);
118
+ this.saveTokens(refreshed);
119
+ return refreshed;
120
+ }
121
+ catch (err) {
122
+ errorLog("Stored Refresh-Token invalid: %o", err);
123
+ }
124
+ }
125
+ }
126
+ return this.runDeviceFlow();
127
+ }
128
+ async getAccountInfo(accessToken) {
129
+ return this.client.fetchAccountInfo(accessToken);
130
+ }
131
+ async runDeviceFlow() {
132
+ const deviceCode = await this.client.requestDeviceCode();
133
+ log("Device code received: user_code=%s", deviceCode.user_code);
134
+ const verificationUrl = deviceCode.verification_uri_complete ?? deviceCode.verification_uri;
135
+ await open(verificationUrl).catch((err) => log("Failed to open browser: %o", err));
136
+ console.log(`Opened ${verificationUrl}. If it didn't open, enter code ${deviceCode.user_code} there.`);
137
+ const token = await this.client.pollForToken(deviceCode.device_code);
138
+ log("Authorization successful");
139
+ this.initConfig(args.model);
140
+ this.saveTokens(token);
141
+ return token;
142
+ }
143
+ readStoredToken() {
144
+ if (!fs.existsSync(TOKENS_PATH))
145
+ return undefined;
146
+ try {
147
+ return JSON.parse(fs.readFileSync(TOKENS_PATH, "utf8"));
148
+ }
149
+ catch {
150
+ return undefined;
151
+ }
152
+ }
153
+ saveTokens(token) {
154
+ fs.writeFileSync(TOKENS_PATH, JSON.stringify(token, null, 2), {
155
+ mode: 0o600,
156
+ });
157
+ this.setApiKey(token.access_token);
158
+ }
159
+ initConfig(model) {
160
+ const config = readConfig();
161
+ config["host"] = "127.0.0.1";
162
+ config["api-keys"] = ["456789"];
163
+ config["openai-compatibility"] = [{ name: "Hermes" }];
164
+ const api = config["openai-compatibility"][0];
165
+ api["base-url"] = "https://inference-api.nousresearch.com/v1";
166
+ api["models"] = [
167
+ { name: model, alias: "claude-opus-5" },
168
+ { name: model, alias: "" },
169
+ ];
170
+ api["headers"] = {
171
+ "User-Agent": "OpenAI/Python 2.24.0",
172
+ "X-Stainless-Arch": "x64",
173
+ "X-Stainless-Async": "false",
174
+ "X-Stainless-Lang": "python",
175
+ "X-Stainless-Os": "Linux",
176
+ "X-Stainless-Package-Version": "2.24.0",
177
+ "X-Stainless-Read-Timeout": "30.0",
178
+ "X-Stainless-Retry-Count": "0",
179
+ "X-Stainless-Runtime": "CPython",
180
+ "X-Stainless-Runtime-Version": "3.11.15",
181
+ };
182
+ api["disable-cooling"] = true;
183
+ const text = `
184
+ #API-KEY: ${config["api-keys"]}
185
+ OpenAI-compatible: http://127.0.0.1:${config["port"]}/v1
186
+ Anthropic-compatible: http://127.0.0.1:${config["port"]}
187
+ Gemini-compatible: http://127.0.0.1:${config["port"]}
188
+
189
+ Model >>> Alias:
190
+ ${model} >>> claude-opus-5
191
+ ${model} >>>
192
+
193
+ [ClaudeCode]
194
+ export ANTHROPIC_MODEL=claude-opus-5
195
+ export ANTHROPIC_BASE_URL=http://127.0.0.1:${config["port"]}
196
+ export ANTHROPIC_AUTH_TOKEN=${config["api-keys"]}
197
+ `;
198
+ console.log(text);
199
+ writeConfig(config);
200
+ }
201
+ setApiKey(apiKey) {
202
+ const config = readConfig();
203
+ const api = config["openai-compatibility"][0];
204
+ api["api-key-entries"] = [{ "api-key": apiKey }];
205
+ api["headers"]["Authorization"] = `Bearer ${apiKey}`;
206
+ writeConfig(config);
207
+ }
208
+ }
209
+ export const hermesProvider = new HermesProvider();
210
+ //# sourceMappingURL=hermes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes.js","sourceRoot":"","sources":["../../src/providers/hermes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Provider } from "./types.ts";
2
+ export declare function getProvider(name: string): Provider;
3
+ export declare const PROVIDER_NAMES: string[];
4
+ export type { Provider };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAQlD;AAED,eAAO,MAAM,cAAc,UAAuB,CAAC;AAEnD,YAAY,EAAE,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { hermesProvider } from "./hermes.js";
2
+ const registry = new Map([["hermes", hermesProvider]]);
3
+ export function getProvider(name) {
4
+ const provider = registry.get(name.toLowerCase());
5
+ if (!provider) {
6
+ throw new Error(`Unknown provider "${name}". Use one of: ${[...registry.keys()].join(", ")}`);
7
+ }
8
+ return provider;
9
+ }
10
+ export const PROVIDER_NAMES = [...registry.keys()];
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAmB,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;AAEzE,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,qBAAqB,IAAI,kBAAkB,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC7E,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { TokenResponse } from "../types.ts";
2
+ export interface Provider {
3
+ readonly name: string;
4
+ getValidToken(): Promise<TokenResponse>;
5
+ getAccountInfo(accessToken: string): Promise<Record<string, unknown>>;
6
+ }
7
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAExC,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export declare function runCliProxy(proxyArgs?: string[]): Promise<number>;
2
+ //# sourceMappingURL=run-cli-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-cli-proxy.d.ts","sourceRoot":"","sources":["../src/run-cli-proxy.ts"],"names":[],"mappings":"AAaA,wBAAsB,WAAW,CAAC,SAAS,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAc3E"}
@@ -0,0 +1,22 @@
1
+ import Debug from "debug";
2
+ import cp from "node:child_process";
3
+ import path from "node:path";
4
+ import { CONFIG_PATH } from "./config-yaml.js";
5
+ import { ensureCliProxy } from "./install-cli-proxy.js";
6
+ const log = Debug("app:run");
7
+ const BINARY = path.join(import.meta.dirname, "..", "tools", "cli-proxy-api");
8
+ // Spawns the extracted binary with tools/config.yaml. `proxyArgs` are passed
9
+ // through verbatim (e.g. --tui, --standalone). Inherits stdio and forwards
10
+ // signals so the user drives it directly (Ctrl+C shuts the server down).
11
+ export async function runCliProxy(proxyArgs = []) {
12
+ await ensureCliProxy();
13
+ const argv = [BINARY, "-config", CONFIG_PATH, ...proxyArgs];
14
+ log("Spawning: %s", argv.join(" "));
15
+ const child = cp.spawn(argv[0], argv.slice(1), { stdio: "inherit" });
16
+ const forward = (sig) => () => child.kill(sig);
17
+ process.on("SIGINT", forward("SIGINT"));
18
+ process.on("SIGTERM", forward("SIGTERM"));
19
+ process.on("exit", () => child.kill());
20
+ return new Promise((resolve) => child.on("exit", (code) => resolve(code ?? 0)));
21
+ }
22
+ //# sourceMappingURL=run-cli-proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-cli-proxy.js","sourceRoot":"","sources":["../src/run-cli-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACpC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;AAE7B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC;AAE9E,6EAA6E;AAC7E,2EAA2E;AAC3E,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,SAAS,GAAa,EAAE;IACxD,MAAM,cAAc,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,CAAC;IAC5D,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAErE,MAAM,OAAO,GAAG,CAAC,GAAmB,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAEvC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAC7B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAC/C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,31 @@
1
+ export type DeviceCodeResponse = {
2
+ device_code: string;
3
+ user_code: string;
4
+ verification_uri: string;
5
+ verification_uri_complete?: string;
6
+ expires_in: number;
7
+ interval: number;
8
+ };
9
+ export type TokenResponse = {
10
+ access_token: string;
11
+ refresh_token?: string;
12
+ token_type: string;
13
+ expires_in?: number;
14
+ };
15
+ export type TokenErrorResponse = {
16
+ error: "authorization_pending" | "slow_down" | "expired_token" | "access_denied" | string;
17
+ error_description?: string;
18
+ };
19
+ export type AccountInfo = Record<string, unknown>;
20
+ export declare class OAuthHttpError extends Error {
21
+ readonly statusCode: number;
22
+ readonly body: unknown;
23
+ constructor(message: string, statusCode: number, body: unknown);
24
+ }
25
+ export declare class DeviceCodeExpiredError extends Error {
26
+ constructor();
27
+ }
28
+ export declare class AccessDeniedError extends Error {
29
+ constructor();
30
+ }
31
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EACD,uBAAuB,GACvB,WAAW,GACX,eAAe,GACf,eAAe,GACf,MAAM,CAAC;IACX,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD,qBAAa,cAAe,SAAQ,KAAK;aAGrB,UAAU,EAAE,MAAM;aAClB,IAAI,EAAE,OAAO;IAH/B,YACE,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,EAI9B;CACF;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,cAGC;CACF;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,cAGC;CACF"}
package/dist/types.js ADDED
@@ -0,0 +1,23 @@
1
+ export class OAuthHttpError extends Error {
2
+ statusCode;
3
+ body;
4
+ constructor(message, statusCode, body) {
5
+ super(message);
6
+ this.statusCode = statusCode;
7
+ this.body = body;
8
+ this.name = "OAuthHttpError";
9
+ }
10
+ }
11
+ export class DeviceCodeExpiredError extends Error {
12
+ constructor() {
13
+ super("Device code expired before authorization completed");
14
+ this.name = "DeviceCodeExpiredError";
15
+ }
16
+ }
17
+ export class AccessDeniedError extends Error {
18
+ constructor() {
19
+ super("User denied the authorization request");
20
+ this.name = "AccessDeniedError";
21
+ }
22
+ }
23
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA4BA,MAAM,OAAO,cAAe,SAAQ,KAAK;IAGrB,UAAU;IACV,IAAI;IAHtB,YACE,OAAe,EACC,UAAkB,EAClB,IAAa;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;0BAHC,UAAU;oBACV,IAAI;QAGpB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C;QACE,KAAK,CAAC,oDAAoD,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C;QACE,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=yaml.example.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml.example.d.ts","sourceRoot":"","sources":["../src/yaml.example.ts"],"names":[],"mappings":""}
@@ -0,0 +1,141 @@
1
+ import Debug from "debug";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { CONFIG_PATH, readConfig, writeConfig } from "./config-yaml.js";
6
+ if (!process.env.DEBUG) {
7
+ Debug.enable("app:*");
8
+ }
9
+ const log = Debug("app:main");
10
+ const logRead = Debug("app:read");
11
+ const logWrite = Debug("app:write");
12
+ const logArray = Debug("app:array");
13
+ const logProxy = Debug("app:proxy");
14
+ const logProvider = Debug("app:provider");
15
+ const logOpenAI = Debug("app:openai-compat");
16
+ const logCache = Debug("app:cache");
17
+ const logError = Debug("app:error");
18
+ const SEED_CONFIG_PATH = CONFIG_PATH;
19
+ // const SEED_CONFIG_PATH = path.join(import.meta.dirname, "config.sample.yaml");
20
+ function dumpFile(filePath, logger, label) {
21
+ logger("%s:\n%s", label, fs.readFileSync(filePath, "utf8"));
22
+ }
23
+ // The old setProxyUrl() validated the value before writing it. `write()` no
24
+ // longer knows anything about specific keys, so validation like this now
25
+ // lives at the call site instead.
26
+ function assertValidProxyUrl(url) {
27
+ const u = url.trim();
28
+ const isEmpty = u === "";
29
+ const isKeyword = /^(direct|none)$/i.test(u);
30
+ const isProxyScheme = /^(socks5|http|https):\/\//i.test(u);
31
+ if (!isEmpty && !isKeyword && !isProxyScheme) {
32
+ throw new Error(`Invalid proxy-url: ${url} (use http/https/socks5://..., "direct", "none", or "")`);
33
+ }
34
+ }
35
+ async function main() {
36
+ const workDir = fs.mkdtempSync(path.join(os.tmpdir(), "app-config-"));
37
+ const configPath = path.join(workDir, "config.yaml");
38
+ fs.copyFileSync(SEED_CONFIG_PATH, configPath);
39
+ log("copied seed config.yaml to scratch path %s", configPath);
40
+ dumpFile(configPath, logRead, "initial config");
41
+ const config = readConfig(configPath);
42
+ logRead("config.host -> %o", config.host);
43
+ logRead("config.port -> %o", config.port);
44
+ logRead("config.debug -> %o", config.debug);
45
+ logRead("config['does-not-exist'] -> %o", config["does-not-exist"]);
46
+ // --- scalar values: just assign directly ---
47
+ config.port = 9090;
48
+ logWrite("config.port = 9090 -> now reads %o", config.port);
49
+ config.debug = true;
50
+ logWrite("config.debug = true -> now reads %o", config.debug);
51
+ config["ws-auth"] = false;
52
+ logWrite("config['ws-auth'] = false -> now reads %o", config["ws-auth"]);
53
+ // --- arrays: ordinary array methods, no dedicated helpers needed ---
54
+ logArray("config['api-keys'] -> %O", config["api-keys"]);
55
+ config["api-keys"].push("your-api-key-4");
56
+ logArray("api-keys.push('your-api-key-4') -> %O", config["api-keys"]);
57
+ config["api-keys"] = config["api-keys"].filter((key) => key !== "your-api-key-2");
58
+ logArray("api-keys filtered out 'your-api-key-2' -> %O", config["api-keys"]);
59
+ config["api-keys"] = ["fresh-key-a", "fresh-key-b"];
60
+ logArray("api-keys reassigned wholesale -> %O", config["api-keys"]);
61
+ config["excluded-models"] = [
62
+ ...(config["excluded-models"] ?? []),
63
+ "gpt-5-*",
64
+ ];
65
+ logArray("excluded-models created on demand -> %O", config["excluded-models"]);
66
+ logArray("Array.isArray(config.port) -> %o (port is a scalar, not an array)", Array.isArray(config.port));
67
+ // --- proxy-url: validate, then assign ---
68
+ assertValidProxyUrl("socks5://proxy.example.com:1080");
69
+ config["proxy-url"] = "socks5://proxy.example.com:1080";
70
+ logProxy("proxy-url = 'socks5://...' -> %o", config["proxy-url"]);
71
+ assertValidProxyUrl("direct");
72
+ config["proxy-url"] = "direct";
73
+ logProxy("proxy-url = 'direct' -> %o", config["proxy-url"]);
74
+ assertValidProxyUrl("");
75
+ config["proxy-url"] = "";
76
+ logProxy("proxy-url = '' -> %o", config["proxy-url"]);
77
+ try {
78
+ assertValidProxyUrl("ftp://not-supported");
79
+ config["proxy-url"] = "ftp://not-supported";
80
+ }
81
+ catch (err) {
82
+ logError("assertValidProxyUrl('ftp://not-supported') threw: %s", err.message);
83
+ }
84
+ // --- provider API keys: `${provider}-api-key` is [{ "api-key": string }] ---
85
+ function setProviderApiKey(provider, apiKey) {
86
+ const key = `${provider}-api-key`;
87
+ const entries = config[key];
88
+ if (!entries?.length) {
89
+ config[key] = [{ "api-key": apiKey }];
90
+ }
91
+ else {
92
+ entries[0]["api-key"] = apiKey;
93
+ }
94
+ }
95
+ setProviderApiKey("claude", "sk-ant-demo-111");
96
+ logProvider("after first setProviderApiKey -> %O", config["claude-api-key"]);
97
+ setProviderApiKey("claude", "sk-ant-demo-222");
98
+ logProvider("after second setProviderApiKey -> %O", config["claude-api-key"]);
99
+ setProviderApiKey("gemini", "AIzaSy-demo-key");
100
+ logProvider("after setProviderApiKey for gemini -> %O", config["gemini-api-key"]);
101
+ // --- openai-compatibility: [{ "api-key-entries": [{ "api-key": string }] }] ---
102
+ function setOpenAICompatApiKey(apiKey) {
103
+ const providers = config["openai-compatibility"];
104
+ if (!providers?.length) {
105
+ config["openai-compatibility"] = [
106
+ { "api-key-entries": [{ "api-key": apiKey }] },
107
+ ];
108
+ return;
109
+ }
110
+ const entries = providers[0]["api-key-entries"];
111
+ if (!entries?.length) {
112
+ providers[0]["api-key-entries"] = [{ "api-key": apiKey }];
113
+ }
114
+ else {
115
+ entries[0]["api-key"] = apiKey;
116
+ }
117
+ }
118
+ setOpenAICompatApiKey("hermes-demo-key-1");
119
+ logOpenAI("after first setOpenAICompatApiKey -> %O", config["openai-compatibility"]);
120
+ setOpenAICompatApiKey("hermes-demo-key-2");
121
+ logOpenAI("after second setOpenAICompatApiKey -> %O", config["openai-compatibility"]);
122
+ // --- one write() persists every mutation made above ---
123
+ writeConfig(config, configPath);
124
+ logWrite("write(config) -> persisted to %s", configPath);
125
+ dumpFile(configPath, log, "config after write()");
126
+ // --- cache behavior ---
127
+ const readAgain = readConfig(configPath);
128
+ logCache("read() right after write() returns the same object: %o", readAgain === config);
129
+ fs.writeFileSync(configPath, "mutated-on-disk: true\n", "utf8");
130
+ const stillCached = readConfig(configPath);
131
+ logCache("read() after an out-of-band file edit still returns the cache (no write() happened): %o", stillCached === config);
132
+ writeConfig(config, configPath);
133
+ dumpFile(configPath, logCache, "write() overwrote the out-of-band edit with the in-memory config");
134
+ fs.rmSync(workDir, { recursive: true, force: true });
135
+ log("cleaned up %s", workDir);
136
+ }
137
+ main().catch((err) => {
138
+ logError("example script failed: %O", err);
139
+ process.exitCode = 1;
140
+ });
141
+ //# sourceMappingURL=yaml.example.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml.example.js","sourceRoot":"","sources":["../src/yaml.example.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "useclaudeproxy",
3
+ "version": "1.0.0",
4
+ "author": "maanimeisam",
5
+ "description": "useclaudeproxy — OAuth device-flow CLI that authenticates the Hermes CLI and runs CLIProxyAPI as a local OpenAI/Claude/Gemini/Codex proxy.",
6
+ "main": "./dist/index.js",
7
+ "type": "module",
8
+ "scripts": {
9
+ "dev": "tsx --watch src/index.ts",
10
+ "dev:once": "tsx src/index.ts",
11
+ "web": "node web/server.js",
12
+ "prod": "node ./dist/index.js",
13
+ "build": "tsc",
14
+ "prebuild": "rimraf dist",
15
+ "type-check": "tsc --noEmit",
16
+ "check": "biome check --write --no-errors-on-unmatched",
17
+ "lint": "biome lint --write",
18
+ "format": "biome format --write",
19
+ "prepare": "husky"
20
+ },
21
+ "license": "MIT",
22
+ "files": [
23
+ "dist",
24
+ "README.md",
25
+ "LICENSE"
26
+ ],
27
+ "bin": {
28
+ "useclaudeproxy": "dist/index.js"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/maanimeisam/useclaudeproxy.git"
33
+ },
34
+ "homepage": "https://github.com/maanimeisam/useclaudeproxy",
35
+ "bugs": {
36
+ "url": "https://github.com/maanimeisam/useclaudeproxy/issues"
37
+ },
38
+ "engines": {
39
+ "node": ">=18"
40
+ },
41
+ "preferGlobal": true,
42
+ "lint-staged": {
43
+ "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": [
44
+ "biome check --write --no-errors-on-unmatched"
45
+ ]
46
+ },
47
+ "devDependencies": {
48
+ "@biomejs/biome": "^2.5.2",
49
+ "@types/debug": "^4.1.13",
50
+ "@types/node": "^26.1.0",
51
+ "globals": "^17.7.0",
52
+ "husky": "^9.1.7",
53
+ "lint-staged": "^17.0.8",
54
+ "rimraf": "^6.1.3",
55
+ "tsx": "^4.23.0",
56
+ "typescript": "^7.0.2"
57
+ },
58
+ "dependencies": {
59
+ "commander": "^15.0.0",
60
+ "debug": "^4.4.3",
61
+ "express": "^5.2.1",
62
+ "got": "^15.1.0",
63
+ "http-proxy-agent": "^9.1.0",
64
+ "https-proxy-agent": "^9.1.0",
65
+ "open": "^11.0.1",
66
+ "socks-proxy-agent": "^10.1.0",
67
+ "tough-cookie": "^6.0.1",
68
+ "yaml": "2.9.0",
69
+ "zod": "^4.4.3"
70
+ },
71
+ "keywords": [
72
+ "claude",
73
+ "CLIProxyAPI",
74
+ "claudecode",
75
+ "useclaudeproxy"
76
+ ],
77
+ "allowScripts": {
78
+ "file:.pnpm/got@15.1.0/node_modules/got": true,
79
+ "file:.pnpm/globals@17.11.0/node_modules/globals": true,
80
+ "file:.pnpm/rimraf@6.1.3/node_modules/rimraf": true,
81
+ "file:../../../@sindresorhus+is@8.1.0/node_modules/@sindresorhus/is": true,
82
+ "file:../../tinyexec@1.3.0/node_modules/tinyexec": true,
83
+ "file:../../esbuild@0.28.2/node_modules/esbuild": true,
84
+ "file:../../glob@13.0.6/node_modules/glob": true,
85
+ "file:../../package-json-from-dist@1.0.1/node_modules/package-json-from-dist": true,
86
+ "file:../../content-type@2.1.0/node_modules/content-type": true,
87
+ "file:../../path-to-regexp@8.4.2/node_modules/path-to-regexp": true,
88
+ "file:../../ip-address@10.5.0/node_modules/ip-address": true,
89
+ "file:../../minimatch@10.2.6/node_modules/minimatch": true,
90
+ "file:../../minipass@7.1.3/node_modules/minipass": true,
91
+ "file:../../path-scurry@2.0.2/node_modules/path-scurry": true,
92
+ "file:../../brace-expansion@5.0.9/node_modules/brace-expansion": true,
93
+ "file:../../lru-cache@11.5.2/node_modules/lru-cache": true,
94
+ "file:../../balanced-match@4.0.4/node_modules/balanced-match": true
95
+ }
96
+ }