@iislee/opencodex 2.11.0 → 2.31.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/AGENTS_INSTALL.md +109 -0
- package/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +618 -74
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +152 -29
- package/src/images/plan.ts +23 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +220 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +865 -181
- package/src/server/lifecycle.ts +284 -13
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +101 -32
- package/src/server/management/model-routes.ts +189 -131
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +288 -32
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +845 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +9 -3
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
package/src/cli/claude.ts
CHANGED
|
@@ -12,11 +12,15 @@ import { injectClaudeAgentDefs } from "../claude/agents-inject";
|
|
|
12
12
|
import { effectiveModelEnv, resolveAutoContext } from "../claude/context-windows";
|
|
13
13
|
import { refreshGatewayModelCacheFromProxy } from "../claude/gateway-cache";
|
|
14
14
|
import { commandInvocation } from "../lib/win-exec";
|
|
15
|
+
import { isProxyAdmissionSecret } from "../server/auth-cors";
|
|
15
16
|
import { findLiveProxy } from "../server/proxy-liveness";
|
|
16
17
|
import type { OcxConfig } from "../types";
|
|
17
18
|
import { configuredAdminToken } from "../lib/admin-secrets";
|
|
18
19
|
import { PROXY_MARKER, ownAdmissionTokens, defaultAuthDetectDeps, detectClaudeAuth, type AuthDetectDeps } from "../claude/auth-detect";
|
|
19
20
|
import { resolveClaudeAuthMode } from "../claude/auth-mode";
|
|
21
|
+
import { withProcessRuntimeProvenance } from "../lib/bun-runtime";
|
|
22
|
+
import { selfLaunchArgv } from "../lib/self-launch-argv";
|
|
23
|
+
import { ANTHROPIC_PARENT_ENV_SLOTS, trustedNodeLauncherContext, type AnthropicParentEnvSlot } from "./launcher-context";
|
|
20
24
|
|
|
21
25
|
export interface ClaudeLaunchEnv {
|
|
22
26
|
[key: string]: string | undefined;
|
|
@@ -26,13 +30,41 @@ export interface ClaudeLaunchEnv {
|
|
|
26
30
|
* Injectable IO for tests. `env` is deliberately NOT injectable: it is bound to the
|
|
27
31
|
* launch base so detection and the spawned process can never disagree (audit R3-3).
|
|
28
32
|
*/
|
|
29
|
-
export type ClaudeEnvDeps = {
|
|
33
|
+
export type ClaudeEnvDeps = {
|
|
34
|
+
authDetect?: Omit<Partial<AuthDetectDeps>, "env" | "ownTokens">;
|
|
35
|
+
/** Test seam; production uses the authenticated Node-launcher context. */
|
|
36
|
+
preBunAnthropicSlots?: readonly AnthropicParentEnvSlot[] | null;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function isClaudeLoopbackHostname(hostname: string): boolean {
|
|
40
|
+
const normalized = hostname.toLowerCase().replace(/\.$/, "");
|
|
41
|
+
return normalized === "localhost"
|
|
42
|
+
|| normalized === "127.0.0.1"
|
|
43
|
+
|| normalized === "::1"
|
|
44
|
+
|| normalized === "[::1]";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function targetsLocalClaudeProxy(value: string | undefined, port: number): boolean {
|
|
48
|
+
if (!value) return false;
|
|
49
|
+
try {
|
|
50
|
+
const parsed = new URL(value);
|
|
51
|
+
const effectivePort = parsed.port === "" ? 80 : Number(parsed.port);
|
|
52
|
+
return parsed.protocol === "http:"
|
|
53
|
+
&& isClaudeLoopbackHostname(parsed.hostname)
|
|
54
|
+
&& effectivePort === port
|
|
55
|
+
&& parsed.username === ""
|
|
56
|
+
&& parsed.password === "";
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
30
61
|
|
|
31
62
|
/**
|
|
32
63
|
* Pure env assembly (unit-tested): never sets ANTHROPIC_API_KEY (setting both
|
|
33
64
|
* token vars triggers Claude Code's auth-conflict warning, 003 E1), and never
|
|
34
|
-
*
|
|
35
|
-
* ANTHROPIC_BASE_URL values owned by a previous
|
|
65
|
+
* preserves Anthropic variables proven to exist in the parent Node launcher,
|
|
66
|
+
* apart from stale loopback ANTHROPIC_BASE_URL values owned by a previous
|
|
67
|
+
* opencodex launch. Unproven ambient values fail closed as project dotenv.
|
|
36
68
|
*/
|
|
37
69
|
export function buildClaudeEnv(
|
|
38
70
|
config: OcxConfig,
|
|
@@ -47,28 +79,37 @@ export function buildClaudeEnv(
|
|
|
47
79
|
// stale marker left in place would suppress the admission key and then be removed,
|
|
48
80
|
// leaving the child with no token at all (audit R2-1). It is opencodex state, never
|
|
49
81
|
// user auth, so dropping it unconditionally is safe.
|
|
50
|
-
if (env.ANTHROPIC_AUTH_TOKEN === PROXY_MARKER) delete env.ANTHROPIC_AUTH_TOKEN;
|
|
51
|
-
// Step 1b — drop Anthropic credentials
|
|
52
|
-
// project `.env`/`.env.local
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
82
|
+
if (env.ANTHROPIC_AUTH_TOKEN?.trim() === PROXY_MARKER) delete env.ANTHROPIC_AUTH_TOKEN;
|
|
83
|
+
// Step 1b — drop Anthropic credentials AND destinations that Bun may have synthesized
|
|
84
|
+
// from a project `.env`/`.env.local`. The plain-Node launcher records genuine parent
|
|
85
|
+
// exports before Bun starts and pairs that context with an argv proof, so with a
|
|
86
|
+
// trusted context we know exactly which slots the user really exported.
|
|
87
|
+
//
|
|
88
|
+
// Without a trusted context all three slots are treated as project-controlled. An
|
|
89
|
+
// earlier revision of this branch preserved credentials here, reasoning that the
|
|
90
|
+
// destination is pinned below so a dotenv key would only ever reach the local proxy.
|
|
91
|
+
// That reasoning is wrong, and review caught it: `CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST`
|
|
92
|
+
// is only set when we own an auth token (see below, and #253 for why asserting it
|
|
93
|
+
// otherwise logs a subscriber out), so on a subscription launch Claude Code's
|
|
94
|
+
// settings.env merge can still replace `ANTHROPIC_BASE_URL` after we return. A
|
|
95
|
+
// preserved key then travels to that host. The repository documents that residual for
|
|
96
|
+
// subscription mode; it must not be widened into a credential leak.
|
|
97
|
+
//
|
|
98
|
+
// Direct `bun src/cli/index.ts` therefore loses ambient Anthropic values. That is a
|
|
99
|
+
// real cost to a documented entry point, and the escape hatch is the launcher: run
|
|
100
|
+
// through `ocx` (the published bin) and genuine shell exports are preserved by proof.
|
|
101
|
+
const explicitSlots = deps.preBunAnthropicSlots;
|
|
102
|
+
const trustedSlots = explicitSlots === undefined
|
|
103
|
+
? trustedNodeLauncherContext()?.anthropicEnvSlots ?? []
|
|
104
|
+
: explicitSlots ?? [];
|
|
105
|
+
const exported = new Set<AnthropicParentEnvSlot>(trustedSlots);
|
|
106
|
+
for (const name of ANTHROPIC_PARENT_ENV_SLOTS) {
|
|
107
|
+
const value = env[name];
|
|
108
|
+
if (value !== undefined && value !== "" && !exported.has(name)) delete env[name];
|
|
69
109
|
}
|
|
70
|
-
// Never forward
|
|
110
|
+
// Never forward old or current provenance seams to Claude Code.
|
|
71
111
|
delete env.OCX_PRE_BUN_ANTHROPIC_ENV;
|
|
112
|
+
delete env.OCX_NODE_LAUNCH_CONTEXT;
|
|
72
113
|
const setDefault = (name: string, value: string | undefined) => {
|
|
73
114
|
if (value === undefined || value.length === 0) return;
|
|
74
115
|
if (env[name] !== undefined && env[name] !== "") return; // user wins
|
|
@@ -79,10 +120,12 @@ export function buildClaudeEnv(
|
|
|
79
120
|
if (existingBaseUrl) {
|
|
80
121
|
try {
|
|
81
122
|
const parsed = new URL(existingBaseUrl);
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
123
|
+
const effectivePort = parsed.port === "" ? 80 : Number(parsed.port);
|
|
124
|
+
if (parsed.protocol === "http:"
|
|
125
|
+
&& isClaudeLoopbackHostname(parsed.hostname)
|
|
126
|
+
&& effectivePort !== port) {
|
|
84
127
|
const replacement = `http://127.0.0.1:${port}`;
|
|
85
|
-
console.error(`⚠ Replacing stale opencodex ANTHROPIC_BASE_URL ${
|
|
128
|
+
console.error(`⚠ Replacing stale opencodex ANTHROPIC_BASE_URL ${parsed.origin} with ${replacement}.`);
|
|
86
129
|
env.ANTHROPIC_BASE_URL = replacement;
|
|
87
130
|
}
|
|
88
131
|
} catch {
|
|
@@ -94,8 +137,26 @@ export function buildClaudeEnv(
|
|
|
94
137
|
// the user's Claude login. Only inject a token when the proxy actually requires an
|
|
95
138
|
// admission key; otherwise Claude Code keeps its own OAuth and sends it to us —
|
|
96
139
|
// native claude models then pass through verbatim (see server/claude-messages.ts).
|
|
97
|
-
|
|
98
|
-
|
|
140
|
+
const ownTokens = ownAdmissionTokens(config);
|
|
141
|
+
const targetsLocalProxy = targetsLocalClaudeProxy(env.ANTHROPIC_BASE_URL, port);
|
|
142
|
+
const inheritedApiKey = env.ANTHROPIC_API_KEY;
|
|
143
|
+
if (typeof inheritedApiKey === "string" && isProxyAdmissionSecret(inheritedApiKey, config)) {
|
|
144
|
+
delete env.ANTHROPIC_API_KEY;
|
|
145
|
+
}
|
|
146
|
+
const hasUserApiKey = Boolean(env.ANTHROPIC_API_KEY?.trim());
|
|
147
|
+
const inheritedAuthToken = env.ANTHROPIC_AUTH_TOKEN;
|
|
148
|
+
const inheritedTokenIsOurs = typeof inheritedAuthToken === "string"
|
|
149
|
+
&& isProxyAdmissionSecret(inheritedAuthToken, config);
|
|
150
|
+
// system-env may have injected the proxy's admission key into the parent. A
|
|
151
|
+
// proof-bound external BASE_URL is still user-owned, so never let our inherited
|
|
152
|
+
// key follow it. A user API key also wins on a local launch; remove only the token
|
|
153
|
+
// values recognized by the shared proxy-admission contract and preserve every
|
|
154
|
+
// other token.
|
|
155
|
+
if (inheritedTokenIsOurs && (!targetsLocalProxy || hasUserApiKey)) {
|
|
156
|
+
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
157
|
+
}
|
|
158
|
+
if (targetsLocalProxy && !hasUserApiKey && ownTokens.length > 0) {
|
|
159
|
+
setDefault("ANTHROPIC_AUTH_TOKEN", ownTokens[0]);
|
|
99
160
|
}
|
|
100
161
|
// Detection reads the SANITIZED launch env — the exact object spawned below — so the
|
|
101
162
|
// resolver and the spawned process cannot disagree. It deliberately does NOT read the
|
|
@@ -110,11 +171,19 @@ export function buildClaudeEnv(
|
|
|
110
171
|
...defaultAuthDetectDeps(env as NodeJS.ProcessEnv),
|
|
111
172
|
...(deps.authDetect ?? {}),
|
|
112
173
|
env: () => env as NodeJS.ProcessEnv,
|
|
113
|
-
ownTokens
|
|
174
|
+
ownTokens,
|
|
114
175
|
}));
|
|
115
|
-
if (!env.ANTHROPIC_AUTH_TOKEN && resolved.markerMode === "proxy") {
|
|
176
|
+
if (!env.ANTHROPIC_AUTH_TOKEN && !hasUserApiKey && targetsLocalProxy && resolved.markerMode === "proxy") {
|
|
116
177
|
env.ANTHROPIC_AUTH_TOKEN = PROXY_MARKER;
|
|
117
178
|
}
|
|
179
|
+
const finalAuthToken = env.ANTHROPIC_AUTH_TOKEN;
|
|
180
|
+
const hostOwnsAuthentication = targetsLocalProxy
|
|
181
|
+
&& !hasUserApiKey
|
|
182
|
+
&& typeof finalAuthToken === "string"
|
|
183
|
+
&& (
|
|
184
|
+
finalAuthToken.trim() === PROXY_MARKER
|
|
185
|
+
|| isProxyAdmissionSecret(finalAuthToken, config)
|
|
186
|
+
);
|
|
118
187
|
if (resolved.origin === "auto-unknown") {
|
|
119
188
|
console.error("⚠ Claude 인증을 확인하지 못했습니다 — 구독 방식으로 진행합니다. GUI에서 인증 모드를 직접 지정하면 이 판단을 덮어쓸 수 있습니다.");
|
|
120
189
|
}
|
|
@@ -136,7 +205,7 @@ export function buildClaudeEnv(
|
|
|
136
205
|
// Claude Code 2.1.206+ also treats this as a host-auth assertion. Injecting it
|
|
137
206
|
// without a host token makes a valid claude.ai subscription look logged out,
|
|
138
207
|
// so the guard is only safe when opencodex actually owns authentication.
|
|
139
|
-
if (
|
|
208
|
+
if (hostOwnsAuthentication) {
|
|
140
209
|
setDefault("CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST", "1");
|
|
141
210
|
}
|
|
142
211
|
// Opt-in effort forcing (devlog 136 B6): opus-shaped aliases already carry
|
|
@@ -201,11 +270,11 @@ async function ensureProxyForClaude(): Promise<number | null> {
|
|
|
201
270
|
if (live) return live.port;
|
|
202
271
|
const cfgPort = loadConfig().port;
|
|
203
272
|
const pinPort = typeof cfgPort === "number" && cfgPort > 0 ? cfgPort : 10100;
|
|
204
|
-
const child = spawn(process.execPath, [
|
|
273
|
+
const child = spawn(process.execPath, selfLaunchArgv(["start", "--port", String(pinPort)]), {
|
|
205
274
|
detached: true,
|
|
206
275
|
stdio: "ignore",
|
|
207
276
|
windowsHide: true,
|
|
208
|
-
env: { ...process.env, OCX_SERVICE: "1" },
|
|
277
|
+
env: withProcessRuntimeProvenance({ ...process.env, OCX_SERVICE: "1" }),
|
|
209
278
|
});
|
|
210
279
|
child.unref();
|
|
211
280
|
const deadline = Date.now() + 8_000;
|
|
@@ -248,7 +317,7 @@ export async function cmdClaude(args: string[]): Promise<number> {
|
|
|
248
317
|
// Pre-write the CLI's gateway-model cache (devlog 030): without a token the CLI
|
|
249
318
|
// never refreshes it, so the picker would keep showing yesterday's aliases.
|
|
250
319
|
try {
|
|
251
|
-
const cachePath = await refreshGatewayModelCacheFromProxy(port);
|
|
320
|
+
const cachePath = await refreshGatewayModelCacheFromProxy(port, { admissionConfig: config });
|
|
252
321
|
if (cachePath === null) {
|
|
253
322
|
console.error("⚠ Gateway model cache could not be refreshed; the model picker may be stale.");
|
|
254
323
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { inspectCodexLogs, type CodexLogGuardInspection } from "../codex/log-guard/inspect";
|
|
2
|
+
import {
|
|
3
|
+
getCodexLogGuardProtectionStatus,
|
|
4
|
+
type CodexLogGuardStatus,
|
|
5
|
+
} from "../codex/log-guard/protection";
|
|
6
|
+
|
|
7
|
+
function kib(bytes: number): string {
|
|
8
|
+
return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function fileMetadataLines(report: CodexLogGuardInspection): string[] {
|
|
12
|
+
if (report.externalSqliteHome === null) return [];
|
|
13
|
+
const location = report.externalSqliteHome ? "external sqlite_home" : "CODEX_HOME sqlite_home";
|
|
14
|
+
return [
|
|
15
|
+
` ${location}; DB ${kib(report.files.databaseBytes)}, WAL ${kib(report.files.walBytes)}, SHM ${kib(report.files.shmBytes)}`,
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type DoctorReport = CodexLogGuardInspection | CodexLogGuardStatus;
|
|
20
|
+
|
|
21
|
+
function protectionLines(report: DoctorReport): string[] {
|
|
22
|
+
if (!("protection" in report)) return [];
|
|
23
|
+
const protection = report.protection;
|
|
24
|
+
switch (protection.state) {
|
|
25
|
+
case "active":
|
|
26
|
+
return [` ok protection active (${protection.desiredMode})`];
|
|
27
|
+
case "off":
|
|
28
|
+
return [" -- protection off"];
|
|
29
|
+
case "drifted":
|
|
30
|
+
return [
|
|
31
|
+
` WARN protection drifted (desired ${protection.desiredMode}; observed ${protection.observedMode})`,
|
|
32
|
+
" Action: ocx storage codex-logs repair",
|
|
33
|
+
];
|
|
34
|
+
case "unsupported":
|
|
35
|
+
return [" -- protection unavailable for this schema"];
|
|
36
|
+
case "unknown":
|
|
37
|
+
return [" WARN protection state unknown; inspect reserved Log Guard triggers before changing mode"];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function formatCodexLogGuardDoctor(report: DoctorReport): string[] {
|
|
42
|
+
const lines = ["Codex diagnostic logs"];
|
|
43
|
+
lines.push(...protectionLines(report));
|
|
44
|
+
|
|
45
|
+
if (report.schema.state === "unavailable") {
|
|
46
|
+
lines.push(" -- inspection unavailable");
|
|
47
|
+
return lines;
|
|
48
|
+
}
|
|
49
|
+
if (report.schema.state === "missing") {
|
|
50
|
+
lines.push(" -- logs_2.sqlite is not present");
|
|
51
|
+
return lines;
|
|
52
|
+
}
|
|
53
|
+
if (report.schema.state === "unreadable") {
|
|
54
|
+
lines.push(" -- logs_2.sqlite is unreadable; inspection metadata only");
|
|
55
|
+
lines.push(...fileMetadataLines(report));
|
|
56
|
+
lines.push(" checkpointed read-only snapshot; activity rate not measured");
|
|
57
|
+
return lines;
|
|
58
|
+
}
|
|
59
|
+
if (report.schema.state === "unsupported") {
|
|
60
|
+
lines.push(" -- unknown schema; inspection only");
|
|
61
|
+
} else {
|
|
62
|
+
lines.push(" ok schema compatible");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
lines.push(...fileMetadataLines(report));
|
|
66
|
+
|
|
67
|
+
if (report.metrics) {
|
|
68
|
+
lines.push(
|
|
69
|
+
` ${report.metrics.totalRows} rows; TRACE ${(report.metrics.traceShare * 100).toFixed(1)}%; reclaimable ${kib(report.metrics.reclaimableBytes)}`,
|
|
70
|
+
);
|
|
71
|
+
const top = report.metrics.topTargets[0];
|
|
72
|
+
if (top) lines.push(` top target ${top.target} (${top.rows} rows)`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
lines.push(" checkpointed read-only snapshot; activity rate not measured");
|
|
76
|
+
return lines;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface CodexLogGuardDoctorDeps {
|
|
80
|
+
inspect?: () => DoctorReport;
|
|
81
|
+
log?: (line: string) => void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Observe-only doctor section. Inspection failures are reported without mutating or failing doctor. */
|
|
85
|
+
export function printCodexLogGuardDoctor(deps: CodexLogGuardDoctorDeps = {}): void {
|
|
86
|
+
const inspect = deps.inspect ?? getCodexLogGuardProtectionStatus;
|
|
87
|
+
const log = deps.log ?? console.log;
|
|
88
|
+
try {
|
|
89
|
+
for (const line of formatCodexLogGuardDoctor(inspect())) log(line);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
// Production can still fall back to PR 1's simpler inspector if the enriched
|
|
92
|
+
// protection lookup fails. An injected inspector is a test/caller boundary:
|
|
93
|
+
// never escape that boundary and touch the real Codex home behind its back.
|
|
94
|
+
if (!deps.inspect) {
|
|
95
|
+
try {
|
|
96
|
+
for (const line of formatCodexLogGuardDoctor(inspectCodexLogs())) log(line);
|
|
97
|
+
return;
|
|
98
|
+
} catch { /* report the original failure below */ }
|
|
99
|
+
}
|
|
100
|
+
log("Codex diagnostic logs");
|
|
101
|
+
log(" -- inspection unavailable");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -17,6 +17,8 @@ const DEFAULT_DEPS: CodexShimAutoRestoreCliDeps = {
|
|
|
17
17
|
|
|
18
18
|
export function skipsCodexShimAutoRestore(command: string | undefined, args: string[]): boolean {
|
|
19
19
|
if (command === "uninstall" || command === "remove") return true;
|
|
20
|
+
// `lab` is read-only inspection; it must not trigger shim side effects.
|
|
21
|
+
if (command === "lab") return true;
|
|
20
22
|
return command === "codex-shim" && ["install", "uninstall", "remove"].includes(args[1] ?? "");
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
currentExternalCodexModelProvider,
|
|
3
|
+
getCodexRoutingKind,
|
|
4
|
+
type CodexRoutingKind,
|
|
5
|
+
} from "../codex/inject";
|
|
6
|
+
import { loadConfig, resolveEnvValue } from "../config";
|
|
7
|
+
|
|
8
|
+
const PROXY_ENV_KEYS = [
|
|
9
|
+
"HTTP_PROXY",
|
|
10
|
+
"HTTPS_PROXY",
|
|
11
|
+
"ALL_PROXY",
|
|
12
|
+
"http_proxy",
|
|
13
|
+
"https_proxy",
|
|
14
|
+
"all_proxy",
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
export interface CodexShimReadinessInputs {
|
|
18
|
+
routingKind: CodexRoutingKind;
|
|
19
|
+
externalProvider: string | null;
|
|
20
|
+
processProxyEnvPresent: boolean;
|
|
21
|
+
configuredProxyResolved: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function externalProviderLabel(provider: string | null): string {
|
|
25
|
+
return provider
|
|
26
|
+
? `external model_provider ${JSON.stringify(provider)}`
|
|
27
|
+
: "the active Codex route";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function codexShimReadinessWarnings(
|
|
31
|
+
inputs: CodexShimReadinessInputs,
|
|
32
|
+
): string[] {
|
|
33
|
+
const warnings: string[] = [];
|
|
34
|
+
const provider = externalProviderLabel(inputs.externalProvider);
|
|
35
|
+
|
|
36
|
+
if (inputs.routingKind === "unknown") {
|
|
37
|
+
warnings.push(
|
|
38
|
+
inputs.externalProvider
|
|
39
|
+
? `Codex still selects ${provider}. The shim can start OpenCodex, but it does not redirect that provider; point it at the live OpenCodex /v1 endpoint with wire_api = "responses", or switch to the built-in openai provider and run 'ocx sync'.`
|
|
40
|
+
: "Codex routing could not be verified. The shim can start OpenCodex, but it may not redirect Codex; run 'ocx doctor' before relying on autostart.",
|
|
41
|
+
);
|
|
42
|
+
} else if (inputs.routingKind === "custom-local") {
|
|
43
|
+
warnings.push(
|
|
44
|
+
`Codex uses ${provider} through a user-owned local gateway. The shim can start OpenCodex, but OpenCodex does not own that route; run 'ocx doctor' to verify its lifecycle.`,
|
|
45
|
+
);
|
|
46
|
+
} else if (inputs.routingKind === "custom-remote") {
|
|
47
|
+
warnings.push(
|
|
48
|
+
`Codex uses ${provider} through a remote gateway. The shim only starts a local OpenCodex proxy and will not affect those requests.`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (inputs.processProxyEnvPresent && !inputs.configuredProxyResolved) {
|
|
53
|
+
warnings.push(
|
|
54
|
+
"Proxy environment variables are present only in this process while config.proxy is unset or unresolved. Codex launchers and background services may not inherit them; persist config.proxy before relying on autostart.",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return warnings;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function collectCodexShimReadinessWarnings(): string[] {
|
|
62
|
+
const config = loadConfig();
|
|
63
|
+
let externalProvider: string | null = null;
|
|
64
|
+
try {
|
|
65
|
+
externalProvider = currentExternalCodexModelProvider();
|
|
66
|
+
} catch {
|
|
67
|
+
// Routing readiness is advisory; getCodexRoutingKind() already reports an
|
|
68
|
+
// unreadable config as unknown, so preserve that warning instead of failing.
|
|
69
|
+
}
|
|
70
|
+
return codexShimReadinessWarnings({
|
|
71
|
+
routingKind: getCodexRoutingKind(),
|
|
72
|
+
externalProvider,
|
|
73
|
+
processProxyEnvPresent: PROXY_ENV_KEYS.some(key => Boolean(process.env[key]?.trim())),
|
|
74
|
+
configuredProxyResolved: Boolean(resolveEnvValue(config.proxy)?.trim()),
|
|
75
|
+
});
|
|
76
|
+
}
|
package/src/cli/combo.ts
CHANGED
|
@@ -16,6 +16,7 @@ const USAGE = `Usage:
|
|
|
16
16
|
ocx combo set <id> --targets <provider/model[:weight],...>
|
|
17
17
|
[--strategy <failover|round-robin>] [--sticky <1-100>]
|
|
18
18
|
[--effort <low|medium|high|xhigh|max|ultra|->] [--alias <name|->]
|
|
19
|
+
[--native-alias] [--display-name <label|->]
|
|
19
20
|
[--rename-from <id>] [--json]
|
|
20
21
|
ocx combo remove <id> --yes [--json]`;
|
|
21
22
|
|
|
@@ -77,6 +78,8 @@ async function set(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
77
78
|
if (stickyLimit > 100) throw new CliUsageError("--sticky must be <= 100", USAGE);
|
|
78
79
|
const effort = takeOption(args, "--effort");
|
|
79
80
|
const alias = takeOption(args, "--alias");
|
|
81
|
+
const nativeAlias = takeFlag(args, "--native-alias");
|
|
82
|
+
const displayName = takeOption(args, "--display-name");
|
|
80
83
|
const renameFrom = takeOption(args, "--rename-from");
|
|
81
84
|
rejectArgs(args, USAGE);
|
|
82
85
|
const combo: Record<string, unknown> = {
|
|
@@ -86,6 +89,11 @@ async function set(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
86
89
|
};
|
|
87
90
|
if (effort !== undefined) combo.defaultEffort = effort === "-" ? null : effort;
|
|
88
91
|
if (alias !== undefined) combo.alias = alias === "-" ? "" : alias;
|
|
92
|
+
if (nativeAlias) combo.nativeAlias = true;
|
|
93
|
+
if (displayName !== undefined) combo.displayName = displayName === "-" ? "" : displayName;
|
|
94
|
+
const current = await runtimeRequest<{ combos?: ComboRow[] }>("/api/combos", {}, deps);
|
|
95
|
+
const existing = (current.combos ?? []).find(row => row.id === (renameFrom ?? id));
|
|
96
|
+
if (existing?.imageInput === "disabled") combo.imageInput = "disabled";
|
|
89
97
|
const result = await runtimeRequest("/api/combos", {
|
|
90
98
|
method: "PUT",
|
|
91
99
|
body: JSON.stringify({ id, combo, ...(renameFrom ? { renameFrom } : {}) }),
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { clearCodexAccountPin } from "../codex/account-priority";
|
|
3
|
+
import { getConfigPath, mutatePersistedConfig, readConfigDiagnostics, sanitizeModelCostsForDisplay, saveConfig, validateConfigCandidate } from "../config";
|
|
4
|
+
import { VISION_REASONING_EFFORTS, isVisionReasoningEffort } from "../reasoning-effort";
|
|
3
5
|
import type { OcxConfig } from "../types";
|
|
6
|
+
import { normalizeVisionReasoningForModel } from "../vision/reasoning";
|
|
4
7
|
import { CliUsageError, printData, rejectArgs, runCliAction, takeFlag } from "./runtime-api";
|
|
5
8
|
|
|
6
9
|
const USAGE = `Usage:
|
|
@@ -17,6 +20,9 @@ const BLOCKED_SEGMENTS = new Set(["__proto__", "prototype", "constructor"]);
|
|
|
17
20
|
|
|
18
21
|
function redact(value: unknown, key = ""): unknown {
|
|
19
22
|
if (SECRET_KEYS.test(key) && typeof value === "string") return value ? "********" : value;
|
|
23
|
+
// modelCosts rows are keyed by model id; a pasted API key in a key position
|
|
24
|
+
// must not be echoed back by config show/get (values are already redacted).
|
|
25
|
+
if (key === "modelCosts") return sanitizeModelCostsForDisplay(value);
|
|
20
26
|
if (Array.isArray(value)) return value.map(item => redact(item));
|
|
21
27
|
if (value && typeof value === "object") {
|
|
22
28
|
return Object.fromEntries(Object.entries(value as Record<string, unknown>).map(([childKey, child]) => [childKey, redact(child, childKey)]));
|
|
@@ -64,10 +70,36 @@ function loadInput(path: string): unknown {
|
|
|
64
70
|
catch { throw new CliUsageError(`invalid JSON in ${path}`); }
|
|
65
71
|
}
|
|
66
72
|
|
|
73
|
+
function visionReasoningError(value: unknown): string | null {
|
|
74
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
75
|
+
const vision = (value as Record<string, unknown>).visionSidecar;
|
|
76
|
+
if (!vision || typeof vision !== "object" || Array.isArray(vision)) return null;
|
|
77
|
+
const reasoning = (vision as Record<string, unknown>).reasoning;
|
|
78
|
+
if (reasoning === undefined || isVisionReasoningEffort(reasoning)) return null;
|
|
79
|
+
return `schema_invalid: visionSidecar.reasoning: must be one of ${VISION_REASONING_EFFORTS.join(", ")}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function validateCandidate(value: unknown): ReturnType<typeof validateConfigCandidate> {
|
|
83
|
+
const error = visionReasoningError(value);
|
|
84
|
+
return error ? { ok: false, error } : validateConfigCandidate(value);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function normalizeVisionConfig(config: OcxConfig): OcxConfig {
|
|
88
|
+
const vision = config.visionSidecar;
|
|
89
|
+
if (!vision || vision.reasoning === undefined) return config;
|
|
90
|
+
// Keep CLI import/set semantics aligned with the execution path: an omitted or blank model means
|
|
91
|
+
// the bounded OpenAI vision default, gpt-5.4-mini, not the Dashboard's web-search default.
|
|
92
|
+
const model = vision.model || "gpt-5.4-mini";
|
|
93
|
+
const normalized = normalizeVisionReasoningForModel(model, vision.reasoning);
|
|
94
|
+
if (normalized === undefined) delete vision.reasoning;
|
|
95
|
+
else vision.reasoning = normalized;
|
|
96
|
+
return config;
|
|
97
|
+
}
|
|
98
|
+
|
|
67
99
|
function validate(value: unknown): OcxConfig {
|
|
68
|
-
const result =
|
|
100
|
+
const result = validateCandidate(value);
|
|
69
101
|
if (!result.ok) throw new CliUsageError(result.error);
|
|
70
|
-
return result.config;
|
|
102
|
+
return normalizeVisionConfig(result.config);
|
|
71
103
|
}
|
|
72
104
|
|
|
73
105
|
export async function handleConfigCommand(argv: string[]): Promise<number> {
|
|
@@ -98,11 +130,42 @@ export async function handleConfigCommand(argv: string[]): Promise<number> {
|
|
|
98
130
|
const raw = action === "set" ? args.shift() : undefined;
|
|
99
131
|
if (!path || (action === "set" && raw === undefined)) throw new CliUsageError("config path and value are required", USAGE);
|
|
100
132
|
rejectArgs(args, USAGE);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
133
|
+
// #1835/#1838: the read used to happen OUTSIDE the mutation lock, so a concurrent
|
|
134
|
+
// edit landing between it and the save was reverted by this whole-snapshot write.
|
|
135
|
+
// `mutatePersistedConfig` reruns this callback against the latest validated disk
|
|
136
|
+
// state, so the operation is applied to what is actually there at commit time.
|
|
137
|
+
let savedValue: unknown = null;
|
|
138
|
+
const outcome = mutatePersistedConfig(fresh => {
|
|
139
|
+
// Snapshot BEFORE mutating: comparing after the write compares a value with
|
|
140
|
+
// itself and would report every no-op as a change, bumping the generation.
|
|
141
|
+
const before = JSON.stringify(fresh);
|
|
142
|
+
const candidate = structuredClone(fresh) as unknown as Record<string, unknown>;
|
|
143
|
+
setPath(candidate, path, raw === undefined ? undefined : parseValue(raw), action === "unset");
|
|
144
|
+
const config = validate(candidate);
|
|
145
|
+
savedValue = action === "unset" ? null : getPath(config, path);
|
|
146
|
+
// Setting the order here is the operator restating it, exactly as through
|
|
147
|
+
// `ocx account priority` or the management route, so it releases the manual pin
|
|
148
|
+
// for the same reason those do: a pin made before any order existed would
|
|
149
|
+
// otherwise outrank every order set afterwards, capping the pool at the pinned
|
|
150
|
+
// account's tier with nothing on any surface explaining why. `import` is
|
|
151
|
+
// deliberately not covered — that file supplies its own pin, so there is no
|
|
152
|
+
// stale one to release.
|
|
153
|
+
if (pathSegments(path)[0] === "codexAccountPriorities") clearCodexAccountPin(config);
|
|
154
|
+
// REPLACE rather than merge: `Object.assign` alone cannot remove a key that
|
|
155
|
+
// `unset` deleted, which would make unset silently succeed while changing nothing.
|
|
156
|
+
for (const key of Object.keys(fresh)) {
|
|
157
|
+
if (!(key in (config as unknown as Record<string, unknown>))) {
|
|
158
|
+
delete (fresh as unknown as Record<string, unknown>)[key];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
Object.assign(fresh, config);
|
|
162
|
+
return { changed: JSON.stringify(fresh) !== before, value: undefined };
|
|
163
|
+
});
|
|
164
|
+
if (outcome.status === "unavailable") {
|
|
165
|
+
throw new Error(outcome.reason === "conflict"
|
|
166
|
+
? "config changed while applying this update; retry"
|
|
167
|
+
: `config is ${outcome.reason}`);
|
|
168
|
+
}
|
|
106
169
|
printData({ ok: true, path, value: redact(savedValue, path.split(".").at(-1)) }, wantsJson,
|
|
107
170
|
[`${action === "unset" ? "Unset" : "Set"} ${path}.`]);
|
|
108
171
|
return;
|
|
@@ -110,9 +173,10 @@ export async function handleConfigCommand(argv: string[]): Promise<number> {
|
|
|
110
173
|
if (action === "validate") {
|
|
111
174
|
const path = args.shift();
|
|
112
175
|
rejectArgs(args, USAGE);
|
|
113
|
-
const result = path ?
|
|
176
|
+
const result = path ? validateCandidate(loadInput(path)) : (() => {
|
|
114
177
|
const diagnostics = readConfigDiagnostics();
|
|
115
|
-
|
|
178
|
+
if (diagnostics.error) return { ok: false as const, error: diagnostics.error };
|
|
179
|
+
return validateCandidate(diagnostics.config);
|
|
116
180
|
})();
|
|
117
181
|
printData(result.ok ? { ok: true, source: path ?? getConfigPath() } : result, wantsJson,
|
|
118
182
|
[result.ok ? "Config is valid." : `Config is invalid: ${result.error}`]);
|