@iislee/opencodex 2.11.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +618 -74
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +152 -29
- package/src/images/plan.ts +23 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +220 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +865 -181
- package/src/server/lifecycle.ts +284 -13
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +101 -32
- package/src/server/management/model-routes.ts +189 -131
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +288 -32
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +845 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +9 -3
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
package/src/cli/doctor.ts
CHANGED
|
@@ -10,16 +10,36 @@
|
|
|
10
10
|
import { accessSync, constants, existsSync, readFileSync } from "node:fs";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import { dirname, join } from "node:path";
|
|
13
|
-
import { getConfigDir, getConfigPath, readConfigDiagnostics, readPid,
|
|
14
|
-
import { findLiveProxy } from "../server/proxy-liveness";
|
|
15
|
-
import {
|
|
13
|
+
import { getConfigDir, getConfigPath, readConfigDiagnostics, readPid, resolveEnvValue } from "../config";
|
|
14
|
+
import { findLiveProxy, type LiveProxy } from "../server/proxy-liveness";
|
|
15
|
+
import { BUN_RUNTIME_SOURCES } from "../lib/bun-runtime";
|
|
16
|
+
import type { BunRuntimeSource } from "../lib/bun-runtime";
|
|
16
17
|
import { maskAccountId } from "../lib/privacy";
|
|
17
18
|
import { PROXY_ENV_KEYS, proxyEnvPresent } from "../lib/proxy-env";
|
|
18
|
-
import {
|
|
19
|
+
import { LOCAL_MANAGEMENT_READ_PATHS } from "../lib/local-management-capability";
|
|
19
20
|
import { readCodexTokens } from "../codex/auth-collision";
|
|
21
|
+
import { withNativeMainSharedClaim } from "../codex/native-main-claim";
|
|
22
|
+
import { probeNativeProfileRecoveryState, resolveNativeProfileContext } from "../codex/native-profile-store";
|
|
23
|
+
import { NativeProfileError } from "../codex/native-profile-types";
|
|
20
24
|
import { collectOrcaCodexHomeDiagnostic, resolveCodexHomeDir as resolveCodexHomeDirImpl, isWslRuntime, listWslWindowsCodexHomes, wslAutomountRoot, type CodexHomeDeps } from "../codex/home";
|
|
25
|
+
import { scanCodexAgentRolesWithTomlModelFallback } from "../codex/subagent-model-fallback";
|
|
21
26
|
import { findCodexOnPath, isWindowsInteropDir } from "../codex/shim";
|
|
22
27
|
import { countPendingOpencodexHistory } from "../codex/history-provider";
|
|
28
|
+
import {
|
|
29
|
+
inspectCodexCoordinator,
|
|
30
|
+
recoverZeroByteCodexCoordinator,
|
|
31
|
+
type CodexCoordinatorDiagnostic,
|
|
32
|
+
} from "../codex/coordinator-doctor";
|
|
33
|
+
import {
|
|
34
|
+
inspectAbandonedResponseStateTemps,
|
|
35
|
+
reclaimAbandonedResponseStateTemps,
|
|
36
|
+
type ResponseStateTempRecoveryResult,
|
|
37
|
+
} from "../responses/state";
|
|
38
|
+
import {
|
|
39
|
+
CodexUserIdentityRefusal,
|
|
40
|
+
probeCodexCoordinatorNamespace,
|
|
41
|
+
resolveEffectiveUserIdentity,
|
|
42
|
+
} from "../codex/user-identity";
|
|
23
43
|
import { collectProjectCodexConfigWarnings, formatProjectCodexConfigWarningsForDoctor } from "../codex/project-config-warnings";
|
|
24
44
|
import { collectStartupHealth, startupHealthSummary } from "../codex/autostart-health";
|
|
25
45
|
import {
|
|
@@ -31,6 +51,10 @@ import {
|
|
|
31
51
|
} from "../codex/runtime";
|
|
32
52
|
import { CODEX_REAUTH_ACTION, collectOAuthHealthEntriesForCli, MASKED_ACCOUNT_FALLBACK, type OAuthHealthEntry } from "../oauth/health";
|
|
33
53
|
import { getAuthRefreshIntentLockPath, getAuthStorePath } from "../oauth/store";
|
|
54
|
+
import {
|
|
55
|
+
fetchBoundLocalManagementRead,
|
|
56
|
+
type LocalManagementReadDeps,
|
|
57
|
+
} from "../server/local-management-read-client";
|
|
34
58
|
export { resolveCodexHomeDir } from "../codex/home";
|
|
35
59
|
|
|
36
60
|
export type OAuthDoctorCheck = { level: "OK" | "WARN"; message: string };
|
|
@@ -479,36 +503,75 @@ export type WhamProbeResult = {
|
|
|
479
503
|
authenticated: boolean;
|
|
480
504
|
};
|
|
481
505
|
|
|
506
|
+
type NativeMainDoctorClaim = <T>(operation: () => Promise<T>) => Promise<T>;
|
|
507
|
+
|
|
508
|
+
export interface WhamProbeDeps {
|
|
509
|
+
withNativeMainClaim?: NativeMainDoctorClaim;
|
|
510
|
+
probeNativeMainRecoveryState?: typeof probeNativeProfileRecoveryState;
|
|
511
|
+
}
|
|
512
|
+
|
|
482
513
|
/**
|
|
483
514
|
* Replicate the runtime WHAM fetch shape (same URL, 8s timeout, main-token
|
|
484
515
|
* headers when present) so the probe fails exactly where the real path fails.
|
|
485
516
|
* `fetchImpl` is injectable for testing.
|
|
486
517
|
*/
|
|
487
|
-
export async function probeWham(
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
headers.Authorization = `Bearer ${tokens.access_token}`;
|
|
492
|
-
headers["ChatGPT-Account-Id"] = tokens.account_id;
|
|
493
|
-
}
|
|
518
|
+
export async function probeWham(
|
|
519
|
+
fetchImpl: typeof fetch = fetch,
|
|
520
|
+
deps: WhamProbeDeps = {},
|
|
521
|
+
): Promise<WhamProbeResult> {
|
|
494
522
|
const start = performance.now();
|
|
523
|
+
let authenticated = false;
|
|
495
524
|
try {
|
|
496
|
-
const
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
525
|
+
const context = resolveNativeProfileContext();
|
|
526
|
+
const withClaim = deps.withNativeMainClaim
|
|
527
|
+
?? (<T>(operation: () => Promise<T>) => withNativeMainSharedClaim(context, operation));
|
|
528
|
+
return await withClaim(async () => {
|
|
529
|
+
const recoveryState = (deps.probeNativeMainRecoveryState ?? probeNativeProfileRecoveryState)(context);
|
|
530
|
+
if (recoveryState !== "none") {
|
|
531
|
+
return {
|
|
532
|
+
ok: false,
|
|
533
|
+
status: null,
|
|
534
|
+
durationMs: Math.round(performance.now() - start),
|
|
535
|
+
classification: `native_main_recovery_${recoveryState}`,
|
|
536
|
+
authenticated: false,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
const tokens = readCodexTokens();
|
|
540
|
+
const headers: Record<string, string> = {};
|
|
541
|
+
if (tokens) {
|
|
542
|
+
headers.Authorization = `Bearer ${tokens.access_token}`;
|
|
543
|
+
headers["ChatGPT-Account-Id"] = tokens.account_id;
|
|
544
|
+
}
|
|
545
|
+
authenticated = !!tokens;
|
|
546
|
+
const resp = await fetchImpl(WHAM_USAGE_URL, { headers, signal: AbortSignal.timeout(PROBE_TIMEOUT_MS) });
|
|
547
|
+
const durationMs = Math.round(performance.now() - start);
|
|
548
|
+
return {
|
|
549
|
+
ok: resp.ok,
|
|
550
|
+
status: resp.status,
|
|
551
|
+
durationMs,
|
|
552
|
+
classification: resp.ok ? "ok" : `http_${resp.status}`,
|
|
553
|
+
authenticated,
|
|
554
|
+
};
|
|
555
|
+
});
|
|
505
556
|
} catch (err) {
|
|
506
557
|
const durationMs = Math.round(performance.now() - start);
|
|
558
|
+
if (
|
|
559
|
+
err instanceof NativeProfileError
|
|
560
|
+
&& (err.code === "NATIVE_MAIN_CLAIM_BUSY" || err.code === "NATIVE_MAIN_CLAIM_UNAVAILABLE")
|
|
561
|
+
) {
|
|
562
|
+
return {
|
|
563
|
+
ok: false,
|
|
564
|
+
status: null,
|
|
565
|
+
durationMs,
|
|
566
|
+
classification: err.code.toLowerCase(),
|
|
567
|
+
authenticated: false,
|
|
568
|
+
};
|
|
569
|
+
}
|
|
507
570
|
const name = err instanceof Error ? err.name : String(err);
|
|
508
571
|
const classification = name === "TimeoutError" || name === "AbortError"
|
|
509
572
|
? "timeout"
|
|
510
573
|
: "connect_error";
|
|
511
|
-
return { ok: false, status: null, durationMs, classification, authenticated
|
|
574
|
+
return { ok: false, status: null, durationMs, classification, authenticated };
|
|
512
575
|
}
|
|
513
576
|
}
|
|
514
577
|
|
|
@@ -523,6 +586,8 @@ export async function probeWham(fetchImpl: typeof fetch = fetch): Promise<WhamPr
|
|
|
523
586
|
export type ServiceMemoryData = {
|
|
524
587
|
pid: number;
|
|
525
588
|
bunVersion: string;
|
|
589
|
+
/** Launch-time provenance; absent for services installed before the marker existed. */
|
|
590
|
+
bunRuntimeSource?: BunRuntimeSource;
|
|
526
591
|
platform: string;
|
|
527
592
|
rss: number;
|
|
528
593
|
heapUsed: number;
|
|
@@ -558,20 +623,28 @@ function observedMemory(data: { rss: number; external?: number; arrayBuffers?: n
|
|
|
558
623
|
}
|
|
559
624
|
|
|
560
625
|
export async function fetchServiceMemory(
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
token: string | null,
|
|
564
|
-
fetchImpl: typeof fetch = fetch,
|
|
626
|
+
target: LiveProxy,
|
|
627
|
+
deps: LocalManagementReadDeps = {},
|
|
565
628
|
): Promise<ServiceMemoryReport> {
|
|
566
629
|
try {
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
|
|
630
|
+
const read = await fetchBoundLocalManagementRead(target, LOCAL_MANAGEMENT_READ_PATHS.systemMemory, {
|
|
631
|
+
...deps,
|
|
632
|
+
timeoutMs: SERVICE_MEMORY_TIMEOUT_MS,
|
|
570
633
|
});
|
|
634
|
+
if (read.kind === "unavailable") {
|
|
635
|
+
return read.reason === "transport"
|
|
636
|
+
? { status: "unreachable", error: "fetch failed" }
|
|
637
|
+
: { status: "unauthorized" };
|
|
638
|
+
}
|
|
639
|
+
const { response: res, targetPid } = read;
|
|
571
640
|
if (res.status === 401 || res.status === 403) return { status: "unauthorized" };
|
|
572
641
|
if (!res.ok) return { status: "unreachable", error: `http ${res.status}` };
|
|
573
642
|
const body = await res.json() as Partial<ServiceMemoryData>;
|
|
574
|
-
if (
|
|
643
|
+
if (
|
|
644
|
+
body.pid !== targetPid
|
|
645
|
+
|| typeof body.bunVersion !== "string"
|
|
646
|
+
|| typeof body.rss !== "number"
|
|
647
|
+
) {
|
|
575
648
|
return { status: "unreachable", error: "malformed response" };
|
|
576
649
|
}
|
|
577
650
|
return {
|
|
@@ -579,6 +652,9 @@ export async function fetchServiceMemory(
|
|
|
579
652
|
data: {
|
|
580
653
|
pid: body.pid,
|
|
581
654
|
bunVersion: body.bunVersion,
|
|
655
|
+
// Allowlisted independently of the server: an unrecognized wire value is
|
|
656
|
+
// treated as absent rather than echoed into user-facing guidance.
|
|
657
|
+
bunRuntimeSource: BUN_RUNTIME_SOURCES.find(source => source === body.bunRuntimeSource),
|
|
582
658
|
platform: typeof body.platform === "string" ? body.platform : "unknown",
|
|
583
659
|
rss: body.rss,
|
|
584
660
|
heapUsed: typeof body.heapUsed === "number" ? body.heapUsed : 0,
|
|
@@ -612,12 +688,118 @@ export async function fetchServiceMemory(
|
|
|
612
688
|
|
|
613
689
|
const mb = (bytes: number): string => `${Math.round(bytes / (1024 * 1024))}MB`;
|
|
614
690
|
|
|
691
|
+
export const RECLAIM_RESPONSE_TEMPS_FLAG = "--reclaim-response-temps";
|
|
692
|
+
export const RECOVER_ZERO_BYTE_COORDINATOR_FLAG = "--recover-zero-byte-coordinator";
|
|
693
|
+
/** Matches the dry run's entry bound so report and reclaim agree on a large backlog. */
|
|
694
|
+
const RESPONSE_TEMP_RECLAIM_MAX_CLEANUPS = 4_096;
|
|
695
|
+
/** Names the subsystem: other components mint temps with the same shape and are not covered. */
|
|
696
|
+
const CLEAN_RESPONSE_TEMP_LINE = " ok No abandoned response-state temp files.";
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Render the abandoned-temp section (testable without console capture).
|
|
700
|
+
*
|
|
701
|
+
* Report is the DEFAULT and reclaim is opt-in: `doctor` is a diagnostic an operator runs
|
|
702
|
+
* to understand a machine, so deleting files as a side effect of asking a question is the
|
|
703
|
+
* wrong default even for cache files.
|
|
704
|
+
*
|
|
705
|
+
* Counts come from `eligible`/`eligibleBytes`, never `matched`: `matched` is incremented
|
|
706
|
+
* before the file-type, age, boot-floor, and liveness gates, so reporting it would tell an
|
|
707
|
+
* operator that live-pid temps and young temps are "abandoned".
|
|
708
|
+
*/
|
|
709
|
+
export function formatResponseTempLines(
|
|
710
|
+
result: ResponseStateTempRecoveryResult,
|
|
711
|
+
reclaimed: boolean,
|
|
712
|
+
): string[] {
|
|
713
|
+
if (reclaimed) {
|
|
714
|
+
if (result.removed === 0 && result.failed === 0) return [CLEAN_RESPONSE_TEMP_LINE];
|
|
715
|
+
const lines = [` ok Reclaimed ${result.removed} abandoned response-state temp file(s), ${mb(result.bytesRemoved)} freed.`];
|
|
716
|
+
if (result.failed > 0) {
|
|
717
|
+
// Never "retried automatically": this command exists for the operator whose proxy will
|
|
718
|
+
// NOT start, and in that state nothing retries anything.
|
|
719
|
+
lines.push(` !! ${result.failed} file(s) could not be removed (in use or locked). Retried on the next reclaim — automatically while the proxy runs, otherwise re-run this command.`);
|
|
720
|
+
}
|
|
721
|
+
// `truncated`, not `eligible > removed + failed`: outside a dry run every eligible entry
|
|
722
|
+
// is unlinked or failed on the same iteration it is counted, so those two are always
|
|
723
|
+
// equal and the comparison never fired. An operator with a backlog past the budget was
|
|
724
|
+
// told the reclaim had finished.
|
|
725
|
+
if (result.truncated) {
|
|
726
|
+
lines.push(" !! Cleanup budget reached; files remain. Run the command again to continue.");
|
|
727
|
+
}
|
|
728
|
+
return lines;
|
|
729
|
+
}
|
|
730
|
+
if (result.eligible === 0) return [CLEAN_RESPONSE_TEMP_LINE];
|
|
731
|
+
const lines = [
|
|
732
|
+
` !! ${result.eligible} abandoned response-state temp file(s), ${mb(result.eligibleBytes)} reclaimable.`,
|
|
733
|
+
" These are interrupted snapshot writes (continuation cache only) and are safe to remove.",
|
|
734
|
+
" Reclaim them with: ocx doctor --reclaim-response-temps",
|
|
735
|
+
];
|
|
736
|
+
// The dry run skips the cleanup budget but is still bounded by the entry cap, so a large
|
|
737
|
+
// enough backlog makes this a floor rather than a total. Say so instead of letting an
|
|
738
|
+
// operator size the problem from a truncated count.
|
|
739
|
+
if (result.truncated) lines.push(" Scan stopped at its entry budget; the real total is higher.");
|
|
740
|
+
return lines;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
export function formatCoordinatorDoctorLines(diagnostic: CodexCoordinatorDiagnostic): string[] {
|
|
744
|
+
const pathLine = diagnostic.path ? [` path: ${diagnostic.path}`] : [];
|
|
745
|
+
const evidenceLines = "evidence" in diagnostic && diagnostic.evidence
|
|
746
|
+
? [
|
|
747
|
+
` size: ${diagnostic.evidence.sizeBytes} bytes; user_version: ${diagnostic.evidence.schemaVersion}`,
|
|
748
|
+
` tables: ${diagnostic.evidence.tables.length === 0 ? "none" : diagnostic.evidence.tables.join(", ")}`,
|
|
749
|
+
` transition rows: ${diagnostic.evidence.transitionRows ?? "not inspected"}; singleton=1 rows: ${diagnostic.evidence.singletonRows ?? "not inspected"}`,
|
|
750
|
+
]
|
|
751
|
+
: [];
|
|
752
|
+
switch (diagnostic.kind) {
|
|
753
|
+
case "absent":
|
|
754
|
+
return [" ok native-write coordinator not created yet", ...pathLine];
|
|
755
|
+
case "ready":
|
|
756
|
+
return [" ok native-write coordinator has an authoritative transition row", ...pathLine, ...evidenceLines];
|
|
757
|
+
case "zero-byte":
|
|
758
|
+
return [
|
|
759
|
+
" !! native-write coordinator is a zero-byte remnant and has no authority",
|
|
760
|
+
...pathLine,
|
|
761
|
+
...evidenceLines,
|
|
762
|
+
` Action: stop the OpenCodex proxy/service, then run ocx doctor ${RECOVER_ZERO_BYTE_COORDINATOR_FLAG} --yes`,
|
|
763
|
+
];
|
|
764
|
+
case "unversioned-empty":
|
|
765
|
+
return [
|
|
766
|
+
" !! native-write coordinator is a non-empty unversioned database; automatic recovery is refused",
|
|
767
|
+
...pathLine,
|
|
768
|
+
...evidenceLines,
|
|
769
|
+
];
|
|
770
|
+
case "rowless":
|
|
771
|
+
return [
|
|
772
|
+
" !! native-write coordinator has schema version 1 but no authoritative row; automatic recovery is refused",
|
|
773
|
+
...pathLine,
|
|
774
|
+
...evidenceLines,
|
|
775
|
+
];
|
|
776
|
+
case "unversioned-nonempty":
|
|
777
|
+
return [
|
|
778
|
+
" !! native-write coordinator is unversioned and contains unknown tables; automatic recovery is refused",
|
|
779
|
+
...pathLine,
|
|
780
|
+
...evidenceLines,
|
|
781
|
+
];
|
|
782
|
+
case "unsupported":
|
|
783
|
+
return [
|
|
784
|
+
` !! native-write coordinator schema version ${diagnostic.version} is unsupported; automatic recovery is refused`,
|
|
785
|
+
...pathLine,
|
|
786
|
+
...evidenceLines,
|
|
787
|
+
];
|
|
788
|
+
case "changed":
|
|
789
|
+
return [" -- native-write coordinator changed during diagnosis; re-run ocx doctor", ...pathLine];
|
|
790
|
+
case "unsafe":
|
|
791
|
+
return [` !! native-write coordinator path is unsafe: ${diagnostic.reason}`, ...pathLine];
|
|
792
|
+
case "unreadable":
|
|
793
|
+
return [` !! native-write coordinator is unreadable: ${diagnostic.reason}`, ...pathLine, ...evidenceLines];
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
615
797
|
/** Render the doctor "Memory / runtime" section lines (testable without console capture). */
|
|
616
798
|
export function formatServiceMemoryLines(report: ServiceMemoryReport): string[] {
|
|
617
799
|
const lines: string[] = [];
|
|
618
800
|
lines.push(` -- doctor process Bun ${Bun.version} (this is NOT the service process)`);
|
|
619
801
|
if (report.status === "unauthorized") {
|
|
620
|
-
lines.push(" --
|
|
802
|
+
lines.push(" -- local diagnostic capability unavailable — restart the running proxy with this OpenCodex version");
|
|
621
803
|
return lines;
|
|
622
804
|
}
|
|
623
805
|
if (report.status === "unreachable") {
|
|
@@ -652,12 +834,22 @@ export function formatServiceMemoryLines(report: ServiceMemoryReport): string[]
|
|
|
652
834
|
} else {
|
|
653
835
|
lines.push(" !! high RSS, indeterminate split — capture two doctor runs over time to see the trend");
|
|
654
836
|
}
|
|
655
|
-
// Version-claiming (never binary-claiming): the endpoint cannot distinguish
|
|
656
|
-
// the bundled binary from an OPENCODEX_BUN_PATH override of the same version.
|
|
657
837
|
if (d.platform === "win32" && d.eagerRelay?.reason === "auto-known-bad") {
|
|
658
838
|
lines.push(` service is running Bun ${d.bunVersion} on Windows — a version affected by the upstream Bun memory issue.`);
|
|
659
|
-
|
|
660
|
-
|
|
839
|
+
// The remediation depends on how the SERVICE was launched, which only the
|
|
840
|
+
// launch-time marker can answer. Telling someone to set OPENCODEX_BUN_PATH
|
|
841
|
+
// when it is already set is the bug this branch exists to avoid (#848).
|
|
842
|
+
if (d.bunRuntimeSource === "override") {
|
|
843
|
+
lines.push(` OPENCODEX_BUN_PATH is already active for this service — the override runtime is itself an affected version (unvalidated — own risk).`);
|
|
844
|
+
lines.push(" Options: point the override at a different runtime, or opt into streamMode \"eager-relay\" via PUT /api/settings (crash risk on this runtime; see docs).");
|
|
845
|
+
} else if (d.bunRuntimeSource === undefined) {
|
|
846
|
+
lines.push(" this service records no runtime origin (installed before provenance tracking), so OpenCodex cannot tell whether an override is already active.");
|
|
847
|
+
lines.push(" Reinstall the service to record it, or opt into streamMode \"eager-relay\" via PUT /api/settings (crash risk on this runtime; see docs).");
|
|
848
|
+
} else {
|
|
849
|
+
const origin = d.bunRuntimeSource === "process" ? "the runtime that launched it" : "the bundled runtime";
|
|
850
|
+
lines.push(` the service is using ${origin}. Options: wait for a bundled runtime update, or set OPENCODEX_BUN_PATH to a runtime you trust (unvalidated — own risk),`);
|
|
851
|
+
lines.push(" or opt into streamMode \"eager-relay\" via PUT /api/settings (crash risk on this runtime; see docs).");
|
|
852
|
+
}
|
|
661
853
|
}
|
|
662
854
|
return lines;
|
|
663
855
|
}
|
|
@@ -671,11 +863,21 @@ export function proxyDownRestartHint(input: {
|
|
|
671
863
|
proxyRunning: boolean;
|
|
672
864
|
port: number;
|
|
673
865
|
serviceViable: boolean;
|
|
866
|
+
/** Absent means "unknown"; the hint then keeps its pre-repair wording. */
|
|
867
|
+
serviceInstalled?: boolean;
|
|
868
|
+
serviceConflict?: boolean;
|
|
674
869
|
}): string | null {
|
|
675
870
|
if (input.proxyRunning) return null;
|
|
871
|
+
// `serviceViable` alone conflates "no service at all" with "registered but stale or
|
|
872
|
+
// stopped". Only the first wants `install`: re-registering an existing service costs a
|
|
873
|
+
// UAC prompt on Windows and can switch a WinSW backend to Task Scheduler. A conflict
|
|
874
|
+
// still needs uninstall-then-install, which repairService() refuses outright.
|
|
875
|
+
const installedButBroken = input.serviceInstalled === true && input.serviceConflict !== true;
|
|
676
876
|
const restart = input.serviceViable
|
|
677
877
|
? "Restart it with 'ocx service start' (service installed) or 'ocx start'."
|
|
678
|
-
:
|
|
878
|
+
: installedButBroken
|
|
879
|
+
? "Restart it with 'ocx start', or refresh the installed service: 'ocx service repair'."
|
|
880
|
+
: "Restart it with 'ocx start', or install the persistent service: 'ocx service install'.";
|
|
679
881
|
return `The ocx proxy is not running. Codex/Claude clients pinned to 127.0.0.1:${input.port} fail with errors like "error sending request for url (http://127.0.0.1:${input.port}/v1/responses)". ${restart}`;
|
|
680
882
|
}
|
|
681
883
|
|
|
@@ -704,6 +906,33 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
704
906
|
return;
|
|
705
907
|
}
|
|
706
908
|
|
|
909
|
+
if (args.includes(RECOVER_ZERO_BYTE_COORDINATOR_FLAG)) {
|
|
910
|
+
if (!args.includes("--yes")) {
|
|
911
|
+
console.log(`Recovery is explicit and creates a same-directory backup. Re-run: ocx doctor ${RECOVER_ZERO_BYTE_COORDINATOR_FLAG} --yes`);
|
|
912
|
+
process.exitCode = 1;
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
const diagnostics = readConfigDiagnostics().config;
|
|
916
|
+
const live = await findLiveProxy({
|
|
917
|
+
configFn: () => ({ port: diagnostics.port, hostname: diagnostics.hostname }),
|
|
918
|
+
});
|
|
919
|
+
if (live) {
|
|
920
|
+
console.log(`Recovery refused: OpenCodex proxy pid ${live.pid} is still running. Stop the proxy/service and retry.`);
|
|
921
|
+
process.exitCode = 1;
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
const recovered = recoverZeroByteCodexCoordinator();
|
|
925
|
+
if (!recovered.ok) {
|
|
926
|
+
console.log(`Recovery refused: ${recovered.reason}.`);
|
|
927
|
+
process.exitCode = 1;
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
console.log(`Moved the non-authoritative coordinator to ${recovered.backupPath}`);
|
|
931
|
+
console.log("Run `ocx sync` to retry Codex config injection. The backup was preserved and no Codex config/catalog file was changed by recovery.");
|
|
932
|
+
process.exitCode = 0;
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
|
|
707
936
|
console.log("opencodex doctor\n");
|
|
708
937
|
|
|
709
938
|
// Ordering note: the memory/runtime section renders after "Running proxy
|
|
@@ -719,6 +948,26 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
719
948
|
console.log(` ${row.exists ? "ok " : "-- "} ${row.label}: ${row.path}${flags ? ` (${flags})` : ""}`);
|
|
720
949
|
}
|
|
721
950
|
|
|
951
|
+
// Runs without the proxy on purpose: the worst accumulation happens when the proxy will
|
|
952
|
+
// not start, which is exactly when the in-process periodic reclaim never ticks.
|
|
953
|
+
const reclaimTemps = args.includes(RECLAIM_RESPONSE_TEMPS_FLAG);
|
|
954
|
+
console.log("\nResponse-state temp files");
|
|
955
|
+
// A typo must not silently degrade into "nothing to reclaim" — the operator would read the
|
|
956
|
+
// report as an answer to a question they never actually asked.
|
|
957
|
+
for (const arg of args) {
|
|
958
|
+
if (arg !== RECLAIM_RESPONSE_TEMPS_FLAG && /^--reclaim/.test(arg)) {
|
|
959
|
+
console.log(` !! Unrecognized flag ${arg}; did you mean ${RECLAIM_RESPONSE_TEMPS_FLAG}? Reporting only.`);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
for (const line of formatResponseTempLines(
|
|
963
|
+
// The reclaim budget matches the report budget: a report bounded by entries and a removal
|
|
964
|
+
// bounded by a smaller cleanup cap would tell an operator 816 and then silently free 512.
|
|
965
|
+
reclaimTemps
|
|
966
|
+
? reclaimAbandonedResponseStateTemps({ maxCleanups: RESPONSE_TEMP_RECLAIM_MAX_CLEANUPS })
|
|
967
|
+
: inspectAbandonedResponseStateTemps(),
|
|
968
|
+
reclaimTemps,
|
|
969
|
+
)) console.log(line);
|
|
970
|
+
|
|
722
971
|
const orcaHome = collectOrcaCodexHomeDiagnostic();
|
|
723
972
|
console.log("\nCodex app home targeting");
|
|
724
973
|
console.log(` ${orcaHome.mismatch ? "!! " : "ok "} Effective Codex home: ${orcaHome.effectiveCodexHome}`);
|
|
@@ -769,10 +1018,6 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
769
1018
|
const live = await findLiveProxy({
|
|
770
1019
|
configFn: () => ({ port: doctorConfig.port, hostname: doctorConfig.hostname }),
|
|
771
1020
|
});
|
|
772
|
-
const livePid = live ? live.pid : readPid();
|
|
773
|
-
const liveRuntime = live
|
|
774
|
-
? { pid: live.pid ?? 0, port: live.port, hostname: live.hostname }
|
|
775
|
-
: (livePid ? readRuntimePort(livePid) : null);
|
|
776
1021
|
|
|
777
1022
|
const currentProxyEnv = collectProxyEnv();
|
|
778
1023
|
const configuredProxy = collectConfiguredProxy();
|
|
@@ -812,13 +1057,11 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
812
1057
|
|
|
813
1058
|
console.log("\nMemory / runtime");
|
|
814
1059
|
{
|
|
815
|
-
|
|
816
|
-
if (!runtime || !live) {
|
|
1060
|
+
if (!live) {
|
|
817
1061
|
console.log(` -- doctor process Bun ${Bun.version} (this is NOT the service process)`);
|
|
818
1062
|
console.log(" -- no running ocx proxy found (no live pid/runtime record)");
|
|
819
1063
|
} else {
|
|
820
|
-
const
|
|
821
|
-
const report = await fetchServiceMemory(gracefulStopHost(runtime.hostname), runtime.port, token);
|
|
1064
|
+
const report = await fetchServiceMemory(live);
|
|
822
1065
|
for (const line of formatServiceMemoryLines(report)) console.log(line);
|
|
823
1066
|
}
|
|
824
1067
|
}
|
|
@@ -833,6 +1076,24 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
833
1076
|
// Codex app until the one-time migration lands. Read-only probe (readonly sqlite, 100ms
|
|
834
1077
|
// busy timeout) — reports state, never mutates.
|
|
835
1078
|
console.log("\nCodex history migration");
|
|
1079
|
+
// The history failure messages point here; make the visit worthwhile by
|
|
1080
|
+
// probing the coordinator namespace the locks live in. The probe exercises
|
|
1081
|
+
// identity, runtime-root, and permission checks without taking any lock or
|
|
1082
|
+
// creating anything (a doctor run must observe, not initialize).
|
|
1083
|
+
try {
|
|
1084
|
+
const identity = resolveEffectiveUserIdentity();
|
|
1085
|
+
const probe = probeCodexCoordinatorNamespace(identity);
|
|
1086
|
+
if (probe.status === "missing") {
|
|
1087
|
+
console.log(" ok history coordinator namespace not created yet (no history operation has run)");
|
|
1088
|
+
} else {
|
|
1089
|
+
console.log(" ok history coordinator namespace resolves");
|
|
1090
|
+
}
|
|
1091
|
+
} catch (cause) {
|
|
1092
|
+
const reason = cause instanceof CodexUserIdentityRefusal ? cause.message : String(cause);
|
|
1093
|
+
console.log(` -- history coordinator namespace refused: ${reason}`);
|
|
1094
|
+
}
|
|
1095
|
+
console.log("\nCodex native-write coordinator");
|
|
1096
|
+
for (const line of formatCoordinatorDoctorLines(inspectCodexCoordinator())) console.log(line);
|
|
836
1097
|
const pending = countPendingOpencodexHistory();
|
|
837
1098
|
if (pending.failed) {
|
|
838
1099
|
console.log(" -- state DB locked or unreadable (Codex app open?) — migration state unknown");
|
|
@@ -852,6 +1113,15 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
852
1113
|
}
|
|
853
1114
|
}
|
|
854
1115
|
|
|
1116
|
+
console.log("\nCodex agent role files");
|
|
1117
|
+
const tomlFallbackRoles = scanCodexAgentRolesWithTomlModelFallback(resolveCodexHomeDirImpl());
|
|
1118
|
+
if (tomlFallbackRoles.length === 0) {
|
|
1119
|
+
console.log(" ok no per-role model_fallback fields in $CODEX_HOME/agents/*.toml");
|
|
1120
|
+
} else {
|
|
1121
|
+
console.log(` [WARN] ${tomlFallbackRoles.length} agent role file${tomlFallbackRoles.length === 1 ? "" : "s"} contain${tomlFallbackRoles.length === 1 ? "s" : ""} \`model_fallback\`: ${tomlFallbackRoles.join(", ")}`);
|
|
1122
|
+
console.log(" Codex >= 0.146 rejects that field as unknown and skips the whole role. Move the chains to opencodex config `subagentModelFallbackByModel` (keyed by primary model) and remove the field from the TOML files.");
|
|
1123
|
+
}
|
|
1124
|
+
|
|
855
1125
|
const dual = collectWslDualInstall();
|
|
856
1126
|
if (dual.wsl) {
|
|
857
1127
|
console.log("\nWSL Codex installs");
|
|
@@ -891,6 +1161,8 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
891
1161
|
proxyRunning: Boolean(live),
|
|
892
1162
|
port: live?.port ?? doctorConfig.port ?? 10100,
|
|
893
1163
|
serviceViable: startup.serviceViable,
|
|
1164
|
+
serviceInstalled: startup.serviceInstalled,
|
|
1165
|
+
serviceConflict: startup.serviceConflict,
|
|
894
1166
|
});
|
|
895
1167
|
if (proxyDown) hints.push(proxyDown);
|
|
896
1168
|
for (const row of providerApiKeys) {
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Align Grok and Claude Desktop files with the durable switches during `ocx ensure`.
|
|
3
|
+
*
|
|
4
|
+
* handleEnsure used to load config once, then health-probe / model-sync / spawn,
|
|
5
|
+
* and only afterwards mutate ~/.grok/config.toml and the Desktop library from
|
|
6
|
+
* that snapshot. An OFF→ON flip in that window stripped a freshly enabled fence
|
|
7
|
+
* or deleted a freshly applied Desktop profile; ON→OFF rewrote the files the
|
|
8
|
+
* user had just turned off. Re-read persisted desired state immediately before
|
|
9
|
+
* each external-file mutation, and use that current config for sync inputs.
|
|
10
|
+
*/
|
|
11
|
+
import { loadConfig } from "../config";
|
|
12
|
+
import { stripGrokConfig, type GrokInjectResult } from "../grok/inject";
|
|
13
|
+
import { removeDesktop3pStandardPivot } from "../claude/desktop-3p";
|
|
14
|
+
import {
|
|
15
|
+
claudeDesktopIntegrationEnabled,
|
|
16
|
+
shouldSyncGrokOnStart,
|
|
17
|
+
} from "../codex/desired-state";
|
|
18
|
+
import type { OcxConfig } from "../types";
|
|
19
|
+
|
|
20
|
+
export function grokSyncFailureMessage(err: unknown): string {
|
|
21
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
22
|
+
return `Grok Build config sync failed: ${detail}. `
|
|
23
|
+
+ "~/.grok/config.toml may still point at a previous proxy port — "
|
|
24
|
+
+ "run 'ocx ensure' (or apply from the dashboard's Grok page) to repoint it.";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface EnsureDesiredIntegrationsDeps {
|
|
28
|
+
loadConfig: () => OcxConfig;
|
|
29
|
+
stripGrokConfig: typeof stripGrokConfig;
|
|
30
|
+
syncGrokConfig: (
|
|
31
|
+
port: number,
|
|
32
|
+
config: OcxConfig,
|
|
33
|
+
opts?: { hostname?: string },
|
|
34
|
+
) => Promise<GrokInjectResult>;
|
|
35
|
+
removeDesktop3pStandardPivot: typeof removeDesktop3pStandardPivot;
|
|
36
|
+
log?: (message: string) => void;
|
|
37
|
+
error?: (message: string) => void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function defaultSyncGrokConfig(
|
|
41
|
+
port: number,
|
|
42
|
+
config: OcxConfig,
|
|
43
|
+
opts: { hostname?: string } = {},
|
|
44
|
+
): Promise<GrokInjectResult> {
|
|
45
|
+
const { syncGrokConfig } = await import("../grok/sync");
|
|
46
|
+
return syncGrokConfig(port, config, opts);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const productionDeps: EnsureDesiredIntegrationsDeps = {
|
|
50
|
+
loadConfig,
|
|
51
|
+
stripGrokConfig,
|
|
52
|
+
syncGrokConfig: defaultSyncGrokConfig,
|
|
53
|
+
removeDesktop3pStandardPivot,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
function io(deps: EnsureDesiredIntegrationsDeps): {
|
|
57
|
+
log: (message: string) => void;
|
|
58
|
+
error: (message: string) => void;
|
|
59
|
+
} {
|
|
60
|
+
return {
|
|
61
|
+
log: deps.log ?? (message => console.log(message)),
|
|
62
|
+
error: deps.error ?? (message => console.error(message)),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Keep ~/.grok/config.toml aligned with the durable Grok switch.
|
|
68
|
+
*
|
|
69
|
+
* `handleStart` already gates inject on `shouldSyncGrokOnStart`. `ocx ensure`
|
|
70
|
+
* used to call `syncGrokConfig` unconditionally, so a dashboard/update/restart
|
|
71
|
+
* path that lands in ensure rewrote the fence while the switch stayed OFF.
|
|
72
|
+
* When the switch is OFF, strip any leftover managed block instead of injecting.
|
|
73
|
+
*/
|
|
74
|
+
export async function ensureGrokFenceMatchesDesired(
|
|
75
|
+
port: number,
|
|
76
|
+
opts: { hostname?: string } = {},
|
|
77
|
+
deps: EnsureDesiredIntegrationsDeps = productionDeps,
|
|
78
|
+
): Promise<void> {
|
|
79
|
+
const config = deps.loadConfig();
|
|
80
|
+
const { log, error } = io(deps);
|
|
81
|
+
if (!shouldSyncGrokOnStart(config)) {
|
|
82
|
+
try {
|
|
83
|
+
const grok = deps.stripGrokConfig();
|
|
84
|
+
if (grok.changed) log(` ↩️ ${grok.message}`);
|
|
85
|
+
else if (!grok.ok) error(`⚠️ ${grok.message}`);
|
|
86
|
+
} catch (err) {
|
|
87
|
+
error(`⚠️ ${grokSyncFailureMessage(err)}`);
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const hostname = opts.hostname ?? config.hostname;
|
|
93
|
+
const g = await deps.syncGrokConfig(
|
|
94
|
+
port,
|
|
95
|
+
config,
|
|
96
|
+
hostname !== undefined ? { hostname } : {},
|
|
97
|
+
);
|
|
98
|
+
if (g.changed) log(" + Grok Build config updated (~/.grok/config.toml)");
|
|
99
|
+
else if (!g.ok) error(`⚠️ ${g.message}`);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
error(`⚠️ ${grokSyncFailureMessage(err)}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* When Claude Desktop is durably OFF, clear any leftover owned gateway profile.
|
|
107
|
+
* ensure/update used to leave Claude-3p residue in place after a failed disable
|
|
108
|
+
* (drifted fingerprint), so the Integrations card kept looking applied/stale.
|
|
109
|
+
*/
|
|
110
|
+
export function ensureClaudeDesktopMatchesDesired(
|
|
111
|
+
deps: EnsureDesiredIntegrationsDeps = productionDeps,
|
|
112
|
+
): void {
|
|
113
|
+
const config = deps.loadConfig();
|
|
114
|
+
const { log, error } = io(deps);
|
|
115
|
+
if (claudeDesktopIntegrationEnabled(config)) return;
|
|
116
|
+
try {
|
|
117
|
+
const removed = deps.removeDesktop3pStandardPivot({
|
|
118
|
+
appliedFingerprint: config.claudeCode?.desktopProfile?.appliedFingerprint ?? null,
|
|
119
|
+
});
|
|
120
|
+
if (removed.ok && removed.changed) {
|
|
121
|
+
log(" ↩️ Claude Desktop integration residue removed.");
|
|
122
|
+
} else if (!removed.ok) {
|
|
123
|
+
error(`⚠️ Claude Desktop cleanup skipped: ${removed.reason ?? removed.kind}.`);
|
|
124
|
+
}
|
|
125
|
+
} catch (err) {
|
|
126
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
127
|
+
error(`⚠️ Claude Desktop cleanup failed: ${detail}.`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export type EnsureDesiredIntegrationsBranch =
|
|
132
|
+
| { kind: "live"; hostname?: string }
|
|
133
|
+
| { kind: "spawned" };
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Reconcile the two external integration files after either ensure race window.
|
|
137
|
+
* Only the live proxy's observed bind host crosses this boundary; persisted
|
|
138
|
+
* config is deliberately loaded inside each mutation helper.
|
|
139
|
+
*/
|
|
140
|
+
export async function reconcileEnsureDesiredIntegrations(
|
|
141
|
+
port: number,
|
|
142
|
+
branch: EnsureDesiredIntegrationsBranch,
|
|
143
|
+
deps: EnsureDesiredIntegrationsDeps = productionDeps,
|
|
144
|
+
): Promise<void> {
|
|
145
|
+
const liveHost = branch.kind === "live" ? branch.hostname : undefined;
|
|
146
|
+
await ensureGrokFenceMatchesDesired(
|
|
147
|
+
port,
|
|
148
|
+
liveHost ? { hostname: liveHost } : {},
|
|
149
|
+
deps,
|
|
150
|
+
);
|
|
151
|
+
ensureClaudeDesktopMatchesDesired(deps);
|
|
152
|
+
}
|