@remodex/rmx 1.0.2
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 +91 -0
- package/LICENSE +21 -0
- package/README.md +242 -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 +584 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-CZqebSPQ.css +1 -0
- package/gui/dist/assets/index-CkETtt7P.js +71 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/fonts/google-sans-cyrillic.woff2 +0 -0
- package/gui/dist/fonts/google-sans-latin.woff2 +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 +118 -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.ts +1205 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +83 -0
- package/src/adapters/client-fingerprint.ts +59 -0
- package/src/adapters/command-code.ts +453 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/cursor-errors.ts +165 -0
- package/src/adapters/cursor/discovery.ts +276 -0
- package/src/adapters/cursor/effort-map.ts +139 -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/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +153 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1235 -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 +59 -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 +548 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +604 -0
- package/src/adapters/cursor/protobuf-events.ts +735 -0
- package/src/adapters/cursor/protobuf-request.ts +719 -0
- package/src/adapters/cursor/request-builder.ts +280 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +621 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +57 -0
- package/src/adapters/cursor/types.ts +59 -0
- package/src/adapters/cursor.ts +196 -0
- package/src/adapters/google-antigravity-replay.ts +520 -0
- package/src/adapters/google-antigravity-wire.ts +140 -0
- package/src/adapters/google-errors.ts +85 -0
- package/src/adapters/google-http.ts +100 -0
- package/src/adapters/google-tool-schema.ts +173 -0
- package/src/adapters/google-truncation.ts +24 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +859 -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 +104 -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 +1924 -0
- package/src/adapters/mimo-free.ts +263 -0
- package/src/adapters/openai-chat.ts +1265 -0
- package/src/adapters/openai-responses.ts +1309 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-catalog-nudge.ts +71 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/android-remote/assets.ts +218 -0
- package/src/android-remote/attachments.ts +168 -0
- package/src/android-remote/auth.ts +237 -0
- package/src/android-remote/cloudflare-provisioning.ts +409 -0
- package/src/android-remote/cloudflare-secret.ts +106 -0
- package/src/android-remote/cloudflare-tunnel.ts +488 -0
- package/src/android-remote/cloudflared.ts +286 -0
- package/src/android-remote/codex-app-server.ts +565 -0
- package/src/android-remote/desktop-history-page.ts +936 -0
- package/src/android-remote/desktop-ipc.ts +3643 -0
- package/src/android-remote/desktop-ownership-store.ts +98 -0
- package/src/android-remote/desktop-project-registration.ts +129 -0
- package/src/android-remote/desktop-session-stream.ts +1110 -0
- package/src/android-remote/desktop-workspace-state.ts +443 -0
- package/src/android-remote/file-change-parser.ts +112 -0
- package/src/android-remote/gateway.ts +9108 -0
- package/src/android-remote/mutation-store.ts +299 -0
- package/src/android-remote/projection.ts +1780 -0
- package/src/android-remote/queued-turn-store.ts +248 -0
- package/src/android-remote/session-command-recovery.ts +1384 -0
- package/src/android-remote/store.ts +466 -0
- package/src/android-remote/thread-reconciliation.ts +133 -0
- package/src/android-remote/thread-source-paths.ts +307 -0
- package/src/android-remote/thread-stream.ts +546 -0
- package/src/android-remote/turn-activity.ts +235 -0
- package/src/android-remote/user-message-identity.ts +94 -0
- package/src/bridge.ts +1793 -0
- package/src/chat/inbound.ts +295 -0
- package/src/chat/outbound.ts +821 -0
- package/src/claude/agents-inject.ts +267 -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 +189 -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 +601 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +70 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +519 -0
- package/src/claude/model-info.ts +154 -0
- package/src/claude/outbound.ts +898 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +296 -0
- package/src/cli/account-auth.ts +250 -0
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +476 -0
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +297 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +184 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-desktop.ts +211 -0
- package/src/cli/claude.ts +302 -0
- package/src/cli/codex-shim-autorestore.ts +45 -0
- package/src/cli/codex-shim-readiness.ts +69 -0
- package/src/cli/combo.ts +124 -0
- package/src/cli/config-command.ts +183 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/desktop-first-run.ts +25 -0
- package/src/cli/doctor.ts +1022 -0
- package/src/cli/export-command.ts +201 -0
- package/src/cli/help.ts +370 -0
- package/src/cli/index.ts +1565 -0
- package/src/cli/init.ts +224 -0
- package/src/cli/integrations.ts +225 -0
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/internal-dispatch.ts +35 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/models-runtime.ts +224 -0
- package/src/cli/models.ts +340 -0
- package/src/cli/observe.ts +170 -0
- package/src/cli/opencode.ts +587 -0
- package/src/cli/provider-runtime.ts +179 -0
- package/src/cli/provider.ts +476 -0
- package/src/cli/ready.ts +301 -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 +321 -0
- package/src/cli/system-command.ts +196 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +205 -0
- package/src/cli/v2.ts +200 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +1109 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +34 -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 +517 -0
- package/src/codex/account-usability.ts +40 -0
- package/src/codex/admission.ts +263 -0
- package/src/codex/app-server-processes.ts +799 -0
- package/src/codex/auth-api.ts +2098 -0
- package/src/codex/auth-collision.ts +107 -0
- package/src/codex/auth-context.ts +480 -0
- package/src/codex/autostart-health.ts +156 -0
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +471 -0
- package/src/codex/catalog/bundled.ts +533 -0
- package/src/codex/catalog/effort.ts +432 -0
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +287 -0
- package/src/codex/catalog/native-models.ts +7 -0
- package/src/codex/catalog/parsing.ts +503 -0
- package/src/codex/catalog/provider-fetch.ts +2267 -0
- package/src/codex/catalog/sync.ts +1606 -0
- package/src/codex/catalog-admission.ts +197 -0
- package/src/codex/catalog-refresh-status.ts +87 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +15 -0
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +593 -0
- package/src/codex/convergence.ts +580 -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/desktop-client-processes.ts +521 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +1091 -0
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +347 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +115 -0
- package/src/codex/history-provider.ts +1075 -0
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +204 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject-coordination.ts +257 -0
- package/src/codex/inject.ts +1857 -0
- package/src/codex/injected-marker.ts +79 -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 +105 -0
- package/src/codex/journal.ts +172 -0
- package/src/codex/main-account-cache.ts +56 -0
- package/src/codex/main-account.ts +40 -0
- package/src/codex/management-convergence.ts +114 -0
- package/src/codex/model-cache.ts +267 -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 +167 -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 +348 -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 +691 -0
- package/src/codex/paths.ts +78 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +295 -0
- package/src/codex/project-config-warnings.ts +426 -0
- package/src/codex/prompt-journal.ts +311 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/provider-adoption.ts +242 -0
- package/src/codex/quota-rejection.ts +224 -0
- package/src/codex/quota.ts +494 -0
- package/src/codex/refresh.ts +60 -0
- package/src/codex/routing.ts +1855 -0
- package/src/codex/runtime.ts +659 -0
- package/src/codex/shim.ts +1215 -0
- package/src/codex/subagent-defaults.ts +557 -0
- package/src/codex/subagent-model-fallback.ts +560 -0
- package/src/codex/sync.ts +238 -0
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +374 -0
- package/src/codex/warmup.ts +192 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +140 -0
- package/src/combos/index.ts +44 -0
- package/src/combos/request.ts +64 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +392 -0
- package/src/config.ts +3270 -0
- package/src/generated/model-metadata.ts +144 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +540 -0
- package/src/grok/inspect.ts +45 -0
- package/src/grok/status.ts +127 -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 +922 -0
- package/src/images/plan.ts +133 -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 +151 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +108 -0
- package/src/integrations/serialize.ts +235 -0
- package/src/integrations/state.ts +290 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer.ts +492 -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 +173 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +242 -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 +127 -0
- package/src/lib/config-ownership.ts +438 -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 +316 -0
- package/src/lib/errors.ts +364 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/open-url.ts +25 -0
- package/src/lib/pinned-http.ts +182 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +168 -0
- package/src/lib/provider-environment.ts +470 -0
- package/src/lib/provider-outbound.ts +203 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +510 -0
- package/src/lib/remodex-home.ts +616 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/service-secrets.ts +178 -0
- package/src/lib/shadow-call.ts +54 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +364 -0
- package/src/lib/state-store-registrations.ts +109 -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 +98 -0
- package/src/lib/token-estimate.ts +69 -0
- package/src/lib/translator-budget.ts +366 -0
- package/src/lib/upstream-reachability.ts +91 -0
- package/src/lib/upstream-retry.ts +508 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-elevation.ts +705 -0
- package/src/lib/windows-secret-acl.ts +817 -0
- package/src/lib/windows-user-principal.ts +283 -0
- package/src/lib/winsw.ts +402 -0
- package/src/model-sources.ts +73 -0
- package/src/oauth/anthropic-routing.ts +594 -0
- package/src/oauth/anthropic.ts +177 -0
- package/src/oauth/callback-server.ts +294 -0
- package/src/oauth/chatgpt.ts +150 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +231 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +230 -0
- package/src/oauth/health.ts +443 -0
- package/src/oauth/index.ts +1280 -0
- package/src/oauth/key-providers.ts +128 -0
- package/src/oauth/kimi.ts +213 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +621 -0
- package/src/oauth/local-token-detect.ts +121 -0
- package/src/oauth/log.ts +48 -0
- package/src/oauth/login-cli.ts +163 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +655 -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 +317 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +64 -0
- package/src/providers/codex-capacity.ts +288 -0
- package/src/providers/command-code-efforts.ts +85 -0
- package/src/providers/context-cap.ts +73 -0
- package/src/providers/derive.ts +451 -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 +361 -0
- package/src/providers/openai-sidecar.ts +235 -0
- package/src/providers/openai-tier-startup.ts +27 -0
- package/src/providers/openai-tiers.ts +301 -0
- package/src/providers/openai-virtual-models.ts +83 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +179 -0
- package/src/providers/quota.ts +1942 -0
- package/src/providers/reasoning-capabilities.ts +336 -0
- package/src/providers/registry.ts +2375 -0
- package/src/providers/slug-codec.ts +74 -0
- package/src/providers/xai-transport.ts +149 -0
- package/src/reasoning-effort.ts +243 -0
- package/src/responses/compaction.ts +124 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/parser.ts +714 -0
- package/src/responses/reasoning-envelope.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +106 -0
- package/src/responses/schema.ts +159 -0
- package/src/responses/spill-store.ts +431 -0
- package/src/responses/state.ts +1039 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/router.ts +802 -0
- package/src/routing/analytics.ts +377 -0
- package/src/routing/capability.ts +205 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +444 -0
- package/src/routing/health.ts +401 -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 +424 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +686 -0
- package/src/server/adapter-resolve.ts +83 -0
- package/src/server/auth-cors.ts +606 -0
- package/src/server/chat-completions.ts +379 -0
- package/src/server/claude-messages.ts +980 -0
- package/src/server/effort-policy.ts +251 -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 +485 -0
- package/src/server/index.ts +1633 -0
- package/src/server/lifecycle.ts +482 -0
- package/src/server/live.ts +609 -0
- package/src/server/management/agent-settings-routes.ts +1180 -0
- package/src/server/management/android-remote-routes.ts +390 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +167 -0
- package/src/server/management/body.ts +35 -0
- package/src/server/management/combo-routes.ts +244 -0
- package/src/server/management/config-routes.ts +602 -0
- package/src/server/management/context.ts +88 -0
- package/src/server/management/integration-routes.ts +538 -0
- package/src/server/management/logs-usage-routes.ts +516 -0
- package/src/server/management/model-routes.ts +519 -0
- package/src/server/management/model-rows.ts +143 -0
- package/src/server/management/native-integration-routes.ts +781 -0
- package/src/server/management/oauth-account-routes.ts +573 -0
- package/src/server/management/provider-routes.ts +781 -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 +384 -0
- package/src/server/management/shared.ts +277 -0
- package/src/server/management/sidebar-routes.ts +106 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +433 -0
- package/src/server/management/system-routes.ts +141 -0
- package/src/server/management/usage-summary-cache.ts +86 -0
- package/src/server/management-api.ts +269 -0
- package/src/server/management-auth.ts +353 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +156 -0
- package/src/server/proxy-liveness.ts +326 -0
- package/src/server/proxy-stop.ts +92 -0
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +353 -0
- package/src/server/relay.ts +1179 -0
- package/src/server/request-decompress.ts +132 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1072 -0
- package/src/server/responses/collaboration.ts +409 -0
- package/src/server/responses/compact.ts +710 -0
- package/src/server/responses/core.ts +3561 -0
- package/src/server/responses/encrypted-payload.ts +308 -0
- package/src/server/responses/fetch-helpers.ts +171 -0
- package/src/server/responses/passthrough-error.ts +78 -0
- package/src/server/responses/policy-fallback.ts +152 -0
- package/src/server/responses/terminal-guard.ts +230 -0
- package/src/server/responses/upstream-error.ts +48 -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 +52 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses.ts +10 -0
- package/src/server/search.ts +181 -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 +308 -0
- package/src/server/startup-health-cache.ts +119 -0
- package/src/server/system-env.ts +418 -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 +470 -0
- package/src/service-manager-probe.ts +824 -0
- package/src/service.ts +3011 -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 +738 -0
- package/src/types.ts +1531 -0
- package/src/update/badge.ts +72 -0
- package/src/update/desktop-release.ts +1620 -0
- package/src/update/index.ts +402 -0
- package/src/update/job.ts +1906 -0
- package/src/update/notify.ts +261 -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/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +283 -0
- package/src/usage/log.ts +695 -0
- package/src/usage/summary.ts +585 -0
- package/src/usage/totals.ts +14 -0
- package/src/vision/anthropic-describe.ts +185 -0
- package/src/vision/describe.ts +127 -0
- package/src/vision/index.ts +558 -0
- package/src/vision/reasoning.ts +55 -0
- package/src/web-search/anthropic-executor.ts +189 -0
- package/src/web-search/executor.ts +105 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/index.ts +196 -0
- package/src/web-search/loop.ts +791 -0
- package/src/web-search/parse.ts +235 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/synthetic-tool.ts +47 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import {
|
|
2
|
+
closeSync,
|
|
3
|
+
constants as fsConstants,
|
|
4
|
+
fstatSync,
|
|
5
|
+
fsyncSync,
|
|
6
|
+
ftruncateSync,
|
|
7
|
+
lstatSync,
|
|
8
|
+
openSync,
|
|
9
|
+
readdirSync,
|
|
10
|
+
realpathSync,
|
|
11
|
+
unlinkSync,
|
|
12
|
+
} from "node:fs";
|
|
13
|
+
import { dirname, join, resolve } from "node:path";
|
|
14
|
+
|
|
15
|
+
import type { NativeProfileContext } from "./native-profile-store";
|
|
16
|
+
import { NativeProfileError } from "./native-profile-types";
|
|
17
|
+
|
|
18
|
+
const AUTH_TEMP_NAME = /^auth\.json\.ocx\.[1-9]\d*\.[1-9]\d*\.tmp$/;
|
|
19
|
+
const MAX_AUTH_TEMP_RESIDUES = 128;
|
|
20
|
+
|
|
21
|
+
interface PathIdentity {
|
|
22
|
+
readonly dev: bigint;
|
|
23
|
+
readonly ino: bigint;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface NativeMainAuthTempScrubTestSeam {
|
|
27
|
+
/** Test-only race seam. Production never supplies this callback. */
|
|
28
|
+
beforeOpen?: (path: string) => void;
|
|
29
|
+
/** Test-only removal-failure seam. Production never supplies this callback. */
|
|
30
|
+
beforeUnlink?: (path: string) => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface NativeMainAuthTempScrubResult {
|
|
34
|
+
scrubbed: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function cleanupRequired(): NativeProfileError {
|
|
38
|
+
return new NativeProfileError(
|
|
39
|
+
"AUTH_TEMP_CLEANUP_REQUIRED",
|
|
40
|
+
"A native-main credential write residue could not be safely removed; manual cleanup is required.",
|
|
41
|
+
500,
|
|
42
|
+
false,
|
|
43
|
+
true,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function errorCode(error: unknown): string | undefined {
|
|
48
|
+
return error && typeof error === "object" && "code" in error
|
|
49
|
+
? String((error as { code?: unknown }).code)
|
|
50
|
+
: undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function sameIdentity(stats: { dev: bigint; ino: bigint }, expected: PathIdentity): boolean {
|
|
54
|
+
return stats.dev === expected.dev && stats.ino === expected.ino;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function samePath(left: string, right: string): boolean {
|
|
58
|
+
return resolve(left) === resolve(right);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function inspectCanonicalParent(path: string, expected?: PathIdentity): PathIdentity {
|
|
62
|
+
const absolute = resolve(path);
|
|
63
|
+
const entry = lstatSync(absolute, { bigint: true });
|
|
64
|
+
if (!entry.isDirectory() || entry.isSymbolicLink()) throw cleanupRequired();
|
|
65
|
+
const canonical = realpathSync.native(absolute);
|
|
66
|
+
if (!samePath(canonical, absolute)) throw cleanupRequired();
|
|
67
|
+
if (expected && !sameIdentity(entry, expected)) throw cleanupRequired();
|
|
68
|
+
return { dev: entry.dev, ino: entry.ino };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function inspectExactPath(path: string, parent: string, expected?: PathIdentity): PathIdentity {
|
|
72
|
+
const absolute = resolve(path);
|
|
73
|
+
if (!samePath(dirname(absolute), parent)) throw cleanupRequired();
|
|
74
|
+
const entry = lstatSync(absolute, { bigint: true });
|
|
75
|
+
if (!entry.isFile() || entry.isSymbolicLink() || entry.nlink !== 1n) throw cleanupRequired();
|
|
76
|
+
const canonical = realpathSync.native(absolute);
|
|
77
|
+
if (!samePath(canonical, absolute) || !samePath(dirname(canonical), parent)) throw cleanupRequired();
|
|
78
|
+
if (expected && !sameIdentity(entry, expected)) throw cleanupRequired();
|
|
79
|
+
return { dev: entry.dev, ino: entry.ino };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function exactResidues(parent: string, parentIdentity: PathIdentity): string[] {
|
|
83
|
+
inspectCanonicalParent(parent, parentIdentity);
|
|
84
|
+
const names = readdirSync(parent).filter(name => AUTH_TEMP_NAME.test(name)).sort();
|
|
85
|
+
inspectCanonicalParent(parent, parentIdentity);
|
|
86
|
+
if (names.length > MAX_AUTH_TEMP_RESIDUES) throw cleanupRequired();
|
|
87
|
+
return names;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function assertOpenIdentity(
|
|
91
|
+
fd: number,
|
|
92
|
+
path: string,
|
|
93
|
+
parent: string,
|
|
94
|
+
parentIdentity: PathIdentity,
|
|
95
|
+
expected: PathIdentity,
|
|
96
|
+
expectedLinks: bigint,
|
|
97
|
+
): void {
|
|
98
|
+
inspectCanonicalParent(parent, parentIdentity);
|
|
99
|
+
const opened = fstatSync(fd, { bigint: true });
|
|
100
|
+
if (
|
|
101
|
+
!opened.isFile()
|
|
102
|
+
|| !sameIdentity(opened, expected)
|
|
103
|
+
|| opened.nlink !== expectedLinks
|
|
104
|
+
) throw cleanupRequired();
|
|
105
|
+
inspectExactPath(path, parent, expected);
|
|
106
|
+
inspectCanonicalParent(parent, parentIdentity);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function scrubOne(
|
|
110
|
+
path: string,
|
|
111
|
+
parent: string,
|
|
112
|
+
parentIdentity: PathIdentity,
|
|
113
|
+
seam: NativeMainAuthTempScrubTestSeam,
|
|
114
|
+
): void {
|
|
115
|
+
const observed = inspectExactPath(path, parent);
|
|
116
|
+
inspectCanonicalParent(parent, parentIdentity);
|
|
117
|
+
seam.beforeOpen?.(path);
|
|
118
|
+
|
|
119
|
+
const flags = process.platform === "win32"
|
|
120
|
+
? fsConstants.O_RDWR
|
|
121
|
+
: fsConstants.O_RDWR | fsConstants.O_NOFOLLOW;
|
|
122
|
+
let fd: number | undefined;
|
|
123
|
+
let failed = false;
|
|
124
|
+
try {
|
|
125
|
+
fd = openSync(path, flags);
|
|
126
|
+
assertOpenIdentity(fd, path, parent, parentIdentity, observed, 1n);
|
|
127
|
+
|
|
128
|
+
ftruncateSync(fd, 0);
|
|
129
|
+
fsyncSync(fd);
|
|
130
|
+
const truncated = fstatSync(fd, { bigint: true });
|
|
131
|
+
if (!sameIdentity(truncated, observed) || truncated.nlink !== 1n || truncated.size !== 0n) {
|
|
132
|
+
throw cleanupRequired();
|
|
133
|
+
}
|
|
134
|
+
assertOpenIdentity(fd, path, parent, parentIdentity, observed, 1n);
|
|
135
|
+
seam.beforeUnlink?.(path);
|
|
136
|
+
|
|
137
|
+
// The lifetime owner and exclusive claim exclude cooperative Remodex writers.
|
|
138
|
+
// A malicious process running as the same OS user can still race Node's final
|
|
139
|
+
// identity-check/unlink gap and is intentionally outside this trusted-owner boundary.
|
|
140
|
+
unlinkSync(path);
|
|
141
|
+
const unlinked = fstatSync(fd, { bigint: true });
|
|
142
|
+
if (!sameIdentity(unlinked, observed) || unlinked.nlink !== 0n || unlinked.size !== 0n) {
|
|
143
|
+
throw cleanupRequired();
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
lstatSync(path);
|
|
147
|
+
throw cleanupRequired();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (error instanceof NativeProfileError) throw error;
|
|
150
|
+
if (errorCode(error) !== "ENOENT") throw error;
|
|
151
|
+
}
|
|
152
|
+
inspectCanonicalParent(parent, parentIdentity);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
failed = true;
|
|
155
|
+
throw error;
|
|
156
|
+
} finally {
|
|
157
|
+
if (fd !== undefined) {
|
|
158
|
+
try { closeSync(fd); }
|
|
159
|
+
catch (error) { if (!failed) throw error; }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Remove only crash residues created by atomicWriteFileAsync for canonical auth.json.
|
|
166
|
+
* The caller must hold the lifetime native-main owner and exclusive credential claim.
|
|
167
|
+
*/
|
|
168
|
+
export function scrubNativeMainAuthTempResidues(
|
|
169
|
+
context: NativeProfileContext,
|
|
170
|
+
seam: NativeMainAuthTempScrubTestSeam = {},
|
|
171
|
+
): NativeMainAuthTempScrubResult {
|
|
172
|
+
try {
|
|
173
|
+
const parent = resolve(context.codexHome);
|
|
174
|
+
const parentIdentity = inspectCanonicalParent(parent);
|
|
175
|
+
const names = exactResidues(parent, parentIdentity);
|
|
176
|
+
for (const name of names) {
|
|
177
|
+
scrubOne(join(parent, name), parent, parentIdentity, seam);
|
|
178
|
+
}
|
|
179
|
+
// A cooperative writer cannot create a new residue while the owner and
|
|
180
|
+
// exclusive claim are held. Seeing one now is ambiguous, so admission stays closed.
|
|
181
|
+
if (exactResidues(parent, parentIdentity).length !== 0) throw cleanupRequired();
|
|
182
|
+
return { scrubbed: names.length };
|
|
183
|
+
} catch (error) {
|
|
184
|
+
if (error instanceof NativeProfileError) throw error;
|
|
185
|
+
throw cleanupRequired();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
|
|
3
|
+
import { Database } from "bun:sqlite";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
assertStableLockFile,
|
|
7
|
+
hardenStableLockFile,
|
|
8
|
+
openStableLockFile,
|
|
9
|
+
type StableLockFile,
|
|
10
|
+
} from "./native-main-lock-file";
|
|
11
|
+
import { nativeMainOwnerFilesystemSupported } from "./native-main-owner";
|
|
12
|
+
import type { NativeProfileContext } from "./native-profile-store";
|
|
13
|
+
import { NativeProfileError } from "./native-profile-types";
|
|
14
|
+
|
|
15
|
+
export const NATIVE_MAIN_CLAIM_DB = ".opencodex-native-main.claim.sqlite";
|
|
16
|
+
|
|
17
|
+
export interface NativeMainClaimOptions {
|
|
18
|
+
waitMs?: number;
|
|
19
|
+
pollMs?: number;
|
|
20
|
+
hardenPath?: (path: string) => Promise<void>;
|
|
21
|
+
platform?: NodeJS.Platform;
|
|
22
|
+
env?: NodeJS.ProcessEnv;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const hardenedIdentities = new Map<string, string>();
|
|
26
|
+
|
|
27
|
+
export function nativeMainClaimPath(context: NativeProfileContext): string {
|
|
28
|
+
return join(context.codexHome, NATIVE_MAIN_CLAIM_DB);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function errorCode(error: unknown): string | undefined {
|
|
32
|
+
return error && typeof error === "object" && "code" in error
|
|
33
|
+
? String((error as { code?: unknown }).code)
|
|
34
|
+
: undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isBusy(error: unknown): boolean {
|
|
38
|
+
const code = errorCode(error);
|
|
39
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
40
|
+
return code === "SQLITE_BUSY" || code === "SQLITE_LOCKED" || /database (?:is|table is) locked/i.test(message);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function busyClaimError(message: string): NativeProfileError {
|
|
44
|
+
return new NativeProfileError("NATIVE_MAIN_CLAIM_BUSY", message, 503, true);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function unavailableClaimError(): NativeProfileError {
|
|
48
|
+
return new NativeProfileError(
|
|
49
|
+
"NATIVE_MAIN_CLAIM_UNAVAILABLE",
|
|
50
|
+
"The native-main cross-process claim is unavailable.",
|
|
51
|
+
503,
|
|
52
|
+
true,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function mapClaimSetupError(error: unknown, busyMessage: string): NativeProfileError {
|
|
57
|
+
if (error instanceof NativeProfileError) return error;
|
|
58
|
+
return isBusy(error) ? busyClaimError(busyMessage) : unavailableClaimError();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function openClaimDatabase(
|
|
62
|
+
context: NativeProfileContext,
|
|
63
|
+
options: NativeMainClaimOptions,
|
|
64
|
+
): Promise<{ database: Database; file: StableLockFile }> {
|
|
65
|
+
const platform = options.platform ?? process.platform;
|
|
66
|
+
if (!nativeMainOwnerFilesystemSupported(context.codexHome, platform, options.env ?? process.env)) {
|
|
67
|
+
throw new NativeProfileError(
|
|
68
|
+
"NATIVE_MAIN_CLAIM_UNAVAILABLE",
|
|
69
|
+
"Native-main claims are unsupported on this CODEX_HOME filesystem.",
|
|
70
|
+
503,
|
|
71
|
+
true,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const path = nativeMainClaimPath(context);
|
|
75
|
+
let file: StableLockFile | undefined;
|
|
76
|
+
let database: Database | undefined;
|
|
77
|
+
try {
|
|
78
|
+
file = openStableLockFile(path, platform);
|
|
79
|
+
const identity = `${file.dev}:${file.ino}`;
|
|
80
|
+
if (hardenedIdentities.get(path) !== identity) {
|
|
81
|
+
// The resolved platform is threaded into the DEFAULT hardener, not left to
|
|
82
|
+
// `hardenStableLockFile`'s own `process.platform` read. Otherwise a test
|
|
83
|
+
// that forces `platform` here still exercises the host's branch, and the
|
|
84
|
+
// production default — the thing that actually hardens a coordinator
|
|
85
|
+
// database — stays unproved. An audit deleted this call entirely and 89
|
|
86
|
+
// tests stayed green, because nearly every claim test injects `hardenPath`.
|
|
87
|
+
await (options.hardenPath ?? ((target: string) => hardenStableLockFile(target, platform)))(path);
|
|
88
|
+
assertStableLockFile(path, file);
|
|
89
|
+
hardenedIdentities.set(path, identity);
|
|
90
|
+
}
|
|
91
|
+
database = new Database(path, { create: true });
|
|
92
|
+
// Journal-mode negotiation itself may need a database lock. Disable
|
|
93
|
+
// SQLite's synchronous busy wait first so a contender never blocks Bun's
|
|
94
|
+
// event loop while the current shared holder is waiting for JS to release.
|
|
95
|
+
database.exec("PRAGMA busy_timeout = 0; PRAGMA locking_mode = NORMAL");
|
|
96
|
+
const mode = database.query<{ journal_mode: string }, []>("PRAGMA journal_mode = DELETE").get()?.journal_mode;
|
|
97
|
+
if (mode?.toLowerCase() !== "delete") throw new Error("native-main claim database is not in rollback-journal mode");
|
|
98
|
+
assertStableLockFile(path, file);
|
|
99
|
+
return { database, file };
|
|
100
|
+
} catch (error) {
|
|
101
|
+
try { database?.close(); } catch { /* mapped below */ }
|
|
102
|
+
try { file?.close(); } catch { /* mapped below */ }
|
|
103
|
+
throw mapClaimSetupError(error, "Native-main credentials are changing.");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function releaseClaim(database: Database | undefined, file: StableLockFile | undefined): void {
|
|
108
|
+
try { database?.exec("ROLLBACK"); } catch { /* close still releases the OS-backed claim */ }
|
|
109
|
+
try { database?.close(); } catch { /* operation already completed */ }
|
|
110
|
+
try { file?.close(); } catch { /* operation already completed */ }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export async function withNativeMainSharedClaim<T>(
|
|
114
|
+
context: NativeProfileContext,
|
|
115
|
+
operation: () => Promise<T>,
|
|
116
|
+
options: NativeMainClaimOptions = {},
|
|
117
|
+
): Promise<T> {
|
|
118
|
+
let database: Database | undefined;
|
|
119
|
+
let file: StableLockFile | undefined;
|
|
120
|
+
try {
|
|
121
|
+
({ database, file } = await openClaimDatabase(context, options));
|
|
122
|
+
database.exec("BEGIN");
|
|
123
|
+
// A deferred BEGIN alone owns no lock. Reading page 1 through sqlite_schema
|
|
124
|
+
// establishes the SHARED lock that an exclusive transition must drain.
|
|
125
|
+
database.query<{ rootpage: number }, []>("SELECT rootpage FROM sqlite_schema LIMIT 1").get();
|
|
126
|
+
assertStableLockFile(nativeMainClaimPath(context), file);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
releaseClaim(database, file);
|
|
129
|
+
throw mapClaimSetupError(error, "Native-main credentials are changing.");
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
return await operation();
|
|
133
|
+
} finally {
|
|
134
|
+
releaseClaim(database, file);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function withNativeMainExclusiveClaim<T>(
|
|
139
|
+
context: NativeProfileContext,
|
|
140
|
+
operation: () => Promise<T>,
|
|
141
|
+
options: NativeMainClaimOptions = {},
|
|
142
|
+
): Promise<T> {
|
|
143
|
+
const deadline = Date.now() + Math.max(0, options.waitMs ?? 0);
|
|
144
|
+
const pollMs = Math.max(1, options.pollMs ?? 50);
|
|
145
|
+
for (;;) {
|
|
146
|
+
let database: Database | undefined;
|
|
147
|
+
let file: StableLockFile | undefined;
|
|
148
|
+
try {
|
|
149
|
+
({ database, file } = await openClaimDatabase(context, options));
|
|
150
|
+
database.exec("BEGIN EXCLUSIVE");
|
|
151
|
+
assertStableLockFile(nativeMainClaimPath(context), file);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
releaseClaim(database, file);
|
|
154
|
+
const mapped = mapClaimSetupError(error, "Native-main credentials are in use.");
|
|
155
|
+
if (mapped.code === "NATIVE_MAIN_CLAIM_BUSY" && Date.now() < deadline) {
|
|
156
|
+
await Bun.sleep(Math.min(pollMs, Math.max(1, deadline - Date.now())));
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
throw mapped;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
return await operation();
|
|
163
|
+
} finally {
|
|
164
|
+
releaseClaim(database, file);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
chmodSync,
|
|
3
|
+
closeSync,
|
|
4
|
+
constants,
|
|
5
|
+
existsSync,
|
|
6
|
+
fstatSync,
|
|
7
|
+
lstatSync,
|
|
8
|
+
openSync,
|
|
9
|
+
type Stats,
|
|
10
|
+
} from "node:fs";
|
|
11
|
+
|
|
12
|
+
import { hardenSecretPathAsync } from "../lib/windows-secret-acl";
|
|
13
|
+
|
|
14
|
+
export interface StableLockFile {
|
|
15
|
+
readonly fd: number;
|
|
16
|
+
readonly dev: number;
|
|
17
|
+
readonly ino: number;
|
|
18
|
+
close(): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class StableLockPathUnsafeError extends Error {
|
|
22
|
+
constructor(message: string) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "StableLockPathUnsafeError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface StableLockEntry {
|
|
29
|
+
readonly fd: number;
|
|
30
|
+
readonly dev: number;
|
|
31
|
+
readonly ino: number;
|
|
32
|
+
refs: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// POSIX fcntl locks are process-associated: closing any raw descriptor for an
|
|
36
|
+
// inode can release SQLite locks held through a different descriptor in this
|
|
37
|
+
// process. Keep one side descriptor per canonical lock path and close it only
|
|
38
|
+
// after every SQLite user has closed its connection and released its reference.
|
|
39
|
+
const stableLockEntries = new Map<string, StableLockEntry>();
|
|
40
|
+
|
|
41
|
+
function reference(path: string, entry: StableLockEntry): StableLockFile {
|
|
42
|
+
let closed = false;
|
|
43
|
+
return {
|
|
44
|
+
fd: entry.fd,
|
|
45
|
+
dev: entry.dev,
|
|
46
|
+
ino: entry.ino,
|
|
47
|
+
close() {
|
|
48
|
+
if (closed) return;
|
|
49
|
+
closed = true;
|
|
50
|
+
entry.refs = Math.max(0, entry.refs - 1);
|
|
51
|
+
if (entry.refs !== 0) return;
|
|
52
|
+
if (stableLockEntries.get(path) === entry) stableLockEntries.delete(path);
|
|
53
|
+
closeSync(entry.fd);
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function assertRegular(stats: Stats, path: string): void {
|
|
59
|
+
if (!stats.isFile() || stats.isSymbolicLink()) {
|
|
60
|
+
throw new StableLockPathUnsafeError(`unsafe SQLite lock path: ${path}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function errorCode(error: unknown): string | undefined {
|
|
65
|
+
return error && typeof error === "object" && "code" in error
|
|
66
|
+
? String((error as { code?: unknown }).code)
|
|
67
|
+
: undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function matches(handle: StableLockFile, stats: Stats): boolean {
|
|
71
|
+
return handle.dev === stats.dev && handle.ino === stats.ino;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function openStableLockFile(path: string, platform: NodeJS.Platform = process.platform): StableLockFile {
|
|
75
|
+
const retained = stableLockEntries.get(path);
|
|
76
|
+
if (retained) {
|
|
77
|
+
retained.refs += 1;
|
|
78
|
+
const handle = reference(path, retained);
|
|
79
|
+
try {
|
|
80
|
+
assertStableLockFile(path, handle);
|
|
81
|
+
return handle;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
handle.close();
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (existsSync(path)) assertRegular(lstatSync(path), path);
|
|
88
|
+
const noFollow = platform === "win32" ? 0 : constants.O_NOFOLLOW;
|
|
89
|
+
const fd = openSync(path, constants.O_RDWR | constants.O_CREAT | noFollow, 0o600);
|
|
90
|
+
try {
|
|
91
|
+
const descriptor = fstatSync(fd);
|
|
92
|
+
assertRegular(descriptor, path);
|
|
93
|
+
const entry: StableLockEntry = {
|
|
94
|
+
fd,
|
|
95
|
+
dev: descriptor.dev,
|
|
96
|
+
ino: descriptor.ino,
|
|
97
|
+
refs: 1,
|
|
98
|
+
};
|
|
99
|
+
stableLockEntries.set(path, entry);
|
|
100
|
+
const handle = reference(path, entry);
|
|
101
|
+
assertStableLockFile(path, handle);
|
|
102
|
+
return handle;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
const entry = stableLockEntries.get(path);
|
|
105
|
+
if (entry?.fd === fd) stableLockEntries.delete(path);
|
|
106
|
+
closeSync(fd);
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function assertStableLockFile(path: string, handle: StableLockFile): void {
|
|
112
|
+
let pathStats: Stats;
|
|
113
|
+
try {
|
|
114
|
+
pathStats = lstatSync(path);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
if (errorCode(error) === "ENOENT") {
|
|
117
|
+
throw new StableLockPathUnsafeError(`SQLite lock path identity changed: ${path}`);
|
|
118
|
+
}
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
assertRegular(pathStats, path);
|
|
122
|
+
if (!matches(handle, pathStats)) {
|
|
123
|
+
throw new StableLockPathUnsafeError(`SQLite lock path identity changed: ${path}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Harden the stable lock file: chmod everywhere, per-user NTFS ACLs on Windows.
|
|
129
|
+
*
|
|
130
|
+
* The platform is a parameter rather than a direct `process.platform` read so the
|
|
131
|
+
* Windows branch is reachable from a test. It was not, and an audit deleted the
|
|
132
|
+
* whole ACL delegation without a single test noticing — the primitive underneath
|
|
133
|
+
* had 73 tests while the call edge that activates it had none. That is the same
|
|
134
|
+
* absence-as-guarantee defect one layer up: proving a mechanism works says nothing
|
|
135
|
+
* about whether production still calls it.
|
|
136
|
+
*
|
|
137
|
+
* `required: true` is deliberate: a failure to apply the ACL must reject rather
|
|
138
|
+
* than leave a coordinator database readable by other accounts.
|
|
139
|
+
*/
|
|
140
|
+
export async function hardenStableLockFile(
|
|
141
|
+
path: string,
|
|
142
|
+
platform: NodeJS.Platform = process.platform,
|
|
143
|
+
options: { retryTimedOutOnce?: boolean } = {},
|
|
144
|
+
): Promise<void> {
|
|
145
|
+
if (platform === "win32") {
|
|
146
|
+
// Best-effort here: POSIX modes are not authoritative on NTFS, and the
|
|
147
|
+
// required ACL hardening below is what actually decides.
|
|
148
|
+
try { chmodSync(path, 0o600); } catch { /* ACL below is authoritative. */ }
|
|
149
|
+
await hardenSecretPathAsync(path, {
|
|
150
|
+
required: true,
|
|
151
|
+
retryTimedOutOnce: options.retryTimedOutOnce,
|
|
152
|
+
});
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
// On POSIX the mode IS the mechanism, so a failure may not be swallowed.
|
|
156
|
+
//
|
|
157
|
+
// The previous unconditional catch was a real fail-open: a coordinator
|
|
158
|
+
// database that already existed with permissive bits stayed permissive, and
|
|
159
|
+
// the caller was told the lock file had been hardened. Creation mode 0600 does
|
|
160
|
+
// not repair an existing file, and there is no ACL fallback outside Windows.
|
|
161
|
+
chmodSync(path, 0o600);
|
|
162
|
+
}
|