@yansigit/opencodex 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/LICENSE +21 -0
- package/README.md +303 -0
- package/assets/architecture.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/claude-code-models.gif +0 -0
- package/assets/codex-app-picker.png +0 -0
- package/bin/ocx.mjs +587 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
- package/gui/dist/assets/index-CGoDO3uO.css +1 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/icons.svg +24 -0
- package/gui/dist/index.html +25 -0
- package/gui/dist/logo.png +0 -0
- package/gui/dist/provider-icons/alibaba-color.svg +1 -0
- package/gui/dist/provider-icons/antigravity-color.svg +1 -0
- package/gui/dist/provider-icons/claude-color.svg +1 -0
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -0
- package/gui/dist/provider-icons/cursor-color.svg +2 -0
- package/gui/dist/provider-icons/deepseek-color.svg +1 -0
- package/gui/dist/provider-icons/discord.svg +1 -0
- package/gui/dist/provider-icons/firepass-color.svg +1 -0
- package/gui/dist/provider-icons/fireworks-color.svg +1 -0
- package/gui/dist/provider-icons/gemini-color.svg +1 -0
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
- package/gui/dist/provider-icons/grok.svg +1 -0
- package/gui/dist/provider-icons/groq-color.svg +1 -0
- package/gui/dist/provider-icons/huggingface-color.svg +1 -0
- package/gui/dist/provider-icons/kimi-color.svg +1 -0
- package/gui/dist/provider-icons/kiro-color.svg +15 -0
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
- package/gui/dist/provider-icons/mistral-color.svg +1 -0
- package/gui/dist/provider-icons/moonshot-color.svg +1 -0
- package/gui/dist/provider-icons/nvidia-color.svg +1 -0
- package/gui/dist/provider-icons/ollama-color.svg +1 -0
- package/gui/dist/provider-icons/openai.svg +1 -0
- package/gui/dist/provider-icons/opencode.svg +2 -0
- package/gui/dist/provider-icons/openrouter-color.svg +1 -0
- package/gui/dist/provider-icons/pi.svg +21 -0
- package/gui/dist/provider-icons/qianfan-color.svg +1 -0
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
- package/gui/dist/provider-icons/telegram.svg +1 -0
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/vllm-color.svg +1 -0
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
- package/package.json +108 -0
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic-image-guard.ts +251 -0
- package/src/adapters/anthropic-image-normalize.ts +518 -0
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +1327 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +121 -0
- package/src/adapters/client-fingerprint.ts +65 -0
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +288 -0
- package/src/adapters/cursor/discovery.ts +333 -0
- package/src/adapters/cursor/effort-map.ts +151 -0
- package/src/adapters/cursor/exec-policy.ts +88 -0
- package/src/adapters/cursor/framing.ts +250 -0
- package/src/adapters/cursor/gen/agent_pb.ts +15274 -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/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +269 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1653 -0
- package/src/adapters/cursor/mcp-config.ts +42 -0
- package/src/adapters/cursor/mcp-manager.ts +333 -0
- package/src/adapters/cursor/message-mapper.ts +49 -0
- package/src/adapters/cursor/native-exec-common.ts +76 -0
- package/src/adapters/cursor/native-exec-desktop.ts +184 -0
- package/src/adapters/cursor/native-exec-fs.ts +332 -0
- package/src/adapters/cursor/native-exec-mcp.ts +153 -0
- package/src/adapters/cursor/native-exec-network.ts +43 -0
- package/src/adapters/cursor/native-exec-shell.ts +547 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +663 -0
- package/src/adapters/cursor/protobuf-events.ts +1381 -0
- package/src/adapters/cursor/protobuf-request.ts +1032 -0
- package/src/adapters/cursor/request-builder.ts +461 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +735 -0
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +79 -0
- package/src/adapters/cursor/types.ts +79 -0
- package/src/adapters/cursor.ts +322 -0
- package/src/adapters/google-antigravity-hosts.ts +48 -0
- package/src/adapters/google-antigravity-replay.ts +827 -0
- package/src/adapters/google-antigravity-tools.ts +105 -0
- package/src/adapters/google-antigravity-wire.ts +141 -0
- package/src/adapters/google-errors.ts +92 -0
- package/src/adapters/google-http.ts +460 -0
- package/src/adapters/google-tool-schema.ts +238 -0
- package/src/adapters/google-truncation.ts +24 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +1377 -0
- package/src/adapters/identity.ts +77 -0
- package/src/adapters/image.ts +23 -0
- package/src/adapters/kiro-constants.ts +16 -0
- package/src/adapters/kiro-errors.ts +208 -0
- package/src/adapters/kiro-events.ts +197 -0
- package/src/adapters/kiro-images.ts +129 -0
- package/src/adapters/kiro-retry.ts +312 -0
- package/src/adapters/kiro-thinking.ts +112 -0
- package/src/adapters/kiro-tool-fallback.ts +36 -0
- package/src/adapters/kiro-tools.ts +224 -0
- package/src/adapters/kiro-truncation.ts +33 -0
- package/src/adapters/kiro-wire.ts +129 -0
- package/src/adapters/kiro.ts +1936 -0
- package/src/adapters/mimo-free.ts +280 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1980 -0
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1911 -0
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +154 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +1986 -0
- package/src/chat/inbound.ts +319 -0
- package/src/chat/outbound.ts +821 -0
- package/src/claude/agents-inject.ts +266 -0
- package/src/claude/alias.ts +149 -0
- package/src/claude/auth-detect.ts +229 -0
- package/src/claude/auth-mode-migration.ts +32 -0
- package/src/claude/auth-mode.ts +62 -0
- package/src/claude/context-windows.ts +205 -0
- package/src/claude/desktop-3p-guard.ts +35 -0
- package/src/claude/desktop-3p-paths.ts +84 -0
- package/src/claude/desktop-3p.ts +615 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +107 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +578 -0
- package/src/claude/model-info.ts +174 -0
- package/src/claude/outbound.ts +926 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +302 -0
- package/src/cli/account-auth.ts +250 -0
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +737 -0
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +299 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +290 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +213 -0
- package/src/cli/claude.ts +355 -0
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +47 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +127 -0
- package/src/cli/config-command.ts +209 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/dispatch.ts +585 -0
- package/src/cli/doctor.ts +1202 -0
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +213 -0
- package/src/cli/help.ts +101 -0
- package/src/cli/index.ts +973 -0
- package/src/cli/init.ts +211 -0
- package/src/cli/integrations.ts +260 -0
- package/src/cli/interactive-confirm.ts +133 -0
- 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 +245 -0
- package/src/cli/models.ts +422 -0
- package/src/cli/observe.ts +206 -0
- package/src/cli/opencode.ts +588 -0
- package/src/cli/provider-replit.ts +232 -0
- package/src/cli/provider-runtime.ts +179 -0
- package/src/cli/provider.ts +492 -0
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +422 -0
- package/src/cli/replit-gateway-key-input.ts +138 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +328 -0
- package/src/cli/star-prompt.ts +211 -0
- package/src/cli/status-oauth.ts +78 -0
- package/src/cli/status.ts +328 -0
- package/src/cli/system-command.ts +112 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +199 -0
- package/src/cli/v2.ts +268 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +1704 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +47 -0
- package/src/codex/account-lifecycle.ts +172 -0
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +195 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-runtime-state.ts +31 -0
- package/src/codex/account-store.ts +544 -0
- package/src/codex/account-usability.ts +43 -0
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/agent-roles-sync.ts +225 -0
- package/src/codex/agent-roles.ts +238 -0
- package/src/codex/app-server-processes.ts +1143 -0
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +2147 -0
- package/src/codex/auth-collision.ts +109 -0
- package/src/codex/auth-context.ts +665 -0
- package/src/codex/autostart-health.ts +156 -0
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +436 -0
- package/src/codex/catalog/bundled.ts +549 -0
- package/src/codex/catalog/effort.ts +446 -0
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +664 -0
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +650 -0
- package/src/codex/catalog/provider-fetch.ts +2064 -0
- package/src/codex/catalog/sync.ts +1883 -0
- 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 +14 -0
- 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/data/upstream-models.json +830 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +1566 -0
- 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 +108 -0
- package/src/codex/history-provider.ts +979 -0
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1733 -0
- package/src/codex/injected-marker.ts +106 -0
- 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 +225 -0
- 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 +56 -0
- package/src/codex/main-account.ts +68 -0
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +273 -0
- 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 +144 -0
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +295 -0
- package/src/codex/project-config-warnings.ts +425 -0
- 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 +573 -0
- package/src/codex/refresh.ts +62 -0
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +1888 -0
- package/src/codex/runtime.ts +659 -0
- package/src/codex/shim.ts +2170 -0
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +784 -0
- package/src/codex/sync.ts +319 -0
- 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 +298 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +160 -0
- package/src/combos/index.ts +45 -0
- package/src/combos/request.ts +94 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +398 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +4041 -0
- package/src/fork/register.ts +3 -0
- package/src/generated/compatibility-version.json +3116 -0
- package/src/generated/model-metadata.ts +106 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +530 -0
- package/src/grok/inspect.ts +45 -0
- package/src/grok/status.ts +121 -0
- package/src/grok/sync.ts +66 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +149 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +955 -0
- package/src/images/plan.ts +143 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/index.ts +22 -0
- 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/abort.ts +146 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/admission.ts +83 -0
- package/src/lib/app-owned-memory-stores.ts +195 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +346 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +184 -0
- package/src/lib/bun-stream-caps.ts +130 -0
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +364 -0
- package/src/lib/crash-guard.ts +344 -0
- package/src/lib/debug-log-buffer.ts +83 -0
- package/src/lib/debug-settings.ts +108 -0
- package/src/lib/debug.ts +31 -0
- package/src/lib/destination-policy.ts +380 -0
- package/src/lib/errors.ts +406 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -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/open-url.ts +25 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +270 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +168 -0
- package/src/lib/provider-outbound.ts +210 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +521 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +25 -0
- package/src/lib/shadow-call.ts +61 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +364 -0
- package/src/lib/state-store-registrations.ts +119 -0
- package/src/lib/state-store-sweeper.ts +184 -0
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/test-home-guard.ts +90 -0
- package/src/lib/token-estimate.ts +86 -0
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +400 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +392 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-atomic-replace.ts +156 -0
- package/src/lib/windows-elevation.ts +773 -0
- package/src/lib/windows-secret-acl.ts +854 -0
- 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 +403 -0
- 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-routing.ts +594 -0
- package/src/oauth/anthropic.ts +188 -0
- package/src/oauth/antigravity-routing.ts +151 -0
- package/src/oauth/callback-server.ts +300 -0
- package/src/oauth/chatgpt.ts +161 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +252 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +262 -0
- package/src/oauth/health.ts +407 -0
- package/src/oauth/index.ts +1504 -0
- package/src/oauth/key-providers.ts +124 -0
- package/src/oauth/kimi.ts +227 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +621 -0
- package/src/oauth/local-token-detect.ts +130 -0
- package/src/oauth/log.ts +50 -0
- package/src/oauth/login-cli.ts +223 -0
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +728 -0
- package/src/oauth/token-guardian.ts +309 -0
- package/src/oauth/types.ts +62 -0
- package/src/oauth/xai.ts +241 -0
- package/src/providers/alibaba-region-backup.ts +75 -0
- package/src/providers/alibaba-region-migration.ts +156 -0
- package/src/providers/alibaba-region-startup.ts +36 -0
- package/src/providers/antigravity-models.ts +695 -0
- package/src/providers/antigravity-quota.ts +216 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +74 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +82 -0
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +586 -0
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +187 -0
- package/src/providers/github-copilot-transport.ts +56 -0
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +271 -0
- package/src/providers/kiro-models.ts +67 -0
- package/src/providers/label.ts +19 -0
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +449 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +243 -0
- package/src/providers/openai-tier-startup.ts +56 -0
- package/src/providers/openai-tiers.ts +423 -0
- package/src/providers/openai-virtual-models.ts +83 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +185 -0
- package/src/providers/quota.ts +2345 -0
- package/src/providers/registry.ts +2918 -0
- package/src/providers/replit/constants.ts +27 -0
- package/src/providers/replit/derive.ts +85 -0
- package/src/providers/replit/headers.ts +28 -0
- package/src/providers/replit/origin.ts +55 -0
- package/src/providers/replit/pair-install-response.ts +72 -0
- package/src/providers/replit/probe.ts +199 -0
- package/src/providers/replit/setup.ts +350 -0
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +103 -0
- 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 +148 -0
- package/src/reasoning-effort.ts +183 -0
- package/src/responses/compaction.ts +142 -0
- 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 +838 -0
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +165 -0
- package/src/responses/spill-store.ts +459 -0
- package/src/responses/state.ts +1433 -0
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +761 -0
- 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 +53 -0
- package/src/server/auth-cors.ts +751 -0
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +442 -0
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +1030 -0
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +190 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +152 -0
- package/src/server/image-retry.ts +42 -0
- package/src/server/images.ts +568 -0
- package/src/server/index.ts +1813 -0
- package/src/server/lifecycle.ts +498 -0
- package/src/server/live.ts +717 -0
- 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 +1433 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +193 -0
- package/src/server/management/body.ts +41 -0
- package/src/server/management/combo-routes.ts +263 -0
- package/src/server/management/config-routes.ts +835 -0
- package/src/server/management/context.ts +113 -0
- 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 +586 -0
- package/src/server/management/model-routes.ts +560 -0
- 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 +637 -0
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +1033 -0
- package/src/server/management/replit-provider-routes.ts +86 -0
- 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 +385 -0
- package/src/server/management/shared.ts +286 -0
- package/src/server/management/sidebar-routes.ts +106 -0
- 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 +435 -0
- package/src/server/management/system-routes.ts +194 -0
- package/src/server/management/usage-summary-cache.ts +94 -0
- 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 +314 -0
- package/src/server/management-auth.ts +482 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +156 -0
- package/src/server/proxy-liveness.ts +328 -0
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +353 -0
- package/src/server/relay.ts +1209 -0
- package/src/server/request-decompress.ts +239 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1259 -0
- 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 +551 -0
- package/src/server/responses/compact.ts +771 -0
- package/src/server/responses/core.ts +5389 -0
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +331 -0
- package/src/server/responses/fetch-helpers.ts +232 -0
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +78 -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 +251 -0
- package/src/server/responses/upstream-error.ts +53 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-image-gen-repair.ts +132 -0
- package/src/server/responses-item-id-repair.ts +272 -0
- 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 +25 -0
- package/src/server/search.ts +201 -0
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +263 -0
- package/src/server/startup-action-control.ts +315 -0
- package/src/server/startup-health-cache.ts +131 -0
- package/src/server/system-env.ts +484 -0
- package/src/server/windows-tcp-drop.ts +184 -0
- package/src/server/windows-tray-control.ts +41 -0
- package/src/server/ws-bridge.ts +472 -0
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +3575 -0
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/stall-timeout.ts +20 -0
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +3085 -0
- package/src/storage/policy-job.ts +457 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +59 -0
- package/src/storage/policy.ts +527 -0
- package/src/storage/restore-job.ts +299 -0
- package/src/storage/restore-worker.ts +58 -0
- package/src/storage/scanner.ts +238 -0
- package/src/storage/storage-mutation-coordinator.ts +139 -0
- package/src/storage/worker-lifecycle.ts +215 -0
- package/src/tray/assets/opencodex-tray-offline.ico +0 -0
- package/src/tray/assets/opencodex-tray-online.ico +0 -0
- package/src/tray/assets/opencodex-tray-warning.ico +0 -0
- package/src/tray/assets/opencodex-tray.png +0 -0
- package/src/tray/windows-tray.ps1 +364 -0
- package/src/tray/windows.ts +757 -0
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +876 -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 +106 -0
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +415 -0
- package/src/update/job.ts +1887 -0
- package/src/update/notify.ts +263 -0
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/update/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +625 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +416 -0
- package/src/usage/log.ts +1223 -0
- package/src/usage/summary.ts +753 -0
- package/src/usage/totals.ts +14 -0
- 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 +189 -0
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +131 -0
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +681 -0
- 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 +195 -0
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +113 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +331 -0
- package/src/web-search/loop.ts +896 -0
- package/src/web-search/parse.ts +315 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/synthetic-tool.ts +47 -0
- package/src/web-search/xai-executor.ts +219 -0
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { chmodSync, lstatSync, mkdirSync, realpathSync } from "node:fs";
|
|
3
|
+
import { dirname, isAbsolute, join } from "node:path";
|
|
4
|
+
|
|
5
|
+
import { Database } from "bun:sqlite";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
normalizeTrustedDarwinSystemAlias,
|
|
9
|
+
sameLogGuardPathIdentity,
|
|
10
|
+
} from "./path-safety";
|
|
11
|
+
import { isSqliteBusy } from "./sqlite-errors";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
CodexUserIdentityRefusal,
|
|
15
|
+
resolveCodexCoordinatorDatabasePath,
|
|
16
|
+
resolveEffectiveUserIdentity,
|
|
17
|
+
} from "../user-identity";
|
|
18
|
+
|
|
19
|
+
export type CodexLogGuardLockOutcome<T> =
|
|
20
|
+
| { kind: "completed"; value: T }
|
|
21
|
+
| { kind: "unavailable"; reason: "busy" | "database" | "unsafe-path" };
|
|
22
|
+
|
|
23
|
+
export interface CodexLogGuardLockDeps {
|
|
24
|
+
/** Test seam. Production resolves a dedicated DB in the trusted user runtime root. */
|
|
25
|
+
resolveDatabasePath?: (canonicalCodexHome: string, canonicalLogsDbPath: string) => string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function lockFileIsSafe(path: string, requireRealpath: boolean): boolean {
|
|
29
|
+
const stat = lstatSync(path);
|
|
30
|
+
if (stat.isSymbolicLink() || !stat.isFile()) return false;
|
|
31
|
+
if (requireRealpath && !sameLogGuardPathIdentity(realpathSync.native(path), path)) return false;
|
|
32
|
+
if (process.platform === "win32") return true;
|
|
33
|
+
const uid = process.getuid?.();
|
|
34
|
+
return uid !== undefined && stat.uid === uid && (stat.mode & 0o777) === 0o600;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function codexLogGuardLockDigest(
|
|
38
|
+
canonicalCodexHome: string,
|
|
39
|
+
canonicalLogsDbPath: string,
|
|
40
|
+
): string {
|
|
41
|
+
const digestCodexHome = normalizeTrustedDarwinSystemAlias(canonicalCodexHome);
|
|
42
|
+
const digestLogsDbPath = normalizeTrustedDarwinSystemAlias(canonicalLogsDbPath);
|
|
43
|
+
return createHash("sha256")
|
|
44
|
+
.update(`${digestCodexHome.length}:${digestCodexHome}`)
|
|
45
|
+
.update(`${digestLogsDbPath.length}:${digestLogsDbPath}`)
|
|
46
|
+
.digest("hex");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function resolveLogGuardLockDatabase(
|
|
50
|
+
canonicalCodexHome: string,
|
|
51
|
+
canonicalLogsDbPath: string,
|
|
52
|
+
): string {
|
|
53
|
+
if (!isAbsolute(canonicalCodexHome) || !isAbsolute(canonicalLogsDbPath)) {
|
|
54
|
+
throw new CodexUserIdentityRefusal("Codex Log Guard lock keys must be absolute paths.");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const identity = resolveEffectiveUserIdentity();
|
|
58
|
+
// Use the native-coordinator resolver only to enter the already-audited,
|
|
59
|
+
// environment-independent per-user runtime root. L itself is a different
|
|
60
|
+
// database in a sibling directory and never acquires N or H.
|
|
61
|
+
const coordinatorPath = resolveCodexCoordinatorDatabasePath(identity, canonicalCodexHome);
|
|
62
|
+
const runtimeRoot = dirname(dirname(coordinatorPath));
|
|
63
|
+
const locksDir = join(runtimeRoot, "log-guard-locks");
|
|
64
|
+
mkdirSync(locksDir, { recursive: true, mode: 0o700 });
|
|
65
|
+
const dirStat = lstatSync(locksDir);
|
|
66
|
+
if (!dirStat.isDirectory() || dirStat.isSymbolicLink()
|
|
67
|
+
|| !sameLogGuardPathIdentity(realpathSync.native(locksDir), locksDir)) {
|
|
68
|
+
throw new CodexUserIdentityRefusal("Codex Log Guard lock directory is unsafe.");
|
|
69
|
+
}
|
|
70
|
+
if (process.platform !== "win32") {
|
|
71
|
+
const uid = process.getuid?.();
|
|
72
|
+
// `mkdirSync` applies `mode` only when it CREATES the directory, so a
|
|
73
|
+
// directory left by an earlier build (or a permissive umask on a older
|
|
74
|
+
// version) keeps its old permissions forever and every Log Guard mutation
|
|
75
|
+
// fails `unsafe_path` with no in-product way out. Tighten it ourselves when
|
|
76
|
+
// we own it, and only refuse if that cannot be achieved.
|
|
77
|
+
if (uid === undefined || dirStat.uid !== uid) {
|
|
78
|
+
throw new CodexUserIdentityRefusal("Codex Log Guard lock directory is not private to the effective user.");
|
|
79
|
+
}
|
|
80
|
+
if ((dirStat.mode & 0o777) !== 0o700) {
|
|
81
|
+
try {
|
|
82
|
+
chmodSync(locksDir, 0o700);
|
|
83
|
+
} catch {
|
|
84
|
+
throw new CodexUserIdentityRefusal("Codex Log Guard lock directory is not private to the effective user.");
|
|
85
|
+
}
|
|
86
|
+
// Re-read rather than trusting the chmod: a filesystem that ignores mode
|
|
87
|
+
// bits must still fail closed.
|
|
88
|
+
if ((lstatSync(locksDir).mode & 0o777) !== 0o700) {
|
|
89
|
+
throw new CodexUserIdentityRefusal("Codex Log Guard lock directory is not private to the effective user.");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return join(locksDir, `${codexLogGuardLockDigest(canonicalCodexHome, canonicalLogsDbPath)}.sqlite`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function withCodexLogGuardLock<T>(
|
|
98
|
+
canonicalCodexHome: string,
|
|
99
|
+
canonicalLogsDbPath: string,
|
|
100
|
+
work: () => T,
|
|
101
|
+
deps: CodexLogGuardLockDeps = {},
|
|
102
|
+
): CodexLogGuardLockOutcome<T> {
|
|
103
|
+
let databasePath: string;
|
|
104
|
+
try {
|
|
105
|
+
databasePath = deps.resolveDatabasePath?.(canonicalCodexHome, canonicalLogsDbPath)
|
|
106
|
+
?? resolveLogGuardLockDatabase(canonicalCodexHome, canonicalLogsDbPath);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof CodexUserIdentityRefusal) {
|
|
109
|
+
return { kind: "unavailable", reason: "unsafe-path" };
|
|
110
|
+
}
|
|
111
|
+
return { kind: "unavailable", reason: "database" };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let database: Database | undefined;
|
|
115
|
+
let transactionOpen = false;
|
|
116
|
+
try {
|
|
117
|
+
let absent = false;
|
|
118
|
+
try {
|
|
119
|
+
if (!lockFileIsSafe(databasePath, false)) {
|
|
120
|
+
return { kind: "unavailable", reason: "unsafe-path" };
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if ((error as NodeJS.ErrnoException | undefined)?.code !== "ENOENT") throw error;
|
|
124
|
+
absent = true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
database = new Database(databasePath, { create: true });
|
|
128
|
+
if (absent) {
|
|
129
|
+
try { chmodSync(databasePath, 0o600); } catch { /* Windows permissions are enforced by the trusted runtime root. */ }
|
|
130
|
+
}
|
|
131
|
+
if (!lockFileIsSafe(databasePath, true)) {
|
|
132
|
+
return { kind: "unavailable", reason: "unsafe-path" };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
database.exec("PRAGMA busy_timeout = 0; BEGIN IMMEDIATE");
|
|
136
|
+
transactionOpen = true;
|
|
137
|
+
const value = work();
|
|
138
|
+
database.exec("COMMIT");
|
|
139
|
+
transactionOpen = false;
|
|
140
|
+
return { kind: "completed", value };
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (transactionOpen) {
|
|
143
|
+
try { database?.exec("ROLLBACK"); } catch { /* close releases it */ }
|
|
144
|
+
}
|
|
145
|
+
if (isSqliteBusy(error)) return { kind: "unavailable", reason: "busy" };
|
|
146
|
+
throw error;
|
|
147
|
+
} finally {
|
|
148
|
+
try { database?.close(); } catch { /* acquisition already settled */ }
|
|
149
|
+
}
|
|
150
|
+
}
|