@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
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* them here breaks that cycle. `inject.ts` imports them back and re-exports the
|
|
8
8
|
* two public predicates, so external callers see no change.
|
|
9
9
|
*/
|
|
10
|
+
import { parseTomlString } from "./paths";
|
|
11
|
+
|
|
10
12
|
export const OCX_SECTION_MARKER = "# Auto-injected by opencodex";
|
|
11
13
|
|
|
12
14
|
export function isRootOpenaiBaseUrlLine(line: string): boolean {
|
|
@@ -16,7 +18,11 @@ export function isRootOpenaiBaseUrlLine(line: string): boolean {
|
|
|
16
18
|
export function tomlStringPattern(key: string): RegExp {
|
|
17
19
|
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
18
20
|
const keyToken = `(?:${escaped}|"${escaped}"|'${escaped}')`;
|
|
19
|
-
|
|
21
|
+
// The quoted value is captured WITH its quotes so callers can decode it as TOML.
|
|
22
|
+
// A basic string escapes backslashes, so a Windows path is stored doubled; reading
|
|
23
|
+
// the raw bytes back returned a path that matched nothing on disk and made the
|
|
24
|
+
// journal's recorded catalog path un-restorable (#1798).
|
|
25
|
+
return new RegExp(`^\\s*${keyToken}\\s*=\\s*("(?:\\\\.|[^"])*"|'[^']*')\\s*(?:#.*)?$`);
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
export function rootTomlString(content: string, key: string): string | null {
|
|
@@ -26,7 +32,7 @@ export function rootTomlString(content: string, key: string): string | null {
|
|
|
26
32
|
const pattern = tomlStringPattern(key);
|
|
27
33
|
for (const line of rootLines) {
|
|
28
34
|
const match = pattern.exec(line);
|
|
29
|
-
if (match?.[1]) return match[1].trim();
|
|
35
|
+
if (match?.[1]) return parseTomlString(match[1]).trim();
|
|
30
36
|
}
|
|
31
37
|
return null;
|
|
32
38
|
}
|
|
@@ -45,11 +51,39 @@ export function providerTableString(content: string, provider: string, key: stri
|
|
|
45
51
|
const pattern = tomlStringPattern(key);
|
|
46
52
|
for (let index = start + 1; index < lines.length && !/^\s*\[/.test(lines[index]); index += 1) {
|
|
47
53
|
const match = pattern.exec(lines[index]);
|
|
48
|
-
if (match?.[1]) return match[1].trim();
|
|
54
|
+
if (match?.[1]) return parseTomlString(match[1]).trim();
|
|
49
55
|
}
|
|
50
56
|
return null;
|
|
51
57
|
}
|
|
52
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Drop a root `openai_base_url` whose VALUE is the one a recorded injection wrote.
|
|
61
|
+
*
|
|
62
|
+
* #1798: the marker-adjacency rule below is formatting evidence, and the Codex app
|
|
63
|
+
* reserializes the file -- values kept, comments dropped. This rule is value evidence
|
|
64
|
+
* instead, so it still recognizes our URL after that rewrite. It is deliberately an
|
|
65
|
+
* EXACT value match against what we recorded writing: a user gateway we never wrote
|
|
66
|
+
* cannot match, so restore can never delete a URL that was not ours.
|
|
67
|
+
*/
|
|
68
|
+
export function stripJournaledOpenaiBaseUrl(content: string, injectedUrl: string | null): string {
|
|
69
|
+
if (!injectedUrl) return content;
|
|
70
|
+
const lines = content.split(String.fromCharCode(10));
|
|
71
|
+
const firstTable = lines.findIndex(l => /^\s*\[/.test(l));
|
|
72
|
+
const rootEnd = firstTable === -1 ? lines.length : firstTable;
|
|
73
|
+
const drop = new Set<number>();
|
|
74
|
+
for (let i = 0; i < rootEnd; i++) {
|
|
75
|
+
const line = lines[i]!;
|
|
76
|
+
if (!isRootOpenaiBaseUrlLine(line)) continue;
|
|
77
|
+
if (rootTomlString(line, "openai_base_url") !== injectedUrl) continue;
|
|
78
|
+
drop.add(i);
|
|
79
|
+
// Take an ownership marker directly above it too, so repeated cycles cannot
|
|
80
|
+
// accumulate orphaned comments.
|
|
81
|
+
if (i > 0 && lines[i - 1]!.includes(OCX_SECTION_MARKER)) drop.add(i - 1);
|
|
82
|
+
}
|
|
83
|
+
if (drop.size === 0) return content;
|
|
84
|
+
return lines.filter((_, i) => !drop.has(i)).join(String.fromCharCode(10));
|
|
85
|
+
}
|
|
86
|
+
|
|
53
87
|
export function hasInjectedOpenaiBaseUrl(content: string): boolean {
|
|
54
88
|
const lines = content.split("\n");
|
|
55
89
|
const firstTable = lines.findIndex(l => /^\s*\[/.test(l));
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sole reader/writer for integrations/codex.json.
|
|
3
|
+
*
|
|
4
|
+
* Provenance once disappeared when a corrupt record was treated as an empty one
|
|
5
|
+
* (005_disable_leaves_a_broken_file.md). Reads therefore validate the complete
|
|
6
|
+
* known shape, and updates refuse malformed bytes instead of manufacturing a new
|
|
7
|
+
* baseline over evidence we can no longer trust.
|
|
8
|
+
*/
|
|
9
|
+
import { mkdirSync, readFileSync } from "node:fs";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
import { atomicWriteFile, getConfigDir, withConfigMutationLockSync } from "../config";
|
|
12
|
+
import type {
|
|
13
|
+
CodexArtifactId,
|
|
14
|
+
CodexIntegrationRecord,
|
|
15
|
+
CodexProvenanceEntry,
|
|
16
|
+
CodexProvenanceLedger,
|
|
17
|
+
} from "./convergence-types";
|
|
18
|
+
|
|
19
|
+
const RECORD_FILENAME = "codex.json";
|
|
20
|
+
const LEGACY_TRANSITION_KEYS = new Set([
|
|
21
|
+
"nativeGeneration",
|
|
22
|
+
"currentTxId",
|
|
23
|
+
"generation",
|
|
24
|
+
"history",
|
|
25
|
+
"historySchedule",
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
function recordPath(): string {
|
|
29
|
+
return join(getConfigDir(), "integrations", RECORD_FILENAME);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
33
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function isMissingPathError(error: unknown): boolean {
|
|
37
|
+
return error instanceof Error && "code" in error && (error as NodeJS.ErrnoException).code === "ENOENT";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function invalid(message: string) {
|
|
41
|
+
return { kind: "invalid" as const, message };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function validateArtifact(value: unknown): value is CodexArtifactId {
|
|
45
|
+
if (!isPlainRecord(value) || typeof value.kind !== "string") return false;
|
|
46
|
+
switch (value.kind) {
|
|
47
|
+
case "config":
|
|
48
|
+
case "generated-profile":
|
|
49
|
+
case "models-cache":
|
|
50
|
+
case "injection-journal":
|
|
51
|
+
return true;
|
|
52
|
+
case "active-catalog":
|
|
53
|
+
case "history-manifest":
|
|
54
|
+
case "history-rollout":
|
|
55
|
+
return typeof value.canonicalPath === "string"
|
|
56
|
+
&& (value.kind === "active-catalog" || typeof value.stateDbId === "string");
|
|
57
|
+
case "catalog-backup":
|
|
58
|
+
return (value.form === "hashed" || value.form === "legacy")
|
|
59
|
+
&& typeof value.canonicalPath === "string";
|
|
60
|
+
case "history-row":
|
|
61
|
+
case "history-manifest-entry":
|
|
62
|
+
return typeof value.stateDbId === "string" && typeof value.threadId === "string";
|
|
63
|
+
default:
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function validateBaseline(value: unknown): boolean {
|
|
69
|
+
if (!isPlainRecord(value)) return false;
|
|
70
|
+
if (value.kind === "absent") return true;
|
|
71
|
+
return value.kind === "present"
|
|
72
|
+
&& typeof value.sha256 === "string"
|
|
73
|
+
&& typeof value.bytesBase64 === "string";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function validateEntry(value: unknown): value is CodexProvenanceEntry {
|
|
77
|
+
return isPlainRecord(value)
|
|
78
|
+
&& validateArtifact(value.artifact)
|
|
79
|
+
&& validateBaseline(value.baseline)
|
|
80
|
+
&& (typeof value.postImage === "string" || value.postImage === null)
|
|
81
|
+
&& typeof value.txId === "string"
|
|
82
|
+
&& typeof value.at === "string";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function validateLedger(value: unknown): value is CodexProvenanceLedger {
|
|
86
|
+
return isPlainRecord(value)
|
|
87
|
+
&& Array.isArray(value.entries)
|
|
88
|
+
&& value.entries.every(validateEntry);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function validateRecord(value: unknown): value is CodexIntegrationRecord {
|
|
92
|
+
return isPlainRecord(value)
|
|
93
|
+
&& value.version === 1
|
|
94
|
+
&& !Object.keys(value).some(key => LEGACY_TRANSITION_KEYS.has(key))
|
|
95
|
+
&& (value.provenance === undefined || validateLedger(value.provenance));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function readIntegrationRecordUnlocked() {
|
|
99
|
+
let raw: string;
|
|
100
|
+
try {
|
|
101
|
+
raw = readFileSync(recordPath(), "utf8");
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if (isMissingPathError(error)) return { kind: "missing" as const, record: null };
|
|
104
|
+
return invalid(`Codex integration record is unreadable: ${error instanceof Error ? error.message : String(error)}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let parsed: unknown;
|
|
108
|
+
try {
|
|
109
|
+
parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
|
|
110
|
+
} catch {
|
|
111
|
+
return invalid("Codex integration record contains invalid JSON");
|
|
112
|
+
}
|
|
113
|
+
if (!validateRecord(parsed)) {
|
|
114
|
+
return invalid("Codex integration record has an unsupported or malformed v1 shape");
|
|
115
|
+
}
|
|
116
|
+
return { kind: "ready" as const, record: parsed };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export const readIntegrationRecord = readIntegrationRecordUnlocked;
|
|
120
|
+
|
|
121
|
+
function copyUnknown(
|
|
122
|
+
previous: Record<string, unknown>,
|
|
123
|
+
next: Record<string, unknown>,
|
|
124
|
+
knownKeys: ReadonlySet<string>,
|
|
125
|
+
): Record<string, unknown> {
|
|
126
|
+
const merged: Record<string, unknown> = {};
|
|
127
|
+
for (const [key, value] of Object.entries(previous)) {
|
|
128
|
+
if (!knownKeys.has(key)) merged[key] = value;
|
|
129
|
+
}
|
|
130
|
+
return { ...merged, ...next };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function artifactKnownKeys(artifact: CodexArtifactId): ReadonlySet<string> {
|
|
134
|
+
switch (artifact.kind) {
|
|
135
|
+
case "config":
|
|
136
|
+
case "generated-profile":
|
|
137
|
+
case "models-cache":
|
|
138
|
+
case "injection-journal":
|
|
139
|
+
return new Set(["kind"]);
|
|
140
|
+
case "active-catalog":
|
|
141
|
+
return new Set(["kind", "canonicalPath"]);
|
|
142
|
+
case "catalog-backup":
|
|
143
|
+
return new Set(["kind", "form", "canonicalPath"]);
|
|
144
|
+
case "history-row":
|
|
145
|
+
case "history-manifest-entry":
|
|
146
|
+
return new Set(["kind", "stateDbId", "threadId"]);
|
|
147
|
+
case "history-manifest":
|
|
148
|
+
case "history-rollout":
|
|
149
|
+
return new Set(["kind", "stateDbId", "canonicalPath"]);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function mergeArtifact(previous: CodexArtifactId, next: CodexArtifactId): CodexArtifactId {
|
|
154
|
+
return copyUnknown(
|
|
155
|
+
previous as CodexArtifactId & Record<string, unknown>,
|
|
156
|
+
next as CodexArtifactId & Record<string, unknown>,
|
|
157
|
+
artifactKnownKeys(previous),
|
|
158
|
+
) as CodexArtifactId;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function mergeBaseline(
|
|
162
|
+
previous: CodexProvenanceEntry["baseline"],
|
|
163
|
+
next: CodexProvenanceEntry["baseline"],
|
|
164
|
+
): CodexProvenanceEntry["baseline"] {
|
|
165
|
+
const known = previous.kind === "present"
|
|
166
|
+
? new Set(["kind", "sha256", "bytesBase64"])
|
|
167
|
+
: new Set(["kind"]);
|
|
168
|
+
return copyUnknown(previous, next, known) as CodexProvenanceEntry["baseline"];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function knownArtifactIdentity(artifact: CodexArtifactId): string {
|
|
172
|
+
switch (artifact.kind) {
|
|
173
|
+
case "config":
|
|
174
|
+
case "generated-profile":
|
|
175
|
+
case "models-cache":
|
|
176
|
+
case "injection-journal":
|
|
177
|
+
return artifact.kind;
|
|
178
|
+
case "active-catalog":
|
|
179
|
+
return `${artifact.kind}\0${artifact.canonicalPath}`;
|
|
180
|
+
case "catalog-backup":
|
|
181
|
+
return `${artifact.kind}\0${artifact.form}\0${artifact.canonicalPath}`;
|
|
182
|
+
case "history-row":
|
|
183
|
+
case "history-manifest-entry":
|
|
184
|
+
return `${artifact.kind}\0${artifact.stateDbId}\0${artifact.threadId}`;
|
|
185
|
+
case "history-manifest":
|
|
186
|
+
case "history-rollout":
|
|
187
|
+
return `${artifact.kind}\0${artifact.stateDbId}\0${artifact.canonicalPath}`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function mergeEntry(previous: CodexProvenanceEntry, next: CodexProvenanceEntry): CodexProvenanceEntry {
|
|
192
|
+
const merged = copyUnknown(
|
|
193
|
+
previous,
|
|
194
|
+
next,
|
|
195
|
+
new Set(["artifact", "baseline", "postImage", "txId", "at"]),
|
|
196
|
+
);
|
|
197
|
+
return {
|
|
198
|
+
...merged,
|
|
199
|
+
artifact: mergeArtifact(previous.artifact, next.artifact),
|
|
200
|
+
baseline: mergeBaseline(previous.baseline, next.baseline),
|
|
201
|
+
} as CodexProvenanceEntry;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function mergeLedger(previous: CodexProvenanceLedger, next: CodexProvenanceLedger): CodexProvenanceLedger {
|
|
205
|
+
const unused = new Set(previous.entries.map((_, index) => index));
|
|
206
|
+
const entries = next.entries.map((entry, nextIndex) => {
|
|
207
|
+
let previousIndex = previous.entries.findIndex((candidate, index) =>
|
|
208
|
+
unused.has(index)
|
|
209
|
+
&& candidate.txId === entry.txId
|
|
210
|
+
&& candidate.at === entry.at
|
|
211
|
+
&& knownArtifactIdentity(candidate.artifact) === knownArtifactIdentity(entry.artifact));
|
|
212
|
+
if (previousIndex < 0 && unused.has(nextIndex)) previousIndex = nextIndex;
|
|
213
|
+
if (previousIndex < 0) return entry;
|
|
214
|
+
unused.delete(previousIndex);
|
|
215
|
+
return mergeEntry(previous.entries[previousIndex]!, entry);
|
|
216
|
+
});
|
|
217
|
+
return {
|
|
218
|
+
...copyUnknown(previous, next, new Set(["entries"])),
|
|
219
|
+
entries,
|
|
220
|
+
} as CodexProvenanceLedger;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function preserveExtensions(
|
|
224
|
+
previous: CodexIntegrationRecord,
|
|
225
|
+
next: CodexIntegrationRecord,
|
|
226
|
+
): CodexIntegrationRecord {
|
|
227
|
+
const merged = copyUnknown(previous, next, new Set(["version", "provenance"]));
|
|
228
|
+
if (previous.provenance && next.provenance) {
|
|
229
|
+
merged.provenance = mergeLedger(previous.provenance, next.provenance);
|
|
230
|
+
}
|
|
231
|
+
return merged as CodexIntegrationRecord;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Keep read, extension merge, and atomic replacement inside the config mutation
|
|
236
|
+
* coordinator. WP12 must call this function instead of recreating the incident's
|
|
237
|
+
* stale read/merge/write sequence at its own call site.
|
|
238
|
+
*/
|
|
239
|
+
export const updateIntegrationRecord = (
|
|
240
|
+
mutate: (record: CodexIntegrationRecord) => CodexIntegrationRecord,
|
|
241
|
+
) => {
|
|
242
|
+
try {
|
|
243
|
+
return withConfigMutationLockSync(() => {
|
|
244
|
+
const read = readIntegrationRecordUnlocked();
|
|
245
|
+
if (read.kind === "invalid") return read;
|
|
246
|
+
const previous: CodexIntegrationRecord = read.kind === "ready" ? read.record : { version: 1 };
|
|
247
|
+
const proposed = mutate(previous);
|
|
248
|
+
if (!validateRecord(proposed)) {
|
|
249
|
+
return { kind: "invalid", message: "Codex integration record update produced a malformed v1 shape" };
|
|
250
|
+
}
|
|
251
|
+
const record = preserveExtensions(previous, proposed);
|
|
252
|
+
if (!validateRecord(record)) {
|
|
253
|
+
return { kind: "invalid", message: "Codex integration record extension merge produced a malformed v1 shape" };
|
|
254
|
+
}
|
|
255
|
+
const path = recordPath();
|
|
256
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
257
|
+
atomicWriteFile(path, `${JSON.stringify(record, null, 2)}\n`);
|
|
258
|
+
return { kind: "updated", record };
|
|
259
|
+
});
|
|
260
|
+
} catch (error) {
|
|
261
|
+
return {
|
|
262
|
+
kind: "invalid",
|
|
263
|
+
message: `Codex integration record update failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { chmodSync, linkSync, mkdirSync, truncateSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
AtomicWriteResidualTempError,
|
|
6
|
+
AtomicWriteSecretResidualError,
|
|
7
|
+
atomicWriteFile,
|
|
8
|
+
resolveWriteTarget,
|
|
9
|
+
type AtomicWriteIO,
|
|
10
|
+
} from "../../config";
|
|
11
|
+
import {
|
|
12
|
+
assertCatalogWritePermit,
|
|
13
|
+
type CatalogWritePermit,
|
|
14
|
+
} from "../catalog-write-serialization";
|
|
15
|
+
import {
|
|
16
|
+
forgetEphemeralSecretPath,
|
|
17
|
+
hardenSecretPath,
|
|
18
|
+
} from "../../lib/windows-secret-acl";
|
|
19
|
+
|
|
20
|
+
export interface PreparedCatalogFileWrite {
|
|
21
|
+
readonly path: string;
|
|
22
|
+
readonly content: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type CatalogBackupPublication = "written" | "preserved";
|
|
26
|
+
|
|
27
|
+
export interface CatalogBackupWriteIO {
|
|
28
|
+
readonly resolveTarget: (path: string) => string;
|
|
29
|
+
readonly write: (path: string, content: string) => void;
|
|
30
|
+
readonly harden: (path: string) => void;
|
|
31
|
+
/** Must fail with EEXIST rather than replacing an existing destination. */
|
|
32
|
+
readonly publishNoReplace: (source: string, destination: string) => void;
|
|
33
|
+
readonly truncate: (path: string) => void;
|
|
34
|
+
readonly unlink: (path: string) => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let backupTempSequence = 0;
|
|
38
|
+
|
|
39
|
+
function isMissingPathError(error: unknown): boolean {
|
|
40
|
+
return (error as NodeJS.ErrnoException | undefined)?.code === "ENOENT";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isExistingPathError(error: unknown): boolean {
|
|
44
|
+
return (error as NodeJS.ErrnoException | undefined)?.code === "EEXIST";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function defaultBackupWriteIO(destinationPath: string): CatalogBackupWriteIO {
|
|
48
|
+
return {
|
|
49
|
+
resolveTarget: resolveWriteTarget,
|
|
50
|
+
write: (path, content) => writeFileSync(path, content, { encoding: "utf8", mode: 0o600 }),
|
|
51
|
+
harden: path => {
|
|
52
|
+
try { chmodSync(path, 0o600); } catch { /* platform may ignore chmod */ }
|
|
53
|
+
if (process.platform === "win32") {
|
|
54
|
+
hardenSecretPath(path, { required: true, timeoutMemoKey: destinationPath });
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
publishNoReplace: linkSync,
|
|
58
|
+
truncate: path => truncateSync(path, 0),
|
|
59
|
+
unlink: unlinkSync,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function removePublishedTemp(tempPath: string, io: CatalogBackupWriteIO): void {
|
|
64
|
+
try {
|
|
65
|
+
io.unlink(tempPath);
|
|
66
|
+
forgetEphemeralSecretPath(tempPath);
|
|
67
|
+
return;
|
|
68
|
+
} catch (firstError) {
|
|
69
|
+
if (isMissingPathError(firstError)) {
|
|
70
|
+
forgetEphemeralSecretPath(tempPath);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
io.unlink(tempPath);
|
|
75
|
+
forgetEphemeralSecretPath(tempPath);
|
|
76
|
+
return;
|
|
77
|
+
} catch (retryError) {
|
|
78
|
+
if (isMissingPathError(retryError)) {
|
|
79
|
+
forgetEphemeralSecretPath(tempPath);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
throw new AtomicWriteResidualTempError(tempPath, true, { cause: retryError });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function scrubAndRemoveUnpublishedTemp(
|
|
88
|
+
tempPath: string,
|
|
89
|
+
hardened: boolean,
|
|
90
|
+
io: CatalogBackupWriteIO,
|
|
91
|
+
cause: unknown,
|
|
92
|
+
): void {
|
|
93
|
+
let scrubbed = false;
|
|
94
|
+
try {
|
|
95
|
+
io.truncate(tempPath);
|
|
96
|
+
scrubbed = true;
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (isMissingPathError(error)) scrubbed = true;
|
|
99
|
+
else {
|
|
100
|
+
try {
|
|
101
|
+
io.write(tempPath, "");
|
|
102
|
+
scrubbed = true;
|
|
103
|
+
} catch { /* removal may still succeed */ }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let removed = false;
|
|
108
|
+
try {
|
|
109
|
+
io.unlink(tempPath);
|
|
110
|
+
removed = true;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (isMissingPathError(error)) removed = true;
|
|
113
|
+
else {
|
|
114
|
+
try {
|
|
115
|
+
io.unlink(tempPath);
|
|
116
|
+
removed = true;
|
|
117
|
+
} catch (retryError) {
|
|
118
|
+
if (isMissingPathError(retryError)) removed = true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!removed && !scrubbed) {
|
|
124
|
+
throw new AtomicWriteSecretResidualError(tempPath, { cause });
|
|
125
|
+
}
|
|
126
|
+
if (!removed && !hardened) {
|
|
127
|
+
try {
|
|
128
|
+
io.harden(tempPath);
|
|
129
|
+
hardened = true;
|
|
130
|
+
} catch { /* zero-byte residual is reported honestly */ }
|
|
131
|
+
}
|
|
132
|
+
if (removed) forgetEphemeralSecretPath(tempPath);
|
|
133
|
+
if (!removed) throw new AtomicWriteResidualTempError(tempPath, hardened, { cause });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function publishCatalogBackup(
|
|
137
|
+
prepared: PreparedCatalogFileWrite,
|
|
138
|
+
suppliedIo?: CatalogBackupWriteIO,
|
|
139
|
+
): CatalogBackupPublication {
|
|
140
|
+
const io = suppliedIo ?? defaultBackupWriteIO(prepared.path);
|
|
141
|
+
const target = io.resolveTarget(prepared.path);
|
|
142
|
+
if (!suppliedIo) mkdirSync(dirname(target), { recursive: true, mode: 0o700 });
|
|
143
|
+
const tempPath = `${target}.ocx.${process.pid}.backup.${++backupTempSequence}.tmp`;
|
|
144
|
+
let hardened = false;
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
io.write(tempPath, prepared.content);
|
|
148
|
+
io.harden(tempPath);
|
|
149
|
+
hardened = true;
|
|
150
|
+
io.publishNoReplace(tempPath, target);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
scrubAndRemoveUnpublishedTemp(tempPath, hardened, io, error);
|
|
153
|
+
if (isExistingPathError(error)) return "preserved";
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
removePublishedTemp(tempPath, io);
|
|
158
|
+
return "written";
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Replace the active catalog with the caller's already-prepared bytes. */
|
|
162
|
+
export function replaceActiveCodexCatalog(
|
|
163
|
+
permit: CatalogWritePermit,
|
|
164
|
+
owningCodexHome: string,
|
|
165
|
+
prepared: PreparedCatalogFileWrite,
|
|
166
|
+
io?: AtomicWriteIO,
|
|
167
|
+
): void {
|
|
168
|
+
assertCatalogWritePermit(permit, owningCodexHome);
|
|
169
|
+
atomicWriteFile(prepared.path, prepared.content, io);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Atomically publish the catalog-path-keyed immutable backup without clobbering. */
|
|
173
|
+
export function publishHashedCodexCatalogBackup(
|
|
174
|
+
permit: CatalogWritePermit,
|
|
175
|
+
owningCodexHome: string,
|
|
176
|
+
prepared: PreparedCatalogFileWrite,
|
|
177
|
+
io?: CatalogBackupWriteIO,
|
|
178
|
+
): CatalogBackupPublication {
|
|
179
|
+
assertCatalogWritePermit(permit, owningCodexHome);
|
|
180
|
+
return publishCatalogBackup(prepared, io);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Atomically publish the legacy immutable backup without clobbering. */
|
|
184
|
+
export function publishLegacyCodexCatalogBackup(
|
|
185
|
+
permit: CatalogWritePermit,
|
|
186
|
+
owningCodexHome: string,
|
|
187
|
+
prepared: PreparedCatalogFileWrite,
|
|
188
|
+
io?: CatalogBackupWriteIO,
|
|
189
|
+
): CatalogBackupPublication {
|
|
190
|
+
assertCatalogWritePermit(permit, owningCodexHome);
|
|
191
|
+
return publishCatalogBackup(prepared, io);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Replace Codex's models cache with the caller's already-prepared bytes. */
|
|
195
|
+
export function replaceCodexModelsCache(
|
|
196
|
+
permit: CatalogWritePermit,
|
|
197
|
+
owningCodexHome: string,
|
|
198
|
+
prepared: PreparedCatalogFileWrite,
|
|
199
|
+
io?: AtomicWriteIO,
|
|
200
|
+
): void {
|
|
201
|
+
assertCatalogWritePermit(permit, owningCodexHome);
|
|
202
|
+
atomicWriteFile(prepared.path, prepared.content, io);
|
|
203
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The history mutation boundary. Every byte Codex history owns is written here,
|
|
3
|
+
* and only while H is held.
|
|
4
|
+
*
|
|
5
|
+
* This module exists because the mutations are spread across three surfaces that
|
|
6
|
+
* do not share a transaction: SQLite rows, the backup manifest, and the rollout
|
|
7
|
+
* files. `syncCodexHistoryProvider` writes the manifest BEFORE its database
|
|
8
|
+
* transaction and patches rollouts inside it; restore writes rollouts, then the
|
|
9
|
+
* database, then the manifest, then ejects again
|
|
10
|
+
* (`src/codex/history-provider.ts:606-648,656-698`). A SQLite busy timeout
|
|
11
|
+
* serializes exactly one of those three, which is why an opposite-direction
|
|
12
|
+
* process could overtake through the other two.
|
|
13
|
+
*
|
|
14
|
+
* The permit argument is not decoration and not a type-level claim. Each entry
|
|
15
|
+
* point asks the lock owner at RUNTIME whether the permit it was handed is still
|
|
16
|
+
* live for the state database about to be written, because a permit leaked past
|
|
17
|
+
* its callback type-checks perfectly. A writer reached without H therefore fails
|
|
18
|
+
* closed rather than racing.
|
|
19
|
+
*
|
|
20
|
+
* Reachability: `src/codex/history-worker.ts` is the only permitted production
|
|
21
|
+
* root. Readers and probes stay in `history-provider.ts`; nothing in the CLI, the
|
|
22
|
+
* server, the guardian, `inject.ts` or `sync.ts` may reach these symbols.
|
|
23
|
+
*
|
|
24
|
+
* Design record: devlog/_fin/260804_codex_write_substrate/020_history_isolation.md.
|
|
25
|
+
*/
|
|
26
|
+
import { assertHistoryWritePermit, type HistoryWritePermit } from "../history-lock";
|
|
27
|
+
import {
|
|
28
|
+
restoreLegacyOpenaiHistory,
|
|
29
|
+
syncCodexHistoryProvider,
|
|
30
|
+
type CodexHistoryProvider,
|
|
31
|
+
type CodexHistorySyncResult,
|
|
32
|
+
} from "../history-provider";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Everything a history mutation needs, with no ambient state.
|
|
36
|
+
*
|
|
37
|
+
* The paths are explicit because a Worker is a separate process: it does not
|
|
38
|
+
* inherit the module-load `CODEX_HOME` that `history-provider.ts` resolves at
|
|
39
|
+
* import time (`:16`, `:22`), so a request that relied on those constants would
|
|
40
|
+
* silently address the wrong home.
|
|
41
|
+
*/
|
|
42
|
+
export interface HistoryWriteTarget {
|
|
43
|
+
/** Canonical, absolute; the same identity H was acquired for. */
|
|
44
|
+
readonly canonicalStateDbPath: string;
|
|
45
|
+
/** Canonical, absolute path of the backup manifest for that database. */
|
|
46
|
+
readonly canonicalBackupPath: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Apply opencodex routing to resumable history, or restore it to native.
|
|
51
|
+
*
|
|
52
|
+
* `provider` is the DURABLE operation's direction, resolved by the caller from
|
|
53
|
+
* the coordinator row — never a caller-supplied preference. The Worker passes
|
|
54
|
+
* what the row said, which is what stops a request from turning a restore into
|
|
55
|
+
* an apply.
|
|
56
|
+
*/
|
|
57
|
+
export function writeHistoryProviderTransition(
|
|
58
|
+
permit: HistoryWritePermit,
|
|
59
|
+
target: HistoryWriteTarget,
|
|
60
|
+
provider: CodexHistoryProvider,
|
|
61
|
+
): CodexHistorySyncResult {
|
|
62
|
+
assertHistoryWritePermit(permit, target.canonicalStateDbPath);
|
|
63
|
+
return syncCodexHistoryProvider(provider, target.canonicalStateDbPath, target.canonicalBackupPath);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Manifest-independent legacy ejection.
|
|
68
|
+
*
|
|
69
|
+
* Distinct from the generic restore above: it never reads, consumes, deletes or
|
|
70
|
+
* replaces the backup manifest. It does patch rollout metadata and returns a
|
|
71
|
+
* `files` count, so calling it "DB-only" would be wrong — the name says what it
|
|
72
|
+
* actually avoids.
|
|
73
|
+
*/
|
|
74
|
+
export function writeLegacyOpenaiHistoryRecovery(
|
|
75
|
+
permit: HistoryWritePermit,
|
|
76
|
+
target: HistoryWriteTarget,
|
|
77
|
+
): CodexHistorySyncResult {
|
|
78
|
+
assertHistoryWritePermit(permit, target.canonicalStateDbPath);
|
|
79
|
+
return restoreLegacyOpenaiHistory(target.canonicalStateDbPath);
|
|
80
|
+
}
|