@iislee/opencodex 2.11.0 → 2.35.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 +117 -22
- package/bin/ocx.mjs +245 -88
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-Be1sDpWw.css +1 -0
- package/gui/dist/assets/index-D4OKgUV4.js +114 -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 +21 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +475 -62
- package/src/adapters/base.ts +82 -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 +637 -0
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/catalog.ts +541 -0
- package/src/adapters/cursor/checkpoint-store.ts +308 -0
- package/src/adapters/cursor/cursor-errors.ts +144 -6
- package/src/adapters/cursor/discovery.ts +122 -14
- package/src/adapters/cursor/effort-map.ts +106 -4
- package/src/adapters/cursor/envelope-echo.ts +290 -0
- 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 +180 -59
- package/src/adapters/cursor/live-transport.ts +623 -170
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-desktop.ts +23 -0
- 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 +5 -3
- package/src/adapters/cursor/native-exec.ts +121 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +447 -75
- package/src/adapters/cursor/request-builder.ts +271 -35
- package/src/adapters/cursor/tool-definitions.ts +252 -12
- package/src/adapters/cursor/tool-result-normalize.ts +115 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +48 -1
- package/src/adapters/cursor.ts +336 -39
- package/src/adapters/exec-tool-result-normalize.ts +99 -0
- package/src/adapters/google-antigravity-replay.ts +713 -41
- package/src/adapters/google-antigravity-wire.ts +48 -10
- package/src/adapters/google-errors.ts +44 -12
- 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 +742 -86
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +27 -0
- 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 +65 -17
- package/src/adapters/kiro.ts +270 -73
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1377 -344
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1164 -64
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +105 -21
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/adapters/xai-web-search.ts +186 -0
- package/src/bridge.ts +512 -92
- package/src/chat/inbound.ts +57 -20
- package/src/chat/outbound.ts +97 -33
- package/src/claude/agents-inject.ts +40 -10
- package/src/claude/context-windows.ts +37 -14
- 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 +88 -21
- package/src/cli/access.ts +46 -3
- package/src/cli/account-api.ts +150 -19
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +648 -28
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +97 -19
- package/src/cli/agent.ts +53 -2
- package/src/cli/alias.ts +66 -0
- package/src/cli/capabilities-command.ts +94 -0
- package/src/cli/capabilities.ts +496 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +60 -15
- package/src/cli/claude.ts +129 -35
- 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 +821 -0
- package/src/cli/doctor.ts +440 -56
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +34 -274
- package/src/cli/index.ts +417 -528
- package/src/cli/init.ts +5 -17
- package/src/cli/inspect.ts +230 -0
- 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 +130 -2
- package/src/cli/models.ts +118 -16
- package/src/cli/observe.ts +123 -11
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +34 -3
- package/src/cli/provider.ts +25 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +476 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +57 -10
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +51 -4
- package/src/cli/storage.ts +234 -0
- package/src/cli/system-command.ts +16 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/usage-report.ts +184 -0
- package/src/cli/v2.ts +137 -18
- package/src/cli/version-skew.ts +46 -0
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1442 -23
- package/src/clients/effective-status.ts +30 -2
- package/src/clients/probes/cline.ts +81 -0
- package/src/codex/account-label.ts +35 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +84 -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 +570 -107
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +893 -246
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +348 -32
- package/src/codex/autostart-health.ts +24 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +86 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +138 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +555 -45
- package/src/codex/catalog/native-models.ts +75 -0
- package/src/codex/catalog/parsing.ts +269 -30
- package/src/codex/catalog/provider-fetch.ts +1626 -144
- package/src/codex/catalog/sync.ts +1576 -187
- 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 +386 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +676 -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/desktop-app-restart.ts +355 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +436 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +30 -24
- package/src/codex/history-provider.ts +1016 -235
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +223 -0
- package/src/codex/inject-coordination.ts +373 -0
- package/src/codex/inject.ts +1114 -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 +81 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +524 -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 +360 -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 +622 -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 +675 -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 +1313 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +264 -21
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +514 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1065 -31
- package/src/codex/subagent-model-fallback.ts +437 -43
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +720 -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 +47 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +91 -9
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +121 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +309 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config/provider-validation.ts +177 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +1713 -709
- package/src/generated/compatibility-version.json +3324 -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 +157 -33
- package/src/images/plan.ts +24 -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-policy.ts +160 -0
- package/src/integrations/ownership.ts +155 -0
- package/src/integrations/registry.ts +166 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +433 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +715 -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/admin-secrets.ts +24 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +167 -11
- 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 +26 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +80 -5
- 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/package-tree-integrity.ts +101 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +6 -2
- 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/service-secrets.ts +15 -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 +253 -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 +30 -4
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/cline.ts +203 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +462 -71
- package/src/oauth/key-providers.ts +25 -0
- package/src/oauth/kimi.ts +25 -3
- package/src/oauth/kiro.ts +95 -6
- package/src/oauth/local-token-detect.ts +13 -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/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +133 -26
- package/src/oauth/token-guardian.ts +9 -3
- package/src/oauth/types.ts +15 -0
- 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/auto-compact-budget.ts +65 -0
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +176 -0
- package/src/providers/context-cap.ts +26 -8
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +281 -6
- package/src/providers/fastwire.ts +507 -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 +35 -2
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/new-model-policy.ts +146 -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 +30 -0
- package/src/providers/quota.ts +1379 -40
- package/src/providers/registry.ts +1545 -112
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +94 -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 +32 -4
- package/src/reasoning-effort.ts +68 -3
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +384 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +435 -0
- package/src/responses/parser.ts +225 -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 +504 -0
- package/src/responses/schema.ts +12 -2
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +659 -31
- package/src/responses/thought-signature-replay.ts +364 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/responses/turn-termination.ts +107 -0
- package/src/router.ts +405 -31
- package/src/routing/analytics.ts +379 -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 +155 -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 +289 -48
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +154 -72
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +445 -0
- package/src/server/claude-messages.ts +160 -44
- 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 +1021 -190
- package/src/server/lifecycle.ts +336 -14
- 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 +433 -116
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +64 -25
- package/src/server/management/config-routes.ts +511 -51
- package/src/server/management/context.ts +89 -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 +127 -52
- package/src/server/management/model-routes.ts +461 -133
- package/src/server/management/model-rows.ts +167 -0
- package/src/server/management/native-integration-routes.ts +770 -0
- package/src/server/management/oauth-account-routes.ts +90 -8
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +836 -159
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/route-registry.ts +332 -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 +289 -33
- 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 +126 -23
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +161 -10
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +221 -54
- package/src/server/relay.ts +479 -87
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log-conversation.ts +51 -0
- package/src/server/request-log.ts +298 -31
- 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/codex-auth-error.ts +55 -0
- package/src/server/responses/collaboration.ts +239 -36
- package/src/server/responses/combo-stream-preflight.ts +178 -0
- package/src/server/responses/compact.ts +444 -72
- package/src/server/responses/core.ts +3579 -436
- package/src/server/responses/empty-completion-guard.ts +333 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +89 -99
- package/src/server/responses/input-admission.ts +187 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +343 -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 +381 -0
- package/src/server/responses-custom-tool-repair.ts +363 -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 +363 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +376 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +319 -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 +53 -40
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1153 -94
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/policy-job.ts +14 -4
- package/src/storage/policy.ts +88 -23
- 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 +911 -0
- package/src/types/provider.ts +614 -0
- package/src/types/request.ts +397 -0
- package/src/types/tools.ts +236 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +107 -1237
- package/src/update/index.ts +37 -23
- package/src/update/job.ts +445 -68
- 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 +266 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +287 -16
- package/src/usage/log.ts +666 -50
- package/src/usage/summary.ts +388 -17
- 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 +27 -16
- 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 +119 -0
- package/src/web-search/executor.ts +21 -6
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +284 -54
- 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
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { OcxConfig } from "../types";
|
|
2
|
+
import { injectClaudeAgentDefs } from "../claude/agents-inject";
|
|
3
|
+
import { fetchClaudeContextWindows } from "./claude";
|
|
4
|
+
import type { ReadinessGate } from "../server/readiness";
|
|
5
|
+
|
|
6
|
+
export interface ClaudeAgentStartupSyncDeps {
|
|
7
|
+
fetchContextWindows?: typeof fetchClaudeContextWindows;
|
|
8
|
+
injectAgentDefs?: typeof injectClaudeAgentDefs;
|
|
9
|
+
warn?: (message: string) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Keep the public readiness gate pending until both startup reconciliations have settled.
|
|
14
|
+
*
|
|
15
|
+
* The Codex sync remains the authority for ready versus failed. Claude roster repair is
|
|
16
|
+
* deliberately best-effort (#2200), but readiness must not become observable between the
|
|
17
|
+
* Codex write and that repair: a service manager could otherwise launch Claude Code against
|
|
18
|
+
* stale `ocx-*.md` files. A small forwarding gate delays only the successful transition;
|
|
19
|
+
* terminal Codex failure is still published immediately.
|
|
20
|
+
*/
|
|
21
|
+
export async function reconcileClientStartupBeforeReady<T>(
|
|
22
|
+
readinessGate: ReadinessGate,
|
|
23
|
+
syncCodex: (deferredGate: ReadinessGate) => Promise<T>,
|
|
24
|
+
syncClaudeRoster: () => Promise<unknown>,
|
|
25
|
+
): Promise<T> {
|
|
26
|
+
let codexReady = false;
|
|
27
|
+
const deferredGate: ReadinessGate = {
|
|
28
|
+
getStatus: () => readinessGate.getStatus(),
|
|
29
|
+
markReady: () => { codexReady = true; },
|
|
30
|
+
markFailed: () => readinessGate.markFailed(),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const result = await syncCodex(deferredGate);
|
|
34
|
+
await syncClaudeRoster();
|
|
35
|
+
if (codexReady) readinessGate.markReady();
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Reconcile the generated Claude Code roster after the proxy listener is live.
|
|
41
|
+
*
|
|
42
|
+
* This belongs to the owning CLI lifecycle rather than `startServer`: the latter is also a
|
|
43
|
+
* library/test primitive and must not mutate a developer's real `~/.claude` directory merely
|
|
44
|
+
* because an in-process test server was created. The live Management API supplies the same bounded
|
|
45
|
+
* context-window map used by `ocx claude`; failure keeps startup available and falls back to an
|
|
46
|
+
* unmarked roster. Disabled integrations skip discovery and prune verified-owned definitions.
|
|
47
|
+
*/
|
|
48
|
+
export async function syncClaudeAgentDefsAtProxyStartup(
|
|
49
|
+
config: OcxConfig,
|
|
50
|
+
port: number,
|
|
51
|
+
deps: ClaudeAgentStartupSyncDeps = {},
|
|
52
|
+
): Promise<string[] | null> {
|
|
53
|
+
const inject = deps.injectAgentDefs ?? injectClaudeAgentDefs;
|
|
54
|
+
const warn = deps.warn ?? (message => console.warn(message));
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
if (config.claudeCode?.enabled === false || config.claudeCode?.injectAgents === false) {
|
|
58
|
+
return inject(config, {});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let windows: Record<string, number> = {};
|
|
62
|
+
try {
|
|
63
|
+
windows = await (deps.fetchContextWindows ?? fetchClaudeContextWindows)(config, port);
|
|
64
|
+
} catch {
|
|
65
|
+
// Startup remains best-effort. The next management mutation or `ocx claude` launch can
|
|
66
|
+
// restore context markers after a transient catalog/Management API failure.
|
|
67
|
+
}
|
|
68
|
+
return inject(config, windows);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
warn(`⚠ Claude agent definitions could not be synced at proxy startup: ${error instanceof Error ? error.message : String(error)}`);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { loadConfig, saveConfigPreservingClaudeCode } from "../config";
|
|
4
|
+
import { setIntegrationEnabled } from "../codex/desired-state";
|
|
4
5
|
import {
|
|
5
6
|
DESKTOP_FAMILIES,
|
|
6
7
|
moveDesktopRoute,
|
|
@@ -10,10 +11,11 @@ import {
|
|
|
10
11
|
type DesktopProfile,
|
|
11
12
|
} from "../claude/desktop-profile";
|
|
12
13
|
import { writeDesktop3pConfig, type Desktop3pConfigMode, parseDesktop3pModeArgs } from "../claude/desktop-3p";
|
|
13
|
-
import { filterCatalogVisibleModels, desktopVisibleNativeSlugs } from "../codex/catalog";
|
|
14
|
+
import { filterCatalogVisibleModels, desktopVisibleNativeSlugs, nativeContextLimits } from "../codex/catalog";
|
|
14
15
|
import { buildClaudeDesktopState, fetchAllModels } from "../server/management-api";
|
|
15
16
|
import { findLiveProxy } from "../server/proxy-liveness";
|
|
16
|
-
import { runtimeRequest } from "./runtime-api";
|
|
17
|
+
import { CliUsageError, runtimeRequest, takeJsonFlag } from "./runtime-api";
|
|
18
|
+
import { OPENAI_CODEX_PROVIDER_ID } from "../providers/openai-tiers";
|
|
17
19
|
|
|
18
20
|
function isFamily(value: string | undefined): value is DesktopFamily {
|
|
19
21
|
return !!value && (DESKTOP_FAMILIES as readonly string[]).includes(value);
|
|
@@ -23,6 +25,7 @@ function printDesktopHelp(): void {
|
|
|
23
25
|
console.log(`Usage:
|
|
24
26
|
ocx claude desktop [apply] [--static|--hybrid|--discovery-only]
|
|
25
27
|
ocx claude desktop show [--json]
|
|
28
|
+
ocx claude desktop status [--json]
|
|
26
29
|
ocx claude desktop move <provider/model> <opus|fable|sonnet|haiku> [--default]
|
|
27
30
|
ocx claude desktop default <family> <provider/model|none>
|
|
28
31
|
ocx claude desktop export <path|->
|
|
@@ -41,7 +44,11 @@ export async function applyProfile(
|
|
|
41
44
|
profile: DesktopProfile,
|
|
42
45
|
mode: Desktop3pConfigMode,
|
|
43
46
|
deps: ApplyProfileDeps = {},
|
|
44
|
-
): Promise<{ ok: boolean; path: string; reason?: string }> {
|
|
47
|
+
): Promise<{ ok: boolean; path: string; reason?: string; warning?: string }> {
|
|
48
|
+
// Explicit apply is an enable action. Persist intent before any Desktop write
|
|
49
|
+
// so a process crash cannot leave a gateway profile that startup immediately removes.
|
|
50
|
+
const desired = setIntegrationEnabled("claude-desktop", true);
|
|
51
|
+
if (!desired.ok) return { ok: false, path: "", reason: desired.message };
|
|
45
52
|
const config = loadConfig();
|
|
46
53
|
const state = await buildClaudeDesktopState(config, profile);
|
|
47
54
|
config.claudeCode = { ...(config.claudeCode ?? {}), desktopProfile: state.profile };
|
|
@@ -52,7 +59,7 @@ export async function applyProfile(
|
|
|
52
59
|
// serving process installs the map there; a local-only write leaves the
|
|
53
60
|
// daemon unable to decode aliases, and the provider rejects them (400).
|
|
54
61
|
const post = deps.postApplyImpl ?? (async (m: Desktop3pConfigMode, p: DesktopProfile) =>
|
|
55
|
-
runtimeRequest<{ ok?: boolean; path?: string; error?: string }>(
|
|
62
|
+
runtimeRequest<{ ok?: boolean; path?: string; error?: string; saved?: boolean; warning?: string }>(
|
|
56
63
|
"/api/claude-desktop/apply",
|
|
57
64
|
// The daemon's config may be older than what we just saved, so the
|
|
58
65
|
// profile travels with the request instead of being re-read there.
|
|
@@ -61,12 +68,26 @@ export async function applyProfile(
|
|
|
61
68
|
try {
|
|
62
69
|
const applied = await post(mode, state.profile);
|
|
63
70
|
if (applied.ok === false) return { ok: false, path: applied.path ?? "", reason: applied.error ?? "daemon apply failed" };
|
|
64
|
-
|
|
71
|
+
// Partial success: Desktop was written but the applied marker was not
|
|
72
|
+
// persisted. Pass the degradation up instead of reporting a clean apply.
|
|
73
|
+
const partial = (applied as { saved?: boolean; warning?: string }).saved === false;
|
|
74
|
+
return {
|
|
75
|
+
ok: true,
|
|
76
|
+
path: applied.path ?? "",
|
|
77
|
+
...(partial ? { warning: (applied as { warning?: string }).warning ?? "applied marker was not saved" } : {}),
|
|
78
|
+
};
|
|
65
79
|
} catch (error) {
|
|
66
80
|
return { ok: false, path: "", reason: error instanceof Error ? error.message : String(error) };
|
|
67
81
|
}
|
|
68
82
|
}
|
|
69
83
|
const allModels = await fetchAllModels(config);
|
|
84
|
+
// The toggle can persist OFF while fetchAllModels was awaiting (same race the
|
|
85
|
+
// management writers fence). Re-read persisted intent immediately before the
|
|
86
|
+
// writer; a lost race is a discriminated skip, not a write.
|
|
87
|
+
const { claudeDesktopIntegrationEnabledNow } = await import("../codex/desired-state");
|
|
88
|
+
if (!claudeDesktopIntegrationEnabledNow()) {
|
|
89
|
+
return { ok: false, path: "", reason: "desired_state_changed" };
|
|
90
|
+
}
|
|
70
91
|
const routed = filterCatalogVisibleModels(allModels, config).map(model => ({
|
|
71
92
|
provider: model.provider,
|
|
72
93
|
id: model.id,
|
|
@@ -79,6 +100,7 @@ export async function applyProfile(
|
|
|
79
100
|
config.apiKeys?.[0]?.key,
|
|
80
101
|
mode,
|
|
81
102
|
state.profile,
|
|
103
|
+
nativeContextLimits(config),
|
|
82
104
|
);
|
|
83
105
|
return { ok: result.written, path: result.path, reason: result.reason };
|
|
84
106
|
}
|
|
@@ -97,10 +119,10 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
97
119
|
const nonMode = argv.filter(arg => !["apply", "--static", "--hybrid", "--discovery-only"].includes(arg));
|
|
98
120
|
if (nonMode.length > 0) {
|
|
99
121
|
console.error(`알 수 없는 인자: ${nonMode.join(" ")}`);
|
|
100
|
-
return
|
|
122
|
+
return 2;
|
|
101
123
|
}
|
|
102
124
|
const parsedMode = parseDesktop3pModeArgs(legacyFlags);
|
|
103
|
-
if ("error" in parsedMode) { console.error(parsedMode.error); return
|
|
125
|
+
if ("error" in parsedMode) { console.error(parsedMode.error); return 2; }
|
|
104
126
|
try {
|
|
105
127
|
const config = loadConfig();
|
|
106
128
|
const state = await buildClaudeDesktopState(config);
|
|
@@ -111,6 +133,9 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
111
133
|
return 1;
|
|
112
134
|
}
|
|
113
135
|
console.log(`Claude Desktop 설정을 적용했습니다: ${result.path}`);
|
|
136
|
+
// The write landed; only the bookkeeping marker did not. Saying nothing
|
|
137
|
+
// would leave the saved-vs-applied display wrong with no explanation.
|
|
138
|
+
if (result.warning) console.warn(`⚠️ ${result.warning}`);
|
|
114
139
|
console.log("Claude Desktop을 완전히 종료한 뒤 다시 열어 주세요.");
|
|
115
140
|
return 0;
|
|
116
141
|
} catch (error) {
|
|
@@ -121,10 +146,29 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
121
146
|
|
|
122
147
|
try {
|
|
123
148
|
const config = loadConfig();
|
|
149
|
+
// `status` is API-backed and must NOT build local state first: the whole point of the
|
|
150
|
+
// route the GUI polls (/api/claude-desktop/status) is the applied-vs-desired comparison,
|
|
151
|
+
// including staleness, drift and health, which only the running proxy knows. `show`
|
|
152
|
+
// reports what this machine would write; `status` reports what is actually in effect.
|
|
153
|
+
if (command === "status") {
|
|
154
|
+
const rest = argv.slice(1);
|
|
155
|
+
const wantsJson = takeJsonFlag(rest);
|
|
156
|
+
if (rest.length > 0) throw new CliUsageError("Usage: ocx claude desktop status [--json]");
|
|
157
|
+
const live = await runtimeRequest<Record<string, unknown>>("/api/claude-desktop/status", {});
|
|
158
|
+
if (wantsJson) console.log(JSON.stringify(live, null, 2));
|
|
159
|
+
else {
|
|
160
|
+
for (const [key, value] of Object.entries(live)) {
|
|
161
|
+
console.log(`${key}: ${typeof value === "object" ? JSON.stringify(value) : String(value)}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return 0;
|
|
165
|
+
}
|
|
124
166
|
const state = await buildClaudeDesktopState(config);
|
|
125
167
|
if (command === "show") {
|
|
126
|
-
|
|
127
|
-
|
|
168
|
+
const rest = argv.slice(1);
|
|
169
|
+
const wantsJson = takeJsonFlag(rest);
|
|
170
|
+
if (rest.length > 0) throw new CliUsageError("Usage: ocx claude desktop show [--json]");
|
|
171
|
+
if (wantsJson) console.log(JSON.stringify(state));
|
|
128
172
|
else {
|
|
129
173
|
for (const family of DESKTOP_FAMILIES) {
|
|
130
174
|
console.log(`${family.toUpperCase()}${state.profile.defaults[family] ? ` (default: ${state.profile.defaults[family]})` : ""}`);
|
|
@@ -137,7 +181,7 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
137
181
|
}
|
|
138
182
|
if (command === "move") {
|
|
139
183
|
const [, route, familyRaw, ...flags] = argv;
|
|
140
|
-
if (!route || !isFamily(familyRaw) || flags.some(flag => flag !== "--default")) throw new
|
|
184
|
+
if (!route || !isFamily(familyRaw) || flags.some(flag => flag !== "--default")) throw new CliUsageError("Usage: ocx claude desktop move <route> <family> [--default]");
|
|
141
185
|
if (!state.models.some(model => model.route === route && model.available)) throw new Error(`현재 사용할 수 없는 모델입니다: ${route}`);
|
|
142
186
|
const profile = moveDesktopRoute(state.profile, route, familyRaw, flags.includes("--default"));
|
|
143
187
|
config.claudeCode = { ...(config.claudeCode ?? {}), desktopProfile: profile };
|
|
@@ -147,7 +191,7 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
147
191
|
}
|
|
148
192
|
if (command === "default") {
|
|
149
193
|
const [, familyRaw, routeRaw] = argv;
|
|
150
|
-
if (!isFamily(familyRaw) || !routeRaw || argv.length !== 3) throw new
|
|
194
|
+
if (!isFamily(familyRaw) || !routeRaw || argv.length !== 3) throw new CliUsageError("Usage: ocx claude desktop default <family> <route|none>");
|
|
151
195
|
const route = routeRaw === "none" ? null : routeRaw;
|
|
152
196
|
if (route && !state.models.some(model => model.route === route && model.available)) throw new Error(`현재 사용할 수 없는 모델입니다: ${route}`);
|
|
153
197
|
const profile = setDesktopFamilyDefault(state.profile, familyRaw, route);
|
|
@@ -158,7 +202,7 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
158
202
|
}
|
|
159
203
|
if (command === "export") {
|
|
160
204
|
const target = argv[1];
|
|
161
|
-
if (!target || argv.length !== 2) throw new
|
|
205
|
+
if (!target || argv.length !== 2) throw new CliUsageError("Usage: ocx claude desktop export <path|->");
|
|
162
206
|
const json = JSON.stringify(state.profile, null, 2) + "\n";
|
|
163
207
|
if (target === "-") process.stdout.write(json);
|
|
164
208
|
else writeFileSync(resolve(target), json, { encoding: "utf8", mode: 0o600 });
|
|
@@ -167,7 +211,7 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
167
211
|
if (command === "import") {
|
|
168
212
|
const source = argv[1];
|
|
169
213
|
const flags = argv.slice(2);
|
|
170
|
-
if (!source || flags.some(flag => flag !== "--apply")) throw new
|
|
214
|
+
if (!source || flags.some(flag => flag !== "--apply")) throw new CliUsageError("Usage: ocx claude desktop import <path> [--apply]");
|
|
171
215
|
const profile = parseDesktopProfile(JSON.parse(readFileSync(resolve(source), "utf8")));
|
|
172
216
|
const reconciled = (await buildClaudeDesktopState(config, profile)).profile;
|
|
173
217
|
config.claudeCode = { ...(config.claudeCode ?? {}), desktopProfile: reconciled };
|
|
@@ -175,14 +219,15 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
175
219
|
if (flags.includes("--apply")) {
|
|
176
220
|
const result = await applyProfile(reconciled, "static", deps);
|
|
177
221
|
if (!result.ok) { console.error(`프로필은 저장했지만 Desktop 적용에 실패했습니다: ${result.reason ?? "unknown error"}`); return 1; }
|
|
222
|
+
if (result.warning) console.warn(`⚠️ ${result.warning}`);
|
|
178
223
|
}
|
|
179
224
|
console.log("Claude Desktop 프로필을 가져왔습니다.");
|
|
180
225
|
return 0;
|
|
181
226
|
}
|
|
182
227
|
printDesktopHelp();
|
|
183
|
-
return
|
|
228
|
+
return 2;
|
|
184
229
|
} catch (error) {
|
|
185
230
|
console.error(error instanceof Error ? error.message : String(error));
|
|
186
|
-
return 1;
|
|
231
|
+
return error instanceof CliUsageError ? 2 : 1;
|
|
187
232
|
}
|
|
188
233
|
}
|
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,43 @@ 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
|
+
/** Explicit unsafe opt-in from a root `--dangerously-skip-permissions` launch. */
|
|
38
|
+
allowRootSkipPermissions?: boolean;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function isClaudeLoopbackHostname(hostname: string): boolean {
|
|
42
|
+
const normalized = hostname.toLowerCase().replace(/\.$/, "");
|
|
43
|
+
return normalized === "localhost"
|
|
44
|
+
|| normalized === "127.0.0.1"
|
|
45
|
+
|| normalized === "::1"
|
|
46
|
+
|| normalized === "[::1]";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function targetsLocalClaudeProxy(value: string | undefined, port: number): boolean {
|
|
50
|
+
if (!value) return false;
|
|
51
|
+
try {
|
|
52
|
+
const parsed = new URL(value);
|
|
53
|
+
const effectivePort = parsed.port === "" ? 80 : Number(parsed.port);
|
|
54
|
+
return parsed.protocol === "http:"
|
|
55
|
+
&& isClaudeLoopbackHostname(parsed.hostname)
|
|
56
|
+
&& effectivePort === port
|
|
57
|
+
&& parsed.username === ""
|
|
58
|
+
&& parsed.password === "";
|
|
59
|
+
} catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
30
63
|
|
|
31
64
|
/**
|
|
32
65
|
* Pure env assembly (unit-tested): never sets ANTHROPIC_API_KEY (setting both
|
|
33
66
|
* token vars triggers Claude Code's auth-conflict warning, 003 E1), and never
|
|
34
|
-
*
|
|
35
|
-
* ANTHROPIC_BASE_URL values owned by a previous
|
|
67
|
+
* preserves Anthropic variables proven to exist in the parent Node launcher,
|
|
68
|
+
* apart from stale loopback ANTHROPIC_BASE_URL values owned by a previous
|
|
69
|
+
* opencodex launch. Unproven ambient values fail closed as project dotenv.
|
|
36
70
|
*/
|
|
37
71
|
export function buildClaudeEnv(
|
|
38
72
|
config: OcxConfig,
|
|
@@ -47,42 +81,56 @@ export function buildClaudeEnv(
|
|
|
47
81
|
// stale marker left in place would suppress the admission key and then be removed,
|
|
48
82
|
// leaving the child with no token at all (audit R2-1). It is opencodex state, never
|
|
49
83
|
// 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
|
-
|
|
84
|
+
if (env.ANTHROPIC_AUTH_TOKEN?.trim() === PROXY_MARKER) delete env.ANTHROPIC_AUTH_TOKEN;
|
|
85
|
+
// Step 1b — drop Anthropic credentials AND destinations that Bun may have synthesized
|
|
86
|
+
// from a project `.env`/`.env.local`. The plain-Node launcher records genuine parent
|
|
87
|
+
// exports before Bun starts and pairs that context with an argv proof, so with a
|
|
88
|
+
// trusted context we know exactly which slots the user really exported.
|
|
89
|
+
//
|
|
90
|
+
// Without a trusted context all three slots are treated as project-controlled. An
|
|
91
|
+
// earlier revision of this branch preserved credentials here, reasoning that the
|
|
92
|
+
// destination is pinned below so a dotenv key would only ever reach the local proxy.
|
|
93
|
+
// That reasoning is wrong, and review caught it: `CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST`
|
|
94
|
+
// is only set when we own an auth token (see below, and #253 for why asserting it
|
|
95
|
+
// otherwise logs a subscriber out), so on a subscription launch Claude Code's
|
|
96
|
+
// settings.env merge can still replace `ANTHROPIC_BASE_URL` after we return. A
|
|
97
|
+
// preserved key then travels to that host. The repository documents that residual for
|
|
98
|
+
// subscription mode; it must not be widened into a credential leak.
|
|
99
|
+
//
|
|
100
|
+
// Direct `bun src/cli/index.ts` therefore loses ambient Anthropic values. That is a
|
|
101
|
+
// real cost to a documented entry point, and the escape hatch is the launcher: run
|
|
102
|
+
// through `ocx` (the published bin) and genuine shell exports are preserved by proof.
|
|
103
|
+
const explicitSlots = deps.preBunAnthropicSlots;
|
|
104
|
+
const trustedSlots = explicitSlots === undefined
|
|
105
|
+
? trustedNodeLauncherContext()?.anthropicEnvSlots ?? []
|
|
106
|
+
: explicitSlots ?? [];
|
|
107
|
+
const exported = new Set<AnthropicParentEnvSlot>(trustedSlots);
|
|
108
|
+
for (const name of ANTHROPIC_PARENT_ENV_SLOTS) {
|
|
109
|
+
const value = env[name];
|
|
110
|
+
if (value !== undefined && value !== "" && !exported.has(name)) delete env[name];
|
|
69
111
|
}
|
|
70
|
-
// Never forward
|
|
112
|
+
// Never forward old or current provenance seams to Claude Code.
|
|
71
113
|
delete env.OCX_PRE_BUN_ANTHROPIC_ENV;
|
|
114
|
+
delete env.OCX_NODE_LAUNCH_CONTEXT;
|
|
72
115
|
const setDefault = (name: string, value: string | undefined) => {
|
|
73
116
|
if (value === undefined || value.length === 0) return;
|
|
74
117
|
if (env[name] !== undefined && env[name] !== "") return; // user wins
|
|
75
118
|
env[name] = value;
|
|
76
119
|
};
|
|
120
|
+
if (deps.allowRootSkipPermissions === true) {
|
|
121
|
+
setDefault("IS_SANDBOX", "1");
|
|
122
|
+
}
|
|
77
123
|
setDefault("ANTHROPIC_BASE_URL", `http://127.0.0.1:${port}`);
|
|
78
124
|
const existingBaseUrl = env.ANTHROPIC_BASE_URL;
|
|
79
125
|
if (existingBaseUrl) {
|
|
80
126
|
try {
|
|
81
127
|
const parsed = new URL(existingBaseUrl);
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
128
|
+
const effectivePort = parsed.port === "" ? 80 : Number(parsed.port);
|
|
129
|
+
if (parsed.protocol === "http:"
|
|
130
|
+
&& isClaudeLoopbackHostname(parsed.hostname)
|
|
131
|
+
&& effectivePort !== port) {
|
|
84
132
|
const replacement = `http://127.0.0.1:${port}`;
|
|
85
|
-
console.error(`⚠ Replacing stale opencodex ANTHROPIC_BASE_URL ${
|
|
133
|
+
console.error(`⚠ Replacing stale opencodex ANTHROPIC_BASE_URL ${parsed.origin} with ${replacement}.`);
|
|
86
134
|
env.ANTHROPIC_BASE_URL = replacement;
|
|
87
135
|
}
|
|
88
136
|
} catch {
|
|
@@ -94,8 +142,26 @@ export function buildClaudeEnv(
|
|
|
94
142
|
// the user's Claude login. Only inject a token when the proxy actually requires an
|
|
95
143
|
// admission key; otherwise Claude Code keeps its own OAuth and sends it to us —
|
|
96
144
|
// native claude models then pass through verbatim (see server/claude-messages.ts).
|
|
97
|
-
|
|
98
|
-
|
|
145
|
+
const ownTokens = ownAdmissionTokens(config);
|
|
146
|
+
const targetsLocalProxy = targetsLocalClaudeProxy(env.ANTHROPIC_BASE_URL, port);
|
|
147
|
+
const inheritedApiKey = env.ANTHROPIC_API_KEY;
|
|
148
|
+
if (typeof inheritedApiKey === "string" && isProxyAdmissionSecret(inheritedApiKey, config)) {
|
|
149
|
+
delete env.ANTHROPIC_API_KEY;
|
|
150
|
+
}
|
|
151
|
+
const hasUserApiKey = Boolean(env.ANTHROPIC_API_KEY?.trim());
|
|
152
|
+
const inheritedAuthToken = env.ANTHROPIC_AUTH_TOKEN;
|
|
153
|
+
const inheritedTokenIsOurs = typeof inheritedAuthToken === "string"
|
|
154
|
+
&& isProxyAdmissionSecret(inheritedAuthToken, config);
|
|
155
|
+
// system-env may have injected the proxy's admission key into the parent. A
|
|
156
|
+
// proof-bound external BASE_URL is still user-owned, so never let our inherited
|
|
157
|
+
// key follow it. A user API key also wins on a local launch; remove only the token
|
|
158
|
+
// values recognized by the shared proxy-admission contract and preserve every
|
|
159
|
+
// other token.
|
|
160
|
+
if (inheritedTokenIsOurs && (!targetsLocalProxy || hasUserApiKey)) {
|
|
161
|
+
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
162
|
+
}
|
|
163
|
+
if (targetsLocalProxy && !hasUserApiKey && ownTokens.length > 0) {
|
|
164
|
+
setDefault("ANTHROPIC_AUTH_TOKEN", ownTokens[0]);
|
|
99
165
|
}
|
|
100
166
|
// Detection reads the SANITIZED launch env — the exact object spawned below — so the
|
|
101
167
|
// resolver and the spawned process cannot disagree. It deliberately does NOT read the
|
|
@@ -110,11 +176,19 @@ export function buildClaudeEnv(
|
|
|
110
176
|
...defaultAuthDetectDeps(env as NodeJS.ProcessEnv),
|
|
111
177
|
...(deps.authDetect ?? {}),
|
|
112
178
|
env: () => env as NodeJS.ProcessEnv,
|
|
113
|
-
ownTokens
|
|
179
|
+
ownTokens,
|
|
114
180
|
}));
|
|
115
|
-
if (!env.ANTHROPIC_AUTH_TOKEN && resolved.markerMode === "proxy") {
|
|
181
|
+
if (!env.ANTHROPIC_AUTH_TOKEN && !hasUserApiKey && targetsLocalProxy && resolved.markerMode === "proxy") {
|
|
116
182
|
env.ANTHROPIC_AUTH_TOKEN = PROXY_MARKER;
|
|
117
183
|
}
|
|
184
|
+
const finalAuthToken = env.ANTHROPIC_AUTH_TOKEN;
|
|
185
|
+
const hostOwnsAuthentication = targetsLocalProxy
|
|
186
|
+
&& !hasUserApiKey
|
|
187
|
+
&& typeof finalAuthToken === "string"
|
|
188
|
+
&& (
|
|
189
|
+
finalAuthToken.trim() === PROXY_MARKER
|
|
190
|
+
|| isProxyAdmissionSecret(finalAuthToken, config)
|
|
191
|
+
);
|
|
118
192
|
if (resolved.origin === "auto-unknown") {
|
|
119
193
|
console.error("⚠ Claude 인증을 확인하지 못했습니다 — 구독 방식으로 진행합니다. GUI에서 인증 모드를 직접 지정하면 이 판단을 덮어쓸 수 있습니다.");
|
|
120
194
|
}
|
|
@@ -136,7 +210,7 @@ export function buildClaudeEnv(
|
|
|
136
210
|
// Claude Code 2.1.206+ also treats this as a host-auth assertion. Injecting it
|
|
137
211
|
// without a host token makes a valid claude.ai subscription look logged out,
|
|
138
212
|
// so the guard is only safe when opencodex actually owns authentication.
|
|
139
|
-
if (
|
|
213
|
+
if (hostOwnsAuthentication) {
|
|
140
214
|
setDefault("CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST", "1");
|
|
141
215
|
}
|
|
142
216
|
// Opt-in effort forcing (devlog 136 B6): opus-shaped aliases already carry
|
|
@@ -201,11 +275,11 @@ async function ensureProxyForClaude(): Promise<number | null> {
|
|
|
201
275
|
if (live) return live.port;
|
|
202
276
|
const cfgPort = loadConfig().port;
|
|
203
277
|
const pinPort = typeof cfgPort === "number" && cfgPort > 0 ? cfgPort : 10100;
|
|
204
|
-
const child = spawn(process.execPath, [
|
|
278
|
+
const child = spawn(process.execPath, selfLaunchArgv(["start", "--port", String(pinPort)]), {
|
|
205
279
|
detached: true,
|
|
206
280
|
stdio: "ignore",
|
|
207
281
|
windowsHide: true,
|
|
208
|
-
env: { ...process.env, OCX_SERVICE: "1" },
|
|
282
|
+
env: withProcessRuntimeProvenance({ ...process.env, OCX_SERVICE: "1" }),
|
|
209
283
|
});
|
|
210
284
|
child.unref();
|
|
211
285
|
const deadline = Date.now() + 8_000;
|
|
@@ -232,6 +306,22 @@ export function claudeNotFoundHint(
|
|
|
232
306
|
return platform === "win32" && code === 9009 && !signal ? CLAUDE_INSTALL_HINT : null;
|
|
233
307
|
}
|
|
234
308
|
|
|
309
|
+
export function shouldAllowRootSkipPermissions(
|
|
310
|
+
args: readonly string[],
|
|
311
|
+
getuid: (() => number) | null | undefined = process.getuid,
|
|
312
|
+
): boolean {
|
|
313
|
+
return args.includes("--dangerously-skip-permissions")
|
|
314
|
+
&& typeof getuid === "function"
|
|
315
|
+
&& getuid() === 0;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export function rootSkipPermissionsNotice(env: ClaudeLaunchEnv): string {
|
|
319
|
+
if (env.IS_SANDBOX === "1") {
|
|
320
|
+
return "⚠ Root --dangerously-skip-permissions requested: OpenCodex set IS_SANDBOX=1 to bypass Claude Code's root guard. OpenCodex did not create an OS sandbox; prefer running as a non-root user.";
|
|
321
|
+
}
|
|
322
|
+
return `⚠ Root --dangerously-skip-permissions requested: preserving user IS_SANDBOX=${env.IS_SANDBOX}; Claude Code's root guard remains in control.`;
|
|
323
|
+
}
|
|
324
|
+
|
|
235
325
|
export async function cmdClaude(args: string[]): Promise<number> {
|
|
236
326
|
const config = loadConfig();
|
|
237
327
|
if (config.claudeCode?.enabled === false) {
|
|
@@ -244,11 +334,15 @@ export async function cmdClaude(args: string[]): Promise<number> {
|
|
|
244
334
|
return 1;
|
|
245
335
|
}
|
|
246
336
|
const contextWindows = await fetchClaudeContextWindows(config, port);
|
|
247
|
-
const
|
|
337
|
+
const allowRootSkipPermissions = shouldAllowRootSkipPermissions(args);
|
|
338
|
+
const env = buildClaudeEnv(config, port, process.env, contextWindows, { allowRootSkipPermissions });
|
|
339
|
+
if (allowRootSkipPermissions) {
|
|
340
|
+
console.error(rootSkipPermissionsNotice(env));
|
|
341
|
+
}
|
|
248
342
|
// Pre-write the CLI's gateway-model cache (devlog 030): without a token the CLI
|
|
249
343
|
// never refreshes it, so the picker would keep showing yesterday's aliases.
|
|
250
344
|
try {
|
|
251
|
-
const cachePath = await refreshGatewayModelCacheFromProxy(port);
|
|
345
|
+
const cachePath = await refreshGatewayModelCacheFromProxy(port, { admissionConfig: config });
|
|
252
346
|
if (cachePath === null) {
|
|
253
347
|
console.error("⚠ Gateway model cache could not be refreshed; the model picker may be stale.");
|
|
254
348
|
}
|
|
@@ -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
|
|