@bitkyc08/opencodex 2.75.0 → 2.76.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.
- package/README.md +6 -1
- package/bin/ocx.mjs +12 -1
- package/gui/dist/assets/App-CddorHdA.js +51 -0
- package/gui/dist/assets/App-DMudtISW.css +1 -0
- package/gui/dist/assets/{Tray-CGAD2AGk.js → Tray-DjNwwrWS.js} +1 -1
- package/gui/dist/assets/index-Btze1I3T.css +1 -0
- package/gui/dist/assets/index-CvnY7E6i.js +86 -0
- package/gui/dist/assets/quota-summary-B_AWpHfP.js +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/opengateway.svg +12 -0
- package/package.json +1 -1
- package/src/adapters/anthropic/account-metadata.ts +17 -0
- package/src/adapters/anthropic/client-identity.ts +69 -0
- package/src/adapters/anthropic/passthrough.ts +23 -4
- package/src/adapters/anthropic.ts +18 -1
- package/src/adapters/command-code-project-context.ts +7 -11
- package/src/adapters/devin/cloud-direct/tool-schema.ts +12 -48
- package/src/adapters/kiro-retry.ts +23 -8
- package/src/adapters/openai-chat/messages.ts +1 -1
- package/src/adapters/registry.ts +8 -1
- package/src/adapters/zed.ts +377 -0
- package/src/bridge/sse.ts +4 -2
- package/src/chatgpt/app-server-shim/app-server-rewrite.ts +45 -0
- package/src/chatgpt/app-server-shim/bundle-trust.ts +77 -0
- package/src/chatgpt/app-server-shim/filter.ts +157 -0
- package/src/chatgpt/app-server-shim/gate-rewrite.ts +99 -0
- package/src/chatgpt/app-server-shim/launcher.ts +91 -0
- package/src/claude/desktop-3p-startup.ts +62 -0
- package/src/claude/desktop-3p.ts +5 -0
- package/src/claude/first-party-settings.ts +14 -0
- package/src/claude/intercept/cli-catalog.ts +150 -0
- package/src/claude/intercept/cli-picker.ts +82 -0
- package/src/claude/intercept/listener.ts +21 -6
- package/src/claude/intercept/picker-bootstrap.ts +23 -5
- package/src/claude/intercept/picker-models.ts +57 -13
- package/src/claude/intercept/runtime.ts +30 -2
- package/src/claude/intercept/settings.ts +3 -0
- package/src/cli/agent.ts +172 -0
- package/src/cli/alias.ts +2 -1
- package/src/cli/capabilities-command.ts +3 -2
- package/src/cli/capabilities.ts +87 -0
- package/src/cli/chatgpt-command.ts +140 -0
- package/src/cli/combo.ts +144 -19
- package/src/cli/config-command.ts +3 -1
- package/src/cli/dispatch.ts +10 -1
- package/src/cli/help.ts +1 -0
- package/src/cli/index.ts +5 -24
- package/src/cli/init.ts +16 -2
- package/src/cli/integrations.ts +13 -0
- package/src/cli/internal-command.ts +12 -5
- package/src/cli/observe.ts +6 -1
- package/src/cli/registry.ts +6 -0
- package/src/cli/route-policy.ts +3 -1
- package/src/cli/runtime-api.ts +5 -2
- package/src/cli/status-oauth.ts +5 -0
- package/src/cli/status.ts +8 -1
- package/src/cli/stop-approval.ts +55 -16
- package/src/cli/stop-report.ts +5 -0
- package/src/clients/lazycodex.ts +48 -0
- package/src/clients/omo-role-models.ts +111 -0
- package/src/codex/account-credit-use.ts +99 -0
- package/src/codex/account-lifecycle.ts +2 -0
- package/src/codex/agent-role-models.ts +171 -0
- package/src/codex/auth-api/account-list.ts +10 -3
- package/src/codex/auth-api/routes.ts +34 -0
- package/src/codex/auth-context.ts +52 -11
- package/src/codex/catalog/discovered-natives.ts +11 -1
- package/src/codex/catalog/gather-capture.ts +6 -1
- package/src/codex/catalog/model-hints.ts +9 -1
- package/src/codex/catalog/provider-models.ts +60 -0
- package/src/codex/catalog/routed-gather.ts +30 -5
- package/src/codex/convergence-types.ts +2 -1
- package/src/codex/main-account-external-usage.ts +62 -0
- package/src/codex/main-account-hard-lock.ts +24 -13
- package/src/codex/native-profile-processes.ts +53 -16
- package/src/codex/prompt-layers/toml-edit.ts +1 -1
- package/src/codex/quota-types.ts +3 -7
- package/src/codex/quota.ts +19 -4
- package/src/codex/role-auto-assign.ts +159 -0
- package/src/codex/role-sizing-limits.ts +2 -0
- package/src/codex/role-sizing.ts +216 -0
- package/src/codex/routing/selection.ts +36 -0
- package/src/codex/routing/thread-affinity.ts +2 -0
- package/src/codex/routing.ts +4 -4
- package/src/codex/subagent-model-fallback.ts +82 -26
- package/src/codex/subagent-selectable-models.ts +32 -0
- package/src/combos/index.ts +18 -0
- package/src/combos/jev-decision-contract.ts +20 -0
- package/src/combos/jev-dispatch.ts +18 -0
- package/src/combos/jev-model-backend.ts +127 -0
- package/src/combos/jev.ts +249 -33
- package/src/combos/types.ts +125 -2
- package/src/config/diagnostics.ts +18 -0
- package/src/config/macos-system-proxy.ts +72 -15
- package/src/config/owner-registry.ts +13 -4
- package/src/config/process-state.ts +17 -8
- package/src/config/proxy-env.ts +35 -5
- package/src/config/schema/config-schema.ts +30 -1
- package/src/config/schema/leaf-validators.ts +4 -0
- package/src/config/serving-runtimes.ts +95 -1
- package/src/generated/compatibility-version.json +336 -156
- package/src/lib/errors.ts +7 -7
- package/src/lib/jsonc.ts +13 -0
- package/src/lib/local-chat-completion.ts +144 -0
- package/src/lib/provider-outbound.ts +87 -1
- package/src/lib/provider-runtime-fetch.ts +23 -0
- package/src/lib/provider-tls-profile.ts +221 -0
- package/src/lib/request-execution-budget.ts +16 -6
- package/src/lib/spend-reservation-ledger.ts +54 -20
- package/src/lib/sse-decoder.ts +20 -17
- package/src/lib/synced-state-location.ts +96 -0
- package/src/lib/winsw.ts +14 -5
- package/src/oauth/anthropic-account-refusal.ts +53 -4
- package/src/oauth/anthropic-model-quota.ts +83 -0
- package/src/oauth/anthropic-rate-limit-policy.ts +37 -0
- package/src/oauth/anthropic-routing.ts +112 -58
- package/src/oauth/health.ts +39 -3
- package/src/oauth/index.ts +14 -0
- package/src/oauth/kiro-account-load.ts +10 -0
- package/src/oauth/zed.ts +134 -0
- package/src/providers/model-discovery.ts +19 -8
- package/src/providers/model-rename-fields.ts +1 -0
- package/src/providers/provider-id-rewrite.ts +9 -2
- package/src/providers/quota/account-cache.ts +29 -7
- package/src/providers/quota/anthropic-cooldown-recovery.ts +18 -0
- package/src/providers/quota/anthropic-family-headers.ts +25 -0
- package/src/providers/quota/vendor-probes-oauth.ts +5 -1
- package/src/providers/quota-types.ts +4 -0
- package/src/providers/registry/entries-core.ts +18 -0
- package/src/providers/registry/entries-extended.ts +55 -0
- package/src/providers/registry/types.ts +3 -0
- package/src/providers/xai-fast-model.ts +12 -4
- package/src/providers/zed.ts +598 -0
- package/src/responses/state/snapshot-select.ts +22 -9
- package/src/responses/state.ts +2 -3
- package/src/router.ts +9 -0
- package/src/server/anthropic-rate-limit-headers.ts +7 -0
- package/src/server/auth-cors.ts +7 -0
- package/src/server/chat-completions.ts +9 -4
- package/src/server/claude-messages.ts +59 -21
- package/src/server/index/claude-intercept-lifecycle.ts +71 -25
- package/src/server/index/optional-listeners.ts +4 -0
- package/src/server/index/spend-ledger-lifecycle.ts +4 -0
- package/src/server/management/agent-settings-routes.ts +74 -37
- package/src/server/management/claude-desktop-picker-routes.ts +7 -0
- package/src/server/management/claude-intercept-routes.ts +35 -0
- package/src/server/management/codex-agent-role-routes.ts +122 -0
- package/src/server/management/codex-role-auto-assign.ts +208 -0
- package/src/server/management/combo-routes.ts +62 -5
- package/src/server/management/config-routes.ts +35 -3
- package/src/server/management/context.ts +4 -1
- package/src/server/management/decision-discovery.ts +74 -0
- package/src/server/management/decision-model-validation.ts +80 -0
- package/src/server/management/decision-routes.ts +160 -0
- package/src/server/management/native-integration-routes.ts +16 -0
- package/src/server/management/provider-routes.ts +30 -34
- package/src/server/management/route-registry.ts +12 -0
- package/src/server/management/sibling-guard.ts +1 -0
- package/src/server/management/zed-provider-probe.ts +38 -0
- package/src/server/management-api.ts +12 -1
- package/src/server/messages-native-oauth.ts +7 -2
- package/src/server/messages-native.ts +7 -3
- package/src/server/relay.ts +3 -1
- package/src/server/request-log.ts +2 -0
- package/src/server/responses/adapter-continuation.ts +3 -3
- package/src/server/responses/adapter-dispatch.ts +18 -3
- package/src/server/responses/compact.ts +14 -1
- package/src/server/responses/core-auth.ts +2 -0
- package/src/server/responses/core-combo.ts +67 -11
- package/src/server/responses/core-normalize.ts +21 -1
- package/src/server/responses/core-options.ts +11 -1
- package/src/server/responses/core.ts +5 -3
- package/src/server/responses/fetch-helpers.ts +6 -3
- package/src/server/responses/jev-model-invoke.ts +190 -0
- package/src/server/responses/passthrough-delivery.ts +16 -0
- package/src/server/responses/policy-fallback.ts +55 -3
- package/src/server/responses/policy-request-scope.ts +80 -0
- package/src/server/responses/request-prepare.ts +70 -18
- package/src/server/responses/request-transport.ts +54 -23
- package/src/server/responses/run-turn-execution.ts +1 -0
- package/src/server/responses/sidecar-execution.ts +9 -3
- package/src/server/responses-hosted-image-display.ts +225 -0
- package/src/service/managing-cli.ts +34 -4
- package/src/service/systemd-env.ts +75 -0
- package/src/service/windows-guarded-manager.ts +60 -19
- package/src/service/windows-scheduler.ts +22 -3
- package/src/service/windows-taskxml.ts +32 -10
- package/src/service-manager-probe.ts +72 -19
- package/src/types/config.ts +31 -1
- package/src/types/provider.ts +2 -0
- package/src/types/request.ts +2 -0
- package/src/update/index.ts +39 -6
- package/src/update/job.ts +63 -63
- package/src/update/npm-cache-preflight.d.mts +33 -1
- package/src/update/npm-cache-preflight.mjs +131 -18
- package/src/update/ownership-transaction.ts +19 -1
- package/src/update/restart-ownership.ts +80 -6
- package/src/update/transactional-install.d.mts +2 -0
- package/src/update/transactional-install.mjs +6 -1
- package/src/usage/jev-stats.ts +28 -1
- package/src/usage/log.ts +1 -1
- package/src/vision/anthropic-describe.ts +5 -3
- package/src/vision/index.ts +1 -0
- package/src/vision/plan.ts +2 -1
- package/src/vision/routed-describe.ts +29 -121
- package/src/web-search/alpha-search.ts +3 -3
- package/src/web-search/anthropic-executor.ts +6 -4
- package/src/web-search/index.ts +1 -1
- package/src/web-search/loop.ts +3 -3
- package/src/web-search/passthrough-bridge.ts +2 -1
- package/src/web-search/run-turn-loop.ts +1 -1
- package/src/web-search/sidecar-providers.ts +2 -1
- package/gui/dist/assets/App-ia4U0ufY.css +0 -1
- package/gui/dist/assets/App-xm0zGNOe.js +0 -51
- package/gui/dist/assets/index-DBT3Q31Y.css +0 -1
- package/gui/dist/assets/index-D_RGAT6Q.js +0 -86
- package/gui/dist/assets/quota-summary-CUFq48t-.js +0 -1
|
@@ -2,10 +2,14 @@ import { execFileSync } from "node:child_process";
|
|
|
2
2
|
import { isIP } from "node:net";
|
|
3
3
|
|
|
4
4
|
export type MacOSProxyReader = () => string | null;
|
|
5
|
+
export type UnrepresentableCounts = { cidr: number; hostname: number; wildcard: number; other: number };
|
|
5
6
|
export type MacOSSystemProxyResult =
|
|
6
7
|
| { kind: "proxy"; httpUrl?: string; httpsUrl?: string; exceptions: string[]; droppedLinkLocal: boolean }
|
|
7
|
-
| { kind: "
|
|
8
|
+
| { kind: "unsafe-exceptions"; unrepresentable?: UnrepresentableCounts; setting?: string }
|
|
9
|
+
| { kind: "socks-only" }
|
|
10
|
+
| { kind: "disabled" | "unreadable" };
|
|
8
11
|
|
|
12
|
+
/** Reads the global proxy dictionary from /usr/sbin/scutil with tight time and size limits. */
|
|
9
13
|
function readScutilProxy(): string {
|
|
10
14
|
return execFileSync("/usr/sbin/scutil", ["--proxy"], {
|
|
11
15
|
encoding: "utf8",
|
|
@@ -15,6 +19,7 @@ function readScutilProxy(): string {
|
|
|
15
19
|
});
|
|
16
20
|
}
|
|
17
21
|
|
|
22
|
+
/** Normalizes an enabled host/port pair into an origin URL, or undefined when unusable. */
|
|
18
23
|
function proxyUrl(host: string | undefined, port: string | undefined): string | undefined {
|
|
19
24
|
if (!host || !port || !/^\d+$/.test(port) || +port < 1 || +port > 65535) return undefined;
|
|
20
25
|
const bareHost = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
@@ -26,11 +31,17 @@ function proxyUrl(host: string | undefined, port: string | undefined): string |
|
|
|
26
31
|
}
|
|
27
32
|
}
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Bun matches a leading-dot entry at DNS-label boundaries and also bypasses the
|
|
36
|
+
* bare apex. Translating "*.local" to ".local" therefore widens only to "local";
|
|
37
|
+
* other glob shapes are refused. Bun cannot represent the default link-local
|
|
38
|
+
* CIDRs, so they are dropped with a diagnostic instead of blocking discovery.
|
|
39
|
+
* Returns the translated entry, null when one of those exact ranges was dropped,
|
|
40
|
+
* or undefined when the shape cannot be represented and refuses discovery.
|
|
41
|
+
* Non-canonical IPv4 literals (e.g. leading-zero octets) return undefined; the
|
|
42
|
+
* refusal counter then reports them in the "other" shape bucket (see
|
|
43
|
+
* unrepresentableCategory) so shape counts stay interpretable.
|
|
44
|
+
*/
|
|
34
45
|
function translateException(value: string): string | null | undefined {
|
|
35
46
|
if (value === "*") return value;
|
|
36
47
|
if (value === "169.254/16" || value === "169.254.0.0/16") return null;
|
|
@@ -52,6 +63,32 @@ function translateException(value: string): string | null | undefined {
|
|
|
52
63
|
return isIP(bare) === 6 ? new URL(`http://[${bare}]`).hostname : undefined;
|
|
53
64
|
}
|
|
54
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Classifies an unrepresentable entry for refusal diagnostics. Refusals must not echo
|
|
68
|
+
* the offending entries (a system bypass list can name internal hosts), so discovery
|
|
69
|
+
* reports only how many entries fall into each shape: CIDR ranges, syntactically
|
|
70
|
+
* valid bare hostnames Bun would widen to subdomains (validated per DNS label, so
|
|
71
|
+
* malformed structures like "foo..bar" do not count), malformed wildcard shapes,
|
|
72
|
+
* and anything else. Non-canonical IPv4 literals (digit-dotted strings that fail
|
|
73
|
+
* canonicalization) are IP-shaped rather than hostnames and count as "other".
|
|
74
|
+
*/
|
|
75
|
+
function unrepresentableCategory(value: string): "cidr" | "hostname" | "wildcard" | "other" {
|
|
76
|
+
if (value.includes("/")) return "cidr";
|
|
77
|
+
if (value.includes("*")) return "wildcard";
|
|
78
|
+
if (isIP(value) || (value.startsWith("[") && value.endsWith("]"))) return "other";
|
|
79
|
+
if (/^\d+(\.\d+)+$/.test(value)) return "other";
|
|
80
|
+
const validLabels = value.split(".").every(label => label.length > 0 && label.length <= 63
|
|
81
|
+
&& /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(label));
|
|
82
|
+
return validLabels ? "hostname" : "other";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Counts unrepresentable entries by shape for the refusal diagnostic. */
|
|
86
|
+
function countUnrepresentable(values: string[]): UnrepresentableCounts {
|
|
87
|
+
const counts: UnrepresentableCounts = { cidr: 0, hostname: 0, wildcard: 0, other: 0 };
|
|
88
|
+
for (const value of values) counts[unrepresentableCategory(value)]++;
|
|
89
|
+
return counts;
|
|
90
|
+
}
|
|
91
|
+
|
|
55
92
|
/** Read only the global dictionary; scoped service dictionaries do not apply globally. */
|
|
56
93
|
export function readMacOSSystemProxy(reader: MacOSProxyReader = readScutilProxy): MacOSSystemProxyResult {
|
|
57
94
|
try {
|
|
@@ -90,24 +127,44 @@ export function readMacOSSystemProxy(reader: MacOSProxyReader = readScutilProxy)
|
|
|
90
127
|
}
|
|
91
128
|
}
|
|
92
129
|
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
130
|
for (const key of ["HTTPEnable", "HTTPSEnable", "ExcludeSimpleHostnames", "ProxyAutoConfigEnable", "ProxyAutoDiscoveryEnable"]) {
|
|
96
131
|
const value = values.get(key);
|
|
97
132
|
if (value !== undefined && value !== "0" && value !== "1") return { kind: "unreadable" };
|
|
98
133
|
}
|
|
99
|
-
const translated = exceptions.map(translateException);
|
|
100
|
-
if (translated.some(value => value === undefined)) return { kind: "unsafe-exceptions" };
|
|
101
134
|
const httpEnabled = values.get("HTTPEnable") === "1";
|
|
102
135
|
const httpsEnabled = values.get("HTTPSEnable") === "1";
|
|
103
136
|
const httpUrl = httpEnabled ? proxyUrl(values.get("HTTPProxy"), values.get("HTTPPort")) : undefined;
|
|
104
137
|
const httpsUrl = httpsEnabled ? proxyUrl(values.get("HTTPSProxy"), values.get("HTTPSPort")) : undefined;
|
|
105
138
|
if ((httpEnabled && !httpUrl) || (httpsEnabled && !httpsUrl)) return { kind: "unreadable" };
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
139
|
+
// Transport precedence: with no HTTP(S) proxy configured, no bypass list or toggle
|
|
140
|
+
// can change the outcome — SOCKS-only is the primary blocker and is reported ahead
|
|
141
|
+
// of exception shapes, which would otherwise mask it (review round 1, P2).
|
|
142
|
+
if (!(httpUrl || httpsUrl)) {
|
|
143
|
+
// PAC and WPAD can route traffic without a static HTTP(S) proxy. Saying "disabled",
|
|
144
|
+
// or "SOCKS-only, using direct egress", would misdescribe that setup, so the
|
|
145
|
+
// automatic-configuration toggle is reported first.
|
|
146
|
+
const autoSetting = values.get("ProxyAutoConfigEnable") === "1" ? "ProxyAutoConfigEnable"
|
|
147
|
+
: values.get("ProxyAutoDiscoveryEnable") === "1" ? "ProxyAutoDiscoveryEnable"
|
|
148
|
+
: undefined;
|
|
149
|
+
if (autoSetting) return { kind: "unsafe-exceptions", setting: autoSetting };
|
|
150
|
+
return values.get("SOCKSEnable") === "1" ? { kind: "socks-only" } : { kind: "disabled" };
|
|
151
|
+
}
|
|
152
|
+
// With a usable HTTP(S) transport, toggles and untranslatable entries refuse
|
|
153
|
+
// discovery together: the user should fix both in one pass, not one per retry.
|
|
154
|
+
const flaggedSetting = values.get("ExcludeSimpleHostnames") === "1" ? "ExcludeSimpleHostnames"
|
|
155
|
+
: values.get("ProxyAutoConfigEnable") === "1" ? "ProxyAutoConfigEnable"
|
|
156
|
+
: values.get("ProxyAutoDiscoveryEnable") === "1" ? "ProxyAutoDiscoveryEnable"
|
|
157
|
+
: undefined;
|
|
158
|
+
const translated = exceptions.map(translateException);
|
|
159
|
+
const unrepresentable = translated.some(value => value === undefined)
|
|
160
|
+
? countUnrepresentable(exceptions.filter((_, index) => translated[index] === undefined))
|
|
161
|
+
: undefined;
|
|
162
|
+
if (flaggedSetting || unrepresentable) {
|
|
163
|
+
return { kind: "unsafe-exceptions", setting: flaggedSetting, unrepresentable };
|
|
164
|
+
}
|
|
165
|
+
return { kind: "proxy", httpUrl, httpsUrl,
|
|
166
|
+
exceptions: translated.filter((value): value is string => typeof value === "string"),
|
|
167
|
+
droppedLinkLocal: translated.includes(null) };
|
|
111
168
|
} catch {
|
|
112
169
|
return { kind: "unreadable" };
|
|
113
170
|
}
|
|
@@ -24,12 +24,13 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { createHash } from "node:crypto";
|
|
27
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, unlinkSync } from "node:fs";
|
|
27
|
+
import { chmodSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, statSync, unlinkSync } from "node:fs";
|
|
28
28
|
import { homedir } from "node:os";
|
|
29
29
|
import { dirname, join, resolve } from "node:path";
|
|
30
|
-
import {
|
|
30
|
+
import { atomicWriteFileNoFollow } from "./atomic-write";
|
|
31
31
|
import { getConfigDir } from "./paths";
|
|
32
32
|
import { assertNotRealHomeUnderTest } from "../lib/test-home-guard";
|
|
33
|
+
import { hardenSecretDir } from "../lib/windows-secret-acl";
|
|
33
34
|
|
|
34
35
|
const REGISTRY_DIR_NAME = "ocx-homes";
|
|
35
36
|
/**
|
|
@@ -83,8 +84,16 @@ export function registerOwnerRegistryHome(home: string): void {
|
|
|
83
84
|
if (parent === ancestor) break;
|
|
84
85
|
ancestor = parent;
|
|
85
86
|
}
|
|
86
|
-
mkdirSync(dir, { recursive: true });
|
|
87
|
-
|
|
87
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
88
|
+
// This locator contains no secret, but its deterministic entry names must not
|
|
89
|
+
// give another local user a place to plant a destination symlink. Refuse a
|
|
90
|
+
// directory symlink and fail closed if an existing directory cannot be made
|
|
91
|
+
// owner-only (for example because another user created it first).
|
|
92
|
+
const registryStat = lstatSync(dir);
|
|
93
|
+
if (!registryStat.isDirectory() || registryStat.isSymbolicLink()) return;
|
|
94
|
+
chmodSync(dir, 0o700);
|
|
95
|
+
hardenSecretDir(dir, { required: true });
|
|
96
|
+
atomicWriteFileNoFollow(
|
|
88
97
|
registryEntryPath(dir, home),
|
|
89
98
|
JSON.stringify({ home: resolve(home), v: 1 }) + "\n",
|
|
90
99
|
);
|
|
@@ -328,14 +328,23 @@ export function readProcessCommandLine(pid: number): string | undefined {
|
|
|
328
328
|
} catch {
|
|
329
329
|
/* WMIC missing or failed — fall through */
|
|
330
330
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
331
|
+
// One bounded retry: a transient CIM timeout answers "unreadable" for an
|
|
332
|
+
// unchanged process and turns a guarded stop into a false approval-changed.
|
|
333
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
334
|
+
try {
|
|
335
|
+
const output = processCommandLineExec(resolveTrustedWindowsPowerShellExe(), [
|
|
336
|
+
"-NoProfile",
|
|
337
|
+
"-NoLogo",
|
|
338
|
+
"-NonInteractive",
|
|
339
|
+
"-Command",
|
|
340
|
+
`(Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}").CommandLine`,
|
|
341
|
+
], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: 3000, windowsHide: true });
|
|
342
|
+
return output.trim() || undefined;
|
|
343
|
+
} catch {
|
|
344
|
+
/* timed out or CIM unavailable — try once more, then unreadable */
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return undefined;
|
|
339
348
|
}
|
|
340
349
|
for (const ps of ["/bin/ps", "/usr/bin/ps"]) {
|
|
341
350
|
try {
|
package/src/config/proxy-env.ts
CHANGED
|
@@ -5,7 +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
|
+
import { readMacOSSystemProxy, type MacOSProxyReader, type MacOSSystemProxyResult } from "./macos-system-proxy";
|
|
9
9
|
import { OPENAI_PROVIDER_TIER_VERSION, type OcxConfig } from "../types";
|
|
10
10
|
import type { OcxRuntimeRole } from "../types/config";
|
|
11
11
|
|
|
@@ -187,6 +187,34 @@ export function applyProxyEnv(config: OcxConfig, announce = false): void {
|
|
|
187
187
|
if (outbound) console.log(` outbound proxy: ${redactUrlForLog(outbound)}`);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Builds the refusal reason for an unsafe macOS discovery outcome. Toggle refusals
|
|
192
|
+
* name the toggle only — they are not an exception-translation problem, so the
|
|
193
|
+
* "exceptions" framing is reserved for entries. Entry refusals report shape counts
|
|
194
|
+
* and setting names, never the entries themselves: naming them would leak
|
|
195
|
+
* bypass-list hostnames (internal servers, banked domains) into shared logs.
|
|
196
|
+
*/
|
|
197
|
+
function describeDiscoveryRefusal(
|
|
198
|
+
found: Extract<MacOSSystemProxyResult, { kind: "unsafe-exceptions" }>,
|
|
199
|
+
): string {
|
|
200
|
+
const counts = found.unrepresentable;
|
|
201
|
+
if (counts) {
|
|
202
|
+
const parts = [
|
|
203
|
+
counts.cidr > 0 && `${counts.cidr} CIDR`,
|
|
204
|
+
counts.hostname > 0 && `${counts.hostname} bare-hostname`,
|
|
205
|
+
counts.wildcard > 0 && `${counts.wildcard} wildcard-shaped`,
|
|
206
|
+
counts.other > 0 && `${counts.other} other`,
|
|
207
|
+
].filter(Boolean).join(", ");
|
|
208
|
+
const entries = counts.cidr + counts.hostname + counts.wildcard + counts.other;
|
|
209
|
+
const entriesPhrase = `${entries} ${entries === 1 ? "exception entry" : "exception entries"} cannot be safely translated (${parts})`;
|
|
210
|
+
return found.setting
|
|
211
|
+
? `${found.setting} is enabled; ${entriesPhrase}; discovery refused`
|
|
212
|
+
: `macOS exceptions cannot be safely translated (${parts}); discovery refused`;
|
|
213
|
+
}
|
|
214
|
+
if (found.setting) return `${found.setting} is enabled; discovery refused`;
|
|
215
|
+
return "macOS exceptions cannot be safely translated; discovery refused";
|
|
216
|
+
}
|
|
217
|
+
|
|
190
218
|
/** Test seam for `proxy: "auto"`: the registry reader and platform are injectable. */
|
|
191
219
|
export function applyProxyEnvWith(
|
|
192
220
|
config: OcxConfig,
|
|
@@ -224,10 +252,12 @@ export function applyProxyEnvWith(
|
|
|
224
252
|
const found = readMacOSSystemProxy(auto.macOSReader);
|
|
225
253
|
if (found.kind !== "proxy") {
|
|
226
254
|
const reason = found.kind === "unsafe-exceptions"
|
|
227
|
-
?
|
|
228
|
-
: found.kind === "
|
|
229
|
-
? "macOS system proxy is
|
|
230
|
-
:
|
|
255
|
+
? describeDiscoveryRefusal(found)
|
|
256
|
+
: found.kind === "socks-only"
|
|
257
|
+
? "macOS system proxy is SOCKS-only, which HTTP_PROXY cannot express; using direct egress"
|
|
258
|
+
: found.kind === "disabled"
|
|
259
|
+
? "macOS system proxy is disabled"
|
|
260
|
+
: "macOS proxy settings could not be read";
|
|
231
261
|
console.log(`[opencodex] proxy "auto": ${reason}; proxy environment unchanged`);
|
|
232
262
|
return;
|
|
233
263
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MAIN_ACCOUNT_HARD_LOCK_MIN_PERCENT } from "../../codex/quota-types";
|
|
1
2
|
import * as z from "zod/v4";
|
|
2
3
|
import { compactionRecoverySchema } from "./compaction-recovery";
|
|
3
4
|
import { blockedModelRedirectsSchema } from "./blocked-model-redirects";
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
remoteGuiConfigSchema,
|
|
18
19
|
runtimeRoleSchema,
|
|
19
20
|
spendSchema,
|
|
21
|
+
chatgptDesktopSchema,
|
|
20
22
|
skillsConfigSchema,
|
|
21
23
|
configuredCodexPoolAccountIds,
|
|
22
24
|
apiKeyEntrySchema,
|
|
@@ -53,10 +55,13 @@ import {
|
|
|
53
55
|
} from "../../codex/account-namespace-match";
|
|
54
56
|
import { UPSTREAM_HOST_CIRCUIT_MAX_THRESHOLD } from "../../codex/upstream-host-health";
|
|
55
57
|
import { MIN_USAGE_LEDGER_MAX_BYTES } from "../../usage/retention-contract";
|
|
56
|
-
|
|
58
|
+
// The schema boundary uses a string-only stand-in for the ingress grammar: importing the server
|
|
59
|
+
// parser here would cycle back through config loading and run Cursor detection during validation.
|
|
60
|
+
import { COMBO_NAMESPACE, comboConfigIssues, lexicalDecisionModelBase } from "../../combos/types";
|
|
57
61
|
import { routingProfileIssues } from "../../routing/profile";
|
|
58
62
|
import { POLICY_NAMESPACE } from "../../routing/profile-namespace";
|
|
59
63
|
import { providerDestinationConfigError } from "../../lib/destination-policy";
|
|
64
|
+
import { providerTlsProfileConfigError } from "../../lib/provider-tls-profile";
|
|
60
65
|
import { redactSecretString } from "../../lib/redact";
|
|
61
66
|
import { openRouterRoutingConfigError } from "../../providers/openrouter-routing";
|
|
62
67
|
import { vercelGatewayRoutingConfigError } from "../../providers/vercel-gateway-routing";
|
|
@@ -69,6 +74,7 @@ import { isInterceptBindingId, isInterceptBindingRoute } from "../../claude/inte
|
|
|
69
74
|
import { DEFAULT_APP_OWNED_MEMORY_BUDGET_BYTES, MAX_APP_OWNED_MEMORY_BUDGET_MB, MIN_APP_OWNED_MEMORY_BUDGET_MB } from "../../lib/app-owned-memory";
|
|
70
75
|
|
|
71
76
|
export const configSchema = z.object({
|
|
77
|
+
chatgptDesktop: chatgptDesktopSchema.optional().catch(undefined),
|
|
72
78
|
codexNativeSteering: z.boolean().optional().catch(false),
|
|
73
79
|
codexNativeInjection: z.boolean().optional().catch(false),
|
|
74
80
|
port: z.number().int().min(0).max(65535).default(10100),
|
|
@@ -186,6 +192,10 @@ export const configSchema = z.object({
|
|
|
186
192
|
// Default-on policy (#5694): absence and malformed hand edits both mean "on", and only an
|
|
187
193
|
// explicit `false` written by the settings PUT opts out.
|
|
188
194
|
codexMainAccountHardLock: z.boolean().optional().catch(undefined),
|
|
195
|
+
codexMainAccountHardLockThresholds: z.object({
|
|
196
|
+
short: z.number().int().min(MAIN_ACCOUNT_HARD_LOCK_MIN_PERCENT).max(100).optional().catch(undefined),
|
|
197
|
+
long: z.number().int().min(MAIN_ACCOUNT_HARD_LOCK_MIN_PERCENT).max(100).optional().catch(undefined),
|
|
198
|
+
}).optional().catch(undefined),
|
|
189
199
|
// Future versions remain opaque through passthrough-compatible whole-config saves.
|
|
190
200
|
// Only version 1 grants deletion authority in the rebase path.
|
|
191
201
|
configRebaseProvenance: z.unknown().optional(),
|
|
@@ -237,6 +247,12 @@ export const configSchema = z.object({
|
|
|
237
247
|
z.string(),
|
|
238
248
|
z.array(z.string().trim().min(1)).min(1),
|
|
239
249
|
).optional().catch(undefined),
|
|
250
|
+
// Advisory input to role auto-assign only; a malformed block falls back to price ranking.
|
|
251
|
+
codexRoleTiers: z.object({
|
|
252
|
+
fast: z.array(z.string().trim().min(1)).optional(),
|
|
253
|
+
standard: z.array(z.string().trim().min(1)).optional(),
|
|
254
|
+
frontier: z.array(z.string().trim().min(1)).optional(),
|
|
255
|
+
}).strict().optional().catch(undefined),
|
|
240
256
|
codexShimAutoRestore: z.boolean().optional(),
|
|
241
257
|
codexDesktopAuthless: z.boolean().optional().catch(undefined),
|
|
242
258
|
codexClientCompaction: z.boolean().optional().catch(undefined),
|
|
@@ -245,6 +261,10 @@ export const configSchema = z.object({
|
|
|
245
261
|
// would refuse to load — the provider id routing depends on is never derived from it.
|
|
246
262
|
codexProviderDisplayName: z.string().trim().min(1).max(128).optional().catch(undefined),
|
|
247
263
|
pausedCodexAccountIds: z.array(z.string().regex(/^[a-zA-Z0-9._-]{1,64}$/)).optional(),
|
|
264
|
+
// A malformed allow-list degrades to "no account spends credits" rather than failing the parse,
|
|
265
|
+
// so a hand-edited typo cannot trip the backup-and-defaults repair path; the write path rejects
|
|
266
|
+
// it (creditCodexAccountIdsError in diagnostics).
|
|
267
|
+
creditCodexAccountIds: z.array(z.string().regex(/^[a-zA-Z0-9._-]{1,64}$/)).optional().catch(undefined),
|
|
248
268
|
// A malformed policy degrades to "no policy" rather than failing the parse, so a hand-edited
|
|
249
269
|
// typo cannot trip the backup-and-defaults repair path and wipe providers or pool accounts.
|
|
250
270
|
// Silently ignoring it would be its own trap, so the write path rejects it and loadConfig warns.
|
|
@@ -470,6 +490,14 @@ export const configSchema = z.object({
|
|
|
470
490
|
});
|
|
471
491
|
}
|
|
472
492
|
}
|
|
493
|
+
const tlsProfileError = providerTlsProfileConfigError(name, provider);
|
|
494
|
+
if (tlsProfileError) {
|
|
495
|
+
ctx.addIssue({
|
|
496
|
+
code: "custom",
|
|
497
|
+
path: ["providers", redactSecretString(name), "tlsProfile"],
|
|
498
|
+
message: tlsProfileError,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
473
501
|
const headersError = providerHeadersConfigError((provider as { headers?: unknown }).headers);
|
|
474
502
|
if (headersError) {
|
|
475
503
|
ctx.addIssue({
|
|
@@ -720,6 +748,7 @@ export const configSchema = z.object({
|
|
|
720
748
|
for (const issue of comboConfigIssues(id, raw, config.providers, {
|
|
721
749
|
combos: combos as Record<string, import("../../types").OcxComboConfig>,
|
|
722
750
|
excludeComboId: id,
|
|
751
|
+
normalizeDecisionModel: model => lexicalDecisionModelBase(model, config.cursorEffortRows === true),
|
|
723
752
|
})) {
|
|
724
753
|
ctx.addIssue({
|
|
725
754
|
code: "custom",
|
|
@@ -43,6 +43,9 @@ import {
|
|
|
43
43
|
import { getConfigDir } from "../paths";
|
|
44
44
|
import { COMPACTION_TRIGGERS } from "./compaction-triggers";
|
|
45
45
|
|
|
46
|
+
/** Experimental macOS ChatGPT app-server shim; only a strict optional boolean is accepted. */
|
|
47
|
+
export const chatgptDesktopSchema = z.object({ appServerShim: z.boolean().optional() }).strict();
|
|
48
|
+
|
|
46
49
|
/** One definition of "usable secret", shared by the schema and the warnings. */
|
|
47
50
|
export function isUsableApiKeySecret(value: unknown): value is string {
|
|
48
51
|
return typeof value === "string" && value.length > 0 && value === value.trim();
|
|
@@ -294,6 +297,7 @@ export const providerConfigSchema = z.object({
|
|
|
294
297
|
autoReviewModelOverrides: autoReviewModelOverridesSchema.optional(),
|
|
295
298
|
adapter: z.string().min(1),
|
|
296
299
|
baseUrl: z.string().min(1),
|
|
300
|
+
tlsProfile: z.literal("antigravity-browser").optional(),
|
|
297
301
|
alias: z.string().optional(),
|
|
298
302
|
modelAliases: z.record(z.string(), z.string()).optional(),
|
|
299
303
|
modelDisplayNames: modelDisplayNamesSchema.optional(),
|
|
@@ -33,7 +33,14 @@ import { assertNotRealHomeUnderTest } from "../lib/test-home-guard";
|
|
|
33
33
|
import { atomicWriteFile } from "./atomic-write";
|
|
34
34
|
import { getConfigDir } from "./paths";
|
|
35
35
|
import { ConfigMutationLockError, withConfigMutationLockSync } from "./mutation-lock";
|
|
36
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
inspectServiceManagerInstallation,
|
|
38
|
+
queryWinswBinaryPathName,
|
|
39
|
+
scBinaryPathNamesExecutable,
|
|
40
|
+
type ServiceManagerClaim,
|
|
41
|
+
type ServiceManagerInstallation,
|
|
42
|
+
} from "../service-manager-probe";
|
|
43
|
+
import { compareServicePathToInstall, currentServiceHomes, SERVICE_MANAGED_ENV } from "../service/state";
|
|
37
44
|
import { WINDOWS_WRAPPER_PROTOCOL_ENV } from "../service/windows-wrapper-exit";
|
|
38
45
|
|
|
39
46
|
export function servingRuntimesPath(dir: string = getConfigDir()): string {
|
|
@@ -253,11 +260,38 @@ export function selectNewerServingRuntime(
|
|
|
253
260
|
return best === null ? null : { ...best.record, version: best.version };
|
|
254
261
|
}
|
|
255
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Whether the census names a command different from self that records a newer
|
|
265
|
+
* version and still exists on disk. Cheap and spawn-free: use it to gate the
|
|
266
|
+
* expensive service-manager provenance probe instead of probing on every start.
|
|
267
|
+
*/
|
|
268
|
+
export function hasNewerRecordedServingRuntime(
|
|
269
|
+
selfVersion: string,
|
|
270
|
+
selfCommand: readonly string[],
|
|
271
|
+
deps: NewerServingRuntimeDeps = {},
|
|
272
|
+
): boolean {
|
|
273
|
+
const self = parseStrictSemver(selfVersion);
|
|
274
|
+
if (self === null) return false;
|
|
275
|
+
const exists = deps.exists ?? existsSync;
|
|
276
|
+
const selfKey = servingRuntimeCommandKey(selfCommand);
|
|
277
|
+
return readServingRuntimes(deps.dir ?? getConfigDir())
|
|
278
|
+
.filter(record => servingRuntimeCommandKey(record.command) !== selfKey)
|
|
279
|
+
.filter(record => {
|
|
280
|
+
const recorded = parseStrictSemver(record.version);
|
|
281
|
+
return recorded !== null && compareStrictSemver(recorded, self) > 0;
|
|
282
|
+
})
|
|
283
|
+
.some(record => record.command.every(part => exists(part) && trustedRecordedPath(part)));
|
|
284
|
+
}
|
|
285
|
+
|
|
256
286
|
export interface DeferToNewerRuntimeDeps extends NewerServingRuntimeDeps {
|
|
257
287
|
readonly runInherited?: (command: readonly string[], args: readonly string[]) => Promise<DelegatedExit>;
|
|
258
288
|
readonly log?: (line: string) => void;
|
|
259
289
|
/** Environment the service manager gave this child; decides its stay-out exit code. */
|
|
260
290
|
readonly env?: NodeJS.ProcessEnv;
|
|
291
|
+
/** Test seam for the manager-definition provenance check at the pre-probe gate. */
|
|
292
|
+
readonly installedServiceOwnsCurrentHome?: () => boolean;
|
|
293
|
+
/** Test seam for the recorded-candidate gate that keeps the manager probe off empty censuses. */
|
|
294
|
+
readonly hasNewerRecordedRuntime?: () => boolean;
|
|
261
295
|
}
|
|
262
296
|
|
|
263
297
|
interface DelegatedExit { readonly exitCode: number; readonly ready: boolean }
|
|
@@ -397,9 +431,69 @@ export async function deferServiceChildToNewerRuntime(options: {
|
|
|
397
431
|
readonly deps?: DeferToNewerRuntimeDeps;
|
|
398
432
|
}): Promise<number | null> {
|
|
399
433
|
if (options.sibling || !isManagedServiceEnvironment(options.env) || options.env[DELEGATED_ONCE_ENV] === "1") return null;
|
|
434
|
+
// Cheap gate first: with no recorded newer candidate there is nothing to delegate to, so
|
|
435
|
+
// the manager-definition probe (a potential full Task Scheduler listing) must not run.
|
|
436
|
+
const hasCandidate = options.deps?.hasNewerRecordedRuntime
|
|
437
|
+
?? (() => hasNewerRecordedServingRuntime(options.selfVersion, options.selfCommand, options.deps));
|
|
438
|
+
if (!hasCandidate()) return null;
|
|
439
|
+
const installedServiceOwnsCurrentHome = options.deps?.installedServiceOwnsCurrentHome
|
|
440
|
+
?? serviceManagerOwnsCurrentHome;
|
|
441
|
+
// Bun may populate the live environment from a project-controlled dotenv file. Markers
|
|
442
|
+
// therefore identify the service protocol but are not authority to execute census paths:
|
|
443
|
+
// require a live manager registration whose generated definition names this home first.
|
|
444
|
+
if (!installedServiceOwnsCurrentHome()) return null;
|
|
400
445
|
return deferToNewerServiceRuntime(options.selfVersion, options.selfCommand, options.port, { env: options.env, ...options.deps });
|
|
401
446
|
}
|
|
402
447
|
|
|
448
|
+
/**
|
|
449
|
+
* A claim's null home key means the definition omitted it, which only happens for a
|
|
450
|
+
* default-home install. Such a claim authorizes nothing when the current process resolved
|
|
451
|
+
* a non-default home — otherwise a project .env setting the env var plus the service marker
|
|
452
|
+
* would borrow a default install's registration for a project-chosen census directory.
|
|
453
|
+
*/
|
|
454
|
+
export function serviceClaimMatchesCurrentHomes(
|
|
455
|
+
claim: ServiceManagerClaim,
|
|
456
|
+
current: { codexHome: string; opencodexHome: string },
|
|
457
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
458
|
+
): boolean {
|
|
459
|
+
return (claim.homes.codexHome === null
|
|
460
|
+
? !env.CODEX_HOME?.trim()
|
|
461
|
+
: compareServicePathToInstall(claim.homes.codexHome, current.codexHome) === "same")
|
|
462
|
+
&& (claim.homes.opencodexHome === null
|
|
463
|
+
? !env.OPENCODEX_HOME?.trim()
|
|
464
|
+
: compareServicePathToInstall(claim.homes.opencodexHome, current.opencodexHome) === "same");
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export interface ServiceOwnershipGateDeps {
|
|
468
|
+
readonly current?: { codexHome: string; opencodexHome: string };
|
|
469
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
470
|
+
/** Test seam for the read-only manager inspection of the current config dir. */
|
|
471
|
+
readonly inspect?: (configDir: string) => ServiceManagerInstallation;
|
|
472
|
+
/** Test seam for the registered WinSW BINARY_PATH_NAME; production asks trusted `sc.exe qc`. */
|
|
473
|
+
readonly winswBinaryPathName?: () => string | null;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* WinSW reports machine-wide SCM registration while its definition is read from the
|
|
478
|
+
* current config dir, so the delegation gate binds the registration to that definition:
|
|
479
|
+
* the registered service binary must be the claim's own executable. Any query failure,
|
|
480
|
+
* missing value, or mismatch refuses delegation. Other backends are unchanged.
|
|
481
|
+
*/
|
|
482
|
+
export function serviceManagerOwnsCurrentHome(deps: ServiceOwnershipGateDeps = {}): boolean {
|
|
483
|
+
const current = deps.current ?? currentServiceHomes();
|
|
484
|
+
const inspect = deps.inspect ?? (configDir => inspectServiceManagerInstallation({ configDir }));
|
|
485
|
+
const installation = inspect(current.opencodexHome);
|
|
486
|
+
if (installation.kind !== "present") return false;
|
|
487
|
+
return installation.claims.some(claim => claim.registration === "present"
|
|
488
|
+
&& serviceClaimMatchesCurrentHomes(claim, current, deps.env)
|
|
489
|
+
&& (claim.backend !== "winsw" || winswRegistrationRunsDefinition(claim, deps)));
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function winswRegistrationRunsDefinition(claim: ServiceManagerClaim, deps: ServiceOwnershipGateDeps): boolean {
|
|
493
|
+
const binaryPathName = (deps.winswBinaryPathName ?? (() => queryWinswBinaryPathName()))();
|
|
494
|
+
return binaryPathName !== null && scBinaryPathNamesExecutable(binaryPathName, claim.definitionPath);
|
|
495
|
+
}
|
|
496
|
+
|
|
403
497
|
/**
|
|
404
498
|
* A child a service manager started, as its environment proves it. launchd, systemd, and
|
|
405
499
|
* current or repaired WinSW definitions write `OCX_SERVICE_MANAGED=1`; the Windows Task
|