@bitkyc08/opencodex 2.68.0 → 2.69.0-preview.20260928
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/bin/ocx.mjs +25 -17
- package/gui/dist/assets/App-cDPyCb_V.js +51 -0
- package/gui/dist/assets/{Tray-Bn8WhKBH.js → Tray-H1IAB8mN.js} +1 -1
- package/gui/dist/assets/index-BF9QnKO_.css +1 -0
- package/gui/dist/assets/index-CI6YTp8z.js +86 -0
- package/gui/dist/assets/{quota-summary-DL-bNuNL.js → quota-summary-CutOlPu2.js} +1 -1
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/factory-droid.svg +8 -0
- package/package.json +1 -1
- package/src/adapters/anthropic-output-schema.ts +109 -11
- package/src/adapters/coding-agent/protocol.ts +106 -11
- package/src/adapters/coding-agent/turn.ts +23 -18
- package/src/adapters/google-errors.ts +16 -1
- package/src/adapters/google-http.ts +14 -0
- package/src/adapters/openai-chat/passthrough.ts +2 -0
- package/src/adapters/openai-chat/summary-budget.ts +72 -0
- package/src/adapters/openai-chat/tool-call-id-remint.ts +11 -2
- package/src/adapters/openai-chat.ts +6 -9
- package/src/bridge/response-json.ts +3 -1
- package/src/bridge/sse.ts +3 -1
- package/src/claude/desktop-picker.ts +6 -2
- package/src/claude/desktop-system-proxy.ts +155 -0
- package/src/claude/inbound-model-options.ts +10 -2
- package/src/claude/inbound.ts +1 -1
- package/src/claude/intercept/picker-ca-cleanup.ts +31 -0
- package/src/claude/intercept/picker-ca.ts +283 -83
- package/src/claude/intercept/picker-models.ts +4 -1
- package/src/claude/intercept/picker-trust.ts +15 -2
- package/src/claude/intercept/runtime.ts +99 -32
- package/src/cli/account-api.ts +5 -2
- package/src/cli/account-extended.ts +47 -11
- package/src/cli/account-target.ts +12 -7
- package/src/cli/account.ts +47 -3
- package/src/cli/capabilities.ts +33 -7
- package/src/cli/claude-agent-startup-sync.ts +2 -0
- package/src/cli/claude-desktop.ts +37 -13
- package/src/cli/cross-home-owner.ts +138 -0
- package/src/cli/dispatch.ts +1 -1
- package/src/cli/doctor.ts +18 -8
- package/src/cli/ensure-desired-integrations.ts +5 -0
- package/src/cli/export-command.ts +6 -6
- package/src/cli/help.ts +1 -1
- package/src/cli/index.ts +15 -18
- package/src/cli/integrations.ts +8 -1
- package/src/cli/models-runtime-subcommands.ts +1 -0
- package/src/cli/models-runtime.ts +106 -4
- package/src/cli/models.ts +6 -1
- package/src/cli/opencode.ts +2 -83
- package/src/cli/registry.ts +3 -2
- package/src/cli/status.ts +86 -7
- package/src/client/connect.ts +24 -10
- package/src/client/link-ingress.ts +3 -1
- package/src/client/link-join.ts +76 -9
- package/src/client/link-relay-transport.ts +184 -0
- package/src/client/link-relay.ts +16 -4
- package/src/client/machine-listener.ts +2 -0
- package/src/clients/config-export/constants.ts +8 -0
- package/src/clients/config-export/contracts.ts +13 -1
- package/src/clients/config-export/droid.ts +71 -0
- package/src/clients/config-export/kilo.ts +116 -0
- package/src/clients/config-export.ts +33 -2
- package/src/codex/auth-api/routes.ts +1 -1
- package/src/codex/catalog/access-programs.ts +14 -2
- package/src/codex/catalog/provider-models.ts +1 -1
- package/src/codex/catalog-auto-refresh.ts +122 -0
- package/src/codex/config-drift-heal.ts +80 -0
- package/src/codex/desktop-switches.ts +7 -5
- package/src/codex/inject/bounded-config-reader.ts +69 -0
- package/src/codex/inject/config-toml.ts +31 -3
- package/src/codex/inject/routing-target.ts +6 -1
- package/src/codex/inject.ts +4 -0
- package/src/codex/model-entitlements.ts +32 -5
- package/src/codex/native-profile-startup.ts +17 -5
- package/src/codex/project-config-warnings.ts +72 -21
- package/src/codex/quota-auto-refresh-state.ts +8 -2
- package/src/codex/quota-auto-refresh.ts +80 -9
- package/src/codex/sync.ts +10 -0
- package/src/combos/failover.ts +4 -1
- package/src/combos/jev.ts +15 -4
- package/src/combos/types.ts +16 -0
- package/src/config/diagnostics.ts +19 -1
- package/src/config/load-degrade.ts +29 -0
- package/src/config/macos-system-proxy.ts +114 -0
- package/src/config/proxy-env.ts +67 -20
- package/src/config/schema/config-schema.ts +15 -0
- package/src/config/schema/leaf-validators.ts +23 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +220 -144
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/config-io.ts +12 -3
- package/src/integrations/droid-settings.ts +65 -0
- package/src/integrations/kilo-candidates.ts +30 -0
- package/src/integrations/mutation-plan.ts +62 -7
- package/src/integrations/native/ownership-preflight.ts +46 -12
- package/src/integrations/registry.ts +136 -7
- package/src/integrations/state.ts +52 -4
- package/src/integrations/target.ts +3 -0
- package/src/integrations/writer.ts +55 -14
- package/src/lib/account-selection-events.ts +14 -0
- package/src/lib/jsonc.ts +110 -0
- package/src/lib/standalone.ts +9 -1
- package/src/lib/windows-system-proxy.ts +101 -1
- package/src/link/relay-auth.ts +29 -0
- package/src/link/ssh-argv.ts +6 -3
- package/src/link/ssh-runner.ts +5 -5
- package/src/oauth/generic-account-failover.ts +52 -8
- package/src/oauth/index.ts +37 -14
- package/src/oauth/store.ts +96 -11
- package/src/oauth/token-guardian.ts +7 -3
- package/src/oauth/types.ts +2 -0
- package/src/plugins/loader.ts +5 -3
- package/src/providers/fastwire.ts +3 -0
- package/src/providers/key-failover.ts +13 -5
- package/src/providers/kiro-model-catalog.ts +4 -3
- package/src/providers/model-rename-fields.ts +1 -0
- package/src/providers/openai-tiers-destination.ts +9 -0
- package/src/providers/quota/account-cache.ts +17 -3
- package/src/providers/quota/vendor-probes-oauth.ts +2 -0
- package/src/providers/quota.ts +2 -2
- package/src/responses/code-mode-helper-compat.ts +14 -1
- package/src/responses/custom-tool-compat.ts +1 -1
- package/src/server/auth-cors.ts +1 -0
- package/src/server/images.ts +70 -20
- package/src/server/index/link-listener.ts +20 -3
- package/src/server/index/link-relay-sessions.ts +138 -0
- package/src/server/index/optional-listeners.ts +11 -1
- package/src/server/index/serve-options.ts +12 -0
- package/src/server/inference/client-encoder-delivery.ts +1 -0
- package/src/server/local-management-read-client.ts +21 -2
- package/src/server/management/agent-settings-routes.ts +19 -5
- package/src/server/management/combo-routes.ts +5 -3
- package/src/server/management/config-routes.ts +32 -6
- package/src/server/management/model-routes.ts +232 -7
- package/src/server/management/model-rows.ts +199 -1
- package/src/server/management/oauth-account-routes.ts +63 -3
- package/src/server/management/route-registry.ts +2 -0
- package/src/server/port-reclaim.ts +170 -32
- package/src/server/responses/adapter-delivery.ts +6 -4
- package/src/server/responses/adapter-dispatch.ts +72 -2
- package/src/server/responses/core-combo.ts +6 -1
- package/src/server/responses/core-normalize.ts +19 -4
- package/src/server/responses/core-options.ts +2 -0
- package/src/server/responses/memory-models.ts +169 -0
- package/src/server/responses/passthrough-delivery.ts +4 -0
- package/src/server/responses/passthrough-dispatch.ts +10 -0
- package/src/server/responses/request-prepare.ts +86 -4
- package/src/server/responses/request-transport.ts +4 -0
- package/src/server/responses/run-turn-execution.ts +5 -2
- package/src/server/responses/shadow-target-availability.ts +17 -4
- package/src/server/responses/sidecar-execution.ts +18 -2
- package/src/server/responses/skills-snapshot.ts +239 -0
- package/src/server/responses-undeclared-tool-guard.ts +43 -6
- package/src/server/search.ts +1 -1
- package/src/service/guards.ts +4 -5
- package/src/service/state.ts +39 -2
- package/src/service.ts +2 -2
- package/src/types/config.ts +46 -4
- package/src/types/provider.ts +9 -0
- package/src/types/request.ts +6 -0
- package/src/types/tools.ts +38 -8
- package/src/types.ts +3 -0
- package/src/update/async-check.ts +5 -1
- package/src/update/index.ts +30 -12
- package/src/update/job.ts +3 -1
- package/src/update/pnpm-read-policy.d.mts +4 -0
- package/src/update/pnpm-read-policy.mjs +44 -0
- package/src/update/worker-launch.ts +152 -11
- package/src/usage/cost.ts +6 -3
- package/src/usage/log.ts +4 -0
- package/src/web-search/backends.ts +2 -2
- package/src/web-search/devin-executor.ts +1 -1
- package/src/web-search/sidecar-providers.ts +5 -5
- package/gui/dist/assets/App-mpsibsFj.js +0 -51
- package/gui/dist/assets/index-BDUBS8PW.css +0 -1
- package/gui/dist/assets/index-kUE8tuAK.js +0 -86
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { isIP } from "node:net";
|
|
3
|
+
|
|
4
|
+
export type MacOSProxyReader = () => string | null;
|
|
5
|
+
export type MacOSSystemProxyResult =
|
|
6
|
+
| { kind: "proxy"; httpUrl?: string; httpsUrl?: string; exceptions: string[]; droppedLinkLocal: boolean }
|
|
7
|
+
| { kind: "disabled" | "unreadable" | "unsafe-exceptions" };
|
|
8
|
+
|
|
9
|
+
function readScutilProxy(): string {
|
|
10
|
+
return execFileSync("/usr/sbin/scutil", ["--proxy"], {
|
|
11
|
+
encoding: "utf8",
|
|
12
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
13
|
+
timeout: 2_000,
|
|
14
|
+
maxBuffer: 64 * 1024,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function proxyUrl(host: string | undefined, port: string | undefined): string | undefined {
|
|
19
|
+
if (!host || !port || !/^\d+$/.test(port) || +port < 1 || +port > 65535) return undefined;
|
|
20
|
+
const bareHost = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
21
|
+
if (!isIP(bareHost) && !/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?\.?$/i.test(host)) return undefined;
|
|
22
|
+
try {
|
|
23
|
+
return new URL(`http://${isIP(bareHost) === 6 ? `[${bareHost}]` : host}:${port}`).origin;
|
|
24
|
+
} catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Bun matches a leading-dot entry at DNS-label boundaries and also bypasses the
|
|
30
|
+
// bare apex. Translating "*.local" to ".local" therefore widens only to "local";
|
|
31
|
+
// other glob shapes are refused. Bun cannot represent the default link-local
|
|
32
|
+
// CIDRs, so they are dropped with a diagnostic instead of blocking discovery.
|
|
33
|
+
// null means one of those exact ranges was dropped; undefined refuses discovery.
|
|
34
|
+
function translateException(value: string): string | null | undefined {
|
|
35
|
+
if (value === "*") return value;
|
|
36
|
+
if (value === "169.254/16" || value === "169.254.0.0/16") return null;
|
|
37
|
+
const ipv6Range = /^(?:\[([0-9a-f:]+)\]|([0-9a-f:]+))\/10$/i.exec(value);
|
|
38
|
+
const ipv6Base = ipv6Range?.[1] ?? ipv6Range?.[2];
|
|
39
|
+
if (ipv6Base && isIP(ipv6Base) === 6
|
|
40
|
+
&& new URL(`http://[${ipv6Base}]`).hostname === "[fe80::]") return null;
|
|
41
|
+
if (value.startsWith("*.")) {
|
|
42
|
+
const domain = value.slice(2);
|
|
43
|
+
if (domain.length > 253 || !domain.split(".").every(label => label.length <= 63
|
|
44
|
+
&& /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(label))) return undefined;
|
|
45
|
+
return `.${domain.toLowerCase()}`;
|
|
46
|
+
}
|
|
47
|
+
if (isIP(value) === 4) {
|
|
48
|
+
const canonical = new URL(`http://${value}`).hostname;
|
|
49
|
+
return value === canonical ? value : undefined;
|
|
50
|
+
}
|
|
51
|
+
const bare = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
52
|
+
return isIP(bare) === 6 ? new URL(`http://[${bare}]`).hostname : undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Read only the global dictionary; scoped service dictionaries do not apply globally. */
|
|
56
|
+
export function readMacOSSystemProxy(reader: MacOSProxyReader = readScutilProxy): MacOSSystemProxyResult {
|
|
57
|
+
try {
|
|
58
|
+
const output = reader();
|
|
59
|
+
if (!output || output.length > 64 * 1024 || !/^\s*<dictionary>\s*\{/.test(output)) return { kind: "unreadable" };
|
|
60
|
+
const values = new Map<string, string>();
|
|
61
|
+
const exceptions: string[] = [];
|
|
62
|
+
let depth = 0;
|
|
63
|
+
let inExceptions = false;
|
|
64
|
+
for (const row of output.split(/\r?\n/)) {
|
|
65
|
+
const line = row.trim();
|
|
66
|
+
if (line.endsWith("{")) {
|
|
67
|
+
if (inExceptions) return { kind: "unreadable" };
|
|
68
|
+
if (depth === 1) {
|
|
69
|
+
inExceptions = /^ExceptionsList\s*:\s*<array>\s*\{$/.test(line);
|
|
70
|
+
if (line.startsWith("ExceptionsList") && !inExceptions) return { kind: "unreadable" };
|
|
71
|
+
}
|
|
72
|
+
depth++;
|
|
73
|
+
} else if (line === "}") {
|
|
74
|
+
if (--depth < 0) return { kind: "unreadable" };
|
|
75
|
+
if (depth === 1) inExceptions = false;
|
|
76
|
+
} else {
|
|
77
|
+
const entry = /^([^:]+)\s*:\s*(.*?)\s*$/.exec(line);
|
|
78
|
+
if (!entry) {
|
|
79
|
+
if (inExceptions) return { kind: "unreadable" };
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (depth === 1) {
|
|
83
|
+
if (entry[1]!.trim() === "ExceptionsList") return { kind: "unreadable" };
|
|
84
|
+
values.set(entry[1]!.trim(), entry[2]!);
|
|
85
|
+
}
|
|
86
|
+
if (depth === 2 && inExceptions) {
|
|
87
|
+
if (!/^\d+$/.test(entry[1]!.trim())) return { kind: "unreadable" };
|
|
88
|
+
exceptions.push(entry[2]!);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (depth !== 0) return { kind: "unreadable" };
|
|
93
|
+
if (values.get("ExcludeSimpleHostnames") === "1" || values.get("ProxyAutoConfigEnable") === "1"
|
|
94
|
+
|| values.get("ProxyAutoDiscoveryEnable") === "1") return { kind: "unsafe-exceptions" };
|
|
95
|
+
for (const key of ["HTTPEnable", "HTTPSEnable", "ExcludeSimpleHostnames", "ProxyAutoConfigEnable", "ProxyAutoDiscoveryEnable"]) {
|
|
96
|
+
const value = values.get(key);
|
|
97
|
+
if (value !== undefined && value !== "0" && value !== "1") return { kind: "unreadable" };
|
|
98
|
+
}
|
|
99
|
+
const translated = exceptions.map(translateException);
|
|
100
|
+
if (translated.some(value => value === undefined)) return { kind: "unsafe-exceptions" };
|
|
101
|
+
const httpEnabled = values.get("HTTPEnable") === "1";
|
|
102
|
+
const httpsEnabled = values.get("HTTPSEnable") === "1";
|
|
103
|
+
const httpUrl = httpEnabled ? proxyUrl(values.get("HTTPProxy"), values.get("HTTPPort")) : undefined;
|
|
104
|
+
const httpsUrl = httpsEnabled ? proxyUrl(values.get("HTTPSProxy"), values.get("HTTPSPort")) : undefined;
|
|
105
|
+
if ((httpEnabled && !httpUrl) || (httpsEnabled && !httpsUrl)) return { kind: "unreadable" };
|
|
106
|
+
return httpUrl || httpsUrl
|
|
107
|
+
? { kind: "proxy", httpUrl, httpsUrl,
|
|
108
|
+
exceptions: translated.filter((value): value is string => typeof value === "string"),
|
|
109
|
+
droppedLinkLocal: translated.includes(null) }
|
|
110
|
+
: { kind: "disabled" };
|
|
111
|
+
} catch {
|
|
112
|
+
return { kind: "unreadable" };
|
|
113
|
+
}
|
|
114
|
+
}
|
package/src/config/proxy-env.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { DEFAULT_SUBAGENT_MODELS, SUBAGENT_MODELS_VERSION } from "./subagent-mod
|
|
|
5
5
|
import { MULTI_AGENT_SURFACE_ADVISORY_VERSION } from "./multi-agent-surface";
|
|
6
6
|
import { DEFAULT_APP_OWNED_MEMORY_BUDGET_BYTES } from "../lib/app-owned-memory";
|
|
7
7
|
import { describeProxyForLog, readWindowsSystemProxy, type WindowsProxyRegistryReader } from "../lib/windows-system-proxy";
|
|
8
|
+
import { readMacOSSystemProxy, type MacOSProxyReader } from "./macos-system-proxy";
|
|
8
9
|
import { OPENAI_PROVIDER_TIER_VERSION, type OcxConfig } from "../types";
|
|
9
10
|
import type { OcxRuntimeRole } from "../types/config";
|
|
10
11
|
|
|
@@ -152,6 +153,23 @@ function mergeNoProxyEntries(configured: readonly string[] = [], loopback: reado
|
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
|
|
156
|
+
function configuredNoProxyEntries(config: OcxConfig): string[] {
|
|
157
|
+
const raw = config.noProxy;
|
|
158
|
+
let entries: string[];
|
|
159
|
+
if (Array.isArray(raw)) {
|
|
160
|
+
if (raw.some(entry => typeof entry !== "string")) warnProxyConfigDiscardOnce("noProxyElements");
|
|
161
|
+
entries = raw.filter((entry): entry is string => typeof entry === "string");
|
|
162
|
+
} else if (typeof raw === "string") {
|
|
163
|
+
const resolved = resolveEnvValue(raw);
|
|
164
|
+
if (raw && resolved === undefined) warnProxyConfigDiscardOnce("noProxy");
|
|
165
|
+
entries = (resolved ?? "").split(",");
|
|
166
|
+
} else {
|
|
167
|
+
if (raw !== undefined) warnProxyConfigDiscardOnce("noProxy");
|
|
168
|
+
entries = [];
|
|
169
|
+
}
|
|
170
|
+
return entries.map(entry => entry.trim()).filter(Boolean);
|
|
171
|
+
}
|
|
172
|
+
|
|
155
173
|
/**
|
|
156
174
|
* Mirror `config.proxy` into HTTP(S)_PROXY env vars. Bun fetch consumes them natively; transports
|
|
157
175
|
* such as the ChatGPT upstream WebSocket select the same environment explicitly. User-set HTTP(S)_PROXY
|
|
@@ -172,7 +190,7 @@ export function applyProxyEnv(config: OcxConfig, announce = false): void {
|
|
|
172
190
|
/** Test seam for `proxy: "auto"`: the registry reader and platform are injectable. */
|
|
173
191
|
export function applyProxyEnvWith(
|
|
174
192
|
config: OcxConfig,
|
|
175
|
-
auto: { reader?: WindowsProxyRegistryReader; platform?: NodeJS.Platform } = {},
|
|
193
|
+
auto: { reader?: WindowsProxyRegistryReader; macOSReader?: MacOSProxyReader; platform?: NodeJS.Platform } = {},
|
|
176
194
|
): void {
|
|
177
195
|
// `proxy` and `noProxy` are not declared in the top-level schema, which ends in
|
|
178
196
|
// `.passthrough()`, so whatever is on disk arrives here verbatim. A non-string value
|
|
@@ -194,6 +212,52 @@ export function applyProxyEnvWith(
|
|
|
194
212
|
return;
|
|
195
213
|
}
|
|
196
214
|
if (proxy.trim().toLowerCase() === "auto") {
|
|
215
|
+
if ((auto.platform ?? process.platform) === "darwin") {
|
|
216
|
+
// An inherited scheme or ALL_PROXY route owns both its proxy and bypass
|
|
217
|
+
// variables. Combining it with system exceptions would change that route.
|
|
218
|
+
if (["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy", "ALL_PROXY", "all_proxy"]
|
|
219
|
+
.some(key => process.env[key]?.trim())) {
|
|
220
|
+
console.log('[opencodex] proxy "auto": existing proxy environment wins; macOS system proxy not consulted');
|
|
221
|
+
configureSocks5Fetch();
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const found = readMacOSSystemProxy(auto.macOSReader);
|
|
225
|
+
if (found.kind !== "proxy") {
|
|
226
|
+
const reason = found.kind === "unsafe-exceptions"
|
|
227
|
+
? "macOS exceptions cannot be safely translated; discovery refused"
|
|
228
|
+
: found.kind === "disabled"
|
|
229
|
+
? "macOS system proxy is disabled"
|
|
230
|
+
: "macOS proxy settings could not be read";
|
|
231
|
+
console.log(`[opencodex] proxy "auto": ${reason}; proxy environment unchanged`);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const configured = configuredNoProxyEntries(config);
|
|
235
|
+
const inheritedLowercase = process.env.no_proxy?.trim();
|
|
236
|
+
if (inheritedLowercase && configured.some(host => /^localhost\.?$/i.test(host))) {
|
|
237
|
+
console.log('[opencodex] proxy "auto": configured noProxy "localhost" cannot be represented exactly for Bun while an inherited no_proxy is set; discovery refused');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const origins = [
|
|
241
|
+
found.httpUrl && `HTTP ${describeProxyForLog(found.httpUrl)}`,
|
|
242
|
+
found.httpsUrl && `HTTPS ${describeProxyForLog(found.httpsUrl)}`,
|
|
243
|
+
].filter(Boolean).join(", ");
|
|
244
|
+
console.log(`[opencodex] proxy "auto": using macOS system proxy ${origins}`);
|
|
245
|
+
if (found.droppedLinkLocal) {
|
|
246
|
+
console.log('[opencodex] proxy "auto": link-local IP literals use the proxy; macOS link-local range exceptions are not expressible');
|
|
247
|
+
}
|
|
248
|
+
if (found.httpUrl) process.env.HTTP_PROXY = found.httpUrl;
|
|
249
|
+
if (found.httpsUrl) process.env.HTTPS_PROXY = found.httpsUrl;
|
|
250
|
+
// Bun gives non-empty lowercase no_proxy priority over NO_PROXY. Before
|
|
251
|
+
// discovery there was no proxy, so an ordinary configured name and its
|
|
252
|
+
// subdomains can stay direct in both paths. Bare localhost is refused
|
|
253
|
+
// above when lowercase is inherited: Bun cannot match it exactly there.
|
|
254
|
+
mergeNoProxyEntries([...configured, ...found.exceptions], LOOPBACK_ADDRESS_NO_PROXY);
|
|
255
|
+
if (process.env.no_proxy?.trim()) {
|
|
256
|
+
process.env.no_proxy = withNoProxyEntries(process.env.no_proxy, [...configured, ...found.exceptions], LOOPBACK_ADDRESS_NO_PROXY);
|
|
257
|
+
}
|
|
258
|
+
configureSocks5Fetch();
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
197
261
|
// #1525 slice 1: one startup read of the Windows static proxy. Never copy the literal
|
|
198
262
|
// "auto" into HTTP_PROXY; every non-proxy outcome leaves outbound routing as it was.
|
|
199
263
|
if (process.env.HTTP_PROXY?.trim() || process.env.http_proxy?.trim()
|
|
@@ -213,7 +277,7 @@ export function applyProxyEnvWith(
|
|
|
213
277
|
proxy = undefined;
|
|
214
278
|
} else {
|
|
215
279
|
const reason = found.kind === "unsupported"
|
|
216
|
-
? "only Windows system proxy discovery is supported; using direct egress on this OS"
|
|
280
|
+
? "only Windows and macOS system proxy discovery is supported; using direct egress on this OS"
|
|
217
281
|
: found.kind === "disabled"
|
|
218
282
|
? "Windows system proxy is disabled; using direct egress"
|
|
219
283
|
: found.kind === "socks-only"
|
|
@@ -240,23 +304,6 @@ export function applyProxyEnvWith(
|
|
|
240
304
|
}
|
|
241
305
|
// Configured entries first, then loopback: loopback is unconditional, so appending it last
|
|
242
306
|
// keeps it present even when the operator lists a loopback host themselves.
|
|
243
|
-
|
|
244
|
-
let configuredEntries: string[];
|
|
245
|
-
if (Array.isArray(raw)) {
|
|
246
|
-
// One unusable element must not discard the operator's other entries.
|
|
247
|
-
if (raw.some(entry => typeof entry !== "string")) warnProxyConfigDiscardOnce("noProxyElements");
|
|
248
|
-
configuredEntries = raw.filter((entry): entry is string => typeof entry === "string");
|
|
249
|
-
} else if (typeof raw === "string") {
|
|
250
|
-
const resolved = resolveEnvValue(raw);
|
|
251
|
-
if (raw && resolved === undefined) warnProxyConfigDiscardOnce("noProxy");
|
|
252
|
-
configuredEntries = (resolved ?? "").split(",");
|
|
253
|
-
} else {
|
|
254
|
-
if (raw !== undefined) warnProxyConfigDiscardOnce("noProxy");
|
|
255
|
-
configuredEntries = [];
|
|
256
|
-
}
|
|
257
|
-
const configured = configuredEntries
|
|
258
|
-
.map(entry => entry.trim())
|
|
259
|
-
.filter(Boolean);
|
|
260
|
-
mergeNoProxyEntries(configured);
|
|
307
|
+
mergeNoProxyEntries(configuredNoProxyEntries(config));
|
|
261
308
|
configureSocks5Fetch();
|
|
262
309
|
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
remoteGuiConfigSchema,
|
|
17
17
|
runtimeRoleSchema,
|
|
18
18
|
spendSchema,
|
|
19
|
+
skillsConfigSchema,
|
|
19
20
|
configuredCodexPoolAccountIds,
|
|
20
21
|
apiKeyEntrySchema,
|
|
21
22
|
asideProfileSyncSchema,
|
|
@@ -24,6 +25,8 @@ import {
|
|
|
24
25
|
codexAccountNamespacesSchema,
|
|
25
26
|
modelPinnedEffortsSchema,
|
|
26
27
|
compactionRoutingSchema,
|
|
28
|
+
memoryModelSettingSchema,
|
|
29
|
+
memoryModelsSchema,
|
|
27
30
|
modelPreferHostedToolsConfigError,
|
|
28
31
|
providerModelCostsConfigError,
|
|
29
32
|
providerRelativeSendPathConfigError,
|
|
@@ -78,6 +81,7 @@ export const configSchema = z.object({
|
|
|
78
81
|
// A malformed privacy block must never be read as "unmask": .catch(undefined) drops it and
|
|
79
82
|
// emailMaskingEnabled then falls back to masked, which is also what an absent block means.
|
|
80
83
|
privacy: z.object({ maskEmails: z.boolean().optional() }).strict().optional().catch(undefined),
|
|
84
|
+
skills: skillsConfigSchema.optional().catch(undefined),
|
|
81
85
|
// Malformed hand edits disable this opt-in exporter. Live writes reject them in diagnostics.ts.
|
|
82
86
|
metricsExport: z.object({ enabled: z.boolean().optional() }).strict().optional().catch(undefined),
|
|
83
87
|
// Kept raw on purpose: `.catch(undefined)` would turn a mistyped `enabled` into "inherit",
|
|
@@ -158,6 +162,17 @@ export const configSchema = z.object({
|
|
|
158
162
|
modelPinnedEfforts: modelPinnedEffortsSchema.optional(),
|
|
159
163
|
compactionRouting: compactionRoutingSchema.optional().catch(undefined),
|
|
160
164
|
compactionRecovery: compactionRecoverySchema.optional().catch(undefined),
|
|
165
|
+
// A hand-edited malformed phase disables only that phase instead of rejecting
|
|
166
|
+
// providers/apiKeys, matching the load-time degradation notice; the management write
|
|
167
|
+
// boundary (validateConfigCandidate) still refuses the bad value through the shared,
|
|
168
|
+
// catch-free memoryModelsSchema.
|
|
169
|
+
memoryModels: z
|
|
170
|
+
.object({
|
|
171
|
+
extract: memoryModelSettingSchema.optional().catch(undefined),
|
|
172
|
+
consolidation: memoryModelSettingSchema.optional().catch(undefined),
|
|
173
|
+
})
|
|
174
|
+
.optional()
|
|
175
|
+
.catch(undefined),
|
|
161
176
|
defaultProvider: z.string().min(1).default("openai"),
|
|
162
177
|
defaultModelAliases: z.boolean().optional(),
|
|
163
178
|
// Malformed hand edits disable this opt-in projection without rejecting providers.
|
|
@@ -55,6 +55,21 @@ export const compactionRoutingSchema = z.object({
|
|
|
55
55
|
.optional(),
|
|
56
56
|
}).strict();
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* One phase of Codex's memory pipeline. A present phase must name a model: the GUI's "Off"
|
|
60
|
+
* removes the phase instead of blanking it, so an empty entry would only ever come from a
|
|
61
|
+
* hand-edited file, where failing the write is the honest answer.
|
|
62
|
+
*/
|
|
63
|
+
export const memoryModelSettingSchema = z.object({
|
|
64
|
+
model: z.string().trim().min(1),
|
|
65
|
+
reasoningEffort: z.string().refine(value => pinnedReasoningEffortConfigError(value) === null).optional(),
|
|
66
|
+
}).strict();
|
|
67
|
+
|
|
68
|
+
export const memoryModelsSchema = z.object({
|
|
69
|
+
extract: memoryModelSettingSchema.optional(),
|
|
70
|
+
consolidation: memoryModelSettingSchema.optional(),
|
|
71
|
+
}).strict();
|
|
72
|
+
|
|
58
73
|
/**
|
|
59
74
|
* Bounds for the opt-in same-target 429 wait-and-retry policy. Single source of truth
|
|
60
75
|
* shared by the config schema, the load-time sanitizer, and the management write
|
|
@@ -297,6 +312,7 @@ export const providerConfigSchema = z.object({
|
|
|
297
312
|
annotateEmptyToolOutputs: z.boolean().optional(),
|
|
298
313
|
foldDeveloperRoleToSystem: z.boolean().optional(),
|
|
299
314
|
fastWire: fastWireSchema.nullable().optional(),
|
|
315
|
+
responseTierAuthoritative: z.boolean().optional(),
|
|
300
316
|
fastEnabled: z.boolean().optional(),
|
|
301
317
|
supportsServiceTier: z.boolean().optional(),
|
|
302
318
|
modelSupportsServiceTier: z.record(z.string().min(1), z.boolean()).optional(),
|
|
@@ -1055,3 +1071,10 @@ export const spendSchema = z.object({
|
|
|
1055
1071
|
pool: spendScopeSchema.optional(),
|
|
1056
1072
|
retentionDays: z.number().int().min(1).max(365).optional(),
|
|
1057
1073
|
}).strict();
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Runtime skills catalog configuration (#5569).
|
|
1077
|
+
*/
|
|
1078
|
+
export const skillsConfigSchema = z.object({
|
|
1079
|
+
catalog_refresh: z.enum(["per_session", "per_turn"]).optional(),
|
|
1080
|
+
}).strict();
|
package/src/config.ts
CHANGED
|
@@ -267,6 +267,7 @@ export function loadConfig(): OcxConfig {
|
|
|
267
267
|
warnConfigRepaired(configPath, result.error);
|
|
268
268
|
const config = normalizeApiKeyIds(retryResult.data as OcxConfig);
|
|
269
269
|
warnInheritedFastWireConflicts(configPath, config);
|
|
270
|
+
warnDegradedTopLevelOptIns(parsed, config);
|
|
270
271
|
warnDegradedHostname(parsed, config);
|
|
271
272
|
warnDegradedListeners(parsed, config);
|
|
272
273
|
warnDegradedApiKeys(parsed, config);
|
|
@@ -296,6 +297,7 @@ export function loadConfig(): OcxConfig {
|
|
|
296
297
|
warnDroppedConfigSections(configPath, salvaged.dropped, salvaged.issues);
|
|
297
298
|
const config = normalizeApiKeyIds(salvaged.parsed);
|
|
298
299
|
warnInheritedFastWireConflicts(configPath, config);
|
|
300
|
+
warnDegradedTopLevelOptIns(parsed, config);
|
|
299
301
|
warnDegradedHostname(parsed, config);
|
|
300
302
|
warnDegradedListeners(parsed, config);
|
|
301
303
|
warnDegradedApiKeys(parsed, config);
|