@bitkyc08/opencodex 2.80.0 → 2.82.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 +3 -3
- package/bin/ocx.mjs +166 -73
- package/gui/dist/assets/App-Ds_qL7o8.js +54 -0
- package/gui/dist/assets/Tray-BqHF5Trd.js +1 -0
- package/gui/dist/assets/{index-Brk6F3fn.css → index-BAbcj51J.css} +1 -1
- package/gui/dist/assets/index-D3FBCNiP.js +94 -0
- package/gui/dist/assets/quota-summary-DTBC8n7-.js +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/claude-green.svg +1 -0
- package/package.json +3 -2
- package/src/adapters/anthropic-model-contract.ts +8 -2
- package/src/adapters/anthropic.ts +8 -3
- package/src/adapters/codebuddy/mcp-server.ts +2 -25
- package/src/adapters/codebuddy/tool-bridge.ts +1 -7
- package/src/adapters/coding-agent/mcp-server.ts +33 -0
- package/src/adapters/coding-agent/protocol.ts +122 -17
- package/src/adapters/coding-agent/tool-catalog.ts +75 -0
- package/src/adapters/coding-agent/turn.ts +101 -44
- package/src/adapters/cursor/catalog.ts +8 -0
- package/src/adapters/cursor/effort-map.ts +2 -0
- package/src/adapters/devin/live-models.ts +2 -0
- package/src/adapters/kiro-retry.ts +9 -4
- package/src/adapters/openai-chat/messages.ts +7 -6
- package/src/adapters/openai-responses/compaction-search-history.ts +109 -0
- package/src/adapters/openai-responses/passthrough.ts +9 -4
- package/src/adapters/openai-responses/tool-output-recovery.ts +20 -0
- package/src/adapters/physical-send.ts +8 -5
- package/src/adapters/qoder/adapter.ts +41 -6
- package/src/adapters/qoder/scaffold-guard.ts +2 -3
- package/src/adapters/zed.ts +16 -1
- package/src/claude/agents-inject.ts +14 -3
- package/src/claude/context-windows.ts +19 -17
- package/src/claude/desktop-3p.ts +88 -12
- package/src/claude/desktop-profile.ts +2 -1
- package/src/claude/gateway-cache.ts +18 -1
- package/src/claude/inbound-cache-stabilize.ts +4 -9
- package/src/claude/inbound.ts +78 -3
- package/src/claude/intercept/cli-catalog.ts +3 -0
- package/src/claude/intercept/model-bindings.ts +1 -0
- package/src/claude/intercept/picker-ca-persistence.ts +7 -6
- package/src/claude/intercept/picker-listener.ts +71 -4
- package/src/claude/intercept/picker-models.ts +14 -6
- package/src/claude/intercept/settings.ts +3 -0
- package/src/claude/long-context.ts +66 -0
- package/src/claude/model-info.ts +19 -16
- package/src/claude/outbound.ts +94 -9
- package/src/claude/subagent-model.ts +40 -11
- package/src/cli/account-anthropic-threshold.ts +14 -5
- package/src/cli/account-api.ts +3 -1
- package/src/cli/account-extended.ts +13 -9
- package/src/cli/account-policy-dto.ts +1 -1
- package/src/cli/account-policy.ts +13 -4
- package/src/cli/account.ts +3 -3
- package/src/cli/agent.ts +9 -5
- package/src/cli/aside-profile-recovery.ts +33 -0
- package/src/cli/capabilities-accounts.ts +2 -2
- package/src/cli/capabilities-agents-routing.ts +24 -0
- package/src/cli/capabilities-base.ts +5 -5
- package/src/cli/capabilities-integrations.ts +18 -2
- package/src/cli/cli-path-diagnostics.ts +132 -0
- package/src/cli/codex-shim-autorestore.ts +3 -0
- package/src/cli/desktop-runtime-guidance.ts +65 -0
- package/src/cli/dispatch.ts +15 -1
- package/src/cli/doctor.ts +16 -3
- package/src/cli/help.ts +4 -1
- package/src/cli/index.ts +25 -14
- package/src/cli/integration-aside-sync.ts +2 -1
- package/src/cli/integration-plan-dto.ts +1 -0
- package/src/cli/integration-preview.ts +8 -1
- package/src/cli/integrations.ts +48 -6
- package/src/cli/message-args.ts +34 -0
- package/src/cli/message-command.ts +43 -0
- package/src/cli/message-runtime.ts +6 -0
- package/src/cli/observe.ts +3 -1
- package/src/cli/provider.ts +29 -6
- package/src/cli/registry.ts +24 -2
- package/src/cli/resolve.ts +25 -2
- package/src/cli/root.ts +4 -2
- package/src/cli/status.ts +64 -12
- package/src/cli/update-restart-child.ts +4 -2
- package/src/cli/update-restart-home.ts +28 -10
- package/src/cli/update-restart-service-record.ts +116 -0
- package/src/cli/update-restart-supervision.ts +96 -0
- package/src/cli/update-restart.ts +59 -13
- package/src/cli/v2.ts +27 -20
- package/src/cli/version-skew-notice.ts +77 -0
- package/src/clients/config-export/commandcode.ts +131 -0
- package/src/clients/config-export/contracts.ts +12 -0
- package/src/clients/config-export.ts +64 -1
- package/src/clients/lazycodex.ts +1 -1
- package/src/clients/omo-role-models.ts +32 -7
- package/src/codex/auth-api/account-list.ts +11 -3
- package/src/codex/auth-api/account-selection.ts +107 -0
- package/src/codex/auth-api/main-account-probe.ts +25 -8
- package/src/codex/auth-api/pool-mode-gate.ts +33 -9
- package/src/codex/auth-api/pool-quota-probe.ts +15 -1
- package/src/codex/auth-api/routes.ts +11 -49
- package/src/codex/auth-context.ts +20 -1
- package/src/codex/autostart-health.ts +12 -3
- package/src/codex/catalog/auto-review.ts +13 -6
- package/src/codex/catalog/build-entries.ts +33 -7
- package/src/codex/catalog/bundled.ts +155 -26
- package/src/codex/catalog/combo-member.ts +3 -2
- package/src/codex/catalog/control-plane.ts +45 -0
- package/src/codex/catalog/effort.ts +37 -6
- package/src/codex/catalog/gather-capture.ts +10 -3
- package/src/codex/catalog/model-hints.ts +15 -8
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/operator-tiers.ts +38 -0
- package/src/codex/catalog/parsing.ts +2 -1
- package/src/codex/catalog/provider-models.ts +58 -44
- package/src/codex/catalog/retained-sync.ts +7 -5
- package/src/codex/catalog/routed-gather.ts +15 -1
- package/src/codex/catalog-auto-refresh-sources.ts +3 -4
- package/src/codex/catalog-auto-refresh.ts +19 -0
- package/src/codex/catalog.ts +1 -1
- package/src/codex/codex-home-owner.ts +3 -0
- package/src/codex/config-write-lock.ts +333 -0
- package/src/codex/control-plane-models.ts +6 -0
- package/src/codex/convergence.ts +2 -1
- package/src/codex/features.ts +257 -200
- package/src/codex/inject/config-write-section.ts +34 -0
- package/src/codex/inject/multi-agent-v2.ts +14 -6
- package/src/codex/inject/remove.ts +36 -11
- package/src/codex/inject/restore.ts +85 -20
- package/src/codex/inject-coordination.ts +15 -6
- package/src/codex/inject.ts +62 -20
- package/src/codex/journal.ts +62 -17
- package/src/codex/main-account-cache.ts +43 -0
- package/src/codex/paths.ts +2 -0
- package/src/codex/prepared-home.ts +18 -0
- package/src/codex/prompt-journal.ts +25 -12
- package/src/codex/prompt-layers.ts +49 -26
- package/src/codex/prompt-lock-claim.ts +134 -0
- package/src/codex/prompt-lock-evidence.ts +26 -0
- package/src/codex/prompt-lock-io.ts +16 -0
- package/src/codex/prompt-lock-owner.ts +130 -0
- package/src/codex/prompt-lock.ts +84 -53
- package/src/codex/routing/failure-window.ts +146 -0
- package/src/codex/routing/selection.ts +4 -1
- package/src/codex/routing.ts +13 -17
- package/src/codex/runtime.ts +106 -18
- package/src/codex/shim.ts +45 -19
- package/src/combos/jev-decision-contract.ts +25 -2
- package/src/combos/jev-service-exchange.ts +281 -0
- package/src/combos/jev.ts +34 -219
- package/src/combos/types.ts +1 -1
- package/src/config/atomic-write.ts +1 -1
- package/src/config/codex-ws-reuse-setting.ts +10 -0
- package/src/config/diagnostics.ts +27 -16
- package/src/config/live-reconcile.ts +17 -0
- package/src/config/load-degrade.ts +42 -0
- package/src/config/rebase-provenance.ts +11 -0
- package/src/config/schema/anthropic-account-pool.ts +143 -0
- package/src/config/schema/config-schema.ts +11 -1
- package/src/config/schema/leaf-validators.ts +4 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +566 -298
- package/src/generated/model-metadata.ts +7 -6
- package/src/grok/inject.ts +50 -4
- package/src/grok/sync.ts +2 -1
- package/src/images/loop.ts +30 -11
- package/src/integrations/aside-profiles.ts +10 -3
- package/src/integrations/catalog-refresh.ts +19 -3
- package/src/integrations/mutation-plan.ts +7 -0
- package/src/integrations/registry.ts +8 -0
- package/src/integrations/state.ts +9 -2
- package/src/integrations/writer.ts +17 -5
- package/src/lib/bun-path-runtime.d.mts +32 -0
- package/src/lib/bun-path-runtime.mjs +95 -0
- package/src/lib/bun-runtime-preflight.ts +140 -0
- package/src/lib/desktop-cli-handoff.d.mts +20 -0
- package/src/lib/desktop-cli-handoff.mjs +92 -0
- package/src/lib/desktop-cli-record.d.mts +29 -0
- package/src/lib/desktop-cli-record.mjs +102 -0
- package/src/lib/lab-live-route-production.ts +9 -1
- package/src/lib/request-execution-budget.ts +244 -58
- package/src/lib/spend-pool-alias-validation.ts +79 -0
- package/src/lib/spend-pool-continuity.ts +34 -0
- package/src/lib/spend-reservation-ledger.ts +412 -50
- package/src/lib/state-store-registrations.ts +20 -3
- package/src/lib/synced-state-location.ts +46 -6
- package/src/lib/test-home-guard.ts +87 -1
- package/src/lib/translator-budget.ts +17 -4
- package/src/lib/upstream-retry.ts +17 -5
- package/src/lib/windows-atomic-replace.ts +38 -16
- package/src/lib/windows-elevation.ts +6 -0
- package/src/lib/windows-secret-acl.ts +92 -25
- package/src/lib/winsw.ts +2 -3
- package/src/lib/workflow-budget.ts +53 -11
- package/src/messaging/budget.ts +45 -0
- package/src/messaging/discovery.ts +57 -0
- package/src/messaging/envelope.ts +49 -0
- package/src/messaging/input.ts +37 -0
- package/src/messaging/rpc.ts +196 -0
- package/src/messaging/send.ts +58 -0
- package/src/messaging/socket.ts +72 -0
- package/src/messaging/types.ts +29 -0
- package/src/oauth/anthropic-account-refusal.ts +90 -18
- package/src/oauth/anthropic-account-threshold.ts +8 -2
- package/src/oauth/anthropic-continuity.ts +15 -1
- package/src/oauth/anthropic-model-quota.ts +120 -48
- package/src/oauth/anthropic-model-routes.ts +11 -3
- package/src/oauth/anthropic-oauth-definitions.ts +98 -0
- package/src/oauth/anthropic-pool-config.ts +30 -0
- package/src/oauth/anthropic-rate-limit-policy.ts +64 -9
- package/src/oauth/anthropic-routing.ts +1202 -866
- package/src/oauth/anthropic-send-ownership.ts +41 -0
- package/src/oauth/anthropic.ts +4 -1
- package/src/oauth/chatgpt.ts +113 -41
- package/src/oauth/generic-account-failover.ts +3 -1
- package/src/oauth/health.ts +8 -6
- package/src/oauth/index.ts +96 -175
- package/src/oauth/kiro.ts +22 -9
- package/src/oauth/login-cli.ts +2 -0
- package/src/oauth/model-discovery-auth.ts +43 -0
- package/src/oauth/pool-kernel.ts +11 -5
- package/src/oauth/pool-settings-capability.ts +5 -3
- package/src/oauth/store-anthropic-instance.ts +87 -0
- package/src/oauth/store.ts +68 -10
- package/src/oauth/token-guardian.ts +2 -0
- package/src/oauth/types.ts +2 -0
- package/src/protocols/plan-snapshot.ts +5 -0
- package/src/protocols/settings.ts +20 -5
- package/src/providers/anthropic-instance-id.ts +47 -0
- package/src/providers/anthropic-instance.ts +48 -0
- package/src/providers/anthropic-reset-grant-ledger.ts +11 -1
- package/src/providers/azure-model-metadata.ts +115 -0
- package/src/providers/derive.ts +23 -0
- package/src/providers/kiro-models.ts +3 -0
- package/src/providers/label.ts +1 -1
- package/src/providers/model-rename-fields.ts +2 -0
- package/src/providers/quota/account-cache.ts +37 -11
- package/src/providers/quota/anthropic-account-quota.ts +93 -0
- package/src/providers/quota/anthropic-cooldown-recovery.ts +222 -111
- package/src/providers/quota/report-cache.ts +24 -1
- package/src/providers/quota/vendor-probes-key.ts +127 -17
- package/src/providers/quota/vendor-probes-oauth.ts +46 -14
- package/src/providers/quota.ts +23 -33
- package/src/providers/registry/entries-core.ts +35 -30
- package/src/providers/registry/model-ids.ts +1 -0
- package/src/providers/registry/model-seeds.ts +7 -4
- package/src/providers/registry/types.ts +3 -0
- package/src/providers/registry.ts +3 -3
- package/src/responses/reasoning-envelope.ts +29 -1
- package/src/responses/reasoning-replay-cache.ts +17 -1
- package/src/responses/spill-store.ts +20 -3
- package/src/responses/state/metrics.ts +95 -0
- package/src/responses/state/snapshot-codec.ts +6 -0
- package/src/responses/state/spill-failure.ts +12 -0
- package/src/responses/state/spill-queue.ts +13 -5
- package/src/responses/state/unforced-store-false.ts +55 -0
- package/src/responses/state.ts +68 -76
- package/src/responses/task-input.ts +17 -0
- package/src/router.ts +28 -4
- package/src/routing/compatibility/assemble.ts +1 -1
- package/src/routing/quota.ts +7 -3
- package/src/server/auth-cors.ts +5 -0
- package/src/server/background-lifecycle.ts +27 -0
- package/src/server/chat-completions.ts +7 -1
- package/src/server/chat-native.ts +64 -28
- package/src/server/claude-messages.ts +59 -8
- package/src/server/gui-static.ts +38 -4
- package/src/server/inbound-body-admission.ts +1 -0
- package/src/server/index/claude-intercept-lifecycle.ts +3 -1
- package/src/server/index/serve-options.ts +10 -2
- package/src/server/index/spend-ledger-lifecycle.ts +12 -5
- package/src/server/index/startup-warnings.ts +19 -0
- package/src/server/index.ts +5 -2
- package/src/server/inference/context.ts +1 -1
- package/src/server/lifecycle.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +123 -38
- package/src/server/management/anthropic-account-threshold.ts +12 -9
- package/src/server/management/anthropic-pool-settings.ts +72 -0
- package/src/server/management/anthropic-reset-grant-routes.ts +98 -39
- package/src/server/management/codex-agent-role-routes.ts +4 -2
- package/src/server/management/codex-prompt-routes.ts +1 -0
- package/src/server/management/codex-role-auto-assign.ts +13 -2
- package/src/server/management/config-routes.ts +85 -14
- package/src/server/management/context.ts +2 -2
- package/src/server/management/decision-routes.ts +2 -1
- package/src/server/management/integration-routes.ts +25 -2
- package/src/server/management/oauth-account-routes.ts +79 -98
- package/src/server/management/provider-instance-ownership.ts +44 -0
- package/src/server/management/provider-routes.ts +21 -28
- package/src/server/management/route-registry.ts +3 -1
- package/src/server/management/routing-profile-routes.ts +4 -4
- package/src/server/management/shared.ts +3 -3
- package/src/server/management/system-restart.ts +44 -14
- package/src/server/management/system-routes.ts +24 -2
- package/src/server/management/vision-sidecar-options.ts +9 -6
- package/src/server/management/web-search-sidecar-options.ts +51 -2
- package/src/server/management-auth.ts +6 -0
- package/src/server/messages-native-eligibility.ts +3 -2
- package/src/server/messages-native-oauth.ts +91 -45
- package/src/server/messages-native-selector.ts +39 -0
- package/src/server/messages-native.ts +133 -38
- package/src/server/messages-response-headers.ts +14 -0
- package/src/server/request-log-conversation.ts +48 -5
- package/src/server/request-log.ts +36 -2
- package/src/server/responses/adapter-continuation.ts +31 -19
- package/src/server/responses/adapter-dispatch.ts +75 -24
- package/src/server/responses/antigravity-validation-refusal.ts +20 -6
- package/src/server/responses/codex-ws-exchange.ts +17 -2
- package/src/server/responses/codex-ws-pool.ts +100 -13
- package/src/server/responses/codex-ws-wire.ts +9 -0
- package/src/server/responses/combo-requested-effort.ts +3 -1
- package/src/server/responses/compact.ts +25 -8
- package/src/server/responses/compaction-recovery.ts +1 -1
- package/src/server/responses/core-codex-account.ts +22 -1
- package/src/server/responses/core-combo-native.ts +24 -4
- package/src/server/responses/core-combo.ts +38 -25
- package/src/server/responses/core-lifetime.ts +3 -36
- package/src/server/responses/core-normalize.ts +1 -0
- package/src/server/responses/core-options.ts +8 -1
- package/src/server/responses/core-replay.ts +78 -0
- package/src/server/responses/core.ts +3 -3
- package/src/server/responses/fetch-helpers.ts +26 -3
- package/src/server/responses/passthrough-delivery.ts +30 -4
- package/src/server/responses/passthrough-dispatch.ts +39 -9
- package/src/server/responses/request-prepare.ts +41 -5
- package/src/server/responses/request-send-budget.ts +150 -50
- package/src/server/responses/request-spend.ts +325 -33
- package/src/server/responses/request-transport.ts +132 -52
- package/src/server/responses/response-effects.ts +1 -0
- package/src/server/responses/run-turn-execution.ts +13 -3
- package/src/server/responses/sidecar-execution.ts +113 -22
- package/src/server/responses/sidecar-send-budget.ts +58 -0
- package/src/server/responses/ws-upstream.ts +19 -6
- package/src/server/responses-undeclared-tool-guard.ts +5 -1
- package/src/server/startup-health-cache.ts +2 -1
- package/src/server/workflow-refusal.ts +33 -0
- package/src/service/cli.ts +20 -4
- package/src/service/desktop-command-guard.ts +32 -0
- package/src/service/desktop-startup.ts +66 -40
- package/src/service/desktop-supervision.d.mts +26 -0
- package/src/service/desktop-supervision.mjs +140 -0
- package/src/service/managing-cli.ts +1 -0
- package/src/service/orchestration.ts +46 -20
- package/src/service/ownership-mutation-lease.d.mts +1 -1
- package/src/service/ownership-mutation-lease.mjs +5 -7
- package/src/service/repair.ts +25 -9
- package/src/service/state.ts +4 -3
- package/src/service/systemd.ts +17 -8
- package/src/service/windows-ops.ts +61 -22
- package/src/sidecar/anthropic-binding.ts +79 -0
- package/src/sidecar/auth.ts +76 -2
- package/src/storage/policy-job.ts +5 -1
- package/src/storage/policy-worker.ts +3 -1
- package/src/storage/policy.ts +9 -0
- package/src/types/anthropic-account-pool.ts +33 -0
- package/src/types/config.ts +33 -28
- package/src/types/provider.ts +5 -0
- package/src/types/request.ts +5 -0
- package/src/types/tools.ts +7 -0
- package/src/types/wire.ts +1 -0
- package/src/types.ts +4 -0
- package/src/update/index.ts +57 -9
- package/src/update/restart-ownership.ts +10 -3
- package/src/update/runtime-ownership.d.mts +6 -0
- package/src/update/runtime-ownership.mjs +23 -7
- package/src/usage/cost.ts +3 -2
- package/src/usage/expected-prices.ts +66 -14
- package/src/vision/anthropic-describe.ts +16 -3
- package/src/vision/index.ts +3 -0
- package/src/vision/plan.ts +19 -6
- package/src/web-search/alpha-search.ts +7 -1
- package/src/web-search/anthropic-executor.ts +16 -4
- package/src/web-search/index.ts +7 -3
- package/src/web-search/loop.ts +32 -7
- package/src/web-search/passthrough-bridge.ts +4 -1
- package/src/web-search/sidecar-providers.ts +4 -3
- package/gui/dist/assets/App-MbDVfUeC.js +0 -54
- package/gui/dist/assets/Tray-CzkxK82A.js +0 -1
- package/gui/dist/assets/index-UJt6npXk.js +0 -94
- package/gui/dist/assets/quota-summary-DU3sD6Z-.js +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readExistingSpendSalt, spendPoolAliasesError, validatePoolAliasOwners } from "../lib/spend-pool-alias-validation";
|
|
1
2
|
import { isSubagentModelEntry, rawSubagentModelForce } from "./subagent-models";
|
|
2
3
|
import { protocolConfigSchema } from "./schema/config-schema";
|
|
3
4
|
import { createHash } from "node:crypto";
|
|
@@ -7,13 +8,13 @@ import * as z from "zod/v4";
|
|
|
7
8
|
import { compactionRecoveryConfigError } from "./schema/compaction-recovery";
|
|
8
9
|
import { blockedModelRedirectsError } from "./schema/blocked-model-redirects";
|
|
9
10
|
import type { OcxConfig } from "../types";
|
|
10
|
-
import {
|
|
11
|
+
import { anthropicAccountPoolConfigError, anthropicOAuthInstanceConfigError, anthropicSidecarConfigError } from "./schema/anthropic-account-pool";
|
|
11
12
|
import { configReasoningPinsConfigError } from "./provider-validation";
|
|
12
13
|
import { loopbackCompanionAllowed } from "../codex/loopback-target";
|
|
13
14
|
import { UPSTREAM_HOST_CIRCUIT_MAX_THRESHOLD } from "../codex/upstream-host-health";
|
|
14
15
|
import { MAX_APP_OWNED_MEMORY_BUDGET_MB, MIN_APP_OWNED_MEMORY_BUDGET_MB } from "../lib/app-owned-memory";
|
|
15
16
|
import { isMissingPathError } from "./atomic-write";
|
|
16
|
-
import { getConfigPath } from "./paths";
|
|
17
|
+
import { getConfigDir, getConfigPath } from "./paths";
|
|
17
18
|
import { getDefaultConfig } from "./proxy-env";
|
|
18
19
|
import { salvageConfigCandidate } from "./salvage";
|
|
19
20
|
import {
|
|
@@ -81,6 +82,23 @@ export type ConfigDiagnostics = {
|
|
|
81
82
|
warnings?: string[];
|
|
82
83
|
};
|
|
83
84
|
|
|
85
|
+
function rawPoolAliasesError(value: unknown): string | undefined {
|
|
86
|
+
const record = rawConfigRecord(value);
|
|
87
|
+
if (!record) return undefined;
|
|
88
|
+
const aliases = record.spendPoolAliases;
|
|
89
|
+
const shapeError = spendPoolAliasesError(aliases);
|
|
90
|
+
if (shapeError) return shapeError;
|
|
91
|
+
const mapping = rawConfigRecord(aliases);
|
|
92
|
+
if (!mapping || Object.keys(mapping).length === 0) return undefined;
|
|
93
|
+
const providers = rawConfigRecord(record.providers ?? {});
|
|
94
|
+
if (!providers) return "providers must be an object to validate spendPoolAliases";
|
|
95
|
+
const targetError = spendPoolAliasesError(aliases, Object.keys(providers));
|
|
96
|
+
if (targetError) return targetError;
|
|
97
|
+
const salt = readExistingSpendSalt(getConfigDir());
|
|
98
|
+
if (!salt) return "spendPoolAliases requires a safely readable existing spend salt";
|
|
99
|
+
return validatePoolAliasOwners(aliases, salt, Object.keys(providers));
|
|
100
|
+
}
|
|
101
|
+
|
|
84
102
|
export type ConfigFileSnapshot = {
|
|
85
103
|
diagnostics: ConfigDiagnostics;
|
|
86
104
|
/** Exact file contents, including a possible BOM, used as the optimistic revision. */
|
|
@@ -145,6 +163,9 @@ function validFileConfigDiagnostics(config: OcxConfig, rawParsed: unknown): Conf
|
|
|
145
163
|
if (codexPoolWarning) warnings.push(codexPoolWarning);
|
|
146
164
|
const spendWarning = malformedSpendWarning(rawParsed);
|
|
147
165
|
if (spendWarning) warnings.push(spendWarning);
|
|
166
|
+
if (rawPoolAliasesError(rawParsed)) {
|
|
167
|
+
warnings.push("spendPoolAliases invalid: configured pool admission is refused until the mapping is corrected");
|
|
168
|
+
}
|
|
148
169
|
const plaintextWarning = malformedPlaintextV2AgentMessagesWarning(rawParsed);
|
|
149
170
|
if (plaintextWarning) warnings.push(plaintextWarning);
|
|
150
171
|
if (syncDisabledReason) {
|
|
@@ -153,7 +174,7 @@ function validFileConfigDiagnostics(config: OcxConfig, rawParsed: unknown): Conf
|
|
|
153
174
|
return {
|
|
154
175
|
config: normalized,
|
|
155
176
|
source: "file",
|
|
156
|
-
error: null,
|
|
177
|
+
error: anthropicOAuthInstanceConfigError(rawParsed) ?? anthropicAccountPoolConfigError(rawParsed) ?? anthropicSidecarConfigError(rawParsed) ?? null,
|
|
157
178
|
...(warnings.length > 0 ? { warnings } : {}),
|
|
158
179
|
};
|
|
159
180
|
}
|
|
@@ -655,19 +676,8 @@ export function validateConfigCandidate(value: unknown): { ok: true; config: Ocx
|
|
|
655
676
|
if (protocols !== undefined && !protocolConfigSchema.safeParse(protocols).success) {
|
|
656
677
|
return { ok: false, error: "schema_invalid: protocols: expected valid protocol policy and boolean rollout flags" };
|
|
657
678
|
}
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
if (rawAnthropicPool !== undefined && !anthropicPool) {
|
|
661
|
-
return { ok: false, error: "schema_invalid: anthropicAccountPool: must be an object" };
|
|
662
|
-
}
|
|
663
|
-
if (anthropicPool && Object.hasOwn(anthropicPool, "nativeMessages") && typeof anthropicPool.nativeMessages !== "boolean") {
|
|
664
|
-
return { ok: false, error: "schema_invalid: anthropicAccountPool.nativeMessages: must be a boolean" };
|
|
665
|
-
}
|
|
666
|
-
const routeValue = anthropicPool?.routes;
|
|
667
|
-
if (routeValue !== undefined) {
|
|
668
|
-
const parsed = parseAnthropicModelRoutes(routeValue);
|
|
669
|
-
if (!parsed.ok) return { ok: false, error: `schema_invalid: anthropicAccountPool.routes: ${parsed.error}` };
|
|
670
|
-
}
|
|
679
|
+
const anthropicError = anthropicOAuthInstanceConfigError(value) ?? anthropicAccountPoolConfigError(value) ?? anthropicSidecarConfigError(value);
|
|
680
|
+
if (anthropicError) return { ok: false, error: anthropicError };
|
|
671
681
|
const boundaryError = blockedModelRedirectsError(value)
|
|
672
682
|
?? compactionRecoveryConfigError(value) ?? configReasoningPinsConfigError(value)
|
|
673
683
|
?? blankHostnameError(value)
|
|
@@ -679,6 +689,7 @@ export function validateConfigCandidate(value: unknown): { ok: true; config: Ocx
|
|
|
679
689
|
?? agentTaskRecoveryError(value)
|
|
680
690
|
?? quotaResetNotifyError(value)
|
|
681
691
|
?? catalogAutoRefreshError(value)
|
|
692
|
+
?? (rawPoolAliasesError(value) ? "schema_invalid: spendPoolAliases: invalid pool identity mapping" : null)
|
|
682
693
|
?? spendError(value)
|
|
683
694
|
?? codexPoolError(value)
|
|
684
695
|
?? googleAntigravityStaticCatalogVersionError(value)
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
clearPendingConfigObjectChildDeletions,
|
|
9
9
|
prepareConfigObjectChildDeletionRebase,
|
|
10
10
|
clearPendingConfigTopLevelDeletions,
|
|
11
|
+
clearConfigTopLevelDeletionIntent,
|
|
11
12
|
configHasRebaseProvenance,
|
|
12
13
|
configRebaseDeletionKeys,
|
|
13
14
|
CONFIG_REBASE_PROVENANCE_KEY,
|
|
@@ -42,6 +43,22 @@ const claudeCodeBaseline = new WeakMap<OcxConfig, unknown>();
|
|
|
42
43
|
*/
|
|
43
44
|
const liveConfigBaseline = new WeakMap<OcxConfig, OcxConfig>();
|
|
44
45
|
|
|
46
|
+
/** Adopt a committed manual selection without advancing unrelated live merge baselines. */
|
|
47
|
+
export function adoptPersistedCodexAccountSelection(
|
|
48
|
+
config: OcxConfig,
|
|
49
|
+
persisted: Pick<OcxConfig, "activeCodexAccountId" | "activeCodexAccountPinned">,
|
|
50
|
+
): void {
|
|
51
|
+
const keys = ["activeCodexAccountId", "activeCodexAccountPinned"] as const;
|
|
52
|
+
const baseline = liveConfigBaseline.get(config);
|
|
53
|
+
for (const key of keys) {
|
|
54
|
+
config[key] = persisted[key];
|
|
55
|
+
// Retain known absent keys: a later disk-only selection is a new edit, not stale intent.
|
|
56
|
+
if (baseline) baseline[key] = persisted[key];
|
|
57
|
+
}
|
|
58
|
+
clearConfigTopLevelDeletionIntent(config, keys);
|
|
59
|
+
if (baseline) clearConfigTopLevelDeletionIntent(baseline, keys);
|
|
60
|
+
}
|
|
61
|
+
|
|
45
62
|
/**
|
|
46
63
|
* Adopt a committed discovery decision and its merge baseline as one synchronous step.
|
|
47
64
|
* Visibility writers assign and save synchronously; any future writer yielding between
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { setCodexWsReuseAcrossTurns } from "./codex-ws-reuse-setting";
|
|
1
2
|
import { isSubagentModelEntry, rawSubagentModelForce } from "./subagent-models";
|
|
2
3
|
import { chmodSync, existsSync } from "node:fs";
|
|
3
4
|
import { join } from "node:path";
|
|
4
5
|
import { compactionRecoveryConfigError } from "./schema/compaction-recovery";
|
|
5
6
|
import { blockedModelRedirectsError } from "./schema/blocked-model-redirects";
|
|
7
|
+
import { anthropicSidecarConfigError } from "./schema/anthropic-account-pool";
|
|
6
8
|
import {
|
|
7
9
|
modelPinnedEffortsConfigError,
|
|
8
10
|
pinnedReasoningEffortConfigError,
|
|
@@ -25,6 +27,7 @@ import { refreshConfigDerivedRegistries } from "./derived-registries";
|
|
|
25
27
|
import { type OcxClaudeCodeConfig, type OcxConfig } from "../types";
|
|
26
28
|
import {
|
|
27
29
|
agentTaskRecoverySchema,
|
|
30
|
+
asideProfileSyncSchema,
|
|
28
31
|
catalogAutoRefreshSchema,
|
|
29
32
|
clientConnectionSchema,
|
|
30
33
|
isUsableApiKeySecret,
|
|
@@ -123,6 +126,7 @@ export function warnDegradedCompactionRouting(rawParsed: unknown, validated: Ocx
|
|
|
123
126
|
* the ratchet only ever moves down: a per-block call there costs a line the file does not have.
|
|
124
127
|
*/
|
|
125
128
|
export function warnDegradedTopLevelOptIns(rawParsed: unknown, validated: OcxConfig): void {
|
|
129
|
+
setCodexWsReuseAcrossTurns(validated.codexWsReuseAcrossTurns === true);
|
|
126
130
|
if (compactionRecoveryConfigError(rawParsed)) console.warn("⚠️ invalid compactionRecovery disabled; the original compaction failure is preserved");
|
|
127
131
|
if (blockedModelRedirectsError(rawParsed)) console.warn("⚠️ invalid blockedModelRedirects ignored; provider routing remains available");
|
|
128
132
|
const chatgptDesktop = chatgptDesktopConfigIssue(rawParsed);
|
|
@@ -130,6 +134,11 @@ export function warnDegradedTopLevelOptIns(rawParsed: unknown, validated: OcxCon
|
|
|
130
134
|
warnDegradedStreamMode(rawParsed, validated);
|
|
131
135
|
warnDegradedCompactionRouting(rawParsed, validated);
|
|
132
136
|
warnDegradedMemoryModels(rawParsed, validated);
|
|
137
|
+
// The schema replaces a malformed policy with { allProfiles: false }, which silently turns every Aside profile off (#6757).
|
|
138
|
+
const asidePolicy = rawParsed && typeof rawParsed === "object" ? (rawParsed as Record<string, unknown>).asideProfileSync : undefined;
|
|
139
|
+
if (asidePolicy !== undefined && !asideProfileSyncSchema.safeParse(asidePolicy).success) {
|
|
140
|
+
console.warn("⚠️ config.json asideProfileSync is invalid — Aside profile sync falls back to all profiles off; fix the block or inspect `ocx integration client status --client aside`");
|
|
141
|
+
}
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
/**
|
|
@@ -160,6 +169,39 @@ export function warnDegradedMemoryModels(rawParsed: unknown, validated: OcxConfi
|
|
|
160
169
|
}
|
|
161
170
|
}
|
|
162
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Load-time degradation for helper `anthropicInstance` (loadConfig only). A malformed id, or one
|
|
174
|
+
* that conflicts with its block's backend or model, drops just that key with a warning, so the
|
|
175
|
+
* helper inherits the request's pool and every provider/key survives. Validated writes still
|
|
176
|
+
* reject the value and file diagnostics still report it from the raw document.
|
|
177
|
+
*
|
|
178
|
+
* Each location is checked in isolation, global blocks first, so a Claude override is judged
|
|
179
|
+
* against the already-degraded global block it inherits from. An override that owns no
|
|
180
|
+
* `anthropicInstance` of its own is left untouched: the conflicting key lives in the global
|
|
181
|
+
* block, which is valid on its own, and the inherited value is still a well-formed instance.
|
|
182
|
+
*/
|
|
183
|
+
export function sanitizeAnthropicSidecarInstanceForLoad(parsed: unknown): void {
|
|
184
|
+
const asRecord = (value: unknown): Record<string, unknown> | undefined =>
|
|
185
|
+
value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : undefined;
|
|
186
|
+
const root = asRecord(parsed);
|
|
187
|
+
if (!root) return;
|
|
188
|
+
for (const scope of ["global", "claude"] as const) {
|
|
189
|
+
const owner = scope === "global" ? root : asRecord(root.claudeCode);
|
|
190
|
+
for (const field of ["webSearchSidecar", "visionSidecar"] as const) {
|
|
191
|
+
const sidecar = asRecord(owner?.[field]);
|
|
192
|
+
if (!sidecar || !Object.hasOwn(sidecar, "anthropicInstance")) continue;
|
|
193
|
+
const probe = scope === "global"
|
|
194
|
+
? { [field]: sidecar }
|
|
195
|
+
: { [field]: root[field], claudeCode: { [field]: sidecar } };
|
|
196
|
+
const error = anthropicSidecarConfigError(probe);
|
|
197
|
+
if (!error) continue;
|
|
198
|
+
delete sidecar.anthropicInstance;
|
|
199
|
+
// The message names a static path and reason only; the hand-edited value is never echoed.
|
|
200
|
+
console.warn(`⚠️ config.json ${error} — ignoring that anthropicInstance; the helper inherits the request's Anthropic pool`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
163
205
|
/**
|
|
164
206
|
* Load-time degradation for `retryOn429` (loadConfig only): one hand-edited invalid optional
|
|
165
207
|
* field (e.g. `attempts: 0` or a string) must not trip the whole provider schema and hide every
|
|
@@ -141,6 +141,17 @@ export function clearPendingConfigTopLevelDeletions(config: OcxConfig): void {
|
|
|
141
141
|
pendingTopLevelDeletions.delete(config);
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
/** A scoped durable adoption consumes only those fields' earlier deletion intent. */
|
|
145
|
+
export function clearConfigTopLevelDeletionIntent(config: OcxConfig, keys: readonly (keyof OcxConfig)[]): void {
|
|
146
|
+
const pending = pendingTopLevelDeletions.get(config);
|
|
147
|
+
for (const key of keys) pending?.delete(key);
|
|
148
|
+
const parsed = parsedConfigRebaseDeletionKeys(config);
|
|
149
|
+
if (parsed === null) return;
|
|
150
|
+
for (const key of keys) parsed.delete(key);
|
|
151
|
+
if (parsed.size === 0) delete config.configRebaseProvenance;
|
|
152
|
+
else config.configRebaseProvenance = { version: 1, deletedTopLevelKeys: [...parsed].sort() };
|
|
153
|
+
}
|
|
154
|
+
|
|
144
155
|
export function clearPendingConfigObjectChildDeletions(config: OcxConfig): void {
|
|
145
156
|
pendingObjectChildDeletions.delete(config);
|
|
146
157
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as z from "zod/v4";
|
|
2
|
+
import { parseAnthropicModelRoutes } from "../../oauth/anthropic-model-routes";
|
|
3
|
+
import { isAnthropicInstanceId } from "../../providers/anthropic-instance-id";
|
|
4
|
+
import { redactSecretString } from "../../lib/redact";
|
|
5
|
+
|
|
6
|
+
/** Historical A load contract, shared verbatim with B: recover only the native preference. */
|
|
7
|
+
export const anthropicAccountPoolSchema = z.object({
|
|
8
|
+
nativeMessages: z.boolean().optional().catch(false),
|
|
9
|
+
}).passthrough().optional().catch(undefined);
|
|
10
|
+
|
|
11
|
+
function record(value: unknown): Record<string, unknown> | undefined {
|
|
12
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
13
|
+
? value as Record<string, unknown> : undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Write/diagnostic contract preserves A's historical nativeMessages and route validation. */
|
|
17
|
+
function poolError(value: unknown, path: string): string | undefined {
|
|
18
|
+
if (value === undefined) return undefined;
|
|
19
|
+
const pool = record(value);
|
|
20
|
+
if (!pool) return `schema_invalid: ${path}: must be an object`;
|
|
21
|
+
if (Object.hasOwn(pool, "nativeMessages") && typeof pool.nativeMessages !== "boolean") {
|
|
22
|
+
return `schema_invalid: ${path}.nativeMessages: must be a boolean`;
|
|
23
|
+
}
|
|
24
|
+
if (pool.routes !== undefined) {
|
|
25
|
+
const parsed = parseAnthropicModelRoutes(pool.routes);
|
|
26
|
+
if (!parsed.ok) return `schema_invalid: ${path}.routes: ${parsed.error}`;
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Inspect raw locations before the tolerant load schema can discard a malformed field. */
|
|
32
|
+
export function anthropicAccountPoolConfigError(value: unknown): string | undefined {
|
|
33
|
+
const config = record(value);
|
|
34
|
+
const primaryError = poolError(config?.anthropicAccountPool, "anthropicAccountPool");
|
|
35
|
+
if (primaryError) return primaryError;
|
|
36
|
+
for (const [name, raw] of Object.entries(record(config?.providers) ?? {})) {
|
|
37
|
+
const provider = record(raw);
|
|
38
|
+
if (!provider || !Object.hasOwn(provider, "anthropicAccountPool")) continue;
|
|
39
|
+
const path = `providers.${redactSecretString(name)}.anthropicAccountPool`;
|
|
40
|
+
if (name !== "anthropic2") {
|
|
41
|
+
return `schema_invalid: ${path}: misplaced field; provider-local anthropicAccountPool is valid only on anthropic2 (anthropic uses the top-level field)`;
|
|
42
|
+
}
|
|
43
|
+
const error = poolError(provider.anthropicAccountPool, path);
|
|
44
|
+
if (error) return error;
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Raw provenance validation runs before tolerant parsing and never adopts or edits a row. */
|
|
50
|
+
export function anthropicOAuthInstanceConfigError(value: unknown): string | undefined {
|
|
51
|
+
const seen = new WeakSet<object>();
|
|
52
|
+
const inspect = (raw: unknown, location: string[]): string | undefined => {
|
|
53
|
+
if (!raw || typeof raw !== "object" || seen.has(raw)) return undefined;
|
|
54
|
+
seen.add(raw);
|
|
55
|
+
for (const [field, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(raw))) {
|
|
56
|
+
const path = [...location, field];
|
|
57
|
+
if (field === "anthropicOAuthInstance") {
|
|
58
|
+
const label = redactSecretString(path.join("."));
|
|
59
|
+
if (!("value" in descriptor)) return `schema_invalid: ${label}: must be an own data property`;
|
|
60
|
+
if (location.length !== 2 || location[0] !== "providers" || location[1] !== "anthropic2") {
|
|
61
|
+
return `schema_invalid: ${label}: misplaced field; valid only on providers.anthropic2`;
|
|
62
|
+
}
|
|
63
|
+
if (descriptor.value !== "anthropic2") return `schema_invalid: ${label}: must be anthropic2`;
|
|
64
|
+
const row = Object.getOwnPropertyDescriptors(raw);
|
|
65
|
+
if (row.adapter?.value !== "anthropic" || row.authMode?.value !== "oauth") {
|
|
66
|
+
return `schema_invalid: ${label}: requires Anthropic adapter and OAuth authMode`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!("value" in descriptor)) continue;
|
|
70
|
+
const error = inspect(descriptor.value, path);
|
|
71
|
+
if (error) return error;
|
|
72
|
+
}
|
|
73
|
+
seen.delete(raw);
|
|
74
|
+
return undefined;
|
|
75
|
+
};
|
|
76
|
+
return inspect(value, []);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Validate explicit helper identity without materializing an absent instance preference. */
|
|
80
|
+
export function anthropicSidecarConfigError(value: unknown): string | undefined {
|
|
81
|
+
const config = record(value);
|
|
82
|
+
const claude = record(config?.claudeCode);
|
|
83
|
+
for (const [prefix, owner] of [["", config], ["claudeCode.", claude]] as const) {
|
|
84
|
+
for (const field of ["webSearchSidecar", "visionSidecar"] as const) {
|
|
85
|
+
const rawSidecar = record(owner?.[field]);
|
|
86
|
+
if (!rawSidecar) continue;
|
|
87
|
+
// Claude overrides inherit individual global fields, just like buildClaudeReplayConfig.
|
|
88
|
+
const sidecar = prefix ? { ...record(config?.[field]), ...rawSidecar } : rawSidecar;
|
|
89
|
+
if (!Object.hasOwn(sidecar, "anthropicInstance")) continue;
|
|
90
|
+
const path = `${prefix}${field}.anthropicInstance`;
|
|
91
|
+
if (!isAnthropicInstanceId(sidecar.anthropicInstance)) {
|
|
92
|
+
return `schema_invalid: ${path}: must be anthropic or anthropic2`;
|
|
93
|
+
}
|
|
94
|
+
// Web search defaults to OpenAI; vision's absent backend keeps its credential-based auto mode.
|
|
95
|
+
const backend = sidecar.backend === undefined
|
|
96
|
+
? (field === "webSearchSidecar" ? "openai" : undefined) : sidecar.backend;
|
|
97
|
+
// An instance inherited from the global block is inert once the override's effective backend
|
|
98
|
+
// leaves Anthropic (the helper resolver only reads it for the Anthropic family), so it is not
|
|
99
|
+
// a conflict. An instance the override sets itself is still validated in full.
|
|
100
|
+
if (prefix && !Object.hasOwn(rawSidecar, "anthropicInstance") && backend !== undefined && backend !== "anthropic") continue;
|
|
101
|
+
const modelProvider = typeof sidecar.model === "string" && sidecar.model.includes("/")
|
|
102
|
+
? sidecar.model.slice(0, sidecar.model.indexOf("/")) : undefined;
|
|
103
|
+
if (modelProvider && isAnthropicInstanceId(modelProvider) && modelProvider !== sidecar.anthropicInstance) {
|
|
104
|
+
return `schema_invalid: ${path}: conflicts with the model's Anthropic instance`;
|
|
105
|
+
}
|
|
106
|
+
if (backend !== undefined && backend !== "anthropic") {
|
|
107
|
+
return `schema_invalid: ${path}: requires an anthropic backend`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Validate the effective settings before either management route mutates live state. */
|
|
115
|
+
export function anthropicSidecarPatchError(
|
|
116
|
+
config: unknown,
|
|
117
|
+
patches: Record<string, unknown>,
|
|
118
|
+
claude = false,
|
|
119
|
+
): string | undefined {
|
|
120
|
+
const source = record(config) ?? {};
|
|
121
|
+
const next = { ...source };
|
|
122
|
+
const owner = claude ? { ...record(source.claudeCode) } : next;
|
|
123
|
+
for (const field of ["webSearchSidecar", "visionSidecar"] as const) {
|
|
124
|
+
if (!Object.hasOwn(patches, field)) continue;
|
|
125
|
+
const patch = patches[field];
|
|
126
|
+
if (patch === null) { delete owner[field]; continue; }
|
|
127
|
+
const section = record(patch);
|
|
128
|
+
if (!section) continue; // Shape validation belongs to the route.
|
|
129
|
+
if (section.anthropicInstance !== undefined && section.anthropicInstance !== null
|
|
130
|
+
&& !isAnthropicInstanceId(section.anthropicInstance)) {
|
|
131
|
+
return `${field}.anthropicInstance must be anthropic, anthropic2, or null`;
|
|
132
|
+
}
|
|
133
|
+
const settings = { ...record(owner[field]) };
|
|
134
|
+
for (const key of ["backend", "model", "anthropicInstance"] as const) {
|
|
135
|
+
if (section[key] === null || (key === "model" && section[key] === "")) delete settings[key];
|
|
136
|
+
else if (section[key] !== undefined) settings[key] = section[key];
|
|
137
|
+
}
|
|
138
|
+
if (claude && (Object.keys(section).length === 0 || Object.keys(settings).length === 0)) delete owner[field];
|
|
139
|
+
else owner[field] = settings;
|
|
140
|
+
}
|
|
141
|
+
if (claude) next.claudeCode = owner;
|
|
142
|
+
return anthropicSidecarConfigError(next);
|
|
143
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MAIN_ACCOUNT_HARD_LOCK_MIN_PERCENT } from "../../codex/quota-types";
|
|
2
2
|
import * as z from "zod/v4";
|
|
3
|
+
import { anthropicAccountPoolSchema } from "./anthropic-account-pool";
|
|
3
4
|
import { compactionRecoverySchema } from "./compaction-recovery";
|
|
4
5
|
import { blockedModelRedirectsSchema } from "./blocked-model-redirects";
|
|
5
6
|
import {
|
|
@@ -298,6 +299,10 @@ export const configSchema = z.object({
|
|
|
298
299
|
codexAccountAutoSwitchThresholds: z.unknown().optional().transform(salvageCodexAccountAutoSwitchThresholds),
|
|
299
300
|
// An invalid optional preference must not discard providers or credential rows.
|
|
300
301
|
codexAccountPriorityFailback: z.boolean().optional().catch(false),
|
|
302
|
+
// Absent or invalid keeps the sliding window on. Explicit false restores consecutive-only steering.
|
|
303
|
+
codexFailureWindow: z.boolean().optional().catch(undefined),
|
|
304
|
+
codexPinnedTransientPolicy: z.enum(["hold", "detour-new-threads"]).optional().catch("hold"),
|
|
305
|
+
codexWsReuseAcrossTurns: z.boolean().optional().catch(false),
|
|
301
306
|
activeCodexAccountPinned: z.string().regex(CODEX_ACCOUNT_PIN_PATTERN).optional().catch(undefined),
|
|
302
307
|
// A malformed hand edit must degrade to false without discarding providers, accounts,
|
|
303
308
|
// or the exact selector map. Live writes remain strict.
|
|
@@ -327,7 +332,7 @@ export const configSchema = z.object({
|
|
|
327
332
|
blockedModelRedirects: blockedModelRedirectsSchema.optional().catch(undefined),
|
|
328
333
|
// Degrade malformed hand edits locally; candidate writes reject them before parsing.
|
|
329
334
|
// An invalid native preference retains the legacy route instead of enabling native by default.
|
|
330
|
-
anthropicAccountPool:
|
|
335
|
+
anthropicAccountPool: anthropicAccountPoolSchema,
|
|
331
336
|
// Same degrade-don't-reject rationale as the fields above: a hand-edited
|
|
332
337
|
// non-string must not trip the backup-and-defaults repair path. Unset then
|
|
333
338
|
// takes the canonical sideband path (src/server/live.ts normalizeSidebandRoot).
|
|
@@ -350,6 +355,11 @@ export const configSchema = z.object({
|
|
|
350
355
|
.map(row => apiKeyEntrySchema.parse(row) as OcxApiKeyEntry);
|
|
351
356
|
}),
|
|
352
357
|
}).passthrough().superRefine((config, ctx) => {
|
|
358
|
+
// Helper `anthropicInstance` is deliberately not refined here. A document-level issue would send
|
|
359
|
+
// loadConfig through salvage (which refuses pathless issues) to the backup-and-defaults path, so
|
|
360
|
+
// one hand-edited helper preference would hide every provider. Writes reject it explicitly in
|
|
361
|
+
// validateConfigCandidate, diagnostics report it from the raw file, and loadConfig drops only the
|
|
362
|
+
// offending key (sanitizeAnthropicSidecarInstanceForLoad).
|
|
353
363
|
const claudeCode = (config as { claudeCode?: unknown }).claudeCode;
|
|
354
364
|
if (claudeCode !== undefined && (!claudeCode || typeof claudeCode !== "object" || Array.isArray(claudeCode))) {
|
|
355
365
|
ctx.addIssue({ code: "custom", path: ["claudeCode"], message: "claudeCode must be an object" });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as z from "zod/v4";
|
|
2
|
+
import { anthropicAccountPoolSchema } from "./anthropic-account-pool";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
import { isValidProviderName } from "../provider-name";
|
|
4
5
|
import {
|
|
@@ -285,6 +286,9 @@ const providerNoProxySchema = z.unknown().superRefine((value, ctx) => {
|
|
|
285
286
|
* fields pass through (preserved for runtime extensions).
|
|
286
287
|
*/
|
|
287
288
|
export const providerConfigSchema = z.object({
|
|
289
|
+
anthropicAccountPool: anthropicAccountPoolSchema,
|
|
290
|
+
// Raw diagnostics/writes reject malformed provenance; tolerant loads preserve the custom row.
|
|
291
|
+
anthropicOAuthInstance: z.literal("anthropic2").optional().catch(undefined),
|
|
288
292
|
modelCapabilities: modelCapabilitiesSchema.optional(),
|
|
289
293
|
modelContextTiers: z.unknown().superRefine((value, ctx) => {
|
|
290
294
|
const error = contextTierRecordConfigError(value);
|
package/src/config.ts
CHANGED
|
@@ -172,6 +172,7 @@ import {
|
|
|
172
172
|
sanitizeModelDisplayNamesForLoad,
|
|
173
173
|
sanitizeAutoReviewForLoad,
|
|
174
174
|
sanitizeRetryOn429ForLoad,
|
|
175
|
+
sanitizeAnthropicSidecarInstanceForLoad,
|
|
175
176
|
sanitizeModelCostsForLoad,
|
|
176
177
|
sanitizeCapabilityDeclarationsForLoad,
|
|
177
178
|
warnInheritedFastWireConflicts,
|
|
@@ -226,6 +227,7 @@ export function loadConfig(): OcxConfig {
|
|
|
226
227
|
sanitizeModelDisplayNamesForLoad(parsed);
|
|
227
228
|
sanitizeAutoReviewForLoad(parsed);
|
|
228
229
|
sanitizeRetryOn429ForLoad(parsed);
|
|
230
|
+
sanitizeAnthropicSidecarInstanceForLoad(parsed);
|
|
229
231
|
sanitizeModelCostsForLoad(parsed);
|
|
230
232
|
sanitizeCapabilityDeclarationsForLoad(parsed);
|
|
231
233
|
const result = configSchema.safeParse(parsed);
|