@iislee/opencodex 2.11.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +618 -74
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +152 -29
- package/src/images/plan.ts +23 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +220 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +865 -181
- package/src/server/lifecycle.ts +284 -13
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +101 -32
- package/src/server/management/model-routes.ts +189 -131
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +288 -32
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +845 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +9 -3
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
package/src/codex/journal.ts
CHANGED
|
@@ -5,7 +5,16 @@ import { atomicWriteFile } from "../config";
|
|
|
5
5
|
import { hasInjectedCodexRouting } from "./injected-marker";
|
|
6
6
|
import { CODEX_HOME, CODEX_CONFIG_PATH, CODEX_PROFILE_PATH } from "./paths";
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Exported so that anything reasoning ABOUT the journal points at the journal.
|
|
10
|
+
*
|
|
11
|
+
* The Codex admission snapshot re-derived this path by hand and got it wrong in
|
|
12
|
+
* both halves — wrong directory and wrong filename — so its "journal identity"
|
|
13
|
+
* watched a file nothing writes. The fixture re-derived it the same wrong way,
|
|
14
|
+
* agreed with the producer, and the pair stayed green. One exported constant
|
|
15
|
+
* removes the opportunity.
|
|
16
|
+
*/
|
|
17
|
+
export const JOURNAL_PATH = join(CODEX_HOME, "opencodex-journal.json");
|
|
9
18
|
|
|
10
19
|
interface Journal {
|
|
11
20
|
version: 1;
|
|
@@ -13,6 +22,24 @@ interface Journal {
|
|
|
13
22
|
originalProfile: string | null;
|
|
14
23
|
injectedConfigHash?: string;
|
|
15
24
|
injectedProfileHash?: string | null;
|
|
25
|
+
/**
|
|
26
|
+
* The exact root `openai_base_url` this injection wrote, when it wrote one.
|
|
27
|
+
*
|
|
28
|
+
* #1798: ownership used to be inferred from a marker COMMENT on the preceding line,
|
|
29
|
+
* which a reserializing Codex app deletes while keeping the value. Recording the value
|
|
30
|
+
* we actually wrote makes ownership provable from evidence rather than from formatting,
|
|
31
|
+
* and it is what lets restore tell OUR loopback URL apart from a gateway the user set.
|
|
32
|
+
*/
|
|
33
|
+
injectedOpenaiBaseUrl?: string | null;
|
|
34
|
+
/**
|
|
35
|
+
* The catalog path this injection actually wrote to.
|
|
36
|
+
*
|
|
37
|
+
* #1798: restore re-resolves the catalog from the CURRENT config, so a Codex app rewrite
|
|
38
|
+
* that dropped `model_catalog_json` sends restore to the default catalog while the
|
|
39
|
+
* proxy-written one is left routed. The injected path is the only durable record of which
|
|
40
|
+
* file we actually touched.
|
|
41
|
+
*/
|
|
42
|
+
injectedCatalogPath?: string | null;
|
|
16
43
|
pid: number;
|
|
17
44
|
timestamp: string;
|
|
18
45
|
}
|
|
@@ -81,15 +108,50 @@ export function writeJournal(options: WriteJournalOptions = {}): void {
|
|
|
81
108
|
atomicWriteFile(JOURNAL_PATH, JSON.stringify(journal));
|
|
82
109
|
}
|
|
83
110
|
|
|
84
|
-
export
|
|
111
|
+
export interface InjectedJournalOwnership {
|
|
112
|
+
injectedOpenaiBaseUrl: string | null;
|
|
113
|
+
injectedCatalogPath: string | null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function markJournalInjectedState(
|
|
117
|
+
config: string,
|
|
118
|
+
profile: string | null,
|
|
119
|
+
ownership: InjectedJournalOwnership,
|
|
120
|
+
): void {
|
|
85
121
|
const journal = readJournal();
|
|
86
122
|
if (!journal) return;
|
|
87
|
-
|
|
88
|
-
|
|
123
|
+
// The first exact injected config is the only safe whole-snapshot restore boundary for
|
|
124
|
+
// the first native snapshot. A later reinjection may preserve user edits made while routed;
|
|
125
|
+
// hashing those newer bytes and restoring the first snapshot would delete those edits.
|
|
126
|
+
// Keep the first hash so changed/reinjected configs take the owned-field fallback path.
|
|
127
|
+
journal.injectedConfigHash ??= sha256(config) ?? undefined;
|
|
128
|
+
// The profile file is wholly generated by OpenCodex, so its latest exact hash remains safe
|
|
129
|
+
// to refresh and lets restore remove the latest generated profile after a port change.
|
|
89
130
|
journal.injectedProfileHash = sha256(profile);
|
|
131
|
+
// Only the caller knows which values it actually owns. Deriving these from the final TOML
|
|
132
|
+
// would mistake a preserved user override for injected routing.
|
|
133
|
+
journal.injectedOpenaiBaseUrl = ownership.injectedOpenaiBaseUrl;
|
|
134
|
+
journal.injectedCatalogPath = ownership.injectedCatalogPath;
|
|
90
135
|
atomicWriteFile(JOURNAL_PATH, JSON.stringify(journal));
|
|
91
136
|
}
|
|
92
137
|
|
|
138
|
+
/**
|
|
139
|
+
* The root `openai_base_url` the last injection wrote, or null when it wrote none.
|
|
140
|
+
*
|
|
141
|
+
* #1798: the fallback strip recognizes an injected URL by the marker COMMENT above it,
|
|
142
|
+
* and a Codex app rewrite keeps values while dropping comments. This is the evidence that
|
|
143
|
+
* survives such a rewrite, so restore can still prove the URL is ours -- and, just as
|
|
144
|
+
* importantly, prove that a DIFFERENT URL is not.
|
|
145
|
+
*/
|
|
146
|
+
export function journaledInjectedOpenaiBaseUrl(): string | null {
|
|
147
|
+
return readJournal()?.injectedOpenaiBaseUrl ?? null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** The catalog path the last injection wrote to, or null when none was recorded. */
|
|
151
|
+
export function journaledInjectedCatalogPath(): string | null {
|
|
152
|
+
return readJournal()?.injectedCatalogPath ?? null;
|
|
153
|
+
}
|
|
154
|
+
|
|
93
155
|
export function removeJournal(): void {
|
|
94
156
|
try { unlinkSync(JOURNAL_PATH); } catch { /* ignore */ }
|
|
95
157
|
}
|
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
import { statSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { Database, constants } from "bun:sqlite";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
getCodexHome,
|
|
8
|
+
resolveCodexSqliteHome,
|
|
9
|
+
type CodexSqliteHomeDeps,
|
|
10
|
+
} from "../paths";
|
|
11
|
+
|
|
12
|
+
const IMMUTABLE_READONLY_FLAGS = constants.SQLITE_OPEN_READONLY | constants.SQLITE_OPEN_URI;
|
|
13
|
+
const KNOWN_LOG_LEVELS = new Set(["TRACE", "DEBUG", "INFO", "WARN", "ERROR"]);
|
|
14
|
+
|
|
15
|
+
interface CurrentLogColumn {
|
|
16
|
+
name: string;
|
|
17
|
+
type: string;
|
|
18
|
+
notnull: number;
|
|
19
|
+
defaultValue: string | null;
|
|
20
|
+
pk: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Pinned to Codex logs migration 0002. Keep this schema private: inspection reports
|
|
24
|
+
// compatibility, not column names, so sensitive payload-bearing fields never leak through
|
|
25
|
+
// the management API. Any additive/rebuilt future schema is monitor-only until reviewed.
|
|
26
|
+
const CURRENT_LOG_SCHEMA: readonly CurrentLogColumn[] = [
|
|
27
|
+
{ name: "id", type: "INTEGER", notnull: 0, defaultValue: null, pk: 1 },
|
|
28
|
+
{ name: "ts", type: "INTEGER", notnull: 1, defaultValue: null, pk: 0 },
|
|
29
|
+
{ name: "ts_nanos", type: "INTEGER", notnull: 1, defaultValue: null, pk: 0 },
|
|
30
|
+
{ name: "level", type: "TEXT", notnull: 1, defaultValue: null, pk: 0 },
|
|
31
|
+
{ name: "target", type: "TEXT", notnull: 1, defaultValue: null, pk: 0 },
|
|
32
|
+
{ name: "feedback_log_body", type: "TEXT", notnull: 0, defaultValue: null, pk: 0 },
|
|
33
|
+
{ name: "module_path", type: "TEXT", notnull: 0, defaultValue: null, pk: 0 },
|
|
34
|
+
{ name: "file", type: "TEXT", notnull: 0, defaultValue: null, pk: 0 },
|
|
35
|
+
{ name: "line", type: "INTEGER", notnull: 0, defaultValue: null, pk: 0 },
|
|
36
|
+
{ name: "thread_id", type: "TEXT", notnull: 0, defaultValue: null, pk: 0 },
|
|
37
|
+
{ name: "process_uuid", type: "TEXT", notnull: 0, defaultValue: null, pk: 0 },
|
|
38
|
+
{ name: "estimated_bytes", type: "INTEGER", notnull: 1, defaultValue: "0", pk: 0 },
|
|
39
|
+
] as const;
|
|
40
|
+
|
|
41
|
+
const CURRENT_LOG_TABLE_SQL = `CREATE TABLE logs (
|
|
42
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
43
|
+
ts INTEGER NOT NULL,
|
|
44
|
+
ts_nanos INTEGER NOT NULL,
|
|
45
|
+
level TEXT NOT NULL,
|
|
46
|
+
target TEXT NOT NULL,
|
|
47
|
+
feedback_log_body TEXT,
|
|
48
|
+
module_path TEXT,
|
|
49
|
+
file TEXT,
|
|
50
|
+
line INTEGER,
|
|
51
|
+
thread_id TEXT,
|
|
52
|
+
process_uuid TEXT,
|
|
53
|
+
estimated_bytes INTEGER NOT NULL DEFAULT 0
|
|
54
|
+
)`;
|
|
55
|
+
|
|
56
|
+
const CURRENT_LOG_INDEX_SQL = {
|
|
57
|
+
idx_logs_ts: "CREATE INDEX idx_logs_ts ON logs(ts DESC, ts_nanos DESC, id DESC)",
|
|
58
|
+
idx_logs_thread_id: "CREATE INDEX idx_logs_thread_id ON logs(thread_id)",
|
|
59
|
+
idx_logs_thread_id_ts: "CREATE INDEX idx_logs_thread_id_ts ON logs(thread_id, ts DESC, ts_nanos DESC, id DESC)",
|
|
60
|
+
idx_logs_process_uuid_threadless_ts: `CREATE INDEX idx_logs_process_uuid_threadless_ts
|
|
61
|
+
ON logs(process_uuid, ts DESC, ts_nanos DESC, id DESC)
|
|
62
|
+
WHERE thread_id IS NULL`,
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
export type CodexLogGuardCapabilityReason =
|
|
66
|
+
| "database_missing"
|
|
67
|
+
| "database_unreadable"
|
|
68
|
+
| "unknown_schema"
|
|
69
|
+
| "inspect_failed";
|
|
70
|
+
|
|
71
|
+
export type CodexLogGuardSchemaState =
|
|
72
|
+
| { state: "compatible" }
|
|
73
|
+
| { state: "missing"; reason: "database_missing" }
|
|
74
|
+
| { state: "unreadable"; reason: "database_unreadable" }
|
|
75
|
+
| { state: "unsupported"; reason: "unknown_schema" }
|
|
76
|
+
| { state: "unavailable"; reason: "inspect_failed" };
|
|
77
|
+
|
|
78
|
+
export type CodexLogGuardCapability =
|
|
79
|
+
| { state: "supported" }
|
|
80
|
+
| { state: "unsupported"; reason: CodexLogGuardCapabilityReason };
|
|
81
|
+
|
|
82
|
+
export interface CodexLogGuardMetrics {
|
|
83
|
+
totalRows: number;
|
|
84
|
+
rowsByLevel: Record<string, number>;
|
|
85
|
+
traceRows: number;
|
|
86
|
+
traceShare: number;
|
|
87
|
+
topTargets: Array<{ target: string; rows: number }>;
|
|
88
|
+
pageSize: number;
|
|
89
|
+
pageCount: number;
|
|
90
|
+
freelistPages: number;
|
|
91
|
+
reclaimableBytes: number;
|
|
92
|
+
estimatedLogBytes: number | null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Serializable, privacy-safe Log Guard inspection result.
|
|
97
|
+
*
|
|
98
|
+
* Canonical filesystem paths are deliberately kept local to the inspector. Consumers get
|
|
99
|
+
* only the coarse location relation (`externalSqliteHome`) and aggregate file/SQLite data.
|
|
100
|
+
* `externalSqliteHome` is null only when config resolution itself is unavailable.
|
|
101
|
+
*/
|
|
102
|
+
export interface CodexLogGuardInspection {
|
|
103
|
+
generatedAt: number;
|
|
104
|
+
externalSqliteHome: boolean | null;
|
|
105
|
+
snapshot: "checkpointed";
|
|
106
|
+
files: {
|
|
107
|
+
databaseBytes: number;
|
|
108
|
+
walBytes: number;
|
|
109
|
+
shmBytes: number;
|
|
110
|
+
};
|
|
111
|
+
schema: CodexLogGuardSchemaState;
|
|
112
|
+
capabilities: {
|
|
113
|
+
inspection: CodexLogGuardCapability;
|
|
114
|
+
protection: CodexLogGuardCapability;
|
|
115
|
+
reclaim: CodexLogGuardCapability;
|
|
116
|
+
};
|
|
117
|
+
metrics: CodexLogGuardMetrics | null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface ColumnRow {
|
|
121
|
+
cid: number;
|
|
122
|
+
name: string;
|
|
123
|
+
type: string;
|
|
124
|
+
notnull: number;
|
|
125
|
+
dflt_value: string | null;
|
|
126
|
+
pk: number;
|
|
127
|
+
}
|
|
128
|
+
interface SchemaObjectRow { name: string; type: string; sql: string | null }
|
|
129
|
+
interface CountRow { n: number }
|
|
130
|
+
interface LevelRow { level: string; rows: number }
|
|
131
|
+
interface TargetCountRow { rows: number }
|
|
132
|
+
interface EstimatedBytesRow { bytes: number | null }
|
|
133
|
+
|
|
134
|
+
type CanonicalTargetState = "missing" | "file" | "unusable";
|
|
135
|
+
|
|
136
|
+
function canonicalTargetState(path: string): CanonicalTargetState {
|
|
137
|
+
try {
|
|
138
|
+
return statSync(path).isFile() ? "file" : "unusable";
|
|
139
|
+
} catch (error) {
|
|
140
|
+
return (error as NodeJS.ErrnoException | undefined)?.code === "ENOENT" ? "missing" : "unusable";
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function fileSize(path: string): number {
|
|
145
|
+
try {
|
|
146
|
+
const stat = statSync(path);
|
|
147
|
+
return stat.isFile() ? stat.size : 0;
|
|
148
|
+
} catch {
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Memoized inspection, keyed by the database and WAL identity.
|
|
155
|
+
*
|
|
156
|
+
* `readMetrics` runs four unbounded aggregates (`count(*)`, two `GROUP BY`s and
|
|
157
|
+
* a `sum`) over the whole `logs` table. `bun:sqlite` is synchronous, so that
|
|
158
|
+
* work occupies the proxy thread for its full duration — measured at ~49s on a
|
|
159
|
+
* 15.6 GB / 302k-row database, exactly the large fragmented case this feature
|
|
160
|
+
* exists to diagnose. Both `/api/storage` and `/api/storage/codex-logs` call it
|
|
161
|
+
* inline, so merely opening or refreshing the Storage page could stall routing
|
|
162
|
+
* and health responses.
|
|
163
|
+
*
|
|
164
|
+
* A dashboard refresh, a page that renders both panels, and a poll loop all
|
|
165
|
+
* repeat an identical scan. Keying on size+mtime of the database and WAL means a
|
|
166
|
+
* repeat inspection is free until Codex actually writes, which removes the
|
|
167
|
+
* repeated stalls without ever serving stale numbers: any write changes the WAL
|
|
168
|
+
* and invalidates the entry.
|
|
169
|
+
*
|
|
170
|
+
* This bounds the repeat cost, not the first one. A cold inspection of a huge
|
|
171
|
+
* database still blocks; moving that work off-thread needs a Worker and is
|
|
172
|
+
* tracked separately.
|
|
173
|
+
*/
|
|
174
|
+
type InspectionCacheEntry = {
|
|
175
|
+
key: string;
|
|
176
|
+
value: CodexLogGuardInspection;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
let inspectionCache: InspectionCacheEntry | null = null;
|
|
180
|
+
|
|
181
|
+
function inspectionCacheKey(databasePath: string): string {
|
|
182
|
+
const stamp = (path: string): string => {
|
|
183
|
+
try {
|
|
184
|
+
// `size:mtimeMs` alone is not an identity. An atomic replace (write a new
|
|
185
|
+
// file, rename over the old one) can preserve both, and the cache then
|
|
186
|
+
// served the previous schema/capability verdict indefinitely — trading a
|
|
187
|
+
// repeated-scan cost for a persistent wrong answer. Include the inode and
|
|
188
|
+
// device so a replaced file is a different key even at identical size and
|
|
189
|
+
// mtime, plus nanosecond ctime/mtime so an in-place rewrite inside one
|
|
190
|
+
// millisecond still invalidates.
|
|
191
|
+
const stat = statSync(path, { bigint: true });
|
|
192
|
+
return [
|
|
193
|
+
stat.dev,
|
|
194
|
+
stat.ino,
|
|
195
|
+
stat.size,
|
|
196
|
+
stat.mtimeNs,
|
|
197
|
+
stat.ctimeNs,
|
|
198
|
+
].join(":");
|
|
199
|
+
} catch {
|
|
200
|
+
return "-";
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
return [
|
|
204
|
+
databasePath,
|
|
205
|
+
stamp(databasePath),
|
|
206
|
+
stamp(`${databasePath}-wal`),
|
|
207
|
+
stamp(`${databasePath}-shm`),
|
|
208
|
+
].join("|");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Drop the memoized inspection. Exported for tests and for post-mutation refresh. */
|
|
212
|
+
export function resetCodexLogGuardInspectionCache(): void {
|
|
213
|
+
inspectionCache = null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function capabilityFor(schema: CodexLogGuardSchemaState): CodexLogGuardCapability {
|
|
217
|
+
if (schema.state === "compatible") return { state: "supported" };
|
|
218
|
+
return { state: "unsupported", reason: schema.reason };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function unavailableInspection(): CodexLogGuardInspection {
|
|
222
|
+
const schema: CodexLogGuardSchemaState = { state: "unavailable", reason: "inspect_failed" };
|
|
223
|
+
const unavailable: CodexLogGuardCapability = { state: "unsupported", reason: "inspect_failed" };
|
|
224
|
+
return {
|
|
225
|
+
generatedAt: Date.now(),
|
|
226
|
+
externalSqliteHome: null,
|
|
227
|
+
snapshot: "checkpointed",
|
|
228
|
+
files: { databaseBytes: 0, walBytes: 0, shmBytes: 0 },
|
|
229
|
+
schema,
|
|
230
|
+
capabilities: {
|
|
231
|
+
inspection: unavailable,
|
|
232
|
+
protection: unavailable,
|
|
233
|
+
reclaim: unavailable,
|
|
234
|
+
},
|
|
235
|
+
metrics: null,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function normalizeDeclaredType(type: string): string {
|
|
240
|
+
return String(type ?? "").trim().toUpperCase();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function normalizeDefault(value: string | null): string | null {
|
|
244
|
+
return value === null ? null : String(value).trim();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function normalizeSchemaSql(sql: string | null | undefined): string {
|
|
248
|
+
return (sql ?? "").trim().replace(/;\s*$/, "").replace(/\s+/g, " ");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function sameColumns(columns: ColumnRow[]): boolean {
|
|
252
|
+
if (columns.length !== CURRENT_LOG_SCHEMA.length) return false;
|
|
253
|
+
return columns.every((column, index) => {
|
|
254
|
+
const expected = CURRENT_LOG_SCHEMA[index];
|
|
255
|
+
return column.cid === index
|
|
256
|
+
&& column.name === expected.name
|
|
257
|
+
&& normalizeDeclaredType(column.type) === expected.type
|
|
258
|
+
&& Number(column.notnull) === expected.notnull
|
|
259
|
+
&& normalizeDefault(column.dflt_value) === expected.defaultValue
|
|
260
|
+
&& Number(column.pk) === expected.pk;
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* The authoritative compatibility predicate: exact table SQL, exact column
|
|
266
|
+
* metadata, and every canonical index.
|
|
267
|
+
*
|
|
268
|
+
* Exported because the mutation paths must apply the SAME test inside their
|
|
269
|
+
* write transaction. They used to check column NAMES only, which is strictly
|
|
270
|
+
* weaker than what the inspector reports, so a schema change landing between
|
|
271
|
+
* the outer inspection and the locked write let Protect install a row-dropping
|
|
272
|
+
* trigger and let Reclaim vacuum pages on a database the inspector classifies
|
|
273
|
+
* as monitor-only. The lock serializes OpenCodex against itself; it does not
|
|
274
|
+
* stop Codex or another SQLite writer, so that TOCTOU window is real.
|
|
275
|
+
*/
|
|
276
|
+
export function hasCurrentLogsSchema(db: Database): boolean {
|
|
277
|
+
const columns = db.query<ColumnRow, []>("PRAGMA table_info(logs)").all();
|
|
278
|
+
return hasCurrentLogsTable(db, columns);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function hasCurrentLogsTable(db: Database, columns: ColumnRow[]): boolean {
|
|
282
|
+
const table = db.query<SchemaObjectRow, []>(
|
|
283
|
+
"SELECT name, type, sql FROM sqlite_schema WHERE name = 'logs' LIMIT 1",
|
|
284
|
+
).get();
|
|
285
|
+
if (table?.type !== "table"
|
|
286
|
+
|| !sameColumns(columns)
|
|
287
|
+
|| normalizeSchemaSql(table.sql) !== normalizeSchemaSql(CURRENT_LOG_TABLE_SQL)) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const indexes = db.query<SchemaObjectRow, []>(`
|
|
292
|
+
SELECT name, type, sql FROM sqlite_schema
|
|
293
|
+
WHERE name IN (
|
|
294
|
+
'idx_logs_ts',
|
|
295
|
+
'idx_logs_thread_id',
|
|
296
|
+
'idx_logs_thread_id_ts',
|
|
297
|
+
'idx_logs_process_uuid_threadless_ts'
|
|
298
|
+
)
|
|
299
|
+
`).all();
|
|
300
|
+
const byName = new Map(indexes.map(row => [row.name, row]));
|
|
301
|
+
for (const [name, expectedSql] of Object.entries(CURRENT_LOG_INDEX_SQL)) {
|
|
302
|
+
const row = byName.get(name);
|
|
303
|
+
if (row?.type !== "index" || normalizeSchemaSql(row.sql) !== normalizeSchemaSql(expectedSql)) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Extra indexes and triggers do not redefine the table contract. In particular,
|
|
309
|
+
// Protect intentionally installs OpenCodex-owned triggers and unrelated user triggers
|
|
310
|
+
// are supported, so compatibility is based on the canonical table plus required indexes.
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function pragmaNumber(db: Database, pragma: "page_size" | "page_count" | "freelist_count"): number {
|
|
315
|
+
const row = db.query<Record<string, number>, []>(`PRAGMA ${pragma}`).get();
|
|
316
|
+
return Number(row?.[pragma] ?? 0);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function readMetrics(db: Database, columns: string[]): CodexLogGuardMetrics | null {
|
|
320
|
+
if (!columns.includes("level") || !columns.includes("target")) return null;
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
const totalRows = Number(db.query<CountRow, []>("SELECT count(*) AS n FROM logs").get()?.n ?? 0);
|
|
324
|
+
const rowsByLevel: Record<string, number> = {};
|
|
325
|
+
for (const row of db.query<LevelRow, []>(
|
|
326
|
+
"SELECT level, count(*) AS rows FROM logs GROUP BY level ORDER BY level",
|
|
327
|
+
).all()) {
|
|
328
|
+
const rawLevel = String(row.level ?? "").toUpperCase();
|
|
329
|
+
const level = KNOWN_LOG_LEVELS.has(rawLevel) ? rawLevel : "OTHER";
|
|
330
|
+
rowsByLevel[level] = (rowsByLevel[level] ?? 0) + Number(row.rows ?? 0);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Preserve the useful top-target distribution without serializing target names from
|
|
334
|
+
// the foreign database. Rank labels are fixed output values and cannot carry local
|
|
335
|
+
// paths, credentials, or other injected diagnostic content.
|
|
336
|
+
const topTargets = db.query<TargetCountRow, []>(
|
|
337
|
+
"SELECT count(*) AS rows FROM logs GROUP BY target ORDER BY rows DESC, target ASC LIMIT 10",
|
|
338
|
+
).all().map((row, index) => ({ target: `TARGET_${index + 1}`, rows: Number(row.rows ?? 0) }));
|
|
339
|
+
|
|
340
|
+
const pageSize = pragmaNumber(db, "page_size");
|
|
341
|
+
const pageCount = pragmaNumber(db, "page_count");
|
|
342
|
+
const freelistPages = pragmaNumber(db, "freelist_count");
|
|
343
|
+
const traceRows = rowsByLevel.TRACE ?? 0;
|
|
344
|
+
const estimatedLogBytes = columns.includes("estimated_bytes")
|
|
345
|
+
? Number(db.query<EstimatedBytesRow, []>(
|
|
346
|
+
"SELECT COALESCE(sum(estimated_bytes), 0) AS bytes FROM logs",
|
|
347
|
+
).get()?.bytes ?? 0)
|
|
348
|
+
: null;
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
totalRows,
|
|
352
|
+
rowsByLevel,
|
|
353
|
+
traceRows,
|
|
354
|
+
traceShare: totalRows > 0 ? traceRows / totalRows : 0,
|
|
355
|
+
topTargets,
|
|
356
|
+
pageSize,
|
|
357
|
+
pageCount,
|
|
358
|
+
freelistPages,
|
|
359
|
+
reclaimableBytes: pageSize * freelistPages,
|
|
360
|
+
estimatedLogBytes,
|
|
361
|
+
};
|
|
362
|
+
} catch {
|
|
363
|
+
// A future schema may still have a `logs` table but change aggregate-compatible
|
|
364
|
+
// columns or virtual-table behaviour. Metadata inspection remains valid; metrics do
|
|
365
|
+
// not become a reason to throw or to open a writable connection.
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Inspect the canonical Codex diagnostic log database without participating in SQLite's
|
|
372
|
+
* write/locking protocol. `immutable=1` intentionally observes the last checkpointed
|
|
373
|
+
* snapshot: file sizes include live sidecars, while SQL aggregates may lag a live WAL.
|
|
374
|
+
* This is a zero-write health view, not an SSD/NAND write-rate measurement.
|
|
375
|
+
*/
|
|
376
|
+
export function inspectCodexLogs(deps: CodexSqliteHomeDeps = {}): CodexLogGuardInspection {
|
|
377
|
+
let cacheKey: string | null = null;
|
|
378
|
+
try {
|
|
379
|
+
const home = deps.codexHome ?? getCodexHome();
|
|
380
|
+
cacheKey = inspectionCacheKey(join(resolveCodexSqliteHome({ ...deps, codexHome: home }), "logs_2.sqlite"));
|
|
381
|
+
if (inspectionCache?.key === cacheKey) return inspectionCache.value;
|
|
382
|
+
} catch {
|
|
383
|
+
cacheKey = null;
|
|
384
|
+
}
|
|
385
|
+
const value = inspectCodexLogsUncached(deps);
|
|
386
|
+
// `generatedAt` is part of the memoized value, so a cached response reports the
|
|
387
|
+
// time the numbers were actually measured rather than the time they were served.
|
|
388
|
+
if (cacheKey !== null) inspectionCache = { key: cacheKey, value };
|
|
389
|
+
return value;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function inspectCodexLogsUncached(deps: CodexSqliteHomeDeps = {}): CodexLogGuardInspection {
|
|
393
|
+
let codexHome: string;
|
|
394
|
+
let sqliteHome: string;
|
|
395
|
+
try {
|
|
396
|
+
codexHome = deps.codexHome ?? getCodexHome();
|
|
397
|
+
sqliteHome = resolveCodexSqliteHome({ ...deps, codexHome });
|
|
398
|
+
} catch {
|
|
399
|
+
// Resolution errors can include config paths. Convert them to a fixed, non-fatal
|
|
400
|
+
// inspection state before they cross any diagnostic/API boundary.
|
|
401
|
+
return unavailableInspection();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Resolve sqlite_home exactly once so the location flag and inspected file cannot refer
|
|
405
|
+
// to different roots if config changes during one inspection.
|
|
406
|
+
const databasePath = join(sqliteHome, "logs_2.sqlite");
|
|
407
|
+
const targetState = canonicalTargetState(databasePath);
|
|
408
|
+
const files = {
|
|
409
|
+
databaseBytes: fileSize(databasePath),
|
|
410
|
+
walBytes: fileSize(`${databasePath}-wal`),
|
|
411
|
+
shmBytes: fileSize(`${databasePath}-shm`),
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const common = {
|
|
415
|
+
generatedAt: Date.now(),
|
|
416
|
+
externalSqliteHome: resolve(sqliteHome) !== resolve(codexHome),
|
|
417
|
+
snapshot: "checkpointed" as const,
|
|
418
|
+
files,
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
if (targetState === "missing") {
|
|
422
|
+
const schema: CodexLogGuardSchemaState = { state: "missing", reason: "database_missing" };
|
|
423
|
+
const mutation = capabilityFor(schema);
|
|
424
|
+
return {
|
|
425
|
+
...common,
|
|
426
|
+
schema,
|
|
427
|
+
metrics: null,
|
|
428
|
+
capabilities: {
|
|
429
|
+
inspection: { state: "supported" },
|
|
430
|
+
protection: mutation,
|
|
431
|
+
reclaim: mutation,
|
|
432
|
+
},
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (targetState === "unusable") {
|
|
437
|
+
const schema: CodexLogGuardSchemaState = { state: "unreadable", reason: "database_unreadable" };
|
|
438
|
+
const mutation = capabilityFor(schema);
|
|
439
|
+
return {
|
|
440
|
+
...common,
|
|
441
|
+
schema,
|
|
442
|
+
metrics: null,
|
|
443
|
+
capabilities: {
|
|
444
|
+
inspection: { state: "supported" },
|
|
445
|
+
protection: mutation,
|
|
446
|
+
reclaim: mutation,
|
|
447
|
+
},
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// SQLite accepts a zero-byte file as an empty database. For Log Guard this is not a
|
|
452
|
+
// compatible future schema: Codex's canonical logs database must already contain its
|
|
453
|
+
// migrated `logs` table before any future mutation capability can be considered safe.
|
|
454
|
+
if (files.databaseBytes === 0) {
|
|
455
|
+
const schema: CodexLogGuardSchemaState = { state: "unreadable", reason: "database_unreadable" };
|
|
456
|
+
const mutation = capabilityFor(schema);
|
|
457
|
+
return {
|
|
458
|
+
...common,
|
|
459
|
+
schema,
|
|
460
|
+
metrics: null,
|
|
461
|
+
capabilities: {
|
|
462
|
+
inspection: { state: "supported" },
|
|
463
|
+
protection: mutation,
|
|
464
|
+
reclaim: mutation,
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
try {
|
|
470
|
+
const uri = `${pathToFileURL(databasePath).href}?immutable=1`;
|
|
471
|
+
const db = new Database(uri, IMMUTABLE_READONLY_FLAGS);
|
|
472
|
+
try {
|
|
473
|
+
const columnRows = db.query<ColumnRow, []>("PRAGMA table_info(logs)").all();
|
|
474
|
+
const columns = columnRows.map(row => row.name);
|
|
475
|
+
const schema: CodexLogGuardSchemaState = hasCurrentLogsTable(db, columnRows)
|
|
476
|
+
? { state: "compatible" }
|
|
477
|
+
: { state: "unsupported", reason: "unknown_schema" };
|
|
478
|
+
const mutation = capabilityFor(schema);
|
|
479
|
+
return {
|
|
480
|
+
...common,
|
|
481
|
+
schema,
|
|
482
|
+
metrics: readMetrics(db, columns),
|
|
483
|
+
capabilities: {
|
|
484
|
+
inspection: { state: "supported" },
|
|
485
|
+
protection: mutation,
|
|
486
|
+
reclaim: mutation,
|
|
487
|
+
},
|
|
488
|
+
};
|
|
489
|
+
} finally {
|
|
490
|
+
db.close();
|
|
491
|
+
}
|
|
492
|
+
} catch {
|
|
493
|
+
const schema: CodexLogGuardSchemaState = { state: "unreadable", reason: "database_unreadable" };
|
|
494
|
+
const mutation = capabilityFor(schema);
|
|
495
|
+
return {
|
|
496
|
+
...common,
|
|
497
|
+
schema,
|
|
498
|
+
metrics: null,
|
|
499
|
+
capabilities: {
|
|
500
|
+
inspection: { state: "supported" },
|
|
501
|
+
protection: mutation,
|
|
502
|
+
reclaim: mutation,
|
|
503
|
+
},
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
}
|