@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,269 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import type { CatalogModel } from "../codex/catalog";
|
|
4
|
+
import { catalogModelSlug, invalidateCodexModelsCache, nativeModelRows, uniqueCatalogModelsForPublicList } from "../codex/catalog";
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_SUBAGENT_MODELS,
|
|
7
|
+
codexAutoStartEnabled,
|
|
8
|
+
hasOwnProvider,
|
|
9
|
+
isValidProviderName,
|
|
10
|
+
multiAgentGuidanceEnabled,
|
|
11
|
+
providerBaseUrlConfigError,
|
|
12
|
+
providerHeadersConfigError,
|
|
13
|
+
saveConfigPreservingClaudeCode,
|
|
14
|
+
} from "../config";
|
|
15
|
+
import {
|
|
16
|
+
clearLoginState,
|
|
17
|
+
getLoginStatus,
|
|
18
|
+
isPublicOAuthProvider,
|
|
19
|
+
listOAuthProviders,
|
|
20
|
+
startLoginFlow,
|
|
21
|
+
submitManualLoginCode,
|
|
22
|
+
upsertOAuthProvider,
|
|
23
|
+
} from "../oauth";
|
|
24
|
+
import { OAuthMutationBusyError, removeCredential } from "../oauth/store";
|
|
25
|
+
import { providerDestinationResolvedError } from "../lib/destination-policy";
|
|
26
|
+
import { enrichProviderFromCatalog, listKeyLoginProviders } from "../oauth/key-providers";
|
|
27
|
+
import { deriveProviderPresets } from "../providers/derive";
|
|
28
|
+
import { providerCodexAccountMode } from "../providers/registry";
|
|
29
|
+
import { routedSlug, slugEquals } from "../providers/slug-codec";
|
|
30
|
+
import { clearProviderQuotaCache, fetchProviderQuotaReports } from "../providers/quota";
|
|
31
|
+
import { isCanonicalOpenAiForwardProvider } from "../providers/openai-tiers";
|
|
32
|
+
import { clearThreadAccountMap } from "../codex/routing";
|
|
33
|
+
import { primeCodexPoolQuotas } from "../codex/auth-api";
|
|
34
|
+
import { DEFAULT_PROVIDER_CONTEXT_CAP, globalContextCapValue, providerContextCap, providerContextCaps, setAllProviderContextCaps, setGlobalContextCapValue, setProviderContextCap } from "../providers/context-cap";
|
|
35
|
+
import { resolveCodexHomeDir } from "../codex/home";
|
|
36
|
+
import { readUsageEntries } from "../usage/log";
|
|
37
|
+
import { getUsageDebugLogEntries } from "../usage/debug";
|
|
38
|
+
import { parseRange, parseUsageSurface, summarizeUsage } from "../usage/summary";
|
|
39
|
+
import { stripCodexRuntimeProviderFields } from "../codex/auth-context";
|
|
40
|
+
import { getProviderRegistryEntry } from "../providers/registry";
|
|
41
|
+
import { getDebugLogEntries } from "../lib/debug-log-buffer";
|
|
42
|
+
import { getInjectionDebugLogEntries } from "../lib/injection-debug-log";
|
|
43
|
+
import {
|
|
44
|
+
clearDebugSettings,
|
|
45
|
+
clearDebugSetting,
|
|
46
|
+
getDebugSettings,
|
|
47
|
+
setDebugSettings,
|
|
48
|
+
type DebugFlag,
|
|
49
|
+
} from "../lib/debug-settings";
|
|
50
|
+
import type { OcxClaudeCodeConfig, OcxClaudeDesktopProfile, OcxConfig, OcxCustomModel, OcxProviderConfig } from "../types";
|
|
51
|
+
import type { DesktopProfileModel } from "../claude/desktop-profile";
|
|
52
|
+
import { acquireTemporaryDrain, beginShutdownDrain, drainAndShutdown } from "./lifecycle";
|
|
53
|
+
import { prepareProxyStop } from "./proxy-stop";
|
|
54
|
+
import { filterRequestLogs, getRequestLogEntries, type RequestLogEntry } from "./request-log";
|
|
55
|
+
import { estimateComboCost, estimateRequestCost, normalizeCostTokens, tokensPerSecond } from "../usage/cost";
|
|
56
|
+
import type { PersistedUsageAttempt } from "../usage/log";
|
|
57
|
+
import { isAllowedManagementOrigin, jsonResponse, providerManagementConfigError, publicProviderBaseUrl, safeConfigDTO } from "./auth-cors";
|
|
58
|
+
import { applySystemEnvToggle } from "./system-env";
|
|
59
|
+
|
|
60
|
+
import type { ManagementApiDeps } from "./management/context";
|
|
61
|
+
import { handleConfigRoutes } from "./management/config-routes";
|
|
62
|
+
import { handleLogsUsageRoutes } from "./management/logs-usage-routes";
|
|
63
|
+
import { handleRequestHistoryRoutes } from "./management/request-history-routes";
|
|
64
|
+
import { handleRoutingAnalyticsRoutes } from "./management/routing-analytics-routes";
|
|
65
|
+
import { handleRoutingProfileRoutes } from "./management/routing-profile-routes";
|
|
66
|
+
import { handleProviderRoutes } from "./management/provider-routes";
|
|
67
|
+
import { handleModelRoutes } from "./management/model-routes";
|
|
68
|
+
import { handleAgentSettingsRoutes } from "./management/agent-settings-routes";
|
|
69
|
+
import { handleOauthAccountRoutes } from "./management/oauth-account-routes";
|
|
70
|
+
import { handleComboRoutes } from "./management/combo-routes";
|
|
71
|
+
import { handleSystemRoutes } from "./management/system-routes";
|
|
72
|
+
import { handleSidebarRoutes } from "./management/sidebar-routes";
|
|
73
|
+
import { handleIntegrationRoutes } from "./management/integration-routes";
|
|
74
|
+
import { handleNativeIntegrationRoutes } from "./management/native-integration-routes";
|
|
75
|
+
import { handleAndroidRemoteRoutes } from "./management/android-remote-routes";
|
|
76
|
+
import type { ManagementContext } from "./management/context";
|
|
77
|
+
import type { ManagementPrincipal } from "./management-auth";
|
|
78
|
+
export type { ManagementApiDeps } from "./management/context";
|
|
79
|
+
import { fetchAllModels } from "./management/shared";
|
|
80
|
+
import { CatalogGatherBusyError } from "../codex/catalog/provider-fetch";
|
|
81
|
+
import type { CatalogDisposition, ConvergeCodex } from "../codex/convergence-types";
|
|
82
|
+
import { normalizeCatalogDisposition } from "../codex/catalog-refresh-status";
|
|
83
|
+
import { managementBodyTooLargeResponse } from "./management/body";
|
|
84
|
+
|
|
85
|
+
// installed npm version instead of a stale hardcode.
|
|
86
|
+
export const VERSION = (() => {
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8")).version as string;
|
|
89
|
+
} catch {
|
|
90
|
+
return "0.0.0";
|
|
91
|
+
}
|
|
92
|
+
})();
|
|
93
|
+
|
|
94
|
+
const managementConvergenceBindings = new WeakMap<object, Readonly<{
|
|
95
|
+
factory: (config: Readonly<OcxConfig>) => ConvergeCodex;
|
|
96
|
+
converge: ConvergeCodex;
|
|
97
|
+
}>>();
|
|
98
|
+
|
|
99
|
+
export async function handleManagementAPI(
|
|
100
|
+
req: Request,
|
|
101
|
+
url: URL,
|
|
102
|
+
config: OcxConfig,
|
|
103
|
+
deps: ManagementApiDeps = {},
|
|
104
|
+
principal?: ManagementPrincipal,
|
|
105
|
+
): Promise<Response | null> {
|
|
106
|
+
if (!isAllowedManagementOrigin(req, config)) {
|
|
107
|
+
return jsonResponse({ error: "cross-origin request blocked" }, 403, req, config);
|
|
108
|
+
}
|
|
109
|
+
// Management bodies are small JSON (provider names, key ids, settings). Reject oversized
|
|
110
|
+
// payloads before any handler buffers them — the data plane has its own decompression cap.
|
|
111
|
+
if (req.method === "POST" || req.method === "PUT" || req.method === "PATCH") {
|
|
112
|
+
const contentLength = Number(req.headers.get("content-length") ?? "0");
|
|
113
|
+
if (Number.isFinite(contentLength) && contentLength > 2 * 1024 * 1024) {
|
|
114
|
+
return jsonResponse({ error: "request body too large" }, 413, req, config);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function convergeCodexCatalog(): Promise<CatalogDisposition> {
|
|
118
|
+
let convergenceInvoked = false;
|
|
119
|
+
let managementConvergeCodex: ConvergeCodex | undefined;
|
|
120
|
+
try {
|
|
121
|
+
if (!managementConvergeCodex) {
|
|
122
|
+
const factory = deps.createManagementConvergeCodex
|
|
123
|
+
?? (await import("../codex/management-convergence")).createManagementConvergeCodex;
|
|
124
|
+
if (typeof factory !== "function") throw new TypeError("Catalog convergence factory is unavailable.");
|
|
125
|
+
let binding = managementConvergenceBindings.get(config);
|
|
126
|
+
if (!binding || binding.factory !== factory) {
|
|
127
|
+
const created = factory(config);
|
|
128
|
+
if (typeof created !== "function") throw new TypeError("Catalog convergence factory returned no function.");
|
|
129
|
+
binding = { factory, converge: created };
|
|
130
|
+
managementConvergenceBindings.set(config, binding);
|
|
131
|
+
}
|
|
132
|
+
managementConvergeCodex = binding.converge;
|
|
133
|
+
}
|
|
134
|
+
const { createCatalogConvergeRequest } = await import("../codex/catalog-admission");
|
|
135
|
+
convergenceInvoked = true;
|
|
136
|
+
const outcome = await managementConvergeCodex(createCatalogConvergeRequest({ deadlineMs: 1_000 }));
|
|
137
|
+
const catalogRefresh = outcome?.kind === "catalog-only"
|
|
138
|
+
? normalizeCatalogDisposition(outcome.catalogRefresh)
|
|
139
|
+
: null;
|
|
140
|
+
if (!catalogRefresh) {
|
|
141
|
+
throw new TypeError("Catalog convergence returned an invalid outcome.");
|
|
142
|
+
}
|
|
143
|
+
return catalogRefresh;
|
|
144
|
+
} catch {
|
|
145
|
+
return {
|
|
146
|
+
status: "failed",
|
|
147
|
+
reason: "disk",
|
|
148
|
+
phase: convergenceInvoked ? "commit" : "gather",
|
|
149
|
+
retryable: false,
|
|
150
|
+
partialWrite: convergenceInvoked,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function syncClaudeAgentDefsBestEffort(): Promise<void> {
|
|
156
|
+
try {
|
|
157
|
+
const { injectClaudeAgentDefs } = await import("../claude/agents-inject");
|
|
158
|
+
if (config.claudeCode?.enabled === false || config.claudeCode?.injectAgents === false) {
|
|
159
|
+
injectClaudeAgentDefs(config, {});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const [models, { buildClaudeContextWindows }, { visibleNativeSlugs }] = await Promise.all([
|
|
164
|
+
fetchAllModels(config),
|
|
165
|
+
import("../claude/context-windows"),
|
|
166
|
+
import("../codex/catalog"),
|
|
167
|
+
]);
|
|
168
|
+
injectClaudeAgentDefs(config, buildClaudeContextWindows([...visibleNativeSlugs(config)], models));
|
|
169
|
+
} catch {
|
|
170
|
+
// Keep routes available through a provider-discovery blip. A later
|
|
171
|
+
// launch-time sync restores any context markers missing from this pass.
|
|
172
|
+
injectClaudeAgentDefs(config, {});
|
|
173
|
+
}
|
|
174
|
+
} catch { /* best-effort */ }
|
|
175
|
+
}
|
|
176
|
+
const ctx: ManagementContext = { req, url, config, deps, principal, convergeCodexCatalog, syncClaudeAgentDefsBestEffort };
|
|
177
|
+
let routed: Response | null;
|
|
178
|
+
try {
|
|
179
|
+
routed = (await handleConfigRoutes(ctx))
|
|
180
|
+
?? (await handleLogsUsageRoutes(ctx))
|
|
181
|
+
?? (await handleRequestHistoryRoutes(ctx))
|
|
182
|
+
?? (await handleRoutingAnalyticsRoutes(ctx))
|
|
183
|
+
?? (await handleRoutingProfileRoutes(ctx))
|
|
184
|
+
?? (await handleProviderRoutes(ctx))
|
|
185
|
+
?? (await handleModelRoutes(ctx))
|
|
186
|
+
?? (await handleIntegrationRoutes(ctx))
|
|
187
|
+
?? (await handleNativeIntegrationRoutes(ctx))
|
|
188
|
+
?? (await handleAndroidRemoteRoutes(ctx))
|
|
189
|
+
?? (await handleAgentSettingsRoutes(ctx))
|
|
190
|
+
?? (await handleOauthAccountRoutes(ctx))
|
|
191
|
+
?? (await handleComboRoutes(ctx))
|
|
192
|
+
?? (await handleSystemRoutes(ctx))
|
|
193
|
+
?? (await handleSidebarRoutes(ctx));
|
|
194
|
+
} catch (error) {
|
|
195
|
+
const tooLarge = managementBodyTooLargeResponse(error, req, config);
|
|
196
|
+
if (tooLarge) return tooLarge;
|
|
197
|
+
if (error instanceof OAuthMutationBusyError) {
|
|
198
|
+
return new Response(JSON.stringify({ error: { type: "server_error", code: "oauth_mutation_busy", message: error.message } }), {
|
|
199
|
+
status: 503,
|
|
200
|
+
headers: { "content-type": "application/json", "Retry-After": "1" },
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
if (!(error instanceof CatalogGatherBusyError)) throw error;
|
|
204
|
+
return new Response(JSON.stringify({ error: { type: "server_error", code: "catalog_busy", message: error.message } }), {
|
|
205
|
+
status: 503,
|
|
206
|
+
headers: { "content-type": "application/json", "Retry-After": "1" },
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (routed) return routed;
|
|
210
|
+
|
|
211
|
+
if (url.pathname === "/api/stop" && req.method === "POST") {
|
|
212
|
+
const { restoreNativeCodexAsync } = await import("../codex/inject");
|
|
213
|
+
const {
|
|
214
|
+
assertServiceEnvironmentMatchesInstall,
|
|
215
|
+
isServiceInstalled,
|
|
216
|
+
stopServiceIfInstalled,
|
|
217
|
+
} = await import("../service");
|
|
218
|
+
const { stripGrokConfig } = await import("../grok/inject");
|
|
219
|
+
const prepared = await prepareProxyStop({
|
|
220
|
+
acquireDrain: () => acquireTemporaryDrain("proxy-stop"),
|
|
221
|
+
assertServiceOwnership: assertServiceEnvironmentMatchesInstall,
|
|
222
|
+
restoreNativeCodex: restoreNativeCodexAsync,
|
|
223
|
+
restoreGrok: stripGrokConfig,
|
|
224
|
+
serviceInstalled: isServiceInstalled,
|
|
225
|
+
stopService: stopServiceIfInstalled,
|
|
226
|
+
beginShutdown: () => { beginShutdownDrain(); },
|
|
227
|
+
});
|
|
228
|
+
if (!prepared.ok) {
|
|
229
|
+
return jsonResponse({ success: false, message: prepared.message }, prepared.status, req, config);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
setTimeout(async () => {
|
|
233
|
+
await drainAndShutdown(undefined, config.shutdownTimeoutMs ?? 5000);
|
|
234
|
+
process.exit(0);
|
|
235
|
+
}, 200);
|
|
236
|
+
return jsonResponse({ success: true, message: prepared.message }, 200, req, config);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (url.pathname.startsWith("/api/native-main-profiles")) {
|
|
240
|
+
const { handleNativeProfileAPI } = await import("../codex/native-profile-api");
|
|
241
|
+
return handleNativeProfileAPI(req, url, config, deps.nativeProfileApi);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (url.pathname.startsWith("/api/codex-auth/")) {
|
|
245
|
+
const { handleCodexAuthAPI } = await import("../codex/auth-api");
|
|
246
|
+
const { ConfigMutationLockError } = await import("../config");
|
|
247
|
+
const { CodexCredentialRefreshLockTimeoutError } = await import("../codex/account-store");
|
|
248
|
+
try {
|
|
249
|
+
return await handleCodexAuthAPI(req, url, config, convergeCodexCatalog);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
// Credential writers remap ConfigMutationLockError to CodexCredentialRefreshLockTimeoutError;
|
|
252
|
+
// treat both as the same retryable busy response.
|
|
253
|
+
if (error instanceof ConfigMutationLockError || error instanceof CodexCredentialRefreshLockTimeoutError) {
|
|
254
|
+
return jsonResponse(
|
|
255
|
+
{ error: "Configuration is busy; retry shortly", code: "CONFIG_MUTATION_LOCK_UNAVAILABLE" },
|
|
256
|
+
503,
|
|
257
|
+
req,
|
|
258
|
+
config,
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
export { buildClaudeDesktopState, fetchAllModels } from "./management/shared";
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
chmodSync,
|
|
4
|
+
closeSync,
|
|
5
|
+
fsyncSync,
|
|
6
|
+
linkSync,
|
|
7
|
+
lstatSync,
|
|
8
|
+
mkdirSync,
|
|
9
|
+
openSync,
|
|
10
|
+
readFileSync,
|
|
11
|
+
unlinkSync,
|
|
12
|
+
writeFileSync,
|
|
13
|
+
} from "node:fs";
|
|
14
|
+
import { dirname, join } from "node:path";
|
|
15
|
+
import { adminApiTokenFilePath } from "../lib/admin-secrets";
|
|
16
|
+
import {
|
|
17
|
+
SYSTEM_RESTART_CAPABILITY_HEADER,
|
|
18
|
+
SYSTEM_RESTART_EXPECTED_PID_HEADER,
|
|
19
|
+
SYSTEM_RESTART_NONCE_HEADER,
|
|
20
|
+
SYSTEM_RESTART_PATH,
|
|
21
|
+
parseExpectedSystemRestartPid,
|
|
22
|
+
verifySystemRestartCapability,
|
|
23
|
+
} from "../lib/system-restart-contract";
|
|
24
|
+
import { forgetEphemeralSecretPath, forgetHardenedSecretPath, hardenSecretDir, hardenSecretPath } from "../lib/windows-secret-acl";
|
|
25
|
+
import type { OcxConfig } from "../types";
|
|
26
|
+
import {
|
|
27
|
+
isAllowedManagementOrigin,
|
|
28
|
+
isApiAuthRequired,
|
|
29
|
+
isDataPlaneAdmissionSecret,
|
|
30
|
+
isLoopbackHostname,
|
|
31
|
+
managementRequestOrigin,
|
|
32
|
+
parseHttpHost,
|
|
33
|
+
} from "./auth-cors";
|
|
34
|
+
|
|
35
|
+
const GUI_SESSION_TTL_MS = 5 * 60_000;
|
|
36
|
+
const GUI_SESSION_LIMIT = 128;
|
|
37
|
+
|
|
38
|
+
interface GuiSessionRecord {
|
|
39
|
+
csrfToken: string;
|
|
40
|
+
origin: string;
|
|
41
|
+
expiresAt: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface GuiSessionBootstrap extends GuiSessionRecord {
|
|
45
|
+
token: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type ManagementAuthState =
|
|
49
|
+
| {
|
|
50
|
+
available: true;
|
|
51
|
+
token: string;
|
|
52
|
+
source: "environment" | "file";
|
|
53
|
+
sessions: Map<string, GuiSessionRecord>;
|
|
54
|
+
}
|
|
55
|
+
| { available: false; reason: string };
|
|
56
|
+
|
|
57
|
+
function fail(reason: string): ManagementAuthState {
|
|
58
|
+
return { available: false, reason };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function assertSafeDirectory(path: string): void {
|
|
62
|
+
mkdirSync(path, { recursive: true, mode: 0o700 });
|
|
63
|
+
const stat = lstatSync(path);
|
|
64
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("management token directory is not a regular directory");
|
|
65
|
+
chmodSync(path, 0o700);
|
|
66
|
+
let hardened: { ok: boolean };
|
|
67
|
+
try {
|
|
68
|
+
hardened = hardenSecretDir(path, { required: true });
|
|
69
|
+
} catch {
|
|
70
|
+
// required:true hardening now fails closed on genuine ACL timeouts too;
|
|
71
|
+
// keep the actionable guidance in the surfaced reason.
|
|
72
|
+
hardened = { ok: false };
|
|
73
|
+
}
|
|
74
|
+
if (!hardened.ok) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
"management token directory ACL hardening did not complete; set OPENCODEX_ADMIN_AUTH_TOKEN to use an environment token instead of a file-backed token",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function readExistingToken(path: string): string {
|
|
82
|
+
const stat = lstatSync(path);
|
|
83
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 512) {
|
|
84
|
+
throw new Error("management token path is not a regular secret file");
|
|
85
|
+
}
|
|
86
|
+
chmodSync(path, 0o600);
|
|
87
|
+
let hardened: { ok: boolean };
|
|
88
|
+
try {
|
|
89
|
+
hardened = hardenSecretPath(path, { required: true });
|
|
90
|
+
} catch {
|
|
91
|
+
hardened = { ok: false };
|
|
92
|
+
}
|
|
93
|
+
if (!hardened.ok) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
"management token file ACL hardening did not complete; set OPENCODEX_ADMIN_AUTH_TOKEN to use an environment token instead of a file-backed token",
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const token = readFileSync(path, "utf8").trim();
|
|
99
|
+
if (!/^ocx_admin_[A-Za-z0-9_-]{43}$/.test(token)) throw new Error("management token file is invalid");
|
|
100
|
+
return token;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function removeManagementTokenPathBestEffort(
|
|
104
|
+
path: string,
|
|
105
|
+
remove: (path: string) => void = unlinkSync,
|
|
106
|
+
options?: { ephemeral?: boolean },
|
|
107
|
+
): void {
|
|
108
|
+
// Temps get the full ephemeral release (success + both timeout namespaces);
|
|
109
|
+
// stable token paths drop only the success memo — destination-keyed timeout
|
|
110
|
+
// memos are intentional anti-restall state.
|
|
111
|
+
const forget = options?.ephemeral ? forgetEphemeralSecretPath : forgetHardenedSecretPath;
|
|
112
|
+
try {
|
|
113
|
+
remove(path);
|
|
114
|
+
forget(path);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") forget(path);
|
|
117
|
+
/* other failures retain fail-closed state for the caller */
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function createTokenFile(path: string): string {
|
|
122
|
+
const directory = dirname(path);
|
|
123
|
+
const token = `ocx_admin_${randomBytes(32).toString("base64url")}`;
|
|
124
|
+
const temporary = join(directory, `.${randomUUID()}.admin-token.tmp`);
|
|
125
|
+
let linked = false;
|
|
126
|
+
let fd: number | null = null;
|
|
127
|
+
try {
|
|
128
|
+
fd = openSync(temporary, "wx", 0o600);
|
|
129
|
+
writeFileSync(fd, `${token}\n`, "utf8");
|
|
130
|
+
fsyncSync(fd);
|
|
131
|
+
closeSync(fd);
|
|
132
|
+
fd = null;
|
|
133
|
+
chmodSync(temporary, 0o600);
|
|
134
|
+
let temporaryHardened: { ok: boolean };
|
|
135
|
+
try {
|
|
136
|
+
// Destination-keyed timeout memo (the final token path), not the temp.
|
|
137
|
+
temporaryHardened = hardenSecretPath(temporary, { required: true, timeoutMemoKey: path });
|
|
138
|
+
} catch {
|
|
139
|
+
temporaryHardened = { ok: false };
|
|
140
|
+
}
|
|
141
|
+
if (!temporaryHardened.ok) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
"management token temporary ACL hardening did not complete; set OPENCODEX_ADMIN_AUTH_TOKEN to use an environment token instead of a file-backed token",
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
linkSync(temporary, path);
|
|
148
|
+
linked = true;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if ((error as NodeJS.ErrnoException).code === "EEXIST") return readExistingToken(path);
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
let finalHardened: { ok: boolean };
|
|
154
|
+
try {
|
|
155
|
+
finalHardened = hardenSecretPath(path, { required: true });
|
|
156
|
+
} catch {
|
|
157
|
+
finalHardened = { ok: false };
|
|
158
|
+
}
|
|
159
|
+
if (!finalHardened.ok) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
"management token file ACL hardening did not complete; set OPENCODEX_ADMIN_AUTH_TOKEN to use an environment token instead of a file-backed token",
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return token;
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if (linked) removeManagementTokenPathBestEffort(path);
|
|
167
|
+
throw error;
|
|
168
|
+
} finally {
|
|
169
|
+
if (fd !== null) {
|
|
170
|
+
try { closeSync(fd); } catch { /* best effort */ }
|
|
171
|
+
}
|
|
172
|
+
removeManagementTokenPathBestEffort(temporary, unlinkSync, { ephemeral: true });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function ready(token: string, source: "environment" | "file", config: OcxConfig): ManagementAuthState {
|
|
177
|
+
if (isDataPlaneAdmissionSecret(token, config)) {
|
|
178
|
+
return fail("management credential conflicts with a data-plane credential");
|
|
179
|
+
}
|
|
180
|
+
return { available: true, token, source, sessions: new Map() };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function initializeManagementAuthState(config: OcxConfig): ManagementAuthState {
|
|
184
|
+
const environmentToken = process.env.OPENCODEX_ADMIN_AUTH_TOKEN?.trim();
|
|
185
|
+
if (environmentToken) {
|
|
186
|
+
return ready(environmentToken, "environment", config);
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
const path = adminApiTokenFilePath();
|
|
190
|
+
assertSafeDirectory(dirname(path));
|
|
191
|
+
let token: string;
|
|
192
|
+
try {
|
|
193
|
+
token = readExistingToken(path);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
196
|
+
token = createTokenFile(path);
|
|
197
|
+
}
|
|
198
|
+
return ready(token, "file", config);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
return fail(error instanceof Error ? error.message : "management token initialization failed");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function equalSecret(actual: string, expected: string): boolean {
|
|
205
|
+
const encoder = new TextEncoder();
|
|
206
|
+
const left = encoder.encode(actual);
|
|
207
|
+
const right = encoder.encode(expected);
|
|
208
|
+
return left.length === right.length && timingSafeEqual(left, right);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function removeExpiredSessions(state: Extract<ManagementAuthState, { available: true }>, now = Date.now()): void {
|
|
212
|
+
for (const [token, session] of state.sessions) {
|
|
213
|
+
if (session.expiresAt <= now) state.sessions.delete(token);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function randomSessionSecret(prefix: "ocx_session_"): string {
|
|
218
|
+
return `${prefix}${randomBytes(32).toString("base64url")}`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function issueGuiSession(
|
|
222
|
+
req: Request,
|
|
223
|
+
config: OcxConfig,
|
|
224
|
+
state: ManagementAuthState,
|
|
225
|
+
): GuiSessionBootstrap | null {
|
|
226
|
+
if (isApiAuthRequired(config) || !state.available || req.method !== "GET" || !isAllowedManagementOrigin(req, config)) return null;
|
|
227
|
+
const host = parseHttpHost(req.headers.get("Host"));
|
|
228
|
+
if (!host || !isLoopbackHostname(host.hostname)) return null;
|
|
229
|
+
const origin = managementRequestOrigin(req, config);
|
|
230
|
+
if (!origin) return null;
|
|
231
|
+
const now = Date.now();
|
|
232
|
+
removeExpiredSessions(state, now);
|
|
233
|
+
while (state.sessions.size >= GUI_SESSION_LIMIT) {
|
|
234
|
+
const oldest = state.sessions.keys().next().value as string | undefined;
|
|
235
|
+
if (!oldest) break;
|
|
236
|
+
state.sessions.delete(oldest);
|
|
237
|
+
}
|
|
238
|
+
const token = randomSessionSecret("ocx_session_");
|
|
239
|
+
const session: GuiSessionRecord = {
|
|
240
|
+
csrfToken: randomBytes(32).toString("base64url"),
|
|
241
|
+
origin,
|
|
242
|
+
expiresAt: now + GUI_SESSION_TTL_MS,
|
|
243
|
+
};
|
|
244
|
+
state.sessions.set(token, session);
|
|
245
|
+
return { token, ...session };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Which credential actually authorized a management request.
|
|
250
|
+
*
|
|
251
|
+
* `admin-token` is the raw token from disk/env: anything running as the user can
|
|
252
|
+
* read it, including a coding agent. `gui-session` is a session token this process
|
|
253
|
+
* minted for a browser, and it only authorizes a mutation after the origin and the
|
|
254
|
+
* per-session CSRF token match. Consent-bearing routes must key off this value
|
|
255
|
+
* rather than off request headers, which the token holder can forge freely.
|
|
256
|
+
* `system-restart-capability` is a process-scoped HMAC accepted only for the exact
|
|
257
|
+
* restart route and bound to the current process PID and listening port.
|
|
258
|
+
*/
|
|
259
|
+
export type ManagementPrincipal = "admin-token" | "gui-session" | "system-restart-capability";
|
|
260
|
+
|
|
261
|
+
export interface LocalManagementAuthContext {
|
|
262
|
+
attestationSecret: string;
|
|
263
|
+
pid: number;
|
|
264
|
+
port: number;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function hasSystemRestartCapability(
|
|
268
|
+
req: Request,
|
|
269
|
+
local: LocalManagementAuthContext | undefined,
|
|
270
|
+
): boolean {
|
|
271
|
+
if (!local || req.method !== "POST") return false;
|
|
272
|
+
let path: string;
|
|
273
|
+
try {
|
|
274
|
+
path = new URL(req.url).pathname;
|
|
275
|
+
} catch {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
if (path !== SYSTEM_RESTART_PATH) return false;
|
|
279
|
+
const expectedPid = parseExpectedSystemRestartPid(
|
|
280
|
+
req.headers.get(SYSTEM_RESTART_EXPECTED_PID_HEADER),
|
|
281
|
+
);
|
|
282
|
+
if (expectedPid.kind !== "present" || expectedPid.pid !== local.pid) return false;
|
|
283
|
+
return verifySystemRestartCapability(
|
|
284
|
+
local.attestationSecret,
|
|
285
|
+
req.headers.get(SYSTEM_RESTART_NONCE_HEADER),
|
|
286
|
+
req.method,
|
|
287
|
+
path,
|
|
288
|
+
local.pid,
|
|
289
|
+
local.port,
|
|
290
|
+
req.headers.get(SYSTEM_RESTART_CAPABILITY_HEADER),
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* The principal for a request that already passed `requireManagementAuth`. Kept as a
|
|
296
|
+
* separate resolution (rather than a changed return type) so every existing caller
|
|
297
|
+
* keeps its `Response | null` contract. Browser and admin principals are derived
|
|
298
|
+
* from the same session table and CSRF comparison the gate uses; the restart
|
|
299
|
+
* principal is derived from the same process-scoped capability check.
|
|
300
|
+
*/
|
|
301
|
+
export function managementPrincipal(
|
|
302
|
+
req: Request,
|
|
303
|
+
state: ManagementAuthState,
|
|
304
|
+
config?: OcxConfig,
|
|
305
|
+
local?: LocalManagementAuthContext,
|
|
306
|
+
): ManagementPrincipal | null {
|
|
307
|
+
if (hasSystemRestartCapability(req, local)) return "system-restart-capability";
|
|
308
|
+
if (!state.available) return null;
|
|
309
|
+
const actual = req.headers.get("x-opencodex-api-key")?.trim()
|
|
310
|
+
|| req.headers.get("authorization")?.replace(/^Bearer\s+/i, "").trim();
|
|
311
|
+
if (!actual) return null;
|
|
312
|
+
if (equalSecret(actual, state.token)) return "admin-token";
|
|
313
|
+
if (!config) return null;
|
|
314
|
+
removeExpiredSessions(state);
|
|
315
|
+
return state.sessions.has(actual) ? "gui-session" : null;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export function requireManagementAuth(
|
|
319
|
+
req: Request,
|
|
320
|
+
state: ManagementAuthState,
|
|
321
|
+
config?: OcxConfig,
|
|
322
|
+
local?: LocalManagementAuthContext,
|
|
323
|
+
): Response | null {
|
|
324
|
+
if (hasSystemRestartCapability(req, local)) return null;
|
|
325
|
+
if (!state.available) {
|
|
326
|
+
return Response.json({
|
|
327
|
+
error: "management API unavailable",
|
|
328
|
+
reason: state.reason,
|
|
329
|
+
hint: "Set OPENCODEX_ADMIN_AUTH_TOKEN to bypass file-backed admin token ACL hardening",
|
|
330
|
+
}, { status: 503 });
|
|
331
|
+
}
|
|
332
|
+
const actual = req.headers.get("x-opencodex-api-key")?.trim()
|
|
333
|
+
|| req.headers.get("authorization")?.replace(/^Bearer\s+/i, "").trim();
|
|
334
|
+
if (actual && equalSecret(actual, state.token)) return null;
|
|
335
|
+
if (actual && config) {
|
|
336
|
+
removeExpiredSessions(state);
|
|
337
|
+
const session = state.sessions.get(actual);
|
|
338
|
+
if (session) {
|
|
339
|
+
const requestOrigin = managementRequestOrigin(req, config);
|
|
340
|
+
const claimedOrigin = req.headers.get("x-opencodex-gui-origin");
|
|
341
|
+
const browserOrigin = req.headers.get("Origin");
|
|
342
|
+
const sameOrigin = requestOrigin === session.origin
|
|
343
|
+
&& claimedOrigin === session.origin
|
|
344
|
+
&& (!browserOrigin || browserOrigin === session.origin);
|
|
345
|
+
const safeMethod = req.method === "GET" || req.method === "HEAD";
|
|
346
|
+
const csrf = req.headers.get("x-opencodex-csrf-token")?.trim();
|
|
347
|
+
if (sameOrigin && (safeMethod || (browserOrigin === session.origin && !!csrf && equalSecret(csrf, session.csrfToken)))) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return Response.json({ error: "Remodex admin token required" }, { status: 401 });
|
|
353
|
+
}
|