@yansigit/opencodex 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/LICENSE +21 -0
- package/README.md +303 -0
- package/assets/architecture.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/claude-code-models.gif +0 -0
- package/assets/codex-app-picker.png +0 -0
- package/bin/ocx.mjs +587 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
- package/gui/dist/assets/index-CGoDO3uO.css +1 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/icons.svg +24 -0
- package/gui/dist/index.html +25 -0
- package/gui/dist/logo.png +0 -0
- package/gui/dist/provider-icons/alibaba-color.svg +1 -0
- package/gui/dist/provider-icons/antigravity-color.svg +1 -0
- package/gui/dist/provider-icons/claude-color.svg +1 -0
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -0
- package/gui/dist/provider-icons/cursor-color.svg +2 -0
- package/gui/dist/provider-icons/deepseek-color.svg +1 -0
- package/gui/dist/provider-icons/discord.svg +1 -0
- package/gui/dist/provider-icons/firepass-color.svg +1 -0
- package/gui/dist/provider-icons/fireworks-color.svg +1 -0
- package/gui/dist/provider-icons/gemini-color.svg +1 -0
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
- package/gui/dist/provider-icons/grok.svg +1 -0
- package/gui/dist/provider-icons/groq-color.svg +1 -0
- package/gui/dist/provider-icons/huggingface-color.svg +1 -0
- package/gui/dist/provider-icons/kimi-color.svg +1 -0
- package/gui/dist/provider-icons/kiro-color.svg +15 -0
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
- package/gui/dist/provider-icons/mistral-color.svg +1 -0
- package/gui/dist/provider-icons/moonshot-color.svg +1 -0
- package/gui/dist/provider-icons/nvidia-color.svg +1 -0
- package/gui/dist/provider-icons/ollama-color.svg +1 -0
- package/gui/dist/provider-icons/openai.svg +1 -0
- package/gui/dist/provider-icons/opencode.svg +2 -0
- package/gui/dist/provider-icons/openrouter-color.svg +1 -0
- package/gui/dist/provider-icons/pi.svg +21 -0
- package/gui/dist/provider-icons/qianfan-color.svg +1 -0
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
- package/gui/dist/provider-icons/telegram.svg +1 -0
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/vllm-color.svg +1 -0
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
- package/package.json +108 -0
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic-image-guard.ts +251 -0
- package/src/adapters/anthropic-image-normalize.ts +518 -0
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +1327 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +121 -0
- package/src/adapters/client-fingerprint.ts +65 -0
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +288 -0
- package/src/adapters/cursor/discovery.ts +333 -0
- package/src/adapters/cursor/effort-map.ts +151 -0
- package/src/adapters/cursor/exec-policy.ts +88 -0
- package/src/adapters/cursor/framing.ts +250 -0
- package/src/adapters/cursor/gen/agent_pb.ts +15274 -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/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +269 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1653 -0
- package/src/adapters/cursor/mcp-config.ts +42 -0
- package/src/adapters/cursor/mcp-manager.ts +333 -0
- package/src/adapters/cursor/message-mapper.ts +49 -0
- package/src/adapters/cursor/native-exec-common.ts +76 -0
- package/src/adapters/cursor/native-exec-desktop.ts +184 -0
- package/src/adapters/cursor/native-exec-fs.ts +332 -0
- package/src/adapters/cursor/native-exec-mcp.ts +153 -0
- package/src/adapters/cursor/native-exec-network.ts +43 -0
- package/src/adapters/cursor/native-exec-shell.ts +547 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +663 -0
- package/src/adapters/cursor/protobuf-events.ts +1381 -0
- package/src/adapters/cursor/protobuf-request.ts +1032 -0
- package/src/adapters/cursor/request-builder.ts +461 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +735 -0
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +79 -0
- package/src/adapters/cursor/types.ts +79 -0
- package/src/adapters/cursor.ts +322 -0
- package/src/adapters/google-antigravity-hosts.ts +48 -0
- package/src/adapters/google-antigravity-replay.ts +827 -0
- package/src/adapters/google-antigravity-tools.ts +105 -0
- package/src/adapters/google-antigravity-wire.ts +141 -0
- package/src/adapters/google-errors.ts +92 -0
- package/src/adapters/google-http.ts +460 -0
- package/src/adapters/google-tool-schema.ts +238 -0
- package/src/adapters/google-truncation.ts +24 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +1377 -0
- package/src/adapters/identity.ts +77 -0
- package/src/adapters/image.ts +23 -0
- package/src/adapters/kiro-constants.ts +16 -0
- package/src/adapters/kiro-errors.ts +208 -0
- package/src/adapters/kiro-events.ts +197 -0
- package/src/adapters/kiro-images.ts +129 -0
- package/src/adapters/kiro-retry.ts +312 -0
- package/src/adapters/kiro-thinking.ts +112 -0
- package/src/adapters/kiro-tool-fallback.ts +36 -0
- package/src/adapters/kiro-tools.ts +224 -0
- package/src/adapters/kiro-truncation.ts +33 -0
- package/src/adapters/kiro-wire.ts +129 -0
- package/src/adapters/kiro.ts +1936 -0
- package/src/adapters/mimo-free.ts +280 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1980 -0
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1911 -0
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +154 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +1986 -0
- package/src/chat/inbound.ts +319 -0
- package/src/chat/outbound.ts +821 -0
- package/src/claude/agents-inject.ts +266 -0
- package/src/claude/alias.ts +149 -0
- package/src/claude/auth-detect.ts +229 -0
- package/src/claude/auth-mode-migration.ts +32 -0
- package/src/claude/auth-mode.ts +62 -0
- package/src/claude/context-windows.ts +205 -0
- package/src/claude/desktop-3p-guard.ts +35 -0
- package/src/claude/desktop-3p-paths.ts +84 -0
- package/src/claude/desktop-3p.ts +615 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +107 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +578 -0
- package/src/claude/model-info.ts +174 -0
- package/src/claude/outbound.ts +926 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +302 -0
- package/src/cli/account-auth.ts +250 -0
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +737 -0
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +299 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +290 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +213 -0
- package/src/cli/claude.ts +355 -0
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +47 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +127 -0
- package/src/cli/config-command.ts +209 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/dispatch.ts +585 -0
- package/src/cli/doctor.ts +1202 -0
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +213 -0
- package/src/cli/help.ts +101 -0
- package/src/cli/index.ts +973 -0
- package/src/cli/init.ts +211 -0
- package/src/cli/integrations.ts +260 -0
- package/src/cli/interactive-confirm.ts +133 -0
- 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 +245 -0
- package/src/cli/models.ts +422 -0
- package/src/cli/observe.ts +206 -0
- package/src/cli/opencode.ts +588 -0
- package/src/cli/provider-replit.ts +232 -0
- package/src/cli/provider-runtime.ts +179 -0
- package/src/cli/provider.ts +492 -0
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +422 -0
- package/src/cli/replit-gateway-key-input.ts +138 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +328 -0
- package/src/cli/star-prompt.ts +211 -0
- package/src/cli/status-oauth.ts +78 -0
- package/src/cli/status.ts +328 -0
- package/src/cli/system-command.ts +112 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +199 -0
- package/src/cli/v2.ts +268 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +1704 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +47 -0
- package/src/codex/account-lifecycle.ts +172 -0
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +195 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-runtime-state.ts +31 -0
- package/src/codex/account-store.ts +544 -0
- package/src/codex/account-usability.ts +43 -0
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/agent-roles-sync.ts +225 -0
- package/src/codex/agent-roles.ts +238 -0
- package/src/codex/app-server-processes.ts +1143 -0
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +2147 -0
- package/src/codex/auth-collision.ts +109 -0
- package/src/codex/auth-context.ts +665 -0
- package/src/codex/autostart-health.ts +156 -0
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +436 -0
- package/src/codex/catalog/bundled.ts +549 -0
- package/src/codex/catalog/effort.ts +446 -0
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +664 -0
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +650 -0
- package/src/codex/catalog/provider-fetch.ts +2064 -0
- package/src/codex/catalog/sync.ts +1883 -0
- 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 +14 -0
- 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/data/upstream-models.json +830 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +1566 -0
- 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 +108 -0
- package/src/codex/history-provider.ts +979 -0
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1733 -0
- package/src/codex/injected-marker.ts +106 -0
- 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 +225 -0
- 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 +56 -0
- package/src/codex/main-account.ts +68 -0
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +273 -0
- 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 +144 -0
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +295 -0
- package/src/codex/project-config-warnings.ts +425 -0
- 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 +573 -0
- package/src/codex/refresh.ts +62 -0
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +1888 -0
- package/src/codex/runtime.ts +659 -0
- package/src/codex/shim.ts +2170 -0
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +784 -0
- package/src/codex/sync.ts +319 -0
- 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 +298 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +160 -0
- package/src/combos/index.ts +45 -0
- package/src/combos/request.ts +94 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +398 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +4041 -0
- package/src/fork/register.ts +3 -0
- package/src/generated/compatibility-version.json +3116 -0
- package/src/generated/model-metadata.ts +106 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +530 -0
- package/src/grok/inspect.ts +45 -0
- package/src/grok/status.ts +121 -0
- package/src/grok/sync.ts +66 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +149 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +955 -0
- package/src/images/plan.ts +143 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/index.ts +22 -0
- 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/abort.ts +146 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/admission.ts +83 -0
- package/src/lib/app-owned-memory-stores.ts +195 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +346 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +184 -0
- package/src/lib/bun-stream-caps.ts +130 -0
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +364 -0
- package/src/lib/crash-guard.ts +344 -0
- package/src/lib/debug-log-buffer.ts +83 -0
- package/src/lib/debug-settings.ts +108 -0
- package/src/lib/debug.ts +31 -0
- package/src/lib/destination-policy.ts +380 -0
- package/src/lib/errors.ts +406 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -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/open-url.ts +25 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +270 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +168 -0
- package/src/lib/provider-outbound.ts +210 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +521 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +25 -0
- package/src/lib/shadow-call.ts +61 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +364 -0
- package/src/lib/state-store-registrations.ts +119 -0
- package/src/lib/state-store-sweeper.ts +184 -0
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/test-home-guard.ts +90 -0
- package/src/lib/token-estimate.ts +86 -0
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +400 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +392 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-atomic-replace.ts +156 -0
- package/src/lib/windows-elevation.ts +773 -0
- package/src/lib/windows-secret-acl.ts +854 -0
- 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 +403 -0
- 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-routing.ts +594 -0
- package/src/oauth/anthropic.ts +188 -0
- package/src/oauth/antigravity-routing.ts +151 -0
- package/src/oauth/callback-server.ts +300 -0
- package/src/oauth/chatgpt.ts +161 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +252 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +262 -0
- package/src/oauth/health.ts +407 -0
- package/src/oauth/index.ts +1504 -0
- package/src/oauth/key-providers.ts +124 -0
- package/src/oauth/kimi.ts +227 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +621 -0
- package/src/oauth/local-token-detect.ts +130 -0
- package/src/oauth/log.ts +50 -0
- package/src/oauth/login-cli.ts +223 -0
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +728 -0
- package/src/oauth/token-guardian.ts +309 -0
- package/src/oauth/types.ts +62 -0
- package/src/oauth/xai.ts +241 -0
- package/src/providers/alibaba-region-backup.ts +75 -0
- package/src/providers/alibaba-region-migration.ts +156 -0
- package/src/providers/alibaba-region-startup.ts +36 -0
- package/src/providers/antigravity-models.ts +695 -0
- package/src/providers/antigravity-quota.ts +216 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +74 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +82 -0
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +586 -0
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +187 -0
- package/src/providers/github-copilot-transport.ts +56 -0
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +271 -0
- package/src/providers/kiro-models.ts +67 -0
- package/src/providers/label.ts +19 -0
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +449 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +243 -0
- package/src/providers/openai-tier-startup.ts +56 -0
- package/src/providers/openai-tiers.ts +423 -0
- package/src/providers/openai-virtual-models.ts +83 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +185 -0
- package/src/providers/quota.ts +2345 -0
- package/src/providers/registry.ts +2918 -0
- package/src/providers/replit/constants.ts +27 -0
- package/src/providers/replit/derive.ts +85 -0
- package/src/providers/replit/headers.ts +28 -0
- package/src/providers/replit/origin.ts +55 -0
- package/src/providers/replit/pair-install-response.ts +72 -0
- package/src/providers/replit/probe.ts +199 -0
- package/src/providers/replit/setup.ts +350 -0
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +103 -0
- 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 +148 -0
- package/src/reasoning-effort.ts +183 -0
- package/src/responses/compaction.ts +142 -0
- 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 +838 -0
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +165 -0
- package/src/responses/spill-store.ts +459 -0
- package/src/responses/state.ts +1433 -0
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +761 -0
- 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 +53 -0
- package/src/server/auth-cors.ts +751 -0
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +442 -0
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +1030 -0
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +190 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +152 -0
- package/src/server/image-retry.ts +42 -0
- package/src/server/images.ts +568 -0
- package/src/server/index.ts +1813 -0
- package/src/server/lifecycle.ts +498 -0
- package/src/server/live.ts +717 -0
- 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 +1433 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +193 -0
- package/src/server/management/body.ts +41 -0
- package/src/server/management/combo-routes.ts +263 -0
- package/src/server/management/config-routes.ts +835 -0
- package/src/server/management/context.ts +113 -0
- 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 +586 -0
- package/src/server/management/model-routes.ts +560 -0
- 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 +637 -0
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +1033 -0
- package/src/server/management/replit-provider-routes.ts +86 -0
- 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 +385 -0
- package/src/server/management/shared.ts +286 -0
- package/src/server/management/sidebar-routes.ts +106 -0
- 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 +435 -0
- package/src/server/management/system-routes.ts +194 -0
- package/src/server/management/usage-summary-cache.ts +94 -0
- 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 +314 -0
- package/src/server/management-auth.ts +482 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +156 -0
- package/src/server/proxy-liveness.ts +328 -0
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +353 -0
- package/src/server/relay.ts +1209 -0
- package/src/server/request-decompress.ts +239 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1259 -0
- 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 +551 -0
- package/src/server/responses/compact.ts +771 -0
- package/src/server/responses/core.ts +5389 -0
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +331 -0
- package/src/server/responses/fetch-helpers.ts +232 -0
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +78 -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 +251 -0
- package/src/server/responses/upstream-error.ts +53 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-image-gen-repair.ts +132 -0
- package/src/server/responses-item-id-repair.ts +272 -0
- 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 +25 -0
- package/src/server/search.ts +201 -0
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +263 -0
- package/src/server/startup-action-control.ts +315 -0
- package/src/server/startup-health-cache.ts +131 -0
- package/src/server/system-env.ts +484 -0
- package/src/server/windows-tcp-drop.ts +184 -0
- package/src/server/windows-tray-control.ts +41 -0
- package/src/server/ws-bridge.ts +472 -0
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +3575 -0
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/stall-timeout.ts +20 -0
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +3085 -0
- package/src/storage/policy-job.ts +457 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +59 -0
- package/src/storage/policy.ts +527 -0
- package/src/storage/restore-job.ts +299 -0
- package/src/storage/restore-worker.ts +58 -0
- package/src/storage/scanner.ts +238 -0
- package/src/storage/storage-mutation-coordinator.ts +139 -0
- package/src/storage/worker-lifecycle.ts +215 -0
- package/src/tray/assets/opencodex-tray-offline.ico +0 -0
- package/src/tray/assets/opencodex-tray-online.ico +0 -0
- package/src/tray/assets/opencodex-tray-warning.ico +0 -0
- package/src/tray/assets/opencodex-tray.png +0 -0
- package/src/tray/windows-tray.ps1 +364 -0
- package/src/tray/windows.ts +757 -0
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +876 -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 +106 -0
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +415 -0
- package/src/update/job.ts +1887 -0
- package/src/update/notify.ts +263 -0
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/update/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +625 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +416 -0
- package/src/usage/log.ts +1223 -0
- package/src/usage/summary.ts +753 -0
- package/src/usage/totals.ts +14 -0
- 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 +189 -0
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +131 -0
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +681 -0
- 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 +195 -0
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +113 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +331 -0
- package/src/web-search/loop.ts +896 -0
- package/src/web-search/parse.ts +315 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/synthetic-tool.ts +47 -0
- package/src/web-search/xai-executor.ts +219 -0
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, unlinkSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { delimiter, join } from "node:path";
|
|
5
|
+
import { atomicWriteFile, getConfigDir } from "../config";
|
|
6
|
+
import { codexExecInvocation, isSpawnableCodexCandidate } from "./exec-invocation";
|
|
7
|
+
import { redactSecretString, redactUserPath } from "../lib/redact";
|
|
8
|
+
|
|
9
|
+
export type CodexRuntimeSource =
|
|
10
|
+
| "environment"
|
|
11
|
+
| "configured"
|
|
12
|
+
| "shim"
|
|
13
|
+
| "path"
|
|
14
|
+
| "fallback";
|
|
15
|
+
|
|
16
|
+
export type DeepReadonly<T> =
|
|
17
|
+
T extends (...args: never[]) => unknown ? T
|
|
18
|
+
: T extends readonly (infer U)[] ? readonly DeepReadonly<U>[]
|
|
19
|
+
: T extends object ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
|
|
20
|
+
: T;
|
|
21
|
+
|
|
22
|
+
export interface ResolvedCodexRuntime {
|
|
23
|
+
readonly command: string;
|
|
24
|
+
readonly version: string | null;
|
|
25
|
+
readonly source: CodexRuntimeSource;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface RuntimeProbeFailure {
|
|
29
|
+
readonly command: string;
|
|
30
|
+
readonly source: CodexRuntimeSource;
|
|
31
|
+
readonly reason: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface EffortClampDiagnostic {
|
|
35
|
+
readonly runtimePath: string;
|
|
36
|
+
readonly runtimeVersion: string | null;
|
|
37
|
+
readonly removedEfforts: readonly string[];
|
|
38
|
+
readonly affectedModels: readonly string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ResolveCodexRuntimeResult {
|
|
42
|
+
readonly runtime: ResolvedCodexRuntime;
|
|
43
|
+
readonly failures: readonly RuntimeProbeFailure[];
|
|
44
|
+
readonly replacedConfigured?: Readonly<{ from: ResolvedCodexRuntime; reason: string }>;
|
|
45
|
+
readonly newerAvailable?: ResolvedCodexRuntime;
|
|
46
|
+
/** Set when the selected runtime could not be written to codex-runtime.json. */
|
|
47
|
+
readonly persistError?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type RuntimeExecFile = (
|
|
51
|
+
file: string,
|
|
52
|
+
args: string[],
|
|
53
|
+
options: {
|
|
54
|
+
encoding: "utf8";
|
|
55
|
+
stdio: ["ignore", "pipe", "ignore"];
|
|
56
|
+
timeout: number;
|
|
57
|
+
windowsHide: boolean;
|
|
58
|
+
shell?: boolean;
|
|
59
|
+
windowsVerbatimArguments?: boolean;
|
|
60
|
+
env?: NodeJS.ProcessEnv;
|
|
61
|
+
},
|
|
62
|
+
) => string;
|
|
63
|
+
|
|
64
|
+
export interface ResolveCodexRuntimeDeps {
|
|
65
|
+
env?: NodeJS.ProcessEnv;
|
|
66
|
+
platform?: NodeJS.Platform;
|
|
67
|
+
configDir?: string;
|
|
68
|
+
execFileSync?: RuntimeExecFile;
|
|
69
|
+
existsSync?: (path: string) => boolean;
|
|
70
|
+
readFileSync?: (path: string, encoding: "utf8") => string;
|
|
71
|
+
now?: () => number;
|
|
72
|
+
/**
|
|
73
|
+
* When false, stop after the first valid priority candidate (skip PATH-wide
|
|
74
|
+
* newerAvailable discovery). Use for hot UI/status paths.
|
|
75
|
+
*/
|
|
76
|
+
discoverAlternatives?: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface PersistedCodexRuntimeState {
|
|
80
|
+
readonly version: 1;
|
|
81
|
+
readonly command: string;
|
|
82
|
+
readonly source: CodexRuntimeSource;
|
|
83
|
+
readonly selectedVersion?: string | null;
|
|
84
|
+
readonly updatedAt: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const PERSIST_FILE = "codex-runtime.json";
|
|
88
|
+
const CLAMP_PERSIST_FILE = "codex-runtime-clamp.json";
|
|
89
|
+
|
|
90
|
+
function cloneAndDeepFreeze<T>(value: T): DeepReadonly<T> {
|
|
91
|
+
const clone = (current: unknown): unknown => {
|
|
92
|
+
if (Array.isArray(current)) return current.map(clone);
|
|
93
|
+
if (current && typeof current === "object") {
|
|
94
|
+
const out: Record<string, unknown> = {};
|
|
95
|
+
for (const [key, child] of Object.entries(current)) out[key] = clone(child);
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
return current;
|
|
99
|
+
};
|
|
100
|
+
const freeze = (current: unknown): unknown => {
|
|
101
|
+
if (!current || typeof current !== "object" || Object.isFrozen(current)) return current;
|
|
102
|
+
for (const child of Object.values(current)) freeze(child);
|
|
103
|
+
return Object.freeze(current);
|
|
104
|
+
};
|
|
105
|
+
return freeze(clone(value)) as DeepReadonly<T>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function isCodexRuntimeSource(value: unknown): value is CodexRuntimeSource {
|
|
109
|
+
return value === "environment"
|
|
110
|
+
|| value === "configured"
|
|
111
|
+
|| value === "shim"
|
|
112
|
+
|| value === "path"
|
|
113
|
+
|| value === "fallback";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function codexRuntimeStatePath(configDir: string = getConfigDir()): string {
|
|
117
|
+
return join(configDir, PERSIST_FILE);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function codexRuntimeClampStatePath(configDir: string = getConfigDir()): string {
|
|
121
|
+
return join(configDir, CLAMP_PERSIST_FILE);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
interface PersistedClampState extends EffortClampDiagnostic {
|
|
125
|
+
version: 1;
|
|
126
|
+
updatedAt: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
interface LoadedEffortClampDiagnostic {
|
|
130
|
+
runtimePath: string;
|
|
131
|
+
runtimeVersion: string | null;
|
|
132
|
+
removedEfforts: string[];
|
|
133
|
+
affectedModels: string[];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function loadLastEffortClamp(
|
|
137
|
+
deps: ResolveCodexRuntimeDeps = {},
|
|
138
|
+
): LoadedEffortClampDiagnostic | null {
|
|
139
|
+
const configDir = deps.configDir ?? getConfigDir();
|
|
140
|
+
const read = deps.readFileSync ?? ((path, encoding) => readFileSync(path, encoding));
|
|
141
|
+
try {
|
|
142
|
+
const raw = JSON.parse(read(codexRuntimeClampStatePath(configDir), "utf8")) as PersistedClampState;
|
|
143
|
+
if (raw?.version !== 1 || !Array.isArray(raw.removedEfforts)) return null;
|
|
144
|
+
return {
|
|
145
|
+
runtimePath: typeof raw.runtimePath === "string" ? raw.runtimePath : "codex",
|
|
146
|
+
runtimeVersion: typeof raw.runtimeVersion === "string" ? raw.runtimeVersion : null,
|
|
147
|
+
removedEfforts: raw.removedEfforts.filter((item): item is string => typeof item === "string"),
|
|
148
|
+
affectedModels: Array.isArray(raw.affectedModels)
|
|
149
|
+
? raw.affectedModels.filter((item): item is string => typeof item === "string")
|
|
150
|
+
: [],
|
|
151
|
+
};
|
|
152
|
+
} catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function persistEffortClamp(
|
|
158
|
+
diagnostic: EffortClampDiagnostic | null,
|
|
159
|
+
deps: ResolveCodexRuntimeDeps = {},
|
|
160
|
+
): void {
|
|
161
|
+
const configDir = deps.configDir ?? getConfigDir();
|
|
162
|
+
const path = codexRuntimeClampStatePath(configDir);
|
|
163
|
+
if (!diagnostic || diagnostic.removedEfforts.length === 0) {
|
|
164
|
+
try {
|
|
165
|
+
unlinkSync(path);
|
|
166
|
+
} catch {
|
|
167
|
+
/* absent is fine */
|
|
168
|
+
}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const payload: PersistedClampState = {
|
|
172
|
+
version: 1,
|
|
173
|
+
updatedAt: new Date((deps.now ?? Date.now)()).toISOString(),
|
|
174
|
+
runtimePath: diagnostic.runtimePath,
|
|
175
|
+
runtimeVersion: diagnostic.runtimeVersion,
|
|
176
|
+
removedEfforts: diagnostic.removedEfforts,
|
|
177
|
+
affectedModels: diagnostic.affectedModels,
|
|
178
|
+
};
|
|
179
|
+
mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
180
|
+
atomicWriteFile(path, `${JSON.stringify(payload, null, 2)}\n`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function displayCodexRuntimePath(command: string): string {
|
|
184
|
+
if (command === "codex") return "codex";
|
|
185
|
+
return redactUserPath(command);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function parseCodexVersionOutput(raw: string): string | null {
|
|
189
|
+
const text = String(raw || "").trim();
|
|
190
|
+
if (!text) return null;
|
|
191
|
+
const match = text.match(/\b(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\b/);
|
|
192
|
+
return match?.[1] ?? null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Compare dotted Codex versions. Returns negative if a < b. */
|
|
196
|
+
export function compareCodexVersions(a: string | null, b: string | null): number {
|
|
197
|
+
if (!a && !b) return 0;
|
|
198
|
+
if (!a) return -1;
|
|
199
|
+
if (!b) return 1;
|
|
200
|
+
const parse = (value: string) => {
|
|
201
|
+
const dash = value.indexOf("-");
|
|
202
|
+
const core = dash < 0 ? value : value.slice(0, dash);
|
|
203
|
+
const pre = dash < 0 ? "" : value.slice(dash + 1);
|
|
204
|
+
const parts = core.split(".").map(part => Number.parseInt(part, 10) || 0);
|
|
205
|
+
// SemVer prerelease identifiers are '.'-separated; keep hyphenated ids intact.
|
|
206
|
+
const preParts = pre
|
|
207
|
+
? pre.split(".").map(part => (/^\d+$/.test(part) ? Number.parseInt(part, 10) : part))
|
|
208
|
+
: [];
|
|
209
|
+
return { parts, preParts };
|
|
210
|
+
};
|
|
211
|
+
const left = parse(a);
|
|
212
|
+
const right = parse(b);
|
|
213
|
+
const len = Math.max(left.parts.length, right.parts.length);
|
|
214
|
+
for (let i = 0; i < len; i += 1) {
|
|
215
|
+
const diff = (left.parts[i] ?? 0) - (right.parts[i] ?? 0);
|
|
216
|
+
if (diff !== 0) return diff;
|
|
217
|
+
}
|
|
218
|
+
if (left.preParts.length === 0 && right.preParts.length > 0) return 1;
|
|
219
|
+
if (left.preParts.length > 0 && right.preParts.length === 0) return -1;
|
|
220
|
+
const preLen = Math.max(left.preParts.length, right.preParts.length);
|
|
221
|
+
for (let i = 0; i < preLen; i += 1) {
|
|
222
|
+
const lp = left.preParts[i];
|
|
223
|
+
const rp = right.preParts[i];
|
|
224
|
+
if (lp === undefined) return -1;
|
|
225
|
+
if (rp === undefined) return 1;
|
|
226
|
+
if (typeof lp === "number" && typeof rp === "number") {
|
|
227
|
+
if (lp !== rp) return lp - rp;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (typeof lp === "number") return -1; // numeric < non-numeric (SemVer)
|
|
231
|
+
if (typeof rp === "number") return 1;
|
|
232
|
+
if (lp < rp) return -1;
|
|
233
|
+
if (lp > rp) return 1;
|
|
234
|
+
}
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Parse already-observed runtime-selection bytes without consulting the filesystem. */
|
|
239
|
+
export function parsePersistedCodexRuntime(
|
|
240
|
+
bytes: string | Uint8Array,
|
|
241
|
+
): DeepReadonly<PersistedCodexRuntimeState> | null {
|
|
242
|
+
try {
|
|
243
|
+
const text = typeof bytes === "string" ? bytes : Buffer.from(bytes).toString("utf8");
|
|
244
|
+
const raw = JSON.parse(text) as Partial<PersistedCodexRuntimeState>;
|
|
245
|
+
if (raw.version !== 1 || typeof raw.command !== "string" || !raw.command.trim()) return null;
|
|
246
|
+
if (!isCodexRuntimeSource(raw.source) || typeof raw.updatedAt !== "string") return null;
|
|
247
|
+
if (raw.selectedVersion !== undefined
|
|
248
|
+
&& raw.selectedVersion !== null
|
|
249
|
+
&& typeof raw.selectedVersion !== "string") return null;
|
|
250
|
+
return cloneAndDeepFreeze(raw as PersistedCodexRuntimeState);
|
|
251
|
+
} catch {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function loadPersistedCodexRuntime(
|
|
257
|
+
deps: ResolveCodexRuntimeDeps = {},
|
|
258
|
+
): DeepReadonly<PersistedCodexRuntimeState> | null {
|
|
259
|
+
const configDir = deps.configDir ?? getConfigDir();
|
|
260
|
+
const read = deps.readFileSync ?? ((path, encoding) => readFileSync(path, encoding));
|
|
261
|
+
try {
|
|
262
|
+
return parsePersistedCodexRuntime(read(codexRuntimeStatePath(configDir), "utf8"));
|
|
263
|
+
} catch {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export function persistCodexRuntime(
|
|
269
|
+
runtime: ResolvedCodexRuntime,
|
|
270
|
+
deps: ResolveCodexRuntimeDeps = {},
|
|
271
|
+
): void {
|
|
272
|
+
const configDir = deps.configDir ?? getConfigDir();
|
|
273
|
+
mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
274
|
+
const payload: PersistedCodexRuntimeState = {
|
|
275
|
+
version: 1,
|
|
276
|
+
command: runtime.command,
|
|
277
|
+
source: runtime.source,
|
|
278
|
+
selectedVersion: runtime.version,
|
|
279
|
+
updatedAt: new Date((deps.now ?? Date.now)()).toISOString(),
|
|
280
|
+
};
|
|
281
|
+
// Invalidate process authority before the persisted replacement is visible.
|
|
282
|
+
clearCodexRuntimeResolveCache();
|
|
283
|
+
atomicWriteFile(codexRuntimeStatePath(configDir), `${JSON.stringify(payload, null, 2)}\n`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function probeVersion(
|
|
287
|
+
command: string,
|
|
288
|
+
deps: ResolveCodexRuntimeDeps,
|
|
289
|
+
): { ok: true; version: string } | { ok: false; reason: string } {
|
|
290
|
+
const platform = deps.platform ?? process.platform;
|
|
291
|
+
if (command.includes("/") || command.includes("\\") || /^[A-Za-z]:/.test(command)) {
|
|
292
|
+
const exists = deps.existsSync ?? existsSync;
|
|
293
|
+
if (!exists(command)) return { ok: false, reason: "path does not exist" };
|
|
294
|
+
if (!isSpawnableCodexCandidate(command, platform)) {
|
|
295
|
+
return { ok: false, reason: "not a spawnable Codex launcher on this platform" };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const execFile = deps.execFileSync ?? (execFileSync as unknown as RuntimeExecFile);
|
|
299
|
+
// Sandbox the probe's CODEX_HOME: a real Codex CLI creates state (tmp/, logs) under
|
|
300
|
+
// CODEX_HOME even for `--version`, and the probe inherits the caller's env — so a
|
|
301
|
+
// read-only `ocx status` would dirty the user's CODEX_HOME. Redirect it to a
|
|
302
|
+
// throwaway dir; if the sandbox cannot be created, skip the probe rather than
|
|
303
|
+
// probe with the inherited env (keeps probeVersion total: it never throws).
|
|
304
|
+
let probeHome: string | undefined;
|
|
305
|
+
try {
|
|
306
|
+
probeHome = mkdtempSync(join(tmpdir(), "ocx-codex-probe-"));
|
|
307
|
+
const invocation = codexExecInvocation(command, ["--version"], platform, {
|
|
308
|
+
env: deps.env,
|
|
309
|
+
exists: deps.existsSync,
|
|
310
|
+
});
|
|
311
|
+
const output = execFile(invocation.file, invocation.args, {
|
|
312
|
+
encoding: "utf8",
|
|
313
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
314
|
+
timeout: 8_000,
|
|
315
|
+
windowsHide: true,
|
|
316
|
+
env: { ...(deps.env ?? process.env), CODEX_HOME: probeHome },
|
|
317
|
+
...invocation.options,
|
|
318
|
+
});
|
|
319
|
+
const version = parseCodexVersionOutput(output);
|
|
320
|
+
if (!version) {
|
|
321
|
+
return { ok: false, reason: "unrecognized --version output" };
|
|
322
|
+
}
|
|
323
|
+
return { ok: true, version };
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (!probeHome) return { ok: false, reason: "probe sandbox unavailable" };
|
|
326
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
327
|
+
const redacted = redactUserPath(redactSecretString(message)).slice(0, 160);
|
|
328
|
+
return { ok: false, reason: `failed --version (${redacted})` };
|
|
329
|
+
} finally {
|
|
330
|
+
if (probeHome) {
|
|
331
|
+
// Nested catch: a transient Windows EBUSY must never mask the probe result.
|
|
332
|
+
try { rmSync(probeHome, { recursive: true, force: true }); } catch { /* best effort */ }
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function shimCandidates(deps: ResolveCodexRuntimeDeps): string[] {
|
|
338
|
+
const configDir = deps.configDir ?? getConfigDir();
|
|
339
|
+
const read = deps.readFileSync ?? ((path, encoding) => readFileSync(path, encoding));
|
|
340
|
+
const platform = deps.platform ?? process.platform;
|
|
341
|
+
try {
|
|
342
|
+
const state = JSON.parse(read(join(configDir, "codex-shim.json"), "utf8")) as {
|
|
343
|
+
wrapperPath?: unknown;
|
|
344
|
+
originalPath?: unknown;
|
|
345
|
+
backupPath?: unknown;
|
|
346
|
+
wrappers?: Array<{ wrapperPath?: unknown; originalPath?: unknown; backupPath?: unknown }>;
|
|
347
|
+
};
|
|
348
|
+
const files = Array.isArray(state.wrappers) && state.wrappers.length > 0 ? state.wrappers : [state];
|
|
349
|
+
const out: string[] = [];
|
|
350
|
+
for (const file of files) {
|
|
351
|
+
for (const value of [file.backupPath, file.originalPath, file.wrapperPath]) {
|
|
352
|
+
if (typeof value !== "string" || value.length === 0) continue;
|
|
353
|
+
if (!isSpawnableCodexCandidate(value, platform)) continue;
|
|
354
|
+
out.push(value);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return [...new Set(out)];
|
|
358
|
+
} catch {
|
|
359
|
+
return [];
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function pathCandidates(deps: ResolveCodexRuntimeDeps): string[] {
|
|
364
|
+
const env = deps.env ?? process.env;
|
|
365
|
+
const platform = deps.platform ?? process.platform;
|
|
366
|
+
const out: string[] = [];
|
|
367
|
+
for (const dir of (env.PATH ?? "").split(delimiter).filter(Boolean)) {
|
|
368
|
+
if (platform === "win32") {
|
|
369
|
+
out.push(join(dir, "codex.exe"), join(dir, "codex.cmd"));
|
|
370
|
+
} else {
|
|
371
|
+
out.push(join(dir, "codex"));
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return [...new Set(out)];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
interface RankedCandidate {
|
|
378
|
+
command: string;
|
|
379
|
+
source: CodexRuntimeSource;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function tryCandidate(
|
|
383
|
+
candidate: RankedCandidate,
|
|
384
|
+
failures: RuntimeProbeFailure[],
|
|
385
|
+
deps: ResolveCodexRuntimeDeps,
|
|
386
|
+
): ResolvedCodexRuntime | null {
|
|
387
|
+
const probed = probeVersion(candidate.command, deps);
|
|
388
|
+
if (!probed.ok) {
|
|
389
|
+
failures.push({ command: candidate.command, source: candidate.source, reason: probed.reason });
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
return {
|
|
393
|
+
command: candidate.command,
|
|
394
|
+
version: probed.version,
|
|
395
|
+
source: candidate.source,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function sameRuntimeCommand(a: string, b: string): boolean {
|
|
400
|
+
return a.trim().toLowerCase() === b.trim().toLowerCase();
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/** True when a persisted clamp diagnostic still applies to the currently selected runtime. */
|
|
404
|
+
export function effortClampAppliesToRuntime(
|
|
405
|
+
diagnostic: EffortClampDiagnostic | null | undefined,
|
|
406
|
+
runtime: Pick<ResolvedCodexRuntime, "command" | "version">,
|
|
407
|
+
): boolean {
|
|
408
|
+
if (!diagnostic || diagnostic.removedEfforts.length === 0) return false;
|
|
409
|
+
if (sameRuntimeCommand(diagnostic.runtimePath, runtime.command)) return true;
|
|
410
|
+
return Boolean(
|
|
411
|
+
diagnostic.runtimeVersion
|
|
412
|
+
&& runtime.version
|
|
413
|
+
&& diagnostic.runtimeVersion === runtime.version,
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const RESOLVE_CACHE_MS = 15_000;
|
|
418
|
+
interface ResolveCacheMemo {
|
|
419
|
+
readonly key: string;
|
|
420
|
+
readonly at: number;
|
|
421
|
+
readonly epoch: number;
|
|
422
|
+
readonly valueIdentity: string;
|
|
423
|
+
readonly value: DeepReadonly<ResolveCodexRuntimeResult>;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export type CodexRuntimeProcessCachePeek =
|
|
427
|
+
| Readonly<{
|
|
428
|
+
kind: "available";
|
|
429
|
+
epoch: number;
|
|
430
|
+
valueIdentity: string;
|
|
431
|
+
value: DeepReadonly<ResolveCodexRuntimeResult>;
|
|
432
|
+
}>
|
|
433
|
+
| Readonly<{ kind: "unavailable"; epoch: number }>;
|
|
434
|
+
|
|
435
|
+
let resolveCacheEpoch = 0;
|
|
436
|
+
let resolveCache: ResolveCacheMemo | null = null;
|
|
437
|
+
|
|
438
|
+
function publishResolveCache(key: string, at: number, value: ResolveCodexRuntimeResult): void {
|
|
439
|
+
const epoch = ++resolveCacheEpoch;
|
|
440
|
+
resolveCache = {
|
|
441
|
+
key,
|
|
442
|
+
at,
|
|
443
|
+
epoch,
|
|
444
|
+
valueIdentity: `runtime:${epoch}`,
|
|
445
|
+
value: cloneAndDeepFreeze(value),
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function clearResolveCache(): void {
|
|
450
|
+
resolveCacheEpoch += 1;
|
|
451
|
+
resolveCache = null;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** Clear process-local runtime authority without resolving a replacement. */
|
|
455
|
+
export function clearCodexRuntimeResolveCache(): void {
|
|
456
|
+
clearResolveCache();
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/** Observe only an unexpired successful process memo; never resolves or probes. */
|
|
460
|
+
export function peekCodexRuntimeProcessCache(): CodexRuntimeProcessCachePeek {
|
|
461
|
+
const memo = resolveCache;
|
|
462
|
+
if (!memo || Date.now() - memo.at >= RESOLVE_CACHE_MS) {
|
|
463
|
+
return Object.freeze({ kind: "unavailable" as const, epoch: resolveCacheEpoch });
|
|
464
|
+
}
|
|
465
|
+
return Object.freeze({
|
|
466
|
+
kind: "available" as const,
|
|
467
|
+
epoch: memo.epoch,
|
|
468
|
+
valueIdentity: memo.valueIdentity,
|
|
469
|
+
value: cloneAndDeepFreeze(memo.value),
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function persistedRuntimeCacheStamp(deps: ResolveCodexRuntimeDeps): string {
|
|
474
|
+
// Include on-disk selection so doctor --fix in another process busts this memo.
|
|
475
|
+
const configDir = deps.configDir ?? getConfigDir();
|
|
476
|
+
const read = deps.readFileSync ?? ((path, encoding) => readFileSync(path, encoding));
|
|
477
|
+
try {
|
|
478
|
+
const raw = parsePersistedCodexRuntime(read(codexRuntimeStatePath(configDir), "utf8"));
|
|
479
|
+
if (!raw) return "";
|
|
480
|
+
return `${raw.command}|${raw.selectedVersion ?? ""}|${raw.updatedAt ?? ""}`;
|
|
481
|
+
} catch {
|
|
482
|
+
return "";
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function resolveCacheKey(deps: ResolveCodexRuntimeDeps): string | null {
|
|
487
|
+
// Only memoize uninjected process-env resolves (settings/status hot paths).
|
|
488
|
+
if (deps.execFileSync || deps.existsSync || deps.readFileSync || deps.configDir || deps.now) {
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
const env = deps.env ?? process.env;
|
|
492
|
+
return JSON.stringify({
|
|
493
|
+
cli: env.CODEX_CLI_PATH ?? "",
|
|
494
|
+
path: env.PATH ?? "",
|
|
495
|
+
platform: deps.platform ?? process.platform,
|
|
496
|
+
discover: deps.discoverAlternatives !== false,
|
|
497
|
+
home: process.env.OPENCODEX_HOME ?? "",
|
|
498
|
+
persisted: persistedRuntimeCacheStamp(deps),
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Resolve the single Codex runtime OpenCodex should use for sync, clamp, and probes.
|
|
504
|
+
*/
|
|
505
|
+
export function resolveCodexRuntime(deps: ResolveCodexRuntimeDeps = {}): ResolveCodexRuntimeResult {
|
|
506
|
+
const cacheKey = resolveCacheKey(deps);
|
|
507
|
+
if (cacheKey && resolveCache && resolveCache.key === cacheKey && Date.now() - resolveCache.at < RESOLVE_CACHE_MS) {
|
|
508
|
+
return cloneAndDeepFreeze(resolveCache.value);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const result = resolveCodexRuntimeUncached(deps);
|
|
512
|
+
if (cacheKey) {
|
|
513
|
+
publishResolveCache(cacheKey, Date.now(), result);
|
|
514
|
+
return cloneAndDeepFreeze(resolveCache!.value);
|
|
515
|
+
}
|
|
516
|
+
return cloneAndDeepFreeze(result);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/** Test-only: drop the short-lived process resolve cache. */
|
|
520
|
+
export function resetCodexRuntimeResolveCacheForTests(): void {
|
|
521
|
+
clearCodexRuntimeResolveCache();
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/** Test-only owner mutation seam; input is cloned and frozen before publication. */
|
|
525
|
+
export function setCodexRuntimeResolveCacheForTests(
|
|
526
|
+
value: ResolveCodexRuntimeResult,
|
|
527
|
+
deps: ResolveCodexRuntimeDeps = {},
|
|
528
|
+
): void {
|
|
529
|
+
const key = resolveCacheKey(deps);
|
|
530
|
+
if (!key) throw new TypeError("Injected runtime dependencies cannot populate the process memo.");
|
|
531
|
+
publishResolveCache(key, Date.now(), value);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function resolveCodexRuntimeUncached(deps: ResolveCodexRuntimeDeps = {}): ResolveCodexRuntimeResult {
|
|
535
|
+
const env = deps.env ?? process.env;
|
|
536
|
+
const failures: RuntimeProbeFailure[] = [];
|
|
537
|
+
const ordered: RankedCandidate[] = [];
|
|
538
|
+
|
|
539
|
+
const envPath = env.CODEX_CLI_PATH?.trim();
|
|
540
|
+
if (envPath) ordered.push({ command: envPath, source: "environment" });
|
|
541
|
+
|
|
542
|
+
const persisted = loadPersistedCodexRuntime(deps);
|
|
543
|
+
if (persisted?.command) {
|
|
544
|
+
ordered.push({ command: persisted.command, source: "configured" });
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
for (const command of shimCandidates(deps)) {
|
|
548
|
+
ordered.push({ command, source: "shim" });
|
|
549
|
+
}
|
|
550
|
+
for (const command of pathCandidates(deps)) {
|
|
551
|
+
ordered.push({ command, source: "path" });
|
|
552
|
+
}
|
|
553
|
+
ordered.push({ command: "codex", source: "fallback" });
|
|
554
|
+
|
|
555
|
+
const seen = new Set<string>();
|
|
556
|
+
const valid: ResolvedCodexRuntime[] = [];
|
|
557
|
+
for (const candidate of ordered) {
|
|
558
|
+
const key = candidate.command.toLowerCase();
|
|
559
|
+
if (seen.has(key)) continue;
|
|
560
|
+
seen.add(key);
|
|
561
|
+
const resolved = tryCandidate(candidate, failures, deps);
|
|
562
|
+
if (!resolved) continue;
|
|
563
|
+
valid.push(resolved);
|
|
564
|
+
if (deps.discoverAlternatives === false) break;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (valid.length === 0) {
|
|
568
|
+
return {
|
|
569
|
+
runtime: { command: "codex", version: null, source: "fallback" },
|
|
570
|
+
failures,
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Prefer first valid in priority order (environment → configured → shim → path → fallback).
|
|
575
|
+
let selected = valid[0]!;
|
|
576
|
+
let replacedConfigured: ResolveCodexRuntimeResult["replacedConfigured"];
|
|
577
|
+
|
|
578
|
+
const envValid = envPath
|
|
579
|
+
? valid.find(item => sameRuntimeCommand(item.command, envPath) && item.source === "environment")
|
|
580
|
+
: undefined;
|
|
581
|
+
if (envValid) selected = envValid;
|
|
582
|
+
|
|
583
|
+
if (persisted?.command) {
|
|
584
|
+
const configuredStillValid = valid.some(item => sameRuntimeCommand(item.command, persisted.command));
|
|
585
|
+
// Only emit replacement diagnostics when we actually searched alternatives or
|
|
586
|
+
// the preferred configured runtime was probed and rejected.
|
|
587
|
+
const configuredRejected = failures.some(item => sameRuntimeCommand(item.command, persisted.command));
|
|
588
|
+
if (!configuredStillValid && (configuredRejected || deps.discoverAlternatives !== false) && !envValid) {
|
|
589
|
+
replacedConfigured = {
|
|
590
|
+
from: {
|
|
591
|
+
command: persisted.command,
|
|
592
|
+
version: persisted.selectedVersion ?? null,
|
|
593
|
+
source: "configured",
|
|
594
|
+
},
|
|
595
|
+
reason: failures.find(item => sameRuntimeCommand(item.command, persisted.command))?.reason
|
|
596
|
+
?? "configured runtime is no longer valid",
|
|
597
|
+
};
|
|
598
|
+
// Keep priority-selected replacement (already in `selected`).
|
|
599
|
+
} else if (!envValid && configuredStillValid) {
|
|
600
|
+
// Stick to configured even when a later PATH entry is also valid.
|
|
601
|
+
selected = valid.find(item => sameRuntimeCommand(item.command, persisted.command)) ?? selected;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const newerAvailable = valid
|
|
606
|
+
.filter(item => !sameRuntimeCommand(item.command, selected.command))
|
|
607
|
+
.sort((a, b) => compareCodexVersions(b.version, a.version))[0];
|
|
608
|
+
const newer =
|
|
609
|
+
newerAvailable && compareCodexVersions(newerAvailable.version, selected.version) > 0
|
|
610
|
+
? newerAvailable
|
|
611
|
+
: undefined;
|
|
612
|
+
|
|
613
|
+
return {
|
|
614
|
+
runtime: selected,
|
|
615
|
+
failures,
|
|
616
|
+
replacedConfigured,
|
|
617
|
+
newerAvailable: newer,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/** Resolve and persist a successful selection (unless source is ephemeral fallback-only with no path). */
|
|
622
|
+
export function resolveAndPersistCodexRuntime(
|
|
623
|
+
deps: ResolveCodexRuntimeDeps = {},
|
|
624
|
+
): ResolveCodexRuntimeResult {
|
|
625
|
+
const result = resolveCodexRuntime(deps);
|
|
626
|
+
// Only WRITE when the selection actually changed. persistCodexRuntime() clears the
|
|
627
|
+
// in-process resolve memo and persistedRuntimeCacheStamp() folds `updatedAt` into the
|
|
628
|
+
// cache key, so an unconditional rewrite made every caller re-run the ~1s
|
|
629
|
+
// `codex --version` probe even when the resolved runtime was byte-identical.
|
|
630
|
+
const persistedRuntime = loadPersistedCodexRuntime(deps);
|
|
631
|
+
const selectionUnchanged = persistedRuntime !== null
|
|
632
|
+
&& persistedRuntime.command === result.runtime.command
|
|
633
|
+
&& persistedRuntime.source === result.runtime.source
|
|
634
|
+
&& (persistedRuntime.selectedVersion ?? null) === (result.runtime.version ?? null);
|
|
635
|
+
if (result.runtime.command && result.runtime.source !== "fallback" && !selectionUnchanged) {
|
|
636
|
+
try {
|
|
637
|
+
persistCodexRuntime(result.runtime, deps);
|
|
638
|
+
} catch (error) {
|
|
639
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
640
|
+
const persistError = redactUserPath(redactSecretString(message)).slice(0, 200);
|
|
641
|
+
console.warn(`[opencodex] Failed to persist Codex runtime selection: ${persistError}`);
|
|
642
|
+
return cloneAndDeepFreeze({ ...result, persistError });
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
return result;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
export function formatRuntimeLogLine(runtime: ResolvedCodexRuntime): string {
|
|
649
|
+
const path = displayCodexRuntimePath(runtime.command);
|
|
650
|
+
return `[opencodex] Codex runtime: ${path} (version=${runtime.version ?? "unknown"}, source=${runtime.source})`;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
export function formatClampLogLines(diagnostic: EffortClampDiagnostic): string[] {
|
|
654
|
+
const efforts = diagnostic.removedEfforts.join(", ");
|
|
655
|
+
return [
|
|
656
|
+
`[opencodex] Removed unsupported reasoning efforts: ${efforts}`,
|
|
657
|
+
"[opencodex] Run ocx doctor for diagnosis and recovery.",
|
|
658
|
+
];
|
|
659
|
+
}
|