@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,172 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { atomicWriteFile } from "../config";
|
|
5
|
+
import { hasInjectedCodexRouting } from "./injected-marker";
|
|
6
|
+
import { CODEX_HOME, CODEX_CONFIG_PATH, CODEX_PROFILE_PATH } from "./paths";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Exported so that anything reasoning ABOUT the journal points at the journal.
|
|
10
|
+
*
|
|
11
|
+
* The Codex admission snapshot re-derived this path by hand and got it wrong in
|
|
12
|
+
* both halves — wrong directory and wrong filename — so its "journal identity"
|
|
13
|
+
* watched a file nothing writes. The fixture re-derived it the same wrong way,
|
|
14
|
+
* agreed with the producer, and the pair stayed green. One exported constant
|
|
15
|
+
* removes the opportunity.
|
|
16
|
+
*/
|
|
17
|
+
export const JOURNAL_PATH = join(CODEX_HOME, "opencodex-journal.json");
|
|
18
|
+
|
|
19
|
+
interface Journal {
|
|
20
|
+
version: 1;
|
|
21
|
+
originalConfig: string;
|
|
22
|
+
originalProfile: string | null;
|
|
23
|
+
injectedConfigHash?: string;
|
|
24
|
+
injectedProfileHash?: string | null;
|
|
25
|
+
pid: number;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface RestoreJournalResult {
|
|
30
|
+
configRestored: boolean;
|
|
31
|
+
profileRestored: boolean;
|
|
32
|
+
configChanged: boolean;
|
|
33
|
+
profileChanged: boolean;
|
|
34
|
+
complete: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function sha256(content: string | null): string | null {
|
|
38
|
+
return content === null ? null : createHash("sha256").update(content).digest("hex");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface WriteJournalOptions {
|
|
42
|
+
/**
|
|
43
|
+
* The caller's verdict on the config it is about to transform: false when
|
|
44
|
+
* `hasInjectedCodexRouting` matched. This does NOT decide whether the content
|
|
45
|
+
* may be journaled — that is checked below, from the bytes themselves. It only
|
|
46
|
+
* authorizes REPLACING an existing snapshot, which is why omitting it still
|
|
47
|
+
* allows a first snapshot but never an overwrite.
|
|
48
|
+
*/
|
|
49
|
+
currentStateIsNative?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* The exact bytes the caller classified. Journaling these rather than re-reading
|
|
52
|
+
* the file keeps the snapshot and the verdict describing the same content when
|
|
53
|
+
* another process rewrites config.toml mid-flight.
|
|
54
|
+
*/
|
|
55
|
+
configContent?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Snapshot the pre-injection Codex state.
|
|
60
|
+
*
|
|
61
|
+
* Only native (non-Remodex-owned) config may be journaled, and native config
|
|
62
|
+
* always supersedes an older snapshot. The first half stops a re-inject from
|
|
63
|
+
* recording Remodex's own routing as the user's original — which would survive
|
|
64
|
+
* `rmx stop` and make the injection unremovable. The second half is the #477 fix:
|
|
65
|
+
* without it the first snapshot a machine ever takes is the only one it ever has,
|
|
66
|
+
* so an unclean shutdown days later replays a day-one config over the user's
|
|
67
|
+
* plugins, model choice, and trusted projects.
|
|
68
|
+
*/
|
|
69
|
+
export function writeJournal(options: WriteJournalOptions = {}): void {
|
|
70
|
+
if (!existsSync(CODEX_CONFIG_PATH)) return;
|
|
71
|
+
const config = options.configContent ?? readFileSync(CODEX_CONFIG_PATH, "utf-8");
|
|
72
|
+
// Ownership is decided HERE, from the bytes about to be journaled — never taken
|
|
73
|
+
// on the caller's word. A caller that says "native" about injected content would
|
|
74
|
+
// otherwise make Remodex's own routing the user's permanent "original".
|
|
75
|
+
if (hasInjectedCodexRouting(config)) return;
|
|
76
|
+
// The caller's verdict only authorizes REPLACEMENT. It is weaker evidence than
|
|
77
|
+
// the check above (it may describe bytes read a moment earlier), so an
|
|
78
|
+
// unclassified call creates a first snapshot but never overwrites one.
|
|
79
|
+
if (existsSync(JOURNAL_PATH) && readJournal() && options.currentStateIsNative !== true) return;
|
|
80
|
+
const profile = existsSync(CODEX_PROFILE_PATH)
|
|
81
|
+
? readFileSync(CODEX_PROFILE_PATH, "utf-8")
|
|
82
|
+
: null;
|
|
83
|
+
const journal: Journal = {
|
|
84
|
+
version: 1,
|
|
85
|
+
originalConfig: Buffer.from(config).toString("base64"),
|
|
86
|
+
originalProfile: profile ? Buffer.from(profile).toString("base64") : null,
|
|
87
|
+
pid: process.pid,
|
|
88
|
+
timestamp: new Date().toISOString(),
|
|
89
|
+
};
|
|
90
|
+
atomicWriteFile(JOURNAL_PATH, JSON.stringify(journal));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function markJournalInjectedState(config: string, profile: string | null): void {
|
|
94
|
+
const journal = readJournal();
|
|
95
|
+
if (!journal) return;
|
|
96
|
+
if (journal.injectedConfigHash) return;
|
|
97
|
+
journal.injectedConfigHash = sha256(config) ?? undefined;
|
|
98
|
+
journal.injectedProfileHash = sha256(profile);
|
|
99
|
+
atomicWriteFile(JOURNAL_PATH, JSON.stringify(journal));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function removeJournal(): void {
|
|
103
|
+
try { unlinkSync(JOURNAL_PATH); } catch { /* ignore */ }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function readJournal(): Journal | null {
|
|
107
|
+
if (!existsSync(JOURNAL_PATH)) return null;
|
|
108
|
+
try {
|
|
109
|
+
const journal = JSON.parse(readFileSync(JOURNAL_PATH, "utf-8")) as Journal;
|
|
110
|
+
if (journal.version !== 1) throw new Error("unknown version");
|
|
111
|
+
return journal;
|
|
112
|
+
} catch {
|
|
113
|
+
removeJournal();
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function restoreJournalState(): RestoreJournalResult {
|
|
119
|
+
const journal = readJournal();
|
|
120
|
+
if (!journal) {
|
|
121
|
+
return { configRestored: false, profileRestored: false, configChanged: false, profileChanged: false, complete: false };
|
|
122
|
+
}
|
|
123
|
+
const currentConfig = existsSync(CODEX_CONFIG_PATH) ? readFileSync(CODEX_CONFIG_PATH, "utf-8") : "";
|
|
124
|
+
const currentProfile = existsSync(CODEX_PROFILE_PATH) ? readFileSync(CODEX_PROFILE_PATH, "utf-8") : null;
|
|
125
|
+
const configUnchanged = !journal.injectedConfigHash || sha256(currentConfig) === journal.injectedConfigHash;
|
|
126
|
+
const profileUnchanged = journal.injectedProfileHash === undefined || sha256(currentProfile) === (journal.injectedProfileHash ?? null);
|
|
127
|
+
|
|
128
|
+
let configRestored = false;
|
|
129
|
+
let profileRestored = false;
|
|
130
|
+
if (configUnchanged) {
|
|
131
|
+
atomicWriteFile(CODEX_CONFIG_PATH, Buffer.from(journal.originalConfig, "base64").toString("utf-8"));
|
|
132
|
+
configRestored = true;
|
|
133
|
+
}
|
|
134
|
+
if (profileUnchanged) {
|
|
135
|
+
if (journal.originalProfile !== null) {
|
|
136
|
+
atomicWriteFile(CODEX_PROFILE_PATH, Buffer.from(journal.originalProfile, "base64").toString("utf-8"));
|
|
137
|
+
} else if (existsSync(CODEX_PROFILE_PATH)) {
|
|
138
|
+
try { unlinkSync(CODEX_PROFILE_PATH); } catch { /* ignore */ }
|
|
139
|
+
}
|
|
140
|
+
profileRestored = true;
|
|
141
|
+
}
|
|
142
|
+
const complete = configRestored && profileRestored;
|
|
143
|
+
if (complete) removeJournal();
|
|
144
|
+
return {
|
|
145
|
+
configRestored,
|
|
146
|
+
profileRestored,
|
|
147
|
+
configChanged: !configUnchanged,
|
|
148
|
+
profileChanged: !profileUnchanged,
|
|
149
|
+
complete,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function restoreJournal(): boolean {
|
|
154
|
+
return restoreJournalState().complete;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function reconcileJournal(): boolean {
|
|
158
|
+
const journal = readJournal();
|
|
159
|
+
if (!journal) return false;
|
|
160
|
+
try {
|
|
161
|
+
process.kill(journal.pid, 0);
|
|
162
|
+
return false;
|
|
163
|
+
} catch (e: unknown) {
|
|
164
|
+
if ((e as NodeJS.ErrnoException).code === "EPERM") {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const restored = restoreJournalState();
|
|
169
|
+
if (!restored.configRestored && !restored.profileRestored) return false;
|
|
170
|
+
console.error(`⚠️ Previous session (PID ${journal.pid}) did not shut down cleanly. Codex state restored from journal.`);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { StoredAccountQuota } from "./quota";
|
|
2
|
+
import { truncateRetainedUtf8 } from "../lib/admission";
|
|
3
|
+
|
|
4
|
+
const MAX_DIAGNOSTIC_VALUE_BYTES = 8 * 1024;
|
|
5
|
+
|
|
6
|
+
export interface MainAccountInfo {
|
|
7
|
+
email: string | null;
|
|
8
|
+
plan: string | null;
|
|
9
|
+
quota: Omit<StoredAccountQuota, "updatedAt"> | null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CachedMainAccountInfo extends MainAccountInfo {
|
|
13
|
+
ts: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let cachedMainAccountInfo: CachedMainAccountInfo | null = null;
|
|
17
|
+
let cachedMainCredentialPresence: boolean | null = null;
|
|
18
|
+
let mainAccountIdentityGeneration = 0;
|
|
19
|
+
|
|
20
|
+
export function captureMainAccountIdentityGeneration(): number {
|
|
21
|
+
return mainAccountIdentityGeneration;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function isMainAccountIdentityGenerationLive(generation: number): boolean {
|
|
25
|
+
return generation === mainAccountIdentityGeneration;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function getMainAccountInfoCache(): CachedMainAccountInfo | null {
|
|
29
|
+
return cachedMainAccountInfo;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function setMainAccountInfoCache(value: CachedMainAccountInfo): void {
|
|
33
|
+
cachedMainAccountInfo = {
|
|
34
|
+
...value,
|
|
35
|
+
email: value.email === null ? null : truncateRetainedUtf8(value.email, MAX_DIAGNOSTIC_VALUE_BYTES),
|
|
36
|
+
plan: value.plan === null ? null : truncateRetainedUtf8(value.plan, MAX_DIAGNOSTIC_VALUE_BYTES),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function clearMainAccountInfoCache(): void {
|
|
41
|
+
cachedMainAccountInfo = null;
|
|
42
|
+
mainAccountIdentityGeneration += 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Last physical credential presence observed while native-main ownership was held. */
|
|
46
|
+
export function getMainAccountCredentialPresence(): boolean | null {
|
|
47
|
+
return cachedMainCredentialPresence;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function setMainAccountCredentialPresence(present: boolean): void {
|
|
51
|
+
cachedMainCredentialPresence = present;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function clearMainAccountCredentialPresence(): void {
|
|
55
|
+
cachedMainCredentialPresence = null;
|
|
56
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { readCodexTokens } from "./auth-collision";
|
|
2
|
+
import { decodeJwtPayload } from "../oauth/chatgpt";
|
|
3
|
+
import { MAIN_CODEX_ACCOUNT_ID } from "./account-id";
|
|
4
|
+
|
|
5
|
+
export { MAIN_CODEX_ACCOUNT_ID } from "./account-id";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Main account plan (e.g. "plus", "go", "free", "team"), populated from the WHAM usage
|
|
9
|
+
* fetch. Used by the rotation usage-score so go/free main accounts score on monthly
|
|
10
|
+
* percent, matching pool-account behavior.
|
|
11
|
+
*/
|
|
12
|
+
let mainAccountPlan: string | null = null;
|
|
13
|
+
|
|
14
|
+
export function setMainAccountPlan(plan: string | null): void {
|
|
15
|
+
mainAccountPlan = plan;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getMainAccountPlan(): string | undefined {
|
|
19
|
+
return mainAccountPlan ?? undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Read-only main account token from ~/.codex/auth.json, or null when not logged in. */
|
|
23
|
+
export function getMainAccountToken(): { accessToken: string; chatgptAccountId: string } | null {
|
|
24
|
+
const tokens = readCodexTokens();
|
|
25
|
+
if (!tokens?.access_token) return null;
|
|
26
|
+
return { accessToken: tokens.access_token, chatgptAccountId: tokens.account_id };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The main token is usable when it exists and — if its JWT carries a decodable `exp` — is
|
|
31
|
+
* not expired. When `exp` cannot be decoded we treat the token as live (best-effort); an
|
|
32
|
+
* actually-invalid token then surfaces via the upstream 401 → cooldown path.
|
|
33
|
+
*/
|
|
34
|
+
export function isMainAccountTokenLive(now = Date.now()): boolean {
|
|
35
|
+
const tokens = readCodexTokens();
|
|
36
|
+
if (!tokens?.access_token) return false;
|
|
37
|
+
const payload = decodeJwtPayload(tokens.access_token);
|
|
38
|
+
const exp = typeof payload?.exp === "number" ? payload.exp * 1000 : undefined;
|
|
39
|
+
return exp === undefined || exp > now;
|
|
40
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { OcxConfig } from "../types";
|
|
2
|
+
import { captureCatalogAdmissionSnapshot } from "./catalog-admission";
|
|
3
|
+
import { convergeCodexCatalog } from "./convergence";
|
|
4
|
+
import type {
|
|
5
|
+
CatalogDisposition,
|
|
6
|
+
CatalogOnlyOutcome,
|
|
7
|
+
CodexHistoryState,
|
|
8
|
+
CodexObservedState,
|
|
9
|
+
ConvergeCodex,
|
|
10
|
+
ProjectCatalogOnlyOutcomeInput,
|
|
11
|
+
} from "./convergence-types";
|
|
12
|
+
|
|
13
|
+
function notEvaluatedHistory(): CodexHistoryState {
|
|
14
|
+
return {
|
|
15
|
+
status: "not-evaluated",
|
|
16
|
+
attempts: 0,
|
|
17
|
+
nextRetryAt: null,
|
|
18
|
+
txId: null,
|
|
19
|
+
pendingRows: null,
|
|
20
|
+
backupEntries: null,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function notEvaluatedObserved(history: CodexHistoryState): CodexObservedState {
|
|
25
|
+
return {
|
|
26
|
+
aggregate: "not-evaluated",
|
|
27
|
+
isApplied: null,
|
|
28
|
+
desired: "unknown",
|
|
29
|
+
converged: null,
|
|
30
|
+
authority: { service: "unknown", externalProvider: null },
|
|
31
|
+
surfaces: {
|
|
32
|
+
config: "not-evaluated",
|
|
33
|
+
profile: "not-evaluated",
|
|
34
|
+
catalog: "not-evaluated",
|
|
35
|
+
cache: "not-evaluated",
|
|
36
|
+
journal: "not-evaluated",
|
|
37
|
+
history: {
|
|
38
|
+
state: history,
|
|
39
|
+
database: "not-evaluated",
|
|
40
|
+
manifest: "not-evaluated",
|
|
41
|
+
rollouts: "not-evaluated",
|
|
42
|
+
},
|
|
43
|
+
provenance: {
|
|
44
|
+
state: "not-evaluated",
|
|
45
|
+
nativeGeneration: null,
|
|
46
|
+
currentTxId: null,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function unexpectedCatalogFailure(commitBegan: boolean): CatalogDisposition {
|
|
53
|
+
return {
|
|
54
|
+
status: "failed",
|
|
55
|
+
reason: "disk",
|
|
56
|
+
phase: commitBegan ? "commit" : "gather",
|
|
57
|
+
retryable: false,
|
|
58
|
+
partialWrite: commitBegan,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function admissionFailure(error: unknown): CatalogDisposition {
|
|
63
|
+
const message = error instanceof Error ? error.message : "";
|
|
64
|
+
if (message.includes("config generation is busy") || message.includes("config generation is database")) {
|
|
65
|
+
return { status: "skipped", reason: "busy", retryable: true };
|
|
66
|
+
}
|
|
67
|
+
return unexpectedCatalogFailure(false);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Project catalog work into the shared no-change/not-evaluated outcome shape. */
|
|
71
|
+
export function projectCatalogOnlyOutcome({
|
|
72
|
+
changed,
|
|
73
|
+
catalogRefresh,
|
|
74
|
+
}: ProjectCatalogOnlyOutcomeInput): CatalogOnlyOutcome {
|
|
75
|
+
const history = notEvaluatedHistory();
|
|
76
|
+
return {
|
|
77
|
+
kind: "catalog-only",
|
|
78
|
+
changed,
|
|
79
|
+
observed: notEvaluatedObserved(history),
|
|
80
|
+
catalogRefresh,
|
|
81
|
+
history,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Bind the management callback's exact config authority to a catalog-only
|
|
87
|
+
* funnel. This module is intentionally not re-exported by a public Codex facade.
|
|
88
|
+
*/
|
|
89
|
+
export function createManagementConvergeCodex(
|
|
90
|
+
config: Readonly<OcxConfig>,
|
|
91
|
+
): ConvergeCodex {
|
|
92
|
+
const retainedConfig = config;
|
|
93
|
+
return async request => {
|
|
94
|
+
let commitBegan = false;
|
|
95
|
+
try {
|
|
96
|
+
if (request.scope !== "catalog" || request.action !== "converge") {
|
|
97
|
+
return projectCatalogOnlyOutcome({
|
|
98
|
+
changed: false,
|
|
99
|
+
catalogRefresh: unexpectedCatalogFailure(false),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const snapshot = captureCatalogAdmissionSnapshot(retainedConfig);
|
|
103
|
+
const result = await convergeCodexCatalog(snapshot, request, {
|
|
104
|
+
onCommitBegin: () => { commitBegan = true; },
|
|
105
|
+
});
|
|
106
|
+
return projectCatalogOnlyOutcome(result);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
return projectCatalogOnlyOutcome({
|
|
109
|
+
changed: false,
|
|
110
|
+
catalogRefresh: commitBegan ? unexpectedCatalogFailure(true) : admissionFailure(error),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory, per-provider TTL cache for live `/models` results.
|
|
3
|
+
*
|
|
4
|
+
* Ported in spirit from jawcode's packages/ai/src/model-manager.ts (the "always load the latest
|
|
5
|
+
* model list" resolver): live fetch when the cache is stale, serve the cache while it is fresh,
|
|
6
|
+
* and fall back to the last-known-good list when a live fetch fails. The Remodex proxy is a single
|
|
7
|
+
* long-running process and the on-disk Codex catalog already persists the last sync across
|
|
8
|
+
* restarts, so an in-memory cache is sufficient here (no SQLite layer needed).
|
|
9
|
+
*/
|
|
10
|
+
import type { CatalogModel } from "./catalog";
|
|
11
|
+
import type { GenerationContext } from "../lib/state-store-sweeper";
|
|
12
|
+
import { enforceAppOwnedMemoryBudget, type RetainedStoreSnapshot } from "../lib/app-owned-memory";
|
|
13
|
+
|
|
14
|
+
/** Default freshness window. Matches Codex's own 5-min models cache so the two stay in step. */
|
|
15
|
+
export const DEFAULT_MODEL_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
16
|
+
|
|
17
|
+
interface CacheEntry {
|
|
18
|
+
models: CatalogModel[];
|
|
19
|
+
fetchedAt: number;
|
|
20
|
+
sizeBytes: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type ProviderModelDiscoveryFailureReason =
|
|
24
|
+
| "http"
|
|
25
|
+
| "blocked"
|
|
26
|
+
| "invalid_response"
|
|
27
|
+
| "network"
|
|
28
|
+
| "provider";
|
|
29
|
+
|
|
30
|
+
export type ProviderModelDiscoveryStatus =
|
|
31
|
+
| { status: "ok" }
|
|
32
|
+
| { status: "failed"; reason: "http"; httpStatus: number }
|
|
33
|
+
| {
|
|
34
|
+
status: "failed";
|
|
35
|
+
reason: Exclude<ProviderModelDiscoveryFailureReason, "http">;
|
|
36
|
+
httpStatus?: never;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type ProviderModelDiscoveryFailure = ProviderModelDiscoveryStatus extends infer Status
|
|
40
|
+
? Status extends { status: "failed" }
|
|
41
|
+
? Omit<Status, "status">
|
|
42
|
+
: never
|
|
43
|
+
: never;
|
|
44
|
+
|
|
45
|
+
/** Whether clearing cache rows also revokes in-flight discovery authority. */
|
|
46
|
+
export type ModelCacheClearReason = "authority" | "eviction";
|
|
47
|
+
|
|
48
|
+
const cache = new Map<string, CacheEntry>();
|
|
49
|
+
let globalCacheGeneration = 0;
|
|
50
|
+
const providerCacheGenerations = new Map<string, number>();
|
|
51
|
+
let cacheBytes = 0;
|
|
52
|
+
let oldestCachedProvider: string | undefined;
|
|
53
|
+
let oldestCachedAt: number | null = null;
|
|
54
|
+
const modelCacheEncoder = new TextEncoder();
|
|
55
|
+
|
|
56
|
+
function recomputeOldestCachedProvider(): void {
|
|
57
|
+
oldestCachedProvider = undefined;
|
|
58
|
+
oldestCachedAt = null;
|
|
59
|
+
for (const [provider, entry] of cache) {
|
|
60
|
+
if (oldestCachedAt !== null && entry.fetchedAt >= oldestCachedAt) continue;
|
|
61
|
+
oldestCachedProvider = provider;
|
|
62
|
+
oldestCachedAt = entry.fetchedAt;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function deleteCachedProvider(provider: string): number {
|
|
67
|
+
const entry = cache.get(provider);
|
|
68
|
+
if (!entry) return 0;
|
|
69
|
+
cache.delete(provider);
|
|
70
|
+
cacheBytes = Math.max(0, cacheBytes - entry.sizeBytes);
|
|
71
|
+
if (oldestCachedProvider === provider) recomputeOldestCachedProvider();
|
|
72
|
+
return entry.sizeBytes;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Cooldown after a failed live `/models` fetch, so a dead/unreachable provider doesn't re-pay
|
|
76
|
+
* the full fetch timeout on every catalog poll (issue #54: UI stalls behind corporate proxies). */
|
|
77
|
+
export const MODELS_FETCH_FAILURE_COOLDOWN_MS = 30_000;
|
|
78
|
+
|
|
79
|
+
const failureAt = new Map<string, number>();
|
|
80
|
+
const discoveryStatus = new Map<string, ProviderModelDiscoveryStatus>();
|
|
81
|
+
/**
|
|
82
|
+
* How many models the last successful discovery actually returned, before any configured-alias
|
|
83
|
+
* augmentation or custom-model merge. Consumers cannot recover this by subtracting known custom
|
|
84
|
+
* ids: a custom id that later also appears upstream would make a real live catalog look
|
|
85
|
+
* custom-only, and the provider's configured fallback would wrongly stay authoritative.
|
|
86
|
+
*/
|
|
87
|
+
const liveModelCounts = new Map<string, number>();
|
|
88
|
+
let lastReconciledGeneration = 0;
|
|
89
|
+
|
|
90
|
+
export function markModelsFetchFailure(provider: string, now = Date.now()): void {
|
|
91
|
+
failureAt.set(provider, now);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** `liveModelCount` is required so a caller that forgets to pass it fails typecheck instead of
|
|
95
|
+
* silently recording zero and misclassifying the provider as having no live catalog. */
|
|
96
|
+
export function markProviderDiscoveryOk(provider: string, liveModelCount: number): void {
|
|
97
|
+
discoveryStatus.set(provider, { status: "ok" });
|
|
98
|
+
liveModelCounts.set(provider, Math.max(0, Math.floor(liveModelCount)));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function markProviderDiscoveryFailed(
|
|
102
|
+
provider: string,
|
|
103
|
+
failure: ProviderModelDiscoveryFailure,
|
|
104
|
+
): void {
|
|
105
|
+
discoveryStatus.set(provider, { status: "failed", ...failure });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Decide whether a discovery FAILURE should be logged, to avoid flooding the log with an identical
|
|
110
|
+
* warning on every poll (#395: an anthropic-adapter baseUrl without `/v1/models`, e.g. Azure AI
|
|
111
|
+
* Foundry, returns HTTP 404 forever; the 30s cooldown re-probes and previously re-logged each time).
|
|
112
|
+
*
|
|
113
|
+
* Returns true only when the failure SIGNATURE changed since the last observed status — i.e. the
|
|
114
|
+
* previous state was ok/undefined, or a different reason/httpStatus. Repeated identical failures
|
|
115
|
+
* stay observable through `getProviderDiscoveryStatus()` / the providers API without log spam.
|
|
116
|
+
* Call this BEFORE `markProviderDiscoveryFailed` so it can see the prior state.
|
|
117
|
+
*/
|
|
118
|
+
export function shouldLogDiscoveryFailure(
|
|
119
|
+
provider: string,
|
|
120
|
+
failure: ProviderModelDiscoveryFailure,
|
|
121
|
+
): boolean {
|
|
122
|
+
const prev = discoveryStatus.get(provider);
|
|
123
|
+
if (!prev || prev.status !== "failed") return true;
|
|
124
|
+
if (prev.reason !== failure.reason) return true;
|
|
125
|
+
if (prev.reason === "http" && failure.reason === "http") {
|
|
126
|
+
return prev.httpStatus !== failure.httpStatus;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function clearProviderDiscoveryStatus(provider: string): void {
|
|
132
|
+
discoveryStatus.delete(provider);
|
|
133
|
+
liveModelCounts.delete(provider);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function getProviderDiscoveryStatus(provider: string): ProviderModelDiscoveryStatus | undefined {
|
|
137
|
+
return discoveryStatus.get(provider);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Undefined when discovery has never succeeded for this provider. A failed refresh keeps the
|
|
141
|
+
* last successful count so a stale catalog is still recognised as live-origin. */
|
|
142
|
+
export function getProviderLiveModelCount(provider: string): number | undefined {
|
|
143
|
+
return liveModelCounts.get(provider);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function isModelsFetchCoolingDown(provider: string, cooldownMs = MODELS_FETCH_FAILURE_COOLDOWN_MS, now = Date.now()): boolean {
|
|
147
|
+
const at = failureAt.get(provider);
|
|
148
|
+
return at !== undefined && now - at < cooldownMs;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Fresh cached models for a provider, or null when absent/stale (caller should re-fetch). */
|
|
152
|
+
export function getFreshCached(provider: string, ttlMs: number, now = Date.now()): CatalogModel[] | null {
|
|
153
|
+
const entry = cache.get(provider);
|
|
154
|
+
if (!entry) return null;
|
|
155
|
+
return now - entry.fetchedAt < ttlMs ? entry.models : null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Last-known-good models regardless of age — the fallback when a live fetch fails. */
|
|
159
|
+
export function getStaleCached(provider: string): CatalogModel[] | null {
|
|
160
|
+
return cache.get(provider)?.models ?? null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Capture the cache generation before an asynchronous provider discovery starts. */
|
|
164
|
+
export function captureModelCacheGeneration(provider: string): string {
|
|
165
|
+
if (!providerCacheGenerations.has(provider)) providerCacheGenerations.set(provider, 0);
|
|
166
|
+
return `${globalCacheGeneration}:${providerCacheGenerations.get(provider)!}`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Whether a discovery started under {@link captureModelCacheGeneration} may still write. */
|
|
170
|
+
export function isModelCacheGenerationCurrent(provider: string, generation: string): boolean {
|
|
171
|
+
return generation === captureModelCacheGeneration(provider);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Store a live result unless the cache was cleared while that asynchronous discovery was running.
|
|
176
|
+
* The optional generation keeps existing direct cache writers unchanged while discovery callers can
|
|
177
|
+
* prevent a previous OAuth account from repopulating the current account's cache.
|
|
178
|
+
*/
|
|
179
|
+
export function setCached(
|
|
180
|
+
provider: string,
|
|
181
|
+
models: CatalogModel[],
|
|
182
|
+
now = Date.now(),
|
|
183
|
+
generation?: string,
|
|
184
|
+
): boolean {
|
|
185
|
+
if (generation !== undefined && !isModelCacheGenerationCurrent(provider, generation)) return false;
|
|
186
|
+
deleteCachedProvider(provider);
|
|
187
|
+
const sizeBytes = modelCacheEncoder.encode(provider).byteLength
|
|
188
|
+
+ modelCacheEncoder.encode(JSON.stringify(models)).byteLength;
|
|
189
|
+
cache.set(provider, { models, fetchedAt: now, sizeBytes });
|
|
190
|
+
cacheBytes += sizeBytes;
|
|
191
|
+
if (oldestCachedAt === null || now < oldestCachedAt) {
|
|
192
|
+
oldestCachedProvider = provider;
|
|
193
|
+
oldestCachedAt = now;
|
|
194
|
+
}
|
|
195
|
+
enforceAppOwnedMemoryBudget();
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Drop one provider's cache (or all) so the next resolve forces a live re-fetch. */
|
|
200
|
+
export function clearModelCache(
|
|
201
|
+
provider?: string,
|
|
202
|
+
reason: ModelCacheClearReason = "authority",
|
|
203
|
+
): void {
|
|
204
|
+
const revokesInFlightDiscovery = reason === "authority";
|
|
205
|
+
if (provider) {
|
|
206
|
+
if (revokesInFlightDiscovery) {
|
|
207
|
+
providerCacheGenerations.set(provider, (providerCacheGenerations.get(provider) ?? 0) + 1);
|
|
208
|
+
}
|
|
209
|
+
deleteCachedProvider(provider);
|
|
210
|
+
failureAt.delete(provider);
|
|
211
|
+
discoveryStatus.delete(provider);
|
|
212
|
+
liveModelCounts.delete(provider);
|
|
213
|
+
} else {
|
|
214
|
+
if (revokesInFlightDiscovery) globalCacheGeneration += 1;
|
|
215
|
+
cache.clear();
|
|
216
|
+
cacheBytes = 0;
|
|
217
|
+
oldestCachedProvider = undefined;
|
|
218
|
+
oldestCachedAt = null;
|
|
219
|
+
failureAt.clear();
|
|
220
|
+
discoveryStatus.clear();
|
|
221
|
+
liveModelCounts.clear();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function reconcileModelCacheProviders(
|
|
226
|
+
validProviders: ReadonlySet<string>,
|
|
227
|
+
generation = lastReconciledGeneration + 1,
|
|
228
|
+
): number {
|
|
229
|
+
if (generation <= lastReconciledGeneration) return 0;
|
|
230
|
+
const removedProviders = new Set<string>();
|
|
231
|
+
const trackedProviders = new Set([
|
|
232
|
+
...providerCacheGenerations.keys(),
|
|
233
|
+
...failureAt.keys(),
|
|
234
|
+
...discoveryStatus.keys(),
|
|
235
|
+
...liveModelCounts.keys(),
|
|
236
|
+
...cache.keys(),
|
|
237
|
+
]);
|
|
238
|
+
for (const provider of trackedProviders) {
|
|
239
|
+
if (validProviders.has(provider)) continue;
|
|
240
|
+
providerCacheGenerations.set(provider, (providerCacheGenerations.get(provider) ?? 0) + 1);
|
|
241
|
+
deleteCachedProvider(provider);
|
|
242
|
+
failureAt.delete(provider);
|
|
243
|
+
discoveryStatus.delete(provider);
|
|
244
|
+
liveModelCounts.delete(provider);
|
|
245
|
+
removedProviders.add(provider);
|
|
246
|
+
}
|
|
247
|
+
lastReconciledGeneration = generation;
|
|
248
|
+
return removedProviders.size;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function reconcileModelCacheGeneration(context: GenerationContext): number {
|
|
252
|
+
return reconcileModelCacheProviders(context.providerNames, context.generation);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function modelCacheRetainedStoreSnapshot(): RetainedStoreSnapshot {
|
|
256
|
+
return {
|
|
257
|
+
count: cache.size,
|
|
258
|
+
bytes: cacheBytes,
|
|
259
|
+
evictableBytes: cacheBytes,
|
|
260
|
+
pinnedBytes: 0,
|
|
261
|
+
oldestAt: oldestCachedAt,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function evictOldestModelCacheForBudget(): number {
|
|
266
|
+
return oldestCachedProvider === undefined ? 0 : deleteCachedProvider(oldestCachedProvider);
|
|
267
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { AdmissionLease } from "../lib/admission";
|
|
2
|
+
import {
|
|
3
|
+
tryAcquireNativeMainProfileClaim as tryAcquireLifecycleNativeMainProfileClaim,
|
|
4
|
+
tryClaimNativeMainProfileForTurn as tryClaimLifecycleNativeMainProfileForTurn,
|
|
5
|
+
} from "../server/lifecycle";
|
|
6
|
+
import { isNativeMainTrafficBlocked } from "./native-profile-startup";
|
|
7
|
+
|
|
8
|
+
export interface NativeMainTurnClaimDeps {
|
|
9
|
+
/** Test seams for the synchronous precheck/claim/postcheck transition. */
|
|
10
|
+
isTrafficBlocked?: typeof isNativeMainTrafficBlocked;
|
|
11
|
+
claimTurn?: typeof tryClaimLifecycleNativeMainProfileForTurn;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Admit a physical native-main credential read on an existing turn.
|
|
16
|
+
*
|
|
17
|
+
* Lifecycle admission owns the scoped switch/shutdown fence while the startup
|
|
18
|
+
* gate owns retained journal/manual recovery. Keep their composition here so
|
|
19
|
+
* low-level server lifecycle code does not import NativeProfileManager through
|
|
20
|
+
* native-profile-startup and create a fragile dependency cycle.
|
|
21
|
+
*/
|
|
22
|
+
export function tryClaimNativeMainProfileForTurn(
|
|
23
|
+
lease?: AdmissionLease,
|
|
24
|
+
deps: NativeMainTurnClaimDeps = {},
|
|
25
|
+
): boolean {
|
|
26
|
+
const isBlocked = deps.isTrafficBlocked ?? isNativeMainTrafficBlocked;
|
|
27
|
+
const claimTurn = deps.claimTurn ?? tryClaimLifecycleNativeMainProfileForTurn;
|
|
28
|
+
if (isBlocked()) return false;
|
|
29
|
+
if (!claimTurn(lease)) return false;
|
|
30
|
+
if (!isBlocked()) return true;
|
|
31
|
+
|
|
32
|
+
// Recovery became visible between the precheck and lifecycle claim. This
|
|
33
|
+
// request must not read auth.json. Keep the caller-owned turn claimed until
|
|
34
|
+
// normal request cleanup: optional routed work may continue, and releasing
|
|
35
|
+
// the whole turn here would let shutdown/profile switching overlap it.
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Acquire standalone ownership only when both native-main gates admit work. */
|
|
40
|
+
export function tryAcquireNativeMainProfileClaim(): AdmissionLease | null {
|
|
41
|
+
if (isNativeMainTrafficBlocked()) return null;
|
|
42
|
+
const claim = tryAcquireLifecycleNativeMainProfileClaim();
|
|
43
|
+
if (!claim) return null;
|
|
44
|
+
if (!isNativeMainTrafficBlocked()) return claim;
|
|
45
|
+
claim.release();
|
|
46
|
+
return null;
|
|
47
|
+
}
|