@iislee/opencodex 2.11.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +618 -74
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +152 -29
- package/src/images/plan.ts +23 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +220 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +865 -181
- package/src/server/lifecycle.ts +284 -13
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +101 -32
- package/src/server/management/model-routes.ts +189 -131
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +288 -32
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +845 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +9 -3
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
import { codexExecInvocation } from "../codex/exec-invocation";
|
|
3
|
+
import { resolveAndPersistCodexRuntime, type ResolveCodexRuntimeDeps } from "../codex/runtime";
|
|
4
|
+
import type { ResolveDeps, SpawnInvocation } from "../lib/win-exec";
|
|
5
|
+
import {
|
|
6
|
+
apiError,
|
|
7
|
+
apiJson,
|
|
8
|
+
proxyUnreachable,
|
|
9
|
+
resolveBaseUrl,
|
|
10
|
+
type AccountDeps,
|
|
11
|
+
type NativeMainLoginChild,
|
|
12
|
+
type StageLeaseClock,
|
|
13
|
+
} from "./account-api";
|
|
14
|
+
|
|
15
|
+
const USAGE = `Usage:
|
|
16
|
+
ocx account main doctor [--json]
|
|
17
|
+
ocx account main list [--json]
|
|
18
|
+
ocx account main register <label> [--json]
|
|
19
|
+
ocx account main add <label>
|
|
20
|
+
ocx account main switch <profile-id-or-label> --yes [--json]
|
|
21
|
+
ocx account main recover [--rollback --yes] [--json]
|
|
22
|
+
|
|
23
|
+
Native main login profiles change the physical Codex App/CLI login in the effective CODEX_HOME.
|
|
24
|
+
They are independent from the OpenCodex Pool selected by 'ocx account use openai'.`;
|
|
25
|
+
|
|
26
|
+
const STAGE_LEASE_SAFETY_MARGIN_MS = 30_000;
|
|
27
|
+
|
|
28
|
+
const systemStageLeaseClock: StageLeaseClock = {
|
|
29
|
+
now: Date.now,
|
|
30
|
+
setTimeout: (callback, ms) => setTimeout(callback, ms),
|
|
31
|
+
clearTimeout: timer => clearTimeout(timer),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
interface PublicProfile {
|
|
35
|
+
id: string;
|
|
36
|
+
label: string;
|
|
37
|
+
identityHint: string;
|
|
38
|
+
state: "active" | "inactive";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type NativeMainCodexLoginInvocationDeps =
|
|
42
|
+
& ResolveDeps
|
|
43
|
+
& Pick<ResolveCodexRuntimeDeps, "existsSync" | "execFileSync" | "configDir" | "readFileSync">;
|
|
44
|
+
|
|
45
|
+
function flag(args: string[], name: string): boolean {
|
|
46
|
+
const index = args.indexOf(name);
|
|
47
|
+
if (index < 0) return false;
|
|
48
|
+
args.splice(index, 1);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function reject(args: string[]): number {
|
|
53
|
+
if (args.length > 0) console.error(`Unexpected argument(s): ${args.join(", ")}`);
|
|
54
|
+
console.error(USAGE);
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function effectiveCodexHome(result: Record<string, unknown>): string {
|
|
59
|
+
return typeof result.effectiveCodexHome === "string" && result.effectiveCodexHome.length > 0
|
|
60
|
+
? result.effectiveCodexHome
|
|
61
|
+
: "the effective CODEX_HOME";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function printProfiles(profiles: PublicProfile[]): void {
|
|
65
|
+
if (profiles.length === 0) { console.log("No native main login profiles registered."); return; }
|
|
66
|
+
const rows = profiles.map(profile => [profile.state === "active" ? "*" : " ", profile.label, profile.id, profile.identityHint]);
|
|
67
|
+
const header = ["", "LABEL", "PROFILE ID", "IDENTITY"];
|
|
68
|
+
const widths = header.map((value, index) => Math.max(value.length, ...rows.map(row => row[index]!.length)));
|
|
69
|
+
const line = (columns: string[]) => columns.map((value, index) => value.padEnd(widths[index]!)).join(" ").trimEnd();
|
|
70
|
+
console.log([line(header), ...rows.map(line)].join("\n"));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function nativeMainCodexLoginInvocation(
|
|
74
|
+
platform: NodeJS.Platform = process.platform,
|
|
75
|
+
deps: NativeMainCodexLoginInvocationDeps = {},
|
|
76
|
+
): SpawnInvocation {
|
|
77
|
+
const command = resolveAndPersistCodexRuntime({
|
|
78
|
+
env: deps.env ?? process.env,
|
|
79
|
+
platform,
|
|
80
|
+
existsSync: deps.existsSync,
|
|
81
|
+
execFileSync: deps.execFileSync,
|
|
82
|
+
configDir: deps.configDir,
|
|
83
|
+
readFileSync: deps.readFileSync,
|
|
84
|
+
discoverAlternatives: false,
|
|
85
|
+
}).runtime.command || "codex";
|
|
86
|
+
return codexExecInvocation(command, ["login"], platform, deps);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function spawnOfficialCodexLogin(codexHome: string): NativeMainLoginChild {
|
|
90
|
+
const invocation = nativeMainCodexLoginInvocation();
|
|
91
|
+
const child = Bun.spawn([invocation.file, ...invocation.args], {
|
|
92
|
+
env: { ...process.env, CODEX_HOME: codexHome },
|
|
93
|
+
stdin: "inherit",
|
|
94
|
+
stdout: "inherit",
|
|
95
|
+
stderr: "inherit",
|
|
96
|
+
...(invocation.options.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}),
|
|
97
|
+
});
|
|
98
|
+
return child;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function abortableDelay(ms: number, signal: AbortSignal, clock: StageLeaseClock): Promise<void> {
|
|
102
|
+
if (signal.aborted) return Promise.resolve();
|
|
103
|
+
return new Promise(resolve => {
|
|
104
|
+
const timer = clock.setTimeout(done, ms);
|
|
105
|
+
signal.addEventListener("abort", done, { once: true });
|
|
106
|
+
function done(): void {
|
|
107
|
+
clock.clearTimeout(timer);
|
|
108
|
+
signal.removeEventListener("abort", done);
|
|
109
|
+
resolve();
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function maintainStageLease(
|
|
115
|
+
deps: AccountDeps,
|
|
116
|
+
baseUrl: string,
|
|
117
|
+
stageId: string,
|
|
118
|
+
writerToken: string,
|
|
119
|
+
initialLeaseExpiresAt: number,
|
|
120
|
+
heartbeatIntervalMs: number,
|
|
121
|
+
child: NativeMainLoginChild,
|
|
122
|
+
signal: AbortSignal,
|
|
123
|
+
clock: StageLeaseClock,
|
|
124
|
+
): Promise<{ lost: boolean }> {
|
|
125
|
+
let leaseExpiresAt = initialLeaseExpiresAt;
|
|
126
|
+
for (;;) {
|
|
127
|
+
if (signal.aborted) return { lost: false };
|
|
128
|
+
const deadlineAt = leaseExpiresAt - STAGE_LEASE_SAFETY_MARGIN_MS;
|
|
129
|
+
if (clock.now() >= deadlineAt) {
|
|
130
|
+
try { child.kill(); } catch { /* child exit below is authoritative */ }
|
|
131
|
+
return { lost: true };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const heartbeatAbort = new AbortController();
|
|
135
|
+
const deadlineReached = Symbol("heartbeat-deadline");
|
|
136
|
+
const parentCancelled = Symbol("heartbeat-parent-cancelled");
|
|
137
|
+
let resolveInterruption!: (result: typeof deadlineReached | typeof parentCancelled) => void;
|
|
138
|
+
const interruption = new Promise<typeof deadlineReached | typeof parentCancelled>(resolve => {
|
|
139
|
+
resolveInterruption = resolve;
|
|
140
|
+
});
|
|
141
|
+
const cancelHeartbeat = () => {
|
|
142
|
+
heartbeatAbort.abort();
|
|
143
|
+
resolveInterruption(parentCancelled);
|
|
144
|
+
};
|
|
145
|
+
signal.addEventListener("abort", cancelHeartbeat, { once: true });
|
|
146
|
+
const deadlineTimer = clock.setTimeout(() => {
|
|
147
|
+
heartbeatAbort.abort();
|
|
148
|
+
resolveInterruption(deadlineReached);
|
|
149
|
+
}, Math.max(0, deadlineAt - clock.now()));
|
|
150
|
+
const heartbeatRequest = apiJson(
|
|
151
|
+
deps,
|
|
152
|
+
baseUrl,
|
|
153
|
+
"POST",
|
|
154
|
+
"/api/native-main-profiles/stage/heartbeat",
|
|
155
|
+
{ stageId, writerToken },
|
|
156
|
+
{ signal: heartbeatAbort.signal },
|
|
157
|
+
);
|
|
158
|
+
const heartbeat = await Promise.race([heartbeatRequest, interruption]);
|
|
159
|
+
clock.clearTimeout(deadlineTimer);
|
|
160
|
+
signal.removeEventListener("abort", cancelHeartbeat);
|
|
161
|
+
if (signal.aborted) return { lost: false };
|
|
162
|
+
if (heartbeat === parentCancelled) return { lost: false };
|
|
163
|
+
if (heartbeat === deadlineReached) {
|
|
164
|
+
try { child.kill(); } catch { /* child exit below is authoritative */ }
|
|
165
|
+
return { lost: true };
|
|
166
|
+
}
|
|
167
|
+
if (heartbeat.status === 200 && typeof heartbeat.json.leaseExpiresAt === "number") {
|
|
168
|
+
leaseExpiresAt = heartbeat.json.leaseExpiresAt;
|
|
169
|
+
await abortableDelay(Math.min(heartbeatIntervalMs, Math.max(0, leaseExpiresAt - STAGE_LEASE_SAFETY_MARGIN_MS - clock.now())), signal, clock);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (heartbeat.status === 0 && clock.now() < leaseExpiresAt - STAGE_LEASE_SAFETY_MARGIN_MS) {
|
|
173
|
+
await abortableDelay(Math.min(5_000, heartbeatIntervalMs, leaseExpiresAt - STAGE_LEASE_SAFETY_MARGIN_MS - clock.now()), signal, clock);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
try { child.kill(); } catch { /* child exit below is authoritative */ }
|
|
177
|
+
return { lost: true };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export async function cmdNativeMainAccount(args: string[], deps: AccountDeps): Promise<number> {
|
|
182
|
+
const sub = args.shift();
|
|
183
|
+
const wantsJson = flag(args, "--json");
|
|
184
|
+
const confirmed = flag(args, "--yes");
|
|
185
|
+
const rollback = flag(args, "--rollback");
|
|
186
|
+
const baseUrl = await resolveBaseUrl(deps);
|
|
187
|
+
if (!baseUrl) return proxyUnreachable();
|
|
188
|
+
|
|
189
|
+
if (sub === "doctor" || sub === "list") {
|
|
190
|
+
if (args.length > 0 || confirmed || rollback) return reject(args);
|
|
191
|
+
const path = sub === "doctor" ? "/api/native-main-profiles/doctor" : "/api/native-main-profiles";
|
|
192
|
+
const result = await apiJson(deps, baseUrl, "GET", path);
|
|
193
|
+
if (result.status === 0) return proxyUnreachable();
|
|
194
|
+
if (result.status !== 200) return apiError(result.json, `failed to ${sub} native profiles`);
|
|
195
|
+
if (wantsJson || sub === "doctor") console.log(JSON.stringify(result.json, null, 2));
|
|
196
|
+
else printProfiles(Array.isArray(result.json.profiles) ? result.json.profiles as PublicProfile[] : []);
|
|
197
|
+
return 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (sub === "register") {
|
|
201
|
+
const label = args.shift();
|
|
202
|
+
if (!label || args.length > 0 || confirmed || rollback) return reject(args);
|
|
203
|
+
const result = await apiJson(deps, baseUrl, "POST", "/api/native-main-profiles/register", { label });
|
|
204
|
+
if (result.status === 0) return proxyUnreachable();
|
|
205
|
+
if (result.status !== 200) return apiError(result.json, "failed to register the current native login");
|
|
206
|
+
if (wantsJson) console.log(JSON.stringify(result.json, null, 2));
|
|
207
|
+
else console.log(`Registered '${label}' for ${effectiveCodexHome(result.json)}.`);
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (sub === "add") {
|
|
212
|
+
const label = args.shift();
|
|
213
|
+
if (!label || args.length > 0 || wantsJson || confirmed || rollback) return reject(args);
|
|
214
|
+
const stage = await apiJson(deps, baseUrl, "POST", "/api/native-main-profiles/stage", {});
|
|
215
|
+
if (stage.status === 0) return proxyUnreachable();
|
|
216
|
+
if (stage.status !== 200) return apiError(stage.json, "failed to prepare native login staging");
|
|
217
|
+
const stageId = typeof stage.json.stageId === "string" ? stage.json.stageId : "";
|
|
218
|
+
const writerToken = typeof stage.json.writerToken === "string" ? stage.json.writerToken : "";
|
|
219
|
+
const stagingHome = typeof stage.json.stagingCodexHome === "string" ? stage.json.stagingCodexHome : "";
|
|
220
|
+
const leaseExpiresAt = typeof stage.json.leaseExpiresAt === "number" ? stage.json.leaseExpiresAt : 0;
|
|
221
|
+
const heartbeatIntervalMs = typeof stage.json.heartbeatIntervalMs === "number"
|
|
222
|
+
? Math.min(5 * 60_000, Math.max(deps.stageHeartbeatIntervalMinMs ?? 5_000, stage.json.heartbeatIntervalMs))
|
|
223
|
+
: 60_000;
|
|
224
|
+
const stageLeaseClock = deps.stageLeaseClock ?? systemStageLeaseClock;
|
|
225
|
+
const stagedEffectiveHome = effectiveCodexHome(stage.json);
|
|
226
|
+
let exitCode = 1;
|
|
227
|
+
let finished = false;
|
|
228
|
+
let leaseLost = false;
|
|
229
|
+
try {
|
|
230
|
+
if (!stageId || !writerToken || !isAbsolute(stagingHome) || leaseExpiresAt <= stageLeaseClock.now()) {
|
|
231
|
+
throw new Error("The proxy returned an invalid staging session.");
|
|
232
|
+
}
|
|
233
|
+
console.error(`Effective CODEX_HOME: ${stagedEffectiveHome}`);
|
|
234
|
+
console.error(`Starting official Codex login in restricted staging home: ${stagingHome}`);
|
|
235
|
+
const child = deps.spawnCodexLoginImpl
|
|
236
|
+
? deps.spawnCodexLoginImpl(stagingHome)
|
|
237
|
+
: deps.runCodexLoginImpl
|
|
238
|
+
? { exited: deps.runCodexLoginImpl(stagingHome), kill: () => {} }
|
|
239
|
+
: spawnOfficialCodexLogin(stagingHome);
|
|
240
|
+
const heartbeatAbort = new AbortController();
|
|
241
|
+
const heartbeat = maintainStageLease(
|
|
242
|
+
deps,
|
|
243
|
+
baseUrl,
|
|
244
|
+
stageId,
|
|
245
|
+
writerToken,
|
|
246
|
+
leaseExpiresAt,
|
|
247
|
+
heartbeatIntervalMs,
|
|
248
|
+
child,
|
|
249
|
+
heartbeatAbort.signal,
|
|
250
|
+
stageLeaseClock,
|
|
251
|
+
);
|
|
252
|
+
try {
|
|
253
|
+
exitCode = await child.exited;
|
|
254
|
+
} finally {
|
|
255
|
+
heartbeatAbort.abort();
|
|
256
|
+
leaseLost = (await heartbeat).lost;
|
|
257
|
+
}
|
|
258
|
+
if (leaseLost) throw new Error("The native-login staging lease was lost before login completed.");
|
|
259
|
+
if (exitCode !== 0) throw new Error("Official Codex login did not complete successfully.");
|
|
260
|
+
const finish = await apiJson(deps, baseUrl, "POST", "/api/native-main-profiles/stage/finish", { stageId, writerToken, label });
|
|
261
|
+
if (finish.status === 0) return proxyUnreachable();
|
|
262
|
+
if (finish.status !== 200) return apiError(finish.json, "failed to encrypt the staged native login");
|
|
263
|
+
finished = true;
|
|
264
|
+
console.log(`Added encrypted native profile '${label}' for ${effectiveCodexHome(finish.json)}.`);
|
|
265
|
+
return 0;
|
|
266
|
+
} catch (error) {
|
|
267
|
+
console.error(`Error: ${error instanceof Error ? error.message : "Official Codex login failed."}`);
|
|
268
|
+
return exitCode === 0 ? 1 : exitCode;
|
|
269
|
+
} finally {
|
|
270
|
+
if (stageId && !finished) {
|
|
271
|
+
const cleanup = await apiJson(deps, baseUrl, "POST", "/api/native-main-profiles/stage/cancel", { stageId, writerToken });
|
|
272
|
+
if (cleanup.status !== 200 || cleanup.json.plaintextMayRemain === true) {
|
|
273
|
+
console.error("Error: the proxy could not confirm native-login staging cleanup; run account main doctor.");
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (sub === "switch") {
|
|
280
|
+
const target = args.shift();
|
|
281
|
+
if (!target || args.length > 0 || rollback || !confirmed) {
|
|
282
|
+
if (!confirmed) console.error("Close Codex App/CLI, then pass --yes to confirm it is stopped.");
|
|
283
|
+
return reject(args);
|
|
284
|
+
}
|
|
285
|
+
const result = await apiJson(deps, baseUrl, "POST", "/api/native-main-profiles/switch", { target, confirmedStopped: true });
|
|
286
|
+
if (result.status === 0) return proxyUnreachable();
|
|
287
|
+
if (result.status !== 200) return apiError(result.json, "failed to switch the native login");
|
|
288
|
+
if (wantsJson) console.log(JSON.stringify(result.json, null, 2));
|
|
289
|
+
else {
|
|
290
|
+
const profile = result.json.activeProfile as PublicProfile | undefined;
|
|
291
|
+
console.log(`Native Codex login for ${effectiveCodexHome(result.json)} is now '${profile?.label ?? target}'. Restart Codex App/CLI before continuing.`);
|
|
292
|
+
}
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (sub === "recover") {
|
|
297
|
+
if (args.length > 0 || (rollback && !confirmed)) {
|
|
298
|
+
if (rollback && !confirmed) console.error("--rollback changes the native login and requires --yes.");
|
|
299
|
+
return reject(args);
|
|
300
|
+
}
|
|
301
|
+
const result = await apiJson(deps, baseUrl, "POST", "/api/native-main-profiles/recover", rollback
|
|
302
|
+
? { rollback: true, confirmedStopped: true }
|
|
303
|
+
: { rollback: false });
|
|
304
|
+
if (result.status === 0) return proxyUnreachable();
|
|
305
|
+
if (result.status !== 200) return apiError(result.json, "failed to recover the native-profile transaction");
|
|
306
|
+
if (wantsJson) console.log(JSON.stringify(result.json, null, 2));
|
|
307
|
+
else {
|
|
308
|
+
const home = effectiveCodexHome(result.json);
|
|
309
|
+
console.log(result.json.recovered === true
|
|
310
|
+
? `Recovery completed for ${home}: ${String(result.json.action ?? "converged")}.`
|
|
311
|
+
: `No recovery journal is pending for ${home}.`);
|
|
312
|
+
}
|
|
313
|
+
return 0;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return reject(args);
|
|
317
|
+
}
|
package/src/cli/account.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { loadConfig } from "../config";
|
|
3
3
|
import { providerCodexAccountMode } from "../providers/registry";
|
|
4
4
|
import type { OcxConfig } from "../types";
|
|
5
|
-
import { cmdAddKey, cmdAlias, cmdAutoSwitch, cmdClearCooldown, cmdRefresh, cmdRemove } from "./account-extended";
|
|
5
|
+
import { cmdAddKey, cmdAlias, cmdAutoSwitch, cmdClearCooldown, cmdImport, cmdPriority, cmdRefresh, cmdRemove } from "./account-extended";
|
|
6
6
|
import { apiError, apiJson, classifyAccount, fetchRows, proxyUnreachable, resolveBaseUrl, type AccountDeps, type AccountRow, type AccountType, type ApiResult }
|
|
7
7
|
from "./account-api";
|
|
8
8
|
|
|
@@ -22,13 +22,16 @@ const ACCOUNT_USAGE = `Usage:
|
|
|
22
22
|
ocx account refresh <provider> [--json]
|
|
23
23
|
ocx account auto-switch <provider> <on|off|status|threshold <0-100>> [--json]
|
|
24
24
|
ocx account alias <provider> <account-or-key-id> <display-name|-> [--json]
|
|
25
|
+
ocx account priority <provider> <account-id|main> [<-100..100|first|earlier|normal|later|last|reset>] [--json]
|
|
25
26
|
ocx account remove <provider> <account-or-key-id|main> --yes [--json]
|
|
26
27
|
ocx account clear-cooldown <provider> <account-id|main> [--json]
|
|
27
28
|
ocx account add-key <provider> [--label <label>] [--json]
|
|
29
|
+
ocx account import <provider> --format <format> (--file <path>|--stdin) [--json]
|
|
28
30
|
ocx account login <provider> [--id <account-id>] [--reauth] [--code -] [--no-wait] [--json]
|
|
29
31
|
ocx account code <provider> [--flow <flow-id>] [--json] (reads the code from stdin)
|
|
30
32
|
ocx account cancel <provider> [--flow <flow-id>] [--json]
|
|
31
33
|
ocx account reset-credits <account-id|main> [--consume --yes] [--json]
|
|
34
|
+
ocx account main <doctor|list|register|add|switch|recover> ...
|
|
32
35
|
|
|
33
36
|
List and switch provider accounts and API-key pools (masked output only).
|
|
34
37
|
'main' selects the Codex App login for the openai account pool.`;
|
|
@@ -66,11 +69,24 @@ function statusText(row: AccountRow): string {
|
|
|
66
69
|
return parts.join(" ");
|
|
67
70
|
}
|
|
68
71
|
|
|
72
|
+
/** Signed so the sort direction reads off the column; "-" where ordering does not apply. */
|
|
73
|
+
function priorityText(row: AccountRow): string {
|
|
74
|
+
if (row.priority === undefined) return "-";
|
|
75
|
+
return row.priority > 0 ? `+${row.priority}` : String(row.priority);
|
|
76
|
+
}
|
|
77
|
+
|
|
69
78
|
export function formatAccountTable(rows: AccountRow[]): string {
|
|
70
|
-
const header = ["PROVIDER", "TYPE", "ID", "PLAN/LABEL", "STATUS"];
|
|
79
|
+
const header = ["PROVIDER", "TYPE", "ID", "PLAN/LABEL", "PRIORITY", "STATUS"];
|
|
71
80
|
const data = rows.map(r => {
|
|
72
81
|
const keyLabel = r.masked && r.label !== r.masked ? `${r.masked} (${r.label})` : r.masked;
|
|
73
|
-
return [
|
|
82
|
+
return [
|
|
83
|
+
r.provider,
|
|
84
|
+
r.type,
|
|
85
|
+
displayId(r.id),
|
|
86
|
+
r.type === "api-key" ? keyLabel ?? "-" : r.label ?? "-",
|
|
87
|
+
priorityText(r),
|
|
88
|
+
statusText(r),
|
|
89
|
+
];
|
|
74
90
|
});
|
|
75
91
|
const widths = header.map((h, i) => Math.max(h.length, ...data.map(d => d[i]!.length)));
|
|
76
92
|
const line = (cols: string[]) => cols.map((c, i) => c.padEnd(widths[i]!)).join(" ").trimEnd();
|
|
@@ -243,9 +259,11 @@ async function cmdUse(rest: string[], deps: AccountDeps): Promise<number> {
|
|
|
243
259
|
if (wantsJson) console.log(JSON.stringify({ ok: true, provider: name, type: c.type, activeId }, null, 2));
|
|
244
260
|
else console.log(`${name}: active ${c.type === "api-key" ? "key" : "account"} is now ${displayId(activeId)}`);
|
|
245
261
|
if (c.type === "codex") {
|
|
246
|
-
console.error("
|
|
247
|
-
|
|
248
|
-
|
|
262
|
+
console.error("Takes effect immediately; running threads move on their next request, and in-flight requests keep the account they captured.");
|
|
263
|
+
const active = await apiJson(deps, baseUrl, "GET", "/api/codex-auth/active");
|
|
264
|
+
if (active.status === 200 && typeof active.json.autoSwitchThreshold === "number" && active.json.autoSwitchThreshold > 0) {
|
|
265
|
+
console.error(`Note: auto-switch (threshold ${active.json.autoSwitchThreshold}%) may override this pin.`);
|
|
266
|
+
}
|
|
249
267
|
}
|
|
250
268
|
return 0;
|
|
251
269
|
}
|
|
@@ -259,9 +277,15 @@ export async function cmdAccount(args: string[], deps: AccountDeps = {}): Promis
|
|
|
259
277
|
if (sub === "refresh") return await cmdRefresh(rest, deps);
|
|
260
278
|
if (sub === "auto-switch") return await cmdAutoSwitch(rest, deps);
|
|
261
279
|
if (sub === "alias" || sub === "rename") return await cmdAlias(rest, deps);
|
|
280
|
+
if (sub === "priority") return await cmdPriority(rest, deps);
|
|
262
281
|
if (sub === "remove") return await cmdRemove(rest, deps);
|
|
263
282
|
if (sub === "clear-cooldown") return await cmdClearCooldown(rest, deps);
|
|
264
283
|
if (sub === "add-key") return await cmdAddKey(rest, deps);
|
|
284
|
+
if (sub === "import") return await cmdImport(rest, deps);
|
|
285
|
+
if (sub === "main") {
|
|
286
|
+
const { cmdNativeMainAccount } = await import("./account-main");
|
|
287
|
+
return await cmdNativeMainAccount(rest, deps);
|
|
288
|
+
}
|
|
265
289
|
if (["login", "reauth", "code", "cancel", "reset-credits"].includes(sub ?? "")) {
|
|
266
290
|
const { handleAccountAuthCommand } = await import("./account-auth");
|
|
267
291
|
return await handleAccountAuthCommand(sub!, rest, deps) ?? 1;
|
package/src/cli/agent.ts
CHANGED
|
@@ -13,6 +13,13 @@ import {
|
|
|
13
13
|
type RuntimeApiDeps,
|
|
14
14
|
} from "./runtime-api";
|
|
15
15
|
|
|
16
|
+
interface WebSearchModelOption {
|
|
17
|
+
value: string;
|
|
18
|
+
model: string;
|
|
19
|
+
backend: "openai" | "anthropic";
|
|
20
|
+
authSlot?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
const USAGE = `Usage:
|
|
17
24
|
ocx agent [status] [--json]
|
|
18
25
|
ocx agent injection <status|set> [--model <id|->] [--effort <level|->]
|
|
@@ -20,7 +27,8 @@ const USAGE = `Usage:
|
|
|
20
27
|
ocx agent effort <status|set> [--main <level|->] [--subagent <level|->] [--json]
|
|
21
28
|
ocx agent subagents <status|set|clear> [model,model...] [--json]
|
|
22
29
|
ocx agent fallback <status|set|clear> [model,model...] [--poll-ms <5000-600000>] [--json]
|
|
23
|
-
ocx agent sidecar <status|web|vision> [--
|
|
30
|
+
ocx agent sidecar <status|web|vision> [--list] [--model <id|->]
|
|
31
|
+
[--backend web:<openai|anthropic|xai|gemini|exa|-> vision:<openai|anthropic|routed|->]
|
|
24
32
|
[--reasoning <level>] [--max-descriptions <n>] [--json]`;
|
|
25
33
|
|
|
26
34
|
function clearable(value: string | undefined): string | null | undefined {
|
|
@@ -152,6 +160,29 @@ async function sidecar(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
152
160
|
return;
|
|
153
161
|
}
|
|
154
162
|
if (section !== "web" && section !== "vision") throw new CliUsageError("sidecar must be web, vision, or status", USAGE);
|
|
163
|
+
// --list must be consumed BEFORE rejectArgs sees it. It prints the server's
|
|
164
|
+
// candidate set — the exact list the GUI picker shows (#2188): the server
|
|
165
|
+
// computes it once and every surface consumes it, so the CLI cannot drift.
|
|
166
|
+
const wantsList = takeFlag(args, "--list");
|
|
167
|
+
if (wantsList) {
|
|
168
|
+
rejectArgs(args, USAGE);
|
|
169
|
+
const settings = await runtimeRequest("/api/sidecar-settings", {}, deps) as {
|
|
170
|
+
webSearchModels?: WebSearchModelOption[];
|
|
171
|
+
visionModels?: Array<{ value: string; backend?: string; baseline?: boolean }>;
|
|
172
|
+
};
|
|
173
|
+
if (section === "web") {
|
|
174
|
+
const options = settings.webSearchModels ?? [];
|
|
175
|
+
printData(options, wantsJson, options.length === 0
|
|
176
|
+
? ["no runnable web-search sidecar models (log in to ChatGPT or Anthropic)"]
|
|
177
|
+
: options.map(option => `${option.value} [${option.backend}]${option.authSlot ? " (auth slot)" : ""}`));
|
|
178
|
+
} else {
|
|
179
|
+
const options = settings.visionModels ?? [];
|
|
180
|
+
printData(options, wantsJson, options.length === 0
|
|
181
|
+
? ["no eligible vision describers"]
|
|
182
|
+
: options.map(option => `${option.value}${option.backend ? ` [${option.backend}]` : ""}${option.baseline ? " (baseline)" : ""}`));
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
155
186
|
const model = takeOption(args, "--model");
|
|
156
187
|
const backend = takeOption(args, "--backend");
|
|
157
188
|
const reasoning = takeOption(args, "--reasoning");
|
|
@@ -163,6 +194,19 @@ async function sidecar(argv: string[], deps: RuntimeApiDeps): Promise<void> {
|
|
|
163
194
|
if (reasoning !== undefined) settings.reasoning = reasoning;
|
|
164
195
|
if (maxDescriptionsPerTurn !== undefined) settings.maxDescriptionsPerTurn = maxDescriptionsPerTurn;
|
|
165
196
|
if (Object.keys(settings).length === 0) throw new CliUsageError("at least one sidecar option is required", USAGE);
|
|
197
|
+
if (section === "web" && model !== undefined && model !== "-") {
|
|
198
|
+
const offered = await runtimeRequest("/api/sidecar-settings", {}, deps) as {
|
|
199
|
+
webSearchModels?: WebSearchModelOption[];
|
|
200
|
+
};
|
|
201
|
+
const requestedBackend = backend === "-" ? "openai" : backend;
|
|
202
|
+
const option = offered.webSearchModels?.find(candidate =>
|
|
203
|
+
(candidate.value === model || candidate.model === model)
|
|
204
|
+
&& (requestedBackend === undefined || candidate.backend === requestedBackend));
|
|
205
|
+
if (option) {
|
|
206
|
+
settings.model = option.model;
|
|
207
|
+
if (backend !== "-") settings.backend = option.backend;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
166
210
|
const body = section === "web" ? { webSearch: settings } : { vision: settings };
|
|
167
211
|
const result = await runtimeRequest("/api/sidecar-settings", { method: "PUT", body: JSON.stringify(body) }, deps);
|
|
168
212
|
printData(result, wantsJson, [`${section} sidecar settings updated.`]);
|
|
@@ -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
17
|
import { runtimeRequest } 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);
|
|
@@ -41,7 +43,11 @@ export async function applyProfile(
|
|
|
41
43
|
profile: DesktopProfile,
|
|
42
44
|
mode: Desktop3pConfigMode,
|
|
43
45
|
deps: ApplyProfileDeps = {},
|
|
44
|
-
): Promise<{ ok: boolean; path: string; reason?: string }> {
|
|
46
|
+
): Promise<{ ok: boolean; path: string; reason?: string; warning?: string }> {
|
|
47
|
+
// Explicit apply is an enable action. Persist intent before any Desktop write
|
|
48
|
+
// so a process crash cannot leave a gateway profile that startup immediately removes.
|
|
49
|
+
const desired = setIntegrationEnabled("claude-desktop", true);
|
|
50
|
+
if (!desired.ok) return { ok: false, path: "", reason: desired.message };
|
|
45
51
|
const config = loadConfig();
|
|
46
52
|
const state = await buildClaudeDesktopState(config, profile);
|
|
47
53
|
config.claudeCode = { ...(config.claudeCode ?? {}), desktopProfile: state.profile };
|
|
@@ -52,7 +58,7 @@ export async function applyProfile(
|
|
|
52
58
|
// serving process installs the map there; a local-only write leaves the
|
|
53
59
|
// daemon unable to decode aliases, and the provider rejects them (400).
|
|
54
60
|
const post = deps.postApplyImpl ?? (async (m: Desktop3pConfigMode, p: DesktopProfile) =>
|
|
55
|
-
runtimeRequest<{ ok?: boolean; path?: string; error?: string }>(
|
|
61
|
+
runtimeRequest<{ ok?: boolean; path?: string; error?: string; saved?: boolean; warning?: string }>(
|
|
56
62
|
"/api/claude-desktop/apply",
|
|
57
63
|
// The daemon's config may be older than what we just saved, so the
|
|
58
64
|
// profile travels with the request instead of being re-read there.
|
|
@@ -61,12 +67,26 @@ export async function applyProfile(
|
|
|
61
67
|
try {
|
|
62
68
|
const applied = await post(mode, state.profile);
|
|
63
69
|
if (applied.ok === false) return { ok: false, path: applied.path ?? "", reason: applied.error ?? "daemon apply failed" };
|
|
64
|
-
|
|
70
|
+
// Partial success: Desktop was written but the applied marker was not
|
|
71
|
+
// persisted. Pass the degradation up instead of reporting a clean apply.
|
|
72
|
+
const partial = (applied as { saved?: boolean; warning?: string }).saved === false;
|
|
73
|
+
return {
|
|
74
|
+
ok: true,
|
|
75
|
+
path: applied.path ?? "",
|
|
76
|
+
...(partial ? { warning: (applied as { warning?: string }).warning ?? "applied marker was not saved" } : {}),
|
|
77
|
+
};
|
|
65
78
|
} catch (error) {
|
|
66
79
|
return { ok: false, path: "", reason: error instanceof Error ? error.message : String(error) };
|
|
67
80
|
}
|
|
68
81
|
}
|
|
69
82
|
const allModels = await fetchAllModels(config);
|
|
83
|
+
// The toggle can persist OFF while fetchAllModels was awaiting (same race the
|
|
84
|
+
// management writers fence). Re-read persisted intent immediately before the
|
|
85
|
+
// writer; a lost race is a discriminated skip, not a write.
|
|
86
|
+
const { claudeDesktopIntegrationEnabledNow } = await import("../codex/desired-state");
|
|
87
|
+
if (!claudeDesktopIntegrationEnabledNow()) {
|
|
88
|
+
return { ok: false, path: "", reason: "desired_state_changed" };
|
|
89
|
+
}
|
|
70
90
|
const routed = filterCatalogVisibleModels(allModels, config).map(model => ({
|
|
71
91
|
provider: model.provider,
|
|
72
92
|
id: model.id,
|
|
@@ -79,6 +99,7 @@ export async function applyProfile(
|
|
|
79
99
|
config.apiKeys?.[0]?.key,
|
|
80
100
|
mode,
|
|
81
101
|
state.profile,
|
|
102
|
+
nativeContextLimits(config),
|
|
82
103
|
);
|
|
83
104
|
return { ok: result.written, path: result.path, reason: result.reason };
|
|
84
105
|
}
|
|
@@ -111,6 +132,9 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
111
132
|
return 1;
|
|
112
133
|
}
|
|
113
134
|
console.log(`Claude Desktop 설정을 적용했습니다: ${result.path}`);
|
|
135
|
+
// The write landed; only the bookkeeping marker did not. Saying nothing
|
|
136
|
+
// would leave the saved-vs-applied display wrong with no explanation.
|
|
137
|
+
if (result.warning) console.warn(`⚠️ ${result.warning}`);
|
|
114
138
|
console.log("Claude Desktop을 완전히 종료한 뒤 다시 열어 주세요.");
|
|
115
139
|
return 0;
|
|
116
140
|
} catch (error) {
|
|
@@ -175,6 +199,7 @@ export async function handleClaudeDesktopCommand(argv: string[], deps: ApplyProf
|
|
|
175
199
|
if (flags.includes("--apply")) {
|
|
176
200
|
const result = await applyProfile(reconciled, "static", deps);
|
|
177
201
|
if (!result.ok) { console.error(`프로필은 저장했지만 Desktop 적용에 실패했습니다: ${result.reason ?? "unknown error"}`); return 1; }
|
|
202
|
+
if (result.warning) console.warn(`⚠️ ${result.warning}`);
|
|
178
203
|
}
|
|
179
204
|
console.log("Claude Desktop 프로필을 가져왔습니다.");
|
|
180
205
|
return 0;
|