@openhoo/hoopilot 0.7.2 → 0.7.4
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 +3 -0
- package/dist/{chunk-TEDEVCKM.js → chunk-7GSQVYYT.js} +61 -7
- package/dist/chunk-7GSQVYYT.js.map +1 -0
- package/dist/cli.js +273 -114
- package/dist/cli.js.map +1 -1
- package/dist/codexx.js +1 -1
- package/dist/index.cjs +352 -117
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +352 -117
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-TEDEVCKM.js.map +0 -1
package/README.md
CHANGED
|
@@ -184,6 +184,7 @@ Supported authentication-related settings:
|
|
|
184
184
|
- `HOOPILOT_GITHUB_DOMAIN`: GitHub domain override. Default: `github.com`.
|
|
185
185
|
- `COPILOT_API_BASE_URL`: upstream Copilot API base URL override. Default: `https://api.githubcopilot.com`.
|
|
186
186
|
- `HOOPILOT_GITHUB_API_BASE_URL`: GitHub REST API base URL used for the Copilot quota lookup. Default: `https://api.github.com`.
|
|
187
|
+
- `HOOPILOT_ALLOW_UNSAFE_UPSTREAM=1`: allow sending the stored OAuth token to nonstandard HTTPS Copilot/GitHub API hosts. Use only for trusted test or enterprise endpoints.
|
|
187
188
|
|
|
188
189
|
## Codex Auth Errors
|
|
189
190
|
|
|
@@ -212,6 +213,7 @@ If that returns `401 copilot_auth_error`, rerun `npx @openhoo/hoopilot login` an
|
|
|
212
213
|
|
|
213
214
|
```powershell
|
|
214
215
|
hoopilot [serve] [options]
|
|
216
|
+
hoopilot codexx [codex options] [prompt]
|
|
215
217
|
hoopilot login [options]
|
|
216
218
|
hoopilot models [options]
|
|
217
219
|
hoopilot usage [options]
|
|
@@ -221,6 +223,7 @@ Commands:
|
|
|
221
223
|
|
|
222
224
|
```txt
|
|
223
225
|
serve Start the proxy server (default)
|
|
226
|
+
codexx Run Codex through the local Hoopilot server
|
|
224
227
|
login Sign in through GitHub OAuth in a browser and verify Copilot access
|
|
225
228
|
models List available GitHub Copilot model IDs
|
|
226
229
|
usage Show GitHub Copilot quota and premium-request usage
|
|
@@ -1,6 +1,56 @@
|
|
|
1
1
|
// src/codexx.ts
|
|
2
2
|
import { spawn } from "child_process";
|
|
3
3
|
import { constants as osConstants } from "os";
|
|
4
|
+
|
|
5
|
+
// src/util.ts
|
|
6
|
+
function trimTrailingSlash(value) {
|
|
7
|
+
return value.replace(/\/+$/, "");
|
|
8
|
+
}
|
|
9
|
+
function envValue(value) {
|
|
10
|
+
const trimmed = value?.trim();
|
|
11
|
+
return trimmed ? trimmed : void 0;
|
|
12
|
+
}
|
|
13
|
+
function isTrustedTokenBaseUrl(rawUrl, allowedHttpsHosts, allowUnsafeHttps = false) {
|
|
14
|
+
const url = parseUrl(rawUrl);
|
|
15
|
+
if (!url) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (url.username || url.password || url.search || url.hash) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (url.pathname !== "" && url.pathname !== "/") {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (isLoopbackHttpUrl(url)) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
if (url.protocol !== "https:") {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const host = url.hostname.toLowerCase();
|
|
31
|
+
return allowedHttpsHosts.includes(host) || allowUnsafeHttps;
|
|
32
|
+
}
|
|
33
|
+
function parseUrl(rawUrl) {
|
|
34
|
+
let url;
|
|
35
|
+
try {
|
|
36
|
+
url = new URL(rawUrl);
|
|
37
|
+
} catch {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
return url;
|
|
41
|
+
}
|
|
42
|
+
function isLoopbackHttpUrl(url) {
|
|
43
|
+
return url.protocol === "http:" && (url.hostname === "127.0.0.1" || url.hostname === "localhost" || url.hostname === "::1" || url.hostname === "[::1]");
|
|
44
|
+
}
|
|
45
|
+
async function truncatedResponseText(response, max = 500) {
|
|
46
|
+
const text = await response.text();
|
|
47
|
+
return text.slice(0, max);
|
|
48
|
+
}
|
|
49
|
+
function asRecord(value) {
|
|
50
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/codexx.ts
|
|
4
54
|
var DEFAULT_BASE_URL = "http://127.0.0.1:4141/v1";
|
|
5
55
|
var DEFAULT_API_KEY = "local-key";
|
|
6
56
|
var DEFAULT_CODEX_BIN = "codex";
|
|
@@ -17,11 +67,11 @@ var PROXY_ENV_KEYS = [
|
|
|
17
67
|
"no_proxy"
|
|
18
68
|
];
|
|
19
69
|
function buildCodexxInvocation(argv, env = process.env) {
|
|
20
|
-
const baseUrl = env.CODEXX_BASE_URL ?? DEFAULT_BASE_URL;
|
|
21
|
-
const apiKey = env.CODEXX_API_KEY ?? env.HOOPILOT_API_KEY ??
|
|
22
|
-
const command = env.CODEXX_CODEX_BIN ?? DEFAULT_CODEX_BIN;
|
|
23
|
-
const model = env.CODEXX_MODEL ?? DEFAULT_MODEL;
|
|
24
|
-
const reasoningEffort = env.CODEXX_MODEL_REASONING_EFFORT ?? DEFAULT_REASONING_EFFORT;
|
|
70
|
+
const baseUrl = envValue(env.CODEXX_BASE_URL) ?? DEFAULT_BASE_URL;
|
|
71
|
+
const apiKey = envValue(env.CODEXX_API_KEY) ?? envValue(env.HOOPILOT_API_KEY) ?? DEFAULT_API_KEY;
|
|
72
|
+
const command = envValue(env.CODEXX_CODEX_BIN) ?? DEFAULT_CODEX_BIN;
|
|
73
|
+
const model = envValue(env.CODEXX_MODEL) ?? DEFAULT_MODEL;
|
|
74
|
+
const reasoningEffort = envValue(env.CODEXX_MODEL_REASONING_EFFORT) ?? DEFAULT_REASONING_EFFORT;
|
|
25
75
|
const providerConfig = [
|
|
26
76
|
'{ name = "Hoopilot"',
|
|
27
77
|
`base_url = ${JSON.stringify(baseUrl)}`,
|
|
@@ -125,7 +175,6 @@ Environment:
|
|
|
125
175
|
CODEXX_BASE_URL OpenAI-compatible base URL. Default: ${DEFAULT_BASE_URL}
|
|
126
176
|
CODEXX_API_KEY API key sent to the local Hoopilot server.
|
|
127
177
|
HOOPILOT_API_KEY Used as the API key when CODEXX_API_KEY is unset.
|
|
128
|
-
OPENAI_API_KEY Used as the API key when both CODEXX_API_KEY and HOOPILOT_API_KEY are unset.
|
|
129
178
|
CODEXX_CODEX_BIN Codex executable to run. Default: ${DEFAULT_CODEX_BIN}
|
|
130
179
|
CODEXX_MODEL Codex model to use. Default: ${DEFAULT_MODEL}
|
|
131
180
|
CODEXX_MODEL_REASONING_EFFORT
|
|
@@ -160,8 +209,13 @@ if (import.meta.main) {
|
|
|
160
209
|
}
|
|
161
210
|
|
|
162
211
|
export {
|
|
212
|
+
trimTrailingSlash,
|
|
213
|
+
envValue,
|
|
214
|
+
isTrustedTokenBaseUrl,
|
|
215
|
+
truncatedResponseText,
|
|
216
|
+
asRecord,
|
|
163
217
|
buildCodexxInvocation,
|
|
164
218
|
main,
|
|
165
219
|
verifyCodexxModel
|
|
166
220
|
};
|
|
167
|
-
//# sourceMappingURL=chunk-
|
|
221
|
+
//# sourceMappingURL=chunk-7GSQVYYT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/codexx.ts","../src/util.ts"],"sourcesContent":["#!/usr/bin/env bun\n\nimport { spawn } from \"node:child_process\";\nimport { constants as osConstants } from \"node:os\";\nimport type { FetchLike } from \"./types\";\nimport { envValue } from \"./util\";\n\nconst DEFAULT_BASE_URL = \"http://127.0.0.1:4141/v1\";\nconst DEFAULT_API_KEY = \"local-key\";\nconst DEFAULT_CODEX_BIN = \"codex\";\nconst DEFAULT_MODEL = \"gpt-5.5\";\nconst DEFAULT_REASONING_EFFORT = \"xhigh\";\nconst PROXY_ENV_KEYS = [\n \"ALL_PROXY\",\n \"HTTPS_PROXY\",\n \"HTTP_PROXY\",\n \"NO_PROXY\",\n \"all_proxy\",\n \"https_proxy\",\n \"http_proxy\",\n \"no_proxy\",\n];\n\nexport interface CodexxInvocation {\n args: string[];\n baseUrl: string;\n command: string;\n env: NodeJS.ProcessEnv;\n model: string;\n}\n\nexport function buildCodexxInvocation(\n argv: string[],\n env: NodeJS.ProcessEnv = process.env,\n): CodexxInvocation {\n const baseUrl = envValue(env.CODEXX_BASE_URL) ?? DEFAULT_BASE_URL;\n const apiKey = envValue(env.CODEXX_API_KEY) ?? envValue(env.HOOPILOT_API_KEY) ?? DEFAULT_API_KEY;\n const command = envValue(env.CODEXX_CODEX_BIN) ?? DEFAULT_CODEX_BIN;\n const model = envValue(env.CODEXX_MODEL) ?? DEFAULT_MODEL;\n const reasoningEffort = envValue(env.CODEXX_MODEL_REASONING_EFFORT) ?? DEFAULT_REASONING_EFFORT;\n const providerConfig = [\n '{ name = \"Hoopilot\"',\n `base_url = ${JSON.stringify(baseUrl)}`,\n 'env_key = \"OPENAI_API_KEY\"',\n 'wire_api = \"responses\"',\n \"supports_websockets = false }\",\n ].join(\", \");\n\n return {\n args: [\n \"--disable\",\n \"network_proxy\",\n \"-c\",\n 'model_provider=\"hoopilot\"',\n \"-c\",\n `model_providers.hoopilot=${providerConfig}`,\n \"-m\",\n model,\n \"-c\",\n `model_reasoning_effort=${JSON.stringify(reasoningEffort)}`,\n ...argv,\n ],\n baseUrl,\n command,\n env: withoutProxyEnv({\n ...env,\n OPENAI_API_KEY: apiKey,\n }),\n model,\n };\n}\n\nfunction withoutProxyEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const next = { ...env };\n for (const key of PROXY_ENV_KEYS) {\n delete next[key];\n }\n return next;\n}\n\nexport async function main(argv = Bun.argv.slice(2), env = process.env): Promise<void> {\n if (argv.length === 1 && (argv[0] === \"--help\" || argv[0] === \"-h\")) {\n console.log(helpText());\n return;\n }\n\n const invocation = buildCodexxInvocation(argv, env);\n if (env.CODEXX_SKIP_MODEL_PREFLIGHT !== \"1\") {\n await verifyCodexxModel(invocation);\n }\n const child = spawn(invocation.command, invocation.args, {\n env: invocation.env,\n shell: process.platform === \"win32\",\n stdio: \"inherit\",\n });\n\n const exitCode = await new Promise<number>((resolve, reject) => {\n child.once(\"error\", reject);\n child.once(\"exit\", (code, signal) => {\n if (typeof code === \"number\") {\n resolve(code);\n return;\n }\n resolve(signal ? 128 + signalNumber(signal) : 1);\n });\n });\n\n process.exitCode = exitCode;\n}\n\nexport async function verifyCodexxModel(\n invocation: Pick<CodexxInvocation, \"baseUrl\" | \"env\" | \"model\">,\n fetcher: FetchLike = fetch,\n): Promise<void> {\n const modelsUrl = `${invocation.baseUrl.replace(/\\/+$/, \"\")}/models`;\n let response: Response;\n try {\n response = await fetcher(modelsUrl, {\n headers: {\n accept: \"application/json\",\n authorization: `Bearer ${invocation.env.OPENAI_API_KEY ?? DEFAULT_API_KEY}`,\n },\n method: \"GET\",\n });\n } catch (error) {\n throw new Error(\n `Could not reach Hoopilot at ${modelsUrl}. Start Hoopilot first, or set CODEXX_SKIP_MODEL_PREFLIGHT=1 to skip this check. ${errorMessage(error)}`,\n );\n }\n\n if (!response.ok) {\n throw new Error(\n `Could not verify model ${JSON.stringify(invocation.model)} because ${modelsUrl} returned ${response.status}: ${await shortResponseText(response)}`,\n );\n }\n\n const models = modelIds(await response.json().catch(() => undefined));\n if (models.length > 0 && !models.includes(invocation.model)) {\n throw new Error(\n `The logged-in Copilot account does not advertise model ${JSON.stringify(invocation.model)} at ${modelsUrl}. Available models: ${models.join(\", \")}. After upgrading Hoopilot, rerun \"hoopilot login\" to refresh the Copilot OAuth token, or set CODEXX_MODEL to one of the advertised model IDs.`,\n );\n }\n}\n\nfunction helpText(): string {\n return `codexx\n\nRun Codex against an already-running local Hoopilot server.\n\nUsage:\n codexx [codex options] [prompt]\n\nEnvironment:\n CODEXX_BASE_URL OpenAI-compatible base URL. Default: ${DEFAULT_BASE_URL}\n CODEXX_API_KEY API key sent to the local Hoopilot server.\n HOOPILOT_API_KEY Used as the API key when CODEXX_API_KEY is unset.\n CODEXX_CODEX_BIN Codex executable to run. Default: ${DEFAULT_CODEX_BIN}\n CODEXX_MODEL Codex model to use. Default: ${DEFAULT_MODEL}\n CODEXX_MODEL_REASONING_EFFORT\n Codex reasoning effort. Default: ${DEFAULT_REASONING_EFFORT}\n CODEXX_SKIP_MODEL_PREFLIGHT\n Set to 1 to skip checking /v1/models before starting Codex.\n\ncodexx does not start Hoopilot and does not change your shell environment. It selects a temporary Hoopilot model provider with Responses WebSockets disabled, uses ${DEFAULT_MODEL} with ${DEFAULT_REASONING_EFFORT} reasoning by default, disables Codex's network_proxy feature, and removes proxy variables only from the spawned Codex process.`;\n}\n\nfunction signalNumber(signal: NodeJS.Signals): number {\n return osConstants.signals[signal] ?? 1;\n}\n\nfunction modelIds(value: unknown): string[] {\n const record = value && typeof value === \"object\" && !Array.isArray(value) ? value : {};\n const data = \"data\" in record && Array.isArray(record.data) ? record.data : [];\n return data\n .map((entry) =>\n entry && typeof entry === \"object\" && \"id\" in entry && typeof entry.id === \"string\"\n ? entry.id\n : undefined,\n )\n .filter((id): id is string => typeof id === \"string\" && id.length > 0);\n}\n\nasync function shortResponseText(response: Response): Promise<string> {\n const text = await response.text();\n return text.slice(0, 500);\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nif (import.meta.main) {\n main().catch((error: unknown) => {\n console.error(errorMessage(error));\n process.exit(1);\n });\n}\n","import type { JsonObject } from \"./types\";\n\n/** Remove any trailing slashes from a URL or path string. */\nexport function trimTrailingSlash(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\n/** Treat blank environment variables as unset while preserving nonblank values. */\nexport function envValue(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\n/** True for HTTPS URLs, or HTTP only on loopback hosts used by local tests/dev. */\nexport function isHttpsOrLoopbackUrl(rawUrl: string): boolean {\n const url = parseUrl(rawUrl);\n if (!url) {\n return false;\n }\n return url.protocol === \"https:\" || isLoopbackHttpUrl(url);\n}\n\n/** Validate a base URL before sending a bearer/OAuth token to it. */\nexport function isTrustedTokenBaseUrl(\n rawUrl: string,\n allowedHttpsHosts: readonly string[],\n allowUnsafeHttps = false,\n): boolean {\n const url = parseUrl(rawUrl);\n if (!url) {\n return false;\n }\n if (url.username || url.password || url.search || url.hash) {\n return false;\n }\n if (url.pathname !== \"\" && url.pathname !== \"/\") {\n return false;\n }\n if (isLoopbackHttpUrl(url)) {\n return true;\n }\n if (url.protocol !== \"https:\") {\n return false;\n }\n const host = url.hostname.toLowerCase();\n return allowedHttpsHosts.includes(host) || allowUnsafeHttps;\n}\n\nfunction parseUrl(rawUrl: string): URL | undefined {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n return undefined;\n }\n return url;\n}\n\nfunction isLoopbackHttpUrl(url: URL): boolean {\n return (\n url.protocol === \"http:\" &&\n (url.hostname === \"127.0.0.1\" ||\n url.hostname === \"localhost\" ||\n url.hostname === \"::1\" ||\n url.hostname === \"[::1]\")\n );\n}\n\n/** Read a response body as text, truncated to keep error messages bounded. */\nexport async function truncatedResponseText(response: Response, max = 500): Promise<string> {\n const text = await response.text();\n return text.slice(0, max);\n}\n\n/** Narrow an unknown value to a plain object, returning {} for arrays/primitives/null. */\nexport function asRecord(value: unknown): JsonObject {\n return value && typeof value === \"object\" && !Array.isArray(value) ? (value as JsonObject) : {};\n}\n"],"mappings":"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","names":[]}
|