pennyrouter 0.3.25 → 0.3.26
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/package.json +1 -1
- package/src/cli.js +11 -2
- package/src/harnesses/codex.js +19 -4
- package/src/launch.js +9 -10
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -19,7 +19,13 @@ import {
|
|
|
19
19
|
} from "./harnesses/claude-code.js";
|
|
20
20
|
import { clineHarness } from "./harnesses/cline.js";
|
|
21
21
|
import { codeGptHarness } from "./harnesses/codegpt.js";
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
codexHarness,
|
|
24
|
+
detectCodexChatgptAuth,
|
|
25
|
+
isCodexSubscriptionAuthGateway,
|
|
26
|
+
isHostedPennyRouterGateway,
|
|
27
|
+
isLocalPennyRouterGateway,
|
|
28
|
+
} from "./harnesses/codex.js";
|
|
23
29
|
import { fetchOpenCodeModels, opencodeHarness } from "./harnesses/opencode.js";
|
|
24
30
|
import { windsurfHarness } from "./harnesses/windsurf.js";
|
|
25
31
|
import { zedHarness } from "./harnesses/zed.js";
|
|
@@ -39,7 +45,10 @@ import {
|
|
|
39
45
|
} from "./session.js";
|
|
40
46
|
|
|
41
47
|
async function codexNativeAuthAvailable({ gatewayBaseUrl, apiKey, localAuth }) {
|
|
42
|
-
if (!
|
|
48
|
+
if (!isCodexSubscriptionAuthGateway(gatewayBaseUrl)) return false;
|
|
49
|
+
// A local gateway should use Codex's detected login as the opt-in. Do not infer
|
|
50
|
+
// subscription auth from some other upstream credential stored on the local gateway.
|
|
51
|
+
if (isLocalPennyRouterGateway(gatewayBaseUrl)) return Boolean(localAuth);
|
|
43
52
|
const capabilities = await fetchGatewayCapabilities({ gatewayBaseUrl, apiKey });
|
|
44
53
|
const hasOpenAiCredential = Array.isArray(capabilities?.upstream_credentials)
|
|
45
54
|
&& capabilities.upstream_credentials.includes("openai_api");
|
package/src/harnesses/codex.js
CHANGED
|
@@ -103,12 +103,13 @@ export function renderCodexConfig(
|
|
|
103
103
|
text,
|
|
104
104
|
{ apiKey, gatewayBaseUrl, subscriptionAuth, surface = "codex-terminal" },
|
|
105
105
|
) {
|
|
106
|
-
// Native Codex subscription
|
|
107
|
-
//
|
|
108
|
-
// ordinary PennyRouter bearer provider, even when Codex itself is logged into ChatGPT.
|
|
106
|
+
// Native Codex ChatGPT subscription auth is allowed through the hosted gateway and the
|
|
107
|
+
// explicitly supported local development gateway. Other custom gateways use Penny auth.
|
|
109
108
|
// Keep this guard at the final renderer so every install/update/desktop path gets the
|
|
110
109
|
// same safety rule regardless of which profile selected it.
|
|
111
|
-
subscriptionAuth = Boolean(
|
|
110
|
+
subscriptionAuth = Boolean(
|
|
111
|
+
subscriptionAuth && isCodexSubscriptionAuthGateway(gatewayBaseUrl),
|
|
112
|
+
);
|
|
112
113
|
const clean = removeManagedCodexConfig(text, { removeRootProvider: true }).trimEnd();
|
|
113
114
|
if (new RegExp(`^\\s*\\[model_providers\\.${escapeRegex(PROVIDER_ID)}\\]\\s*$`, "m").test(clean)) {
|
|
114
115
|
throw new Error(
|
|
@@ -156,6 +157,20 @@ export function isHostedPennyRouterGateway(gatewayBaseUrl) {
|
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
export function isLocalPennyRouterGateway(gatewayBaseUrl) {
|
|
161
|
+
try {
|
|
162
|
+
const url = new URL(String(gatewayBaseUrl));
|
|
163
|
+
return url.hostname.toLowerCase() === "localhost" && url.port === "8400";
|
|
164
|
+
} catch {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function isCodexSubscriptionAuthGateway(gatewayBaseUrl) {
|
|
170
|
+
return isHostedPennyRouterGateway(gatewayBaseUrl)
|
|
171
|
+
|| isLocalPennyRouterGateway(gatewayBaseUrl);
|
|
172
|
+
}
|
|
173
|
+
|
|
159
174
|
export function removeManagedCodexConfig(text, { removeRootProvider = false } = {}) {
|
|
160
175
|
let out = String(text || "").replace(
|
|
161
176
|
new RegExp(`${escapeRegex(MANAGED_START)}[\\s\\S]*?${escapeRegex(MANAGED_END)}\\n?`, "g"),
|
package/src/launch.js
CHANGED
|
@@ -24,7 +24,10 @@ import {
|
|
|
24
24
|
upgradeClaudeCodeModelValue,
|
|
25
25
|
writeClaudeCodeModelPresentation,
|
|
26
26
|
} from "./harnesses/claude-code.js";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
isCodexSubscriptionAuthGateway,
|
|
29
|
+
renderCodexConfig,
|
|
30
|
+
} from "./harnesses/codex.js";
|
|
28
31
|
import {
|
|
29
32
|
OPENCODE_MODEL_CHOICES,
|
|
30
33
|
fetchOpenCodeModels,
|
|
@@ -440,16 +443,12 @@ export async function installPennyRuntime({ updatePath = true } = {}) {
|
|
|
440
443
|
}
|
|
441
444
|
|
|
442
445
|
export function renderCodexLaunchProfile({ gatewayBaseUrl, subscriptionAuth }) {
|
|
443
|
-
//
|
|
444
|
-
// Apply the same
|
|
446
|
+
// Native ChatGPT subscription auth is allowed for the hosted gateway and the explicitly
|
|
447
|
+
// supported local development gateway. Apply the same rule as the config renderer at this
|
|
445
448
|
// boundary, since this path is what bare `penny codex` selects at runtime.
|
|
446
|
-
|
|
447
|
-
subscriptionAuth
|
|
448
|
-
|
|
449
|
-
);
|
|
450
|
-
} catch {
|
|
451
|
-
subscriptionAuth = false;
|
|
452
|
-
}
|
|
449
|
+
subscriptionAuth = Boolean(
|
|
450
|
+
subscriptionAuth && isCodexSubscriptionAuthGateway(gatewayBaseUrl),
|
|
451
|
+
);
|
|
453
452
|
if (subscriptionAuth) {
|
|
454
453
|
return [
|
|
455
454
|
CODEX_PROFILE_MARKER,
|