@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,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observe and explicitly quarantine non-authoritative native-write coordinators.
|
|
3
|
+
*
|
|
4
|
+
* Default doctor runs use immutable SQLite reads so diagnostics cannot create
|
|
5
|
+
* WAL/SHM sidecars. Recovery is deliberately opt-in and moves, never deletes,
|
|
6
|
+
* only a file that is still the same private regular file observed beforehand.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import {
|
|
10
|
+
existsSync,
|
|
11
|
+
lstatSync,
|
|
12
|
+
realpathSync,
|
|
13
|
+
renameSync,
|
|
14
|
+
type Stats,
|
|
15
|
+
} from "node:fs";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { pathToFileURL } from "node:url";
|
|
18
|
+
|
|
19
|
+
import { Database, constants as sqliteConstants } from "bun:sqlite";
|
|
20
|
+
|
|
21
|
+
import { resolveCodexHomeDir } from "./home";
|
|
22
|
+
import {
|
|
23
|
+
CodexUserIdentityRefusal,
|
|
24
|
+
probeCodexCoordinatorNamespace,
|
|
25
|
+
resolveEffectiveUserIdentity,
|
|
26
|
+
samePathIdentity,
|
|
27
|
+
} from "./user-identity";
|
|
28
|
+
import {
|
|
29
|
+
CODEX_COORDINATOR_SCHEMA_VERSION,
|
|
30
|
+
readCodexCoordinatorState,
|
|
31
|
+
} from "./transition-state";
|
|
32
|
+
|
|
33
|
+
const IMMUTABLE_READONLY_FLAGS =
|
|
34
|
+
sqliteConstants.SQLITE_OPEN_READONLY | sqliteConstants.SQLITE_OPEN_URI;
|
|
35
|
+
|
|
36
|
+
export type FileIdentity = Pick<Stats, "dev" | "ino" | "size" | "mtimeMs" | "ctimeMs">;
|
|
37
|
+
|
|
38
|
+
export interface CodexCoordinatorDiagnosticEvidence {
|
|
39
|
+
sizeBytes: number;
|
|
40
|
+
schemaVersion: number;
|
|
41
|
+
tables: readonly string[];
|
|
42
|
+
transitionRows: number | null;
|
|
43
|
+
singletonRows: number | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type CodexCoordinatorDiagnostic =
|
|
47
|
+
| { kind: "absent"; path: string | null }
|
|
48
|
+
| { kind: "zero-byte"; path: string; identity: FileIdentity; evidence: CodexCoordinatorDiagnosticEvidence }
|
|
49
|
+
| { kind: "unversioned-empty"; path: string; identity: FileIdentity; evidence: CodexCoordinatorDiagnosticEvidence }
|
|
50
|
+
| { kind: "unversioned-nonempty"; path: string; identity: FileIdentity; evidence: CodexCoordinatorDiagnosticEvidence }
|
|
51
|
+
| { kind: "rowless"; path: string; identity: FileIdentity; evidence: CodexCoordinatorDiagnosticEvidence }
|
|
52
|
+
| { kind: "ready"; path: string; identity: FileIdentity; evidence: CodexCoordinatorDiagnosticEvidence }
|
|
53
|
+
| { kind: "unsupported"; path: string; identity: FileIdentity; version: number; evidence: CodexCoordinatorDiagnosticEvidence }
|
|
54
|
+
| { kind: "changed"; path: string }
|
|
55
|
+
| { kind: "unsafe"; path: string | null; reason: string }
|
|
56
|
+
| { kind: "unreadable"; path: string; reason: string; evidence?: CodexCoordinatorDiagnosticEvidence };
|
|
57
|
+
|
|
58
|
+
export type CodexCoordinatorRecoveryResult =
|
|
59
|
+
| { ok: true; backupPath: string }
|
|
60
|
+
| { ok: false; reason: string };
|
|
61
|
+
|
|
62
|
+
function errorCode(error: unknown): string {
|
|
63
|
+
return error && typeof error === "object" && "code" in error
|
|
64
|
+
? String((error as { code?: unknown }).code)
|
|
65
|
+
: "";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function sameIdentity(left: FileIdentity, right: FileIdentity): boolean {
|
|
69
|
+
return left.dev === right.dev
|
|
70
|
+
&& left.ino === right.ino
|
|
71
|
+
&& left.size === right.size
|
|
72
|
+
&& left.mtimeMs === right.mtimeMs
|
|
73
|
+
&& left.ctimeMs === right.ctimeMs;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function sameNodeAndSize(left: FileIdentity, right: FileIdentity): boolean {
|
|
77
|
+
return left.dev === right.dev && left.ino === right.ino && left.size === right.size;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function coordinatorPathWithoutCreation(): { kind: "absent"; path: string | null } | { kind: "path"; path: string } {
|
|
81
|
+
const identity = resolveEffectiveUserIdentity();
|
|
82
|
+
const canonicalCodexHome = realpathSync.native(resolveCodexHomeDir());
|
|
83
|
+
const namespace = probeCodexCoordinatorNamespace(identity);
|
|
84
|
+
if (namespace.status === "missing") return { kind: "absent", path: null };
|
|
85
|
+
|
|
86
|
+
const locks = join(namespace.root, "native-write-locks");
|
|
87
|
+
let locksEntry: Stats;
|
|
88
|
+
try {
|
|
89
|
+
locksEntry = lstatSync(locks);
|
|
90
|
+
} catch (cause) {
|
|
91
|
+
if (errorCode(cause) === "ENOENT") {
|
|
92
|
+
const digest = createHash("sha256").update(canonicalCodexHome).digest("hex");
|
|
93
|
+
return { kind: "absent", path: join(locks, `${digest}.sqlite`) };
|
|
94
|
+
}
|
|
95
|
+
throw new CodexUserIdentityRefusal("The coordinator lock directory cannot be inspected.", { cause });
|
|
96
|
+
}
|
|
97
|
+
if (locksEntry.isSymbolicLink() || !locksEntry.isDirectory()) {
|
|
98
|
+
throw new CodexUserIdentityRefusal("The coordinator lock namespace is not a real directory.");
|
|
99
|
+
}
|
|
100
|
+
if (identity.platform === "posix") {
|
|
101
|
+
if (locksEntry.uid !== identity.uid || (locksEntry.mode & 0o777) !== 0o700) {
|
|
102
|
+
throw new CodexUserIdentityRefusal("The coordinator lock namespace has unsafe ownership or permissions.");
|
|
103
|
+
}
|
|
104
|
+
} else if (!samePathIdentity(realpathSync.native(locks), locks, "win32")) {
|
|
105
|
+
throw new CodexUserIdentityRefusal("The coordinator lock namespace is redirected by a junction or reparse point.");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const digest = createHash("sha256").update(canonicalCodexHome).digest("hex");
|
|
109
|
+
return { kind: "path", path: join(locks, `${digest}.sqlite`) };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function inspectTarget(
|
|
113
|
+
path: string,
|
|
114
|
+
options: { allowSqliteSidecars?: boolean } = {},
|
|
115
|
+
): { kind: "absent" } | { kind: "file"; identity: FileIdentity } | { kind: "unsafe"; reason: string } {
|
|
116
|
+
let entry: Stats;
|
|
117
|
+
try {
|
|
118
|
+
entry = lstatSync(path);
|
|
119
|
+
} catch (cause) {
|
|
120
|
+
if (errorCode(cause) === "ENOENT") return { kind: "absent" };
|
|
121
|
+
return { kind: "unsafe", reason: "the coordinator file cannot be inspected" };
|
|
122
|
+
}
|
|
123
|
+
if (entry.isSymbolicLink() || !entry.isFile()) {
|
|
124
|
+
return { kind: "unsafe", reason: "the coordinator path is not a real file" };
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
if (!samePathIdentity(realpathSync.native(path), path)) {
|
|
128
|
+
return { kind: "unsafe", reason: "the coordinator path is redirected" };
|
|
129
|
+
}
|
|
130
|
+
} catch {
|
|
131
|
+
return { kind: "unsafe", reason: "the coordinator path cannot be resolved" };
|
|
132
|
+
}
|
|
133
|
+
if (process.platform !== "win32") {
|
|
134
|
+
const uid = process.getuid?.();
|
|
135
|
+
if (uid === undefined || entry.uid !== uid || (entry.mode & 0o777) !== 0o600) {
|
|
136
|
+
return { kind: "unsafe", reason: "the coordinator file has unsafe ownership or permissions" };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (!options.allowSqliteSidecars) {
|
|
140
|
+
for (const suffix of ["-journal", "-wal", "-shm"]) {
|
|
141
|
+
if (existsSync(`${path}${suffix}`)) {
|
|
142
|
+
return { kind: "unsafe", reason: `the coordinator has an active SQLite ${suffix.slice(1)} sidecar` };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return { kind: "file", identity: entry };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function classifyOpenedDatabase(
|
|
150
|
+
database: Database,
|
|
151
|
+
path: string,
|
|
152
|
+
identity: FileIdentity,
|
|
153
|
+
): CodexCoordinatorDiagnostic {
|
|
154
|
+
const version = database.query<{ user_version: number }, []>("PRAGMA user_version").get()?.user_version ?? 0;
|
|
155
|
+
const tables = database.query<{ name: string }, []>(
|
|
156
|
+
"SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name",
|
|
157
|
+
).all().map(row => row.name);
|
|
158
|
+
const baseEvidence = {
|
|
159
|
+
sizeBytes: identity.size,
|
|
160
|
+
schemaVersion: version,
|
|
161
|
+
tables,
|
|
162
|
+
transitionRows: null,
|
|
163
|
+
singletonRows: null,
|
|
164
|
+
} satisfies CodexCoordinatorDiagnosticEvidence;
|
|
165
|
+
if (version === 0) {
|
|
166
|
+
const evidence = tables.length === 0
|
|
167
|
+
? { ...baseEvidence, transitionRows: 0, singletonRows: 0 }
|
|
168
|
+
: baseEvidence;
|
|
169
|
+
return tables.length === 0
|
|
170
|
+
? { kind: "unversioned-empty", path, identity, evidence }
|
|
171
|
+
: { kind: "unversioned-nonempty", path, identity, evidence };
|
|
172
|
+
}
|
|
173
|
+
if (version !== CODEX_COORDINATOR_SCHEMA_VERSION) {
|
|
174
|
+
return { kind: "unsupported", path, identity, version, evidence: baseEvidence };
|
|
175
|
+
}
|
|
176
|
+
if (tables.length !== 1 || tables[0] !== "codex_transition_state") {
|
|
177
|
+
return tables.length === 0
|
|
178
|
+
? { kind: "rowless", path, identity, evidence: baseEvidence }
|
|
179
|
+
: { kind: "unreadable", path, reason: "the coordinator contains unexpected tables", evidence: baseEvidence };
|
|
180
|
+
}
|
|
181
|
+
let rowCounts: { total: number; singleton: number } | null;
|
|
182
|
+
try {
|
|
183
|
+
rowCounts = database.query<{ total: number; singleton: number }, []>(
|
|
184
|
+
"SELECT count(*) AS total, sum(CASE WHEN singleton = 1 THEN 1 ELSE 0 END) AS singleton FROM codex_transition_state",
|
|
185
|
+
).get() ?? null;
|
|
186
|
+
} catch {
|
|
187
|
+
return {
|
|
188
|
+
kind: "unreadable",
|
|
189
|
+
path,
|
|
190
|
+
reason: "the transition table schema is not recognized",
|
|
191
|
+
evidence: baseEvidence,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
const evidence = {
|
|
195
|
+
...baseEvidence,
|
|
196
|
+
transitionRows: rowCounts?.total ?? null,
|
|
197
|
+
singletonRows: rowCounts?.singleton ?? null,
|
|
198
|
+
};
|
|
199
|
+
if (!rowCounts || rowCounts.total === 0) return { kind: "rowless", path, identity, evidence };
|
|
200
|
+
if (rowCounts.total !== 1 || rowCounts.singleton !== 1) {
|
|
201
|
+
return {
|
|
202
|
+
kind: "unreadable",
|
|
203
|
+
path,
|
|
204
|
+
reason: "the coordinator does not contain exactly one singleton row",
|
|
205
|
+
evidence,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
readCodexCoordinatorState(database);
|
|
210
|
+
} catch {
|
|
211
|
+
return {
|
|
212
|
+
kind: "unreadable",
|
|
213
|
+
path,
|
|
214
|
+
reason: "the authoritative transition row is malformed",
|
|
215
|
+
evidence,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return { kind: "ready", path, identity, evidence };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function inspectCodexCoordinator(): CodexCoordinatorDiagnostic {
|
|
222
|
+
let resolved: ReturnType<typeof coordinatorPathWithoutCreation>;
|
|
223
|
+
try {
|
|
224
|
+
resolved = coordinatorPathWithoutCreation();
|
|
225
|
+
} catch (cause) {
|
|
226
|
+
return {
|
|
227
|
+
kind: "unsafe",
|
|
228
|
+
path: null,
|
|
229
|
+
reason: cause instanceof Error ? cause.message : String(cause),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (resolved.kind === "absent") return resolved;
|
|
233
|
+
return inspectCodexCoordinatorPath(resolved.path);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Inspect one already-resolved coordinator path without creating SQLite state. */
|
|
237
|
+
export function inspectCodexCoordinatorPath(path: string): CodexCoordinatorDiagnostic {
|
|
238
|
+
const target = inspectTarget(path);
|
|
239
|
+
if (target.kind === "absent") return { kind: "absent", path };
|
|
240
|
+
if (target.kind === "unsafe") return { kind: "unsafe", path, reason: target.reason };
|
|
241
|
+
|
|
242
|
+
let database: Database | undefined;
|
|
243
|
+
try {
|
|
244
|
+
const uri = `${pathToFileURL(path).href}?immutable=1`;
|
|
245
|
+
database = new Database(uri, IMMUTABLE_READONLY_FLAGS);
|
|
246
|
+
const result = classifyOpenedDatabase(database, path, target.identity);
|
|
247
|
+
const after = inspectTarget(path);
|
|
248
|
+
if (after.kind !== "file" || !sameIdentity(target.identity, after.identity)) {
|
|
249
|
+
return { kind: "changed", path };
|
|
250
|
+
}
|
|
251
|
+
// Size alone is not evidence that this is a non-authoritative remnant.
|
|
252
|
+
// Query the immutable snapshot too, so the recovery label means all three
|
|
253
|
+
// facts were observed together: zero bytes, schema version zero, no tables.
|
|
254
|
+
if (target.identity.size === 0 && result.kind === "unversioned-empty") {
|
|
255
|
+
return { kind: "zero-byte", path, identity: target.identity, evidence: result.evidence };
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
} catch (cause) {
|
|
259
|
+
return { kind: "unreadable", path, reason: cause instanceof Error ? cause.message : String(cause) };
|
|
260
|
+
} finally {
|
|
261
|
+
try { database?.close(); } catch { /* diagnostics already completed */ }
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function recoverable(diagnostic: CodexCoordinatorDiagnostic): diagnostic is Extract<
|
|
266
|
+
CodexCoordinatorDiagnostic,
|
|
267
|
+
{ kind: "zero-byte" }
|
|
268
|
+
> {
|
|
269
|
+
return diagnostic.kind === "zero-byte";
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function backupTimestamp(now: Date): string {
|
|
273
|
+
return now.toISOString().replace(/[-:.]/g, "");
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export function recoverZeroByteCodexCoordinator(now = new Date()): CodexCoordinatorRecoveryResult {
|
|
277
|
+
const observed = inspectCodexCoordinator();
|
|
278
|
+
if (!recoverable(observed)) {
|
|
279
|
+
if (observed.kind === "unsafe" || observed.kind === "unreadable") {
|
|
280
|
+
return { ok: false, reason: `coordinator state is ${observed.kind}: ${observed.reason}` };
|
|
281
|
+
}
|
|
282
|
+
return { ok: false, reason: `coordinator state is ${observed.kind}, not a recoverable zero-byte remnant` };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let database: Database | undefined;
|
|
286
|
+
let transactionOpen = false;
|
|
287
|
+
try {
|
|
288
|
+
database = new Database(observed.path, { readwrite: true, create: false });
|
|
289
|
+
database.exec("PRAGMA busy_timeout = 0; BEGIN IMMEDIATE");
|
|
290
|
+
transactionOpen = true;
|
|
291
|
+
const lockedEntry = inspectTarget(observed.path, { allowSqliteSidecars: true });
|
|
292
|
+
// SQLite may update file timestamps merely by opening a zero-byte database
|
|
293
|
+
// for BEGIN IMMEDIATE. Device/inode/size are the stable identity here; the
|
|
294
|
+
// transaction excludes content writers while we reclassify the database.
|
|
295
|
+
if (lockedEntry.kind !== "file" || !sameNodeAndSize(observed.identity, lockedEntry.identity)) {
|
|
296
|
+
return { ok: false, reason: "the coordinator changed before recovery acquired its SQLite lock" };
|
|
297
|
+
}
|
|
298
|
+
if (lockedEntry.identity.size !== 0) {
|
|
299
|
+
return { ok: false, reason: "the coordinator stopped being zero-byte before recovery" };
|
|
300
|
+
}
|
|
301
|
+
database.exec("ROLLBACK");
|
|
302
|
+
transactionOpen = false;
|
|
303
|
+
database.close();
|
|
304
|
+
database = undefined;
|
|
305
|
+
|
|
306
|
+
const finalEntry = inspectTarget(observed.path);
|
|
307
|
+
if (finalEntry.kind !== "file" || !sameIdentity(lockedEntry.identity, finalEntry.identity)) {
|
|
308
|
+
return { ok: false, reason: "the coordinator changed before the backup move" };
|
|
309
|
+
}
|
|
310
|
+
const backupPath = `${observed.path}.zero-byte-backup-${backupTimestamp(now)}`;
|
|
311
|
+
if (existsSync(backupPath)) return { ok: false, reason: "the same-directory backup path already exists" };
|
|
312
|
+
renameSync(observed.path, backupPath);
|
|
313
|
+
const backupEntry = inspectTarget(backupPath);
|
|
314
|
+
// The rename itself can advance ctime, so post-move verification uses the
|
|
315
|
+
// stable filesystem object and byte size. The full timestamp identity was
|
|
316
|
+
// already revalidated immediately before rename while the source existed.
|
|
317
|
+
if (backupEntry.kind !== "file" || !sameNodeAndSize(finalEntry.identity, backupEntry.identity) || existsSync(observed.path)) {
|
|
318
|
+
return { ok: false, reason: "the coordinator backup move could not be verified" };
|
|
319
|
+
}
|
|
320
|
+
return { ok: true, backupPath };
|
|
321
|
+
} catch (cause) {
|
|
322
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
323
|
+
const busy = errorCode(cause) === "SQLITE_BUSY" || errorCode(cause) === "SQLITE_LOCKED"
|
|
324
|
+
|| /database (?:is|table is) locked/i.test(message);
|
|
325
|
+
return { ok: false, reason: busy ? "the coordinator is busy; stop active sync/service writers and retry" : message };
|
|
326
|
+
} finally {
|
|
327
|
+
if (transactionOpen) {
|
|
328
|
+
try { database?.exec("ROLLBACK"); } catch { /* close releases the lock */ }
|
|
329
|
+
}
|
|
330
|
+
try { database?.close(); } catch { /* recovery already completed */ }
|
|
331
|
+
}
|
|
332
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { routedSlug, slugEquivalenceKey } from "../providers/slug-codec";
|
|
2
|
+
import type { OcxConfig } from "../types";
|
|
3
|
+
|
|
4
|
+
const MIGRATION_FIELD = "customModelCatalogMigration";
|
|
5
|
+
const MIGRATION_VERSION = 1;
|
|
6
|
+
|
|
7
|
+
type ConfigRecord = Record<string, unknown>;
|
|
8
|
+
|
|
9
|
+
interface SupportedMigrationState {
|
|
10
|
+
readonly record: ConfigRecord;
|
|
11
|
+
readonly legacyOwnedSlugs: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type ParsedMigrationState =
|
|
15
|
+
| { readonly kind: "absent" }
|
|
16
|
+
| { readonly kind: "supported"; readonly state: SupportedMigrationState }
|
|
17
|
+
| { readonly kind: "unsupported"; readonly value: unknown };
|
|
18
|
+
|
|
19
|
+
type CustomModelSlugSet =
|
|
20
|
+
| { readonly kind: "valid"; readonly byKey: ReadonlyMap<string, string> }
|
|
21
|
+
| { readonly kind: "invalid" };
|
|
22
|
+
|
|
23
|
+
function configRecord(value: unknown): ConfigRecord | null {
|
|
24
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
25
|
+
? value as ConfigRecord
|
|
26
|
+
: null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function canonicalRoutedSlug(value: unknown): string | null {
|
|
30
|
+
if (typeof value !== "string") return null;
|
|
31
|
+
const slug = value.trim();
|
|
32
|
+
const slash = slug.indexOf("/");
|
|
33
|
+
if (slash <= 0 || slash === slug.length - 1) return null;
|
|
34
|
+
const provider = slug.slice(0, slash).trim();
|
|
35
|
+
const modelId = slug.slice(slash + 1).trim();
|
|
36
|
+
if (!provider || !modelId || provider.includes("/")) return null;
|
|
37
|
+
return routedSlug(provider, modelId);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function canonicalSlugMap(values: readonly unknown[]): ReadonlyMap<string, string> | null {
|
|
41
|
+
const byKey = new Map<string, string>();
|
|
42
|
+
for (const value of values) {
|
|
43
|
+
const slug = canonicalRoutedSlug(value);
|
|
44
|
+
if (slug === null) return null;
|
|
45
|
+
byKey.set(slugEquivalenceKey(slug), slug);
|
|
46
|
+
}
|
|
47
|
+
return byKey;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function parseMigrationState(config: unknown): ParsedMigrationState {
|
|
51
|
+
const record = configRecord(config);
|
|
52
|
+
if (!record || !Object.hasOwn(record, MIGRATION_FIELD)) return { kind: "absent" };
|
|
53
|
+
const value = record[MIGRATION_FIELD];
|
|
54
|
+
const state = configRecord(value);
|
|
55
|
+
if (!state || state.version !== MIGRATION_VERSION || !Array.isArray(state.legacyOwnedSlugs)) {
|
|
56
|
+
return { kind: "unsupported", value };
|
|
57
|
+
}
|
|
58
|
+
const slugs = canonicalSlugMap(state.legacyOwnedSlugs);
|
|
59
|
+
if (slugs === null) return { kind: "unsupported", value };
|
|
60
|
+
return {
|
|
61
|
+
kind: "supported",
|
|
62
|
+
state: {
|
|
63
|
+
record: state,
|
|
64
|
+
legacyOwnedSlugs: [...slugs.values()].sort(),
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function customModelSlugs(config: unknown): CustomModelSlugSet {
|
|
70
|
+
const record = configRecord(config);
|
|
71
|
+
if (!record || record.customModels === undefined) {
|
|
72
|
+
return { kind: "valid", byKey: new Map() };
|
|
73
|
+
}
|
|
74
|
+
if (!Array.isArray(record.customModels)) return { kind: "invalid" };
|
|
75
|
+
const byKey = new Map<string, string>();
|
|
76
|
+
for (const value of record.customModels) {
|
|
77
|
+
const custom = configRecord(value);
|
|
78
|
+
if (!custom || typeof custom.provider !== "string" || typeof custom.modelId !== "string") {
|
|
79
|
+
return { kind: "invalid" };
|
|
80
|
+
}
|
|
81
|
+
const provider = custom.provider.trim();
|
|
82
|
+
const modelId = custom.modelId.trim();
|
|
83
|
+
if (!provider || !modelId || provider.includes("/")) return { kind: "invalid" };
|
|
84
|
+
const slug = routedSlug(provider, modelId);
|
|
85
|
+
byKey.set(slugEquivalenceKey(slug), slug);
|
|
86
|
+
}
|
|
87
|
+
return { kind: "valid", byKey };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function copyMigrationField(target: OcxConfig, source: OcxConfig): void {
|
|
91
|
+
const targetRecord = target as unknown as ConfigRecord;
|
|
92
|
+
const sourceRecord = source as unknown as ConfigRecord;
|
|
93
|
+
if (Object.hasOwn(sourceRecord, MIGRATION_FIELD)) {
|
|
94
|
+
targetRecord[MIGRATION_FIELD] = structuredClone(sourceRecord[MIGRATION_FIELD]);
|
|
95
|
+
} else {
|
|
96
|
+
delete targetRecord[MIGRATION_FIELD];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Project one-time legacy custom-model ownership onto a whole-config write.
|
|
102
|
+
*
|
|
103
|
+
* The persisted pre-write config is the only authority for pre-marker ownership.
|
|
104
|
+
* Unknown future/malformed state is carried forward byte-for-value and grants no
|
|
105
|
+
* deletion authority; an older binary must never reinterpret or erase it.
|
|
106
|
+
*/
|
|
107
|
+
export function projectCustomModelCatalogMigration(
|
|
108
|
+
persistedConfig: unknown,
|
|
109
|
+
candidateConfig: OcxConfig,
|
|
110
|
+
): OcxConfig {
|
|
111
|
+
const persistedState = parseMigrationState(persistedConfig);
|
|
112
|
+
const candidateState = parseMigrationState(candidateConfig);
|
|
113
|
+
const projected = { ...candidateConfig } as OcxConfig;
|
|
114
|
+
const projectedRecord = projected as unknown as ConfigRecord;
|
|
115
|
+
|
|
116
|
+
if (persistedState.kind === "unsupported") {
|
|
117
|
+
projectedRecord[MIGRATION_FIELD] = structuredClone(persistedState.value);
|
|
118
|
+
return projected;
|
|
119
|
+
}
|
|
120
|
+
if (persistedState.kind === "absent" && candidateState.kind === "unsupported") {
|
|
121
|
+
projectedRecord[MIGRATION_FIELD] = structuredClone(candidateState.value);
|
|
122
|
+
return projected;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const legacyByKey = new Map<string, string>();
|
|
126
|
+
const addLegacy = (slugs: readonly string[]): void => {
|
|
127
|
+
for (const slug of slugs) legacyByKey.set(slugEquivalenceKey(slug), slug);
|
|
128
|
+
};
|
|
129
|
+
if (persistedState.kind === "supported") addLegacy(persistedState.state.legacyOwnedSlugs);
|
|
130
|
+
if (candidateState.kind === "supported") addLegacy(candidateState.state.legacyOwnedSlugs);
|
|
131
|
+
|
|
132
|
+
const persistedCustom = customModelSlugs(persistedConfig);
|
|
133
|
+
const candidateCustom = customModelSlugs(candidateConfig);
|
|
134
|
+
// Only an absent persisted version means these rows can predate the ownership marker.
|
|
135
|
+
// Never add candidate-only or post-version models: those are born with custom-model-v1.
|
|
136
|
+
if (persistedState.kind === "absent" && persistedCustom.kind === "valid") {
|
|
137
|
+
for (const [key, slug] of persistedCustom.byKey) legacyByKey.set(key, slug);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Establish an empty v1 on the first custom-model add too: the cutover, not list
|
|
141
|
+
// non-emptiness, proves that candidate-only models can never be inferred as legacy.
|
|
142
|
+
// Unrelated saves for users who never configured custom models remain untouched.
|
|
143
|
+
const shouldVersion = persistedState.kind === "supported"
|
|
144
|
+
|| candidateState.kind === "supported"
|
|
145
|
+
|| (persistedState.kind === "absent"
|
|
146
|
+
&& ((persistedCustom.kind === "valid" && persistedCustom.byKey.size > 0)
|
|
147
|
+
|| (candidateCustom.kind === "valid" && candidateCustom.byKey.size > 0)));
|
|
148
|
+
if (!shouldVersion) {
|
|
149
|
+
delete projectedRecord[MIGRATION_FIELD];
|
|
150
|
+
return projected;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const priorRecord = persistedState.kind === "supported" ? persistedState.state.record : {};
|
|
154
|
+
const nextRecord = candidateState.kind === "supported" ? candidateState.state.record : {};
|
|
155
|
+
projectedRecord[MIGRATION_FIELD] = {
|
|
156
|
+
...structuredClone(priorRecord),
|
|
157
|
+
...structuredClone(nextRecord),
|
|
158
|
+
version: MIGRATION_VERSION,
|
|
159
|
+
legacyOwnedSlugs: [...legacyByKey.values()].sort(),
|
|
160
|
+
};
|
|
161
|
+
return projected;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Copy only the internal migration state after the projected write succeeds. */
|
|
165
|
+
export function adoptCustomModelCatalogMigration(
|
|
166
|
+
target: OcxConfig,
|
|
167
|
+
projected: OcxConfig,
|
|
168
|
+
): void {
|
|
169
|
+
copyMigrationField(target, projected);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Canonical slugs that may classify old, unmarked OpenCodex custom rows. */
|
|
173
|
+
export function legacyCustomModelCatalogSlugs(config: OcxConfig): ReadonlySet<string> {
|
|
174
|
+
const state = parseMigrationState(config);
|
|
175
|
+
return new Set(state.kind === "supported" ? state.state.legacyOwnedSlugs : []);
|
|
176
|
+
}
|