@iislee/opencodex 2.11.0 → 2.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/README.md +117 -22
- package/bin/ocx.mjs +245 -88
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-Be1sDpWw.css +1 -0
- package/gui/dist/assets/index-D4OKgUV4.js +114 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +21 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +475 -62
- package/src/adapters/base.ts +82 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +637 -0
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/catalog.ts +541 -0
- package/src/adapters/cursor/checkpoint-store.ts +308 -0
- package/src/adapters/cursor/cursor-errors.ts +144 -6
- package/src/adapters/cursor/discovery.ts +122 -14
- package/src/adapters/cursor/effort-map.ts +106 -4
- package/src/adapters/cursor/envelope-echo.ts +290 -0
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +180 -59
- package/src/adapters/cursor/live-transport.ts +623 -170
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-desktop.ts +23 -0
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +5 -3
- package/src/adapters/cursor/native-exec.ts +121 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +447 -75
- package/src/adapters/cursor/request-builder.ts +271 -35
- package/src/adapters/cursor/tool-definitions.ts +252 -12
- package/src/adapters/cursor/tool-result-normalize.ts +115 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +48 -1
- package/src/adapters/cursor.ts +336 -39
- package/src/adapters/exec-tool-result-normalize.ts +99 -0
- package/src/adapters/google-antigravity-replay.ts +713 -41
- package/src/adapters/google-antigravity-wire.ts +48 -10
- package/src/adapters/google-errors.ts +44 -12
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +742 -86
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +27 -0
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +65 -17
- package/src/adapters/kiro.ts +270 -73
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1377 -344
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1164 -64
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +105 -21
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/adapters/xai-web-search.ts +186 -0
- package/src/bridge.ts +512 -92
- package/src/chat/inbound.ts +57 -20
- package/src/chat/outbound.ts +97 -33
- package/src/claude/agents-inject.ts +40 -10
- package/src/claude/context-windows.ts +37 -14
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +88 -21
- package/src/cli/access.ts +46 -3
- package/src/cli/account-api.ts +150 -19
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +648 -28
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +97 -19
- package/src/cli/agent.ts +53 -2
- package/src/cli/alias.ts +66 -0
- package/src/cli/capabilities-command.ts +94 -0
- package/src/cli/capabilities.ts +496 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +60 -15
- package/src/cli/claude.ts +129 -35
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +821 -0
- package/src/cli/doctor.ts +440 -56
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +34 -274
- package/src/cli/index.ts +417 -528
- package/src/cli/init.ts +5 -17
- package/src/cli/inspect.ts +230 -0
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +130 -2
- package/src/cli/models.ts +118 -16
- package/src/cli/observe.ts +123 -11
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +34 -3
- package/src/cli/provider.ts +25 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +476 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +57 -10
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +51 -4
- package/src/cli/storage.ts +234 -0
- package/src/cli/system-command.ts +16 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/usage-report.ts +184 -0
- package/src/cli/v2.ts +137 -18
- package/src/cli/version-skew.ts +46 -0
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1442 -23
- package/src/clients/effective-status.ts +30 -2
- package/src/clients/probes/cline.ts +81 -0
- package/src/codex/account-label.ts +35 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +84 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +570 -107
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +893 -246
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +348 -32
- package/src/codex/autostart-health.ts +24 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +86 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +138 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +555 -45
- package/src/codex/catalog/native-models.ts +75 -0
- package/src/codex/catalog/parsing.ts +269 -30
- package/src/codex/catalog/provider-fetch.ts +1626 -144
- package/src/codex/catalog/sync.ts +1576 -187
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +386 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +676 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/desktop-app-restart.ts +355 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +436 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +30 -24
- package/src/codex/history-provider.ts +1016 -235
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +223 -0
- package/src/codex/inject-coordination.ts +373 -0
- package/src/codex/inject.ts +1114 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +81 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +524 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +360 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +622 -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 +675 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +1313 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +264 -21
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +514 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1065 -31
- package/src/codex/subagent-model-fallback.ts +437 -43
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +720 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +47 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +91 -9
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +121 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +309 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config/provider-validation.ts +177 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +1713 -709
- package/src/generated/compatibility-version.json +3324 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +157 -33
- package/src/images/plan.ts +24 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership-policy.ts +160 -0
- package/src/integrations/ownership.ts +155 -0
- package/src/integrations/registry.ts +166 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +433 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +715 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/admin-secrets.ts +24 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +167 -11
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +26 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +80 -5
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/package-tree-integrity.ts +101 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +6 -2
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +15 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +253 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +30 -4
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/cline.ts +203 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +462 -71
- package/src/oauth/key-providers.ts +25 -0
- package/src/oauth/kimi.ts +25 -3
- package/src/oauth/kiro.ts +95 -6
- package/src/oauth/local-token-detect.ts +13 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +133 -26
- package/src/oauth/token-guardian.ts +9 -3
- package/src/oauth/types.ts +15 -0
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/auto-compact-budget.ts +65 -0
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +176 -0
- package/src/providers/context-cap.ts +26 -8
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +281 -6
- package/src/providers/fastwire.ts +507 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +35 -2
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/new-model-policy.ts +146 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +30 -0
- package/src/providers/quota.ts +1379 -40
- package/src/providers/registry.ts +1545 -112
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +94 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +32 -4
- package/src/reasoning-effort.ts +68 -3
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +384 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +435 -0
- package/src/responses/parser.ts +225 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +504 -0
- package/src/responses/schema.ts +12 -2
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +659 -31
- package/src/responses/thought-signature-replay.ts +364 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/responses/turn-termination.ts +107 -0
- package/src/router.ts +405 -31
- package/src/routing/analytics.ts +379 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +155 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +289 -48
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +154 -72
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +445 -0
- package/src/server/claude-messages.ts +160 -44
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +1021 -190
- package/src/server/lifecycle.ts +336 -14
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +433 -116
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +64 -25
- package/src/server/management/config-routes.ts +511 -51
- package/src/server/management/context.ts +89 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +127 -52
- package/src/server/management/model-routes.ts +461 -133
- package/src/server/management/model-rows.ts +167 -0
- package/src/server/management/native-integration-routes.ts +770 -0
- package/src/server/management/oauth-account-routes.ts +90 -8
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +836 -159
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/route-registry.ts +332 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +289 -33
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +126 -23
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +161 -10
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +221 -54
- package/src/server/relay.ts +479 -87
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log-conversation.ts +51 -0
- package/src/server/request-log.ts +298 -31
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/codex-auth-error.ts +55 -0
- package/src/server/responses/collaboration.ts +239 -36
- package/src/server/responses/combo-stream-preflight.ts +178 -0
- package/src/server/responses/compact.ts +444 -72
- package/src/server/responses/core.ts +3579 -436
- package/src/server/responses/empty-completion-guard.ts +333 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +89 -99
- package/src/server/responses/input-admission.ts +187 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +343 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +381 -0
- package/src/server/responses-custom-tool-repair.ts +363 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +363 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +376 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +319 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +53 -40
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1153 -94
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/policy-job.ts +14 -4
- package/src/storage/policy.ts +88 -23
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +911 -0
- package/src/types/provider.ts +614 -0
- package/src/types/request.ts +397 -0
- package/src/types/tools.ts +236 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +107 -1237
- package/src/update/index.ts +37 -23
- package/src/update/job.ts +445 -68
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +266 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +287 -16
- package/src/usage/log.ts +666 -50
- package/src/usage/summary.ts +388 -17
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +27 -16
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +119 -0
- package/src/web-search/executor.ts +21 -6
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +284 -54
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { resolveCodexHomeDir } from "../../codex/home";
|
|
2
|
+
import {
|
|
3
|
+
compactCodexLogs,
|
|
4
|
+
type CodexLogGuardCompactionResult,
|
|
5
|
+
} from "../../codex/log-guard/maintenance";
|
|
6
|
+
import {
|
|
7
|
+
getCodexLogGuardProtectionStatus,
|
|
8
|
+
protectCodexLogs,
|
|
9
|
+
repairCodexLogGuardProtection,
|
|
10
|
+
unprotectCodexLogs,
|
|
11
|
+
type CodexLogGuardMutationResult,
|
|
12
|
+
type CodexLogGuardStatus,
|
|
13
|
+
} from "../../codex/log-guard/protection";
|
|
14
|
+
import { scanStorage } from "../../storage/scanner";
|
|
15
|
+
import { jsonResponse } from "../auth-cors";
|
|
16
|
+
import {
|
|
17
|
+
managementBodyTooLargeResponse,
|
|
18
|
+
readManagementJsonBody,
|
|
19
|
+
} from "./body";
|
|
20
|
+
import type { ManagementContext } from "./context";
|
|
21
|
+
|
|
22
|
+
const INSPECTION_FAILED_MESSAGE = "Codex log inspection failed";
|
|
23
|
+
|
|
24
|
+
function inspectionUnavailable(report: CodexLogGuardStatus): boolean {
|
|
25
|
+
return report.schema.state === "unavailable";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function mutationStatus(result: CodexLogGuardMutationResult): number {
|
|
29
|
+
if (result.ok) return 200;
|
|
30
|
+
switch (result.error) {
|
|
31
|
+
case "process_enumeration_failed":
|
|
32
|
+
return 503;
|
|
33
|
+
case "codex_running":
|
|
34
|
+
case "busy":
|
|
35
|
+
case "unsupported_schema":
|
|
36
|
+
case "trigger_collision":
|
|
37
|
+
case "unsafe_path":
|
|
38
|
+
return 409;
|
|
39
|
+
case "database_error":
|
|
40
|
+
case "config_write_failed":
|
|
41
|
+
return 500;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function compactStatus(result: CodexLogGuardCompactionResult): number {
|
|
46
|
+
if (result.ok) return 200;
|
|
47
|
+
switch (result.error) {
|
|
48
|
+
case "process_enumeration_failed":
|
|
49
|
+
return 503;
|
|
50
|
+
case "codex_running":
|
|
51
|
+
case "busy":
|
|
52
|
+
case "unsupported_schema":
|
|
53
|
+
case "auto_vacuum_not_incremental":
|
|
54
|
+
case "unsafe_path":
|
|
55
|
+
case "integrity_check_failed":
|
|
56
|
+
return 409;
|
|
57
|
+
case "database_error":
|
|
58
|
+
return 500;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function mutationResponse(
|
|
63
|
+
result: CodexLogGuardMutationResult,
|
|
64
|
+
ctx: ManagementContext,
|
|
65
|
+
): Response {
|
|
66
|
+
return result.ok
|
|
67
|
+
? jsonResponse(result.status, 200, ctx.req, ctx.config)
|
|
68
|
+
: jsonResponse({ error: result.error }, mutationStatus(result), ctx.req, ctx.config);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function compactResponse(
|
|
72
|
+
result: CodexLogGuardCompactionResult,
|
|
73
|
+
ctx: ManagementContext,
|
|
74
|
+
): Response {
|
|
75
|
+
if (result.ok) {
|
|
76
|
+
return jsonResponse({ report: result.report }, 200, ctx.req, ctx.config);
|
|
77
|
+
}
|
|
78
|
+
return jsonResponse(
|
|
79
|
+
result.error === "integrity_check_failed"
|
|
80
|
+
? { error: result.error, phase: result.phase }
|
|
81
|
+
: { error: result.error },
|
|
82
|
+
compactStatus(result),
|
|
83
|
+
ctx.req,
|
|
84
|
+
ctx.config,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function readProtectMode(ctx: ManagementContext): Promise<"compat" | "quiet" | Response> {
|
|
89
|
+
let body: unknown;
|
|
90
|
+
try {
|
|
91
|
+
body = await readManagementJsonBody(ctx.req);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
const tooLarge = managementBodyTooLargeResponse(error, ctx.req, ctx.config);
|
|
94
|
+
if (tooLarge) return tooLarge;
|
|
95
|
+
return jsonResponse({ error: "invalid_request" }, 400, ctx.req, ctx.config);
|
|
96
|
+
}
|
|
97
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
98
|
+
return jsonResponse({ error: "invalid_request" }, 400, ctx.req, ctx.config);
|
|
99
|
+
}
|
|
100
|
+
const mode = (body as Record<string, unknown>).mode;
|
|
101
|
+
if (mode !== "compat" && mode !== "quiet") {
|
|
102
|
+
return jsonResponse({ error: "invalid_mode" }, 400, ctx.req, ctx.config);
|
|
103
|
+
}
|
|
104
|
+
return mode;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Codex Log Guard diagnostics plus explicit protection and maintenance mutations. */
|
|
108
|
+
export async function handleStorageLogGuardRoutes(ctx: ManagementContext): Promise<Response | null> {
|
|
109
|
+
const { req, url, config, deps } = ctx;
|
|
110
|
+
const protectionDeps = deps.codexLogGuardProtectionDeps;
|
|
111
|
+
|
|
112
|
+
if (url.pathname === "/api/storage/codex-logs") {
|
|
113
|
+
if (req.method !== "GET") return null;
|
|
114
|
+
try {
|
|
115
|
+
const report = getCodexLogGuardProtectionStatus(protectionDeps);
|
|
116
|
+
if (inspectionUnavailable(report)) {
|
|
117
|
+
return jsonResponse({ error: "inspect_failed", message: INSPECTION_FAILED_MESSAGE }, 500, req, config);
|
|
118
|
+
}
|
|
119
|
+
return jsonResponse(report, 200, req, config);
|
|
120
|
+
} catch {
|
|
121
|
+
return jsonResponse({
|
|
122
|
+
error: "inspect_failed",
|
|
123
|
+
message: INSPECTION_FAILED_MESSAGE,
|
|
124
|
+
}, 500, req, config);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (url.pathname === "/api/storage/codex-logs/protect") {
|
|
129
|
+
if (req.method !== "POST") return null;
|
|
130
|
+
const mode = await readProtectMode(ctx);
|
|
131
|
+
if (mode instanceof Response) return mode;
|
|
132
|
+
return mutationResponse(protectCodexLogs(mode, protectionDeps), ctx);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (url.pathname === "/api/storage/codex-logs/unprotect") {
|
|
136
|
+
if (req.method !== "POST") return null;
|
|
137
|
+
return mutationResponse(unprotectCodexLogs(protectionDeps), ctx);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (url.pathname === "/api/storage/codex-logs/repair") {
|
|
141
|
+
if (req.method !== "POST") return null;
|
|
142
|
+
return mutationResponse(repairCodexLogGuardProtection(protectionDeps), ctx);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (url.pathname === "/api/storage/codex-logs/compact") {
|
|
146
|
+
if (req.method !== "POST") return null;
|
|
147
|
+
return compactResponse(compactCodexLogs(deps.codexLogGuardMaintenanceDeps), ctx);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (url.pathname !== "/api/storage" || req.method !== "GET") return null;
|
|
151
|
+
|
|
152
|
+
// Keep the existing CODEX_HOME scan as the primary storage contract. The Log Guard
|
|
153
|
+
// report is attached separately so an external sqlite_home is visible without being
|
|
154
|
+
// silently folded into CODEX_HOME totals.
|
|
155
|
+
let storage;
|
|
156
|
+
try {
|
|
157
|
+
storage = scanStorage();
|
|
158
|
+
} catch {
|
|
159
|
+
const fallback = {
|
|
160
|
+
codexHome: resolveCodexHomeDir(),
|
|
161
|
+
generatedAt: Date.now(),
|
|
162
|
+
total: { bytes: 0, fileCount: 0 },
|
|
163
|
+
buckets: [],
|
|
164
|
+
error: "scan_failed",
|
|
165
|
+
};
|
|
166
|
+
try {
|
|
167
|
+
const report = getCodexLogGuardProtectionStatus(protectionDeps);
|
|
168
|
+
return inspectionUnavailable(report)
|
|
169
|
+
? jsonResponse({ ...fallback, codexLogs: null, codexLogsError: "inspect_failed" }, 200, req, config)
|
|
170
|
+
: jsonResponse({ ...fallback, codexLogs: report }, 200, req, config);
|
|
171
|
+
} catch {
|
|
172
|
+
return jsonResponse({ ...fallback, codexLogs: null, codexLogsError: "inspect_failed" }, 200, req, config);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
const report = getCodexLogGuardProtectionStatus(protectionDeps);
|
|
178
|
+
return inspectionUnavailable(report)
|
|
179
|
+
? jsonResponse({ ...storage, codexLogs: null, codexLogsError: "inspect_failed" }, 200, req, config)
|
|
180
|
+
: jsonResponse({ ...storage, codexLogs: report }, 200, req, config);
|
|
181
|
+
} catch {
|
|
182
|
+
// Log Guard inspection is auxiliary to the existing Storage page. A config/path
|
|
183
|
+
// resolution failure must not take the legacy read-only storage report down with it.
|
|
184
|
+
return jsonResponse({ ...storage, codexLogs: null, codexLogsError: "inspect_failed" }, 200, req, config);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single HTTP projection of ConvergeOutcome.
|
|
3
|
+
*
|
|
4
|
+
* Three phase documents once mapped /api/sync independently and one silently
|
|
5
|
+
* dropped Retry-After. Keeping the exhaustive switch here makes a new domain
|
|
6
|
+
* outcome a compile error until its management contract is chosen explicitly.
|
|
7
|
+
*/
|
|
8
|
+
import type { ConvergeOutcome } from "../../codex/convergence-types";
|
|
9
|
+
import { jsonResponse } from "../auth-cors";
|
|
10
|
+
|
|
11
|
+
export function toSyncResponse(outcome: ConvergeOutcome): Response {
|
|
12
|
+
switch (outcome.kind) {
|
|
13
|
+
case "catalog-only":
|
|
14
|
+
return jsonResponse({
|
|
15
|
+
ok: true,
|
|
16
|
+
changed: outcome.changed,
|
|
17
|
+
observed: outcome.observed,
|
|
18
|
+
catalogRefresh: outcome.catalogRefresh,
|
|
19
|
+
history: outcome.history,
|
|
20
|
+
});
|
|
21
|
+
case "converged":
|
|
22
|
+
return jsonResponse({
|
|
23
|
+
ok: true,
|
|
24
|
+
changed: outcome.changed,
|
|
25
|
+
observed: outcome.observed,
|
|
26
|
+
catalogRefresh: outcome.catalogRefresh,
|
|
27
|
+
history: outcome.history,
|
|
28
|
+
});
|
|
29
|
+
case "skipped":
|
|
30
|
+
return jsonResponse({
|
|
31
|
+
ok: true,
|
|
32
|
+
changed: false,
|
|
33
|
+
observed: outcome.observed,
|
|
34
|
+
catalogRefresh: outcome.catalogRefresh,
|
|
35
|
+
history: outcome.history,
|
|
36
|
+
});
|
|
37
|
+
case "refused":
|
|
38
|
+
return jsonResponse({
|
|
39
|
+
ok: false,
|
|
40
|
+
authority: outcome.authority,
|
|
41
|
+
message: outcome.message,
|
|
42
|
+
observed: outcome.observed,
|
|
43
|
+
}, 409);
|
|
44
|
+
case "busy": {
|
|
45
|
+
const response = jsonResponse({
|
|
46
|
+
ok: false,
|
|
47
|
+
surface: outcome.surface,
|
|
48
|
+
retryAfterMs: outcome.retryAfterMs,
|
|
49
|
+
}, 503);
|
|
50
|
+
response.headers.set("Retry-After", String(Math.ceil(outcome.retryAfterMs / 1_000)));
|
|
51
|
+
return response;
|
|
52
|
+
}
|
|
53
|
+
case "deferred":
|
|
54
|
+
return jsonResponse({
|
|
55
|
+
ok: true,
|
|
56
|
+
changed: outcome.changed,
|
|
57
|
+
unresolved: outcome.unresolved,
|
|
58
|
+
observed: outcome.observed,
|
|
59
|
+
catalogRefresh: outcome.catalogRefresh,
|
|
60
|
+
history: outcome.history,
|
|
61
|
+
});
|
|
62
|
+
case "failed":
|
|
63
|
+
return jsonResponse({ error: outcome.message, surface: outcome.surface }, 500);
|
|
64
|
+
default: {
|
|
65
|
+
const exhaustive: never = outcome;
|
|
66
|
+
return exhaustive;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -17,45 +17,123 @@
|
|
|
17
17
|
* - If detached spawn fails (sync throw or pre-start `error`): exit(1) without
|
|
18
18
|
* markRecycling — after drain the listen socket is already closed, so a latch
|
|
19
19
|
* reset cannot recover serving. Clear inherited `OCX_SERVICE` so exit cleanup
|
|
20
|
-
* can restore Codex/Grok fences
|
|
21
|
-
*
|
|
20
|
+
* can restore Codex/Grok fences when a stale service marker has no viable
|
|
21
|
+
* supervisor. Log only a stable errno code — never the raw message
|
|
22
22
|
* (paths in ENOENT often include the OS username).
|
|
23
23
|
*/
|
|
24
24
|
import { spawn } from "node:child_process";
|
|
25
25
|
import {
|
|
26
|
+
beginShutdownDrain,
|
|
26
27
|
drainAndShutdown,
|
|
27
28
|
getActiveTurnCount,
|
|
28
29
|
getServerListenPort,
|
|
29
30
|
isDraining,
|
|
31
|
+
isShutdownDraining,
|
|
30
32
|
markRecyclingForExit,
|
|
31
|
-
|
|
33
|
+
stopServerListener,
|
|
32
34
|
} from "../lifecycle";
|
|
33
35
|
import { isServiceViable } from "../../service";
|
|
34
|
-
import { readRuntimePort } from "../../config";
|
|
36
|
+
import { readRuntimePort } from "../../config/process-state";
|
|
37
|
+
import { withProcessRuntimeProvenance } from "../../lib/bun-runtime";
|
|
38
|
+
import { selfLaunchArgv } from "../../lib/self-launch-argv";
|
|
39
|
+
import {
|
|
40
|
+
MEMORY_DRAIN_RESTART_MS,
|
|
41
|
+
REPLACEMENT_READY_TIMEOUT_MS,
|
|
42
|
+
} from "../../lib/system-restart-contract";
|
|
43
|
+
import { findLiveProxy } from "../proxy-liveness";
|
|
44
|
+
|
|
45
|
+
export { MEMORY_DRAIN_RESTART_MS, REPLACEMENT_READY_TIMEOUT_MS } from "../../lib/system-restart-contract";
|
|
46
|
+
export const DEADLINE_LISTENER_STOP_TIMEOUT_MS = 5_000;
|
|
47
|
+
const REPLACEMENT_READY_POLL_MS = 150;
|
|
35
48
|
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
export interface ReplacementReadinessIo {
|
|
50
|
+
findLive?: typeof findLiveProxy;
|
|
51
|
+
now?: () => number;
|
|
52
|
+
sleep?: (ms: number) => Promise<void>;
|
|
53
|
+
}
|
|
38
54
|
|
|
39
55
|
export interface SystemRestartIo {
|
|
40
56
|
drainAndShutdown?: typeof drainAndShutdown;
|
|
41
57
|
/** True when a background service can actually respawn this process after exit(1). */
|
|
42
58
|
isServiceViable?: () => boolean;
|
|
43
59
|
isSupervisedServiceChild?: () => boolean;
|
|
44
|
-
/**
|
|
45
|
-
spawnStart?: (port?: number) => void | Promise<void>;
|
|
60
|
+
/** Ordinary start; deadline handoff may defer health until parent exit releases OS locks. */
|
|
61
|
+
spawnStart?: (port?: number, waitForHealthBeforeParentExit?: boolean) => void | Promise<void>;
|
|
62
|
+
/** Idempotent listener close; must settle before an ordinary start is spawned. */
|
|
63
|
+
stopListener?: () => void | Promise<void>;
|
|
46
64
|
markRecycling?: () => void;
|
|
47
65
|
exitProcess?: (code: number) => void;
|
|
48
66
|
schedule?: (fn: () => void | Promise<void>, ms: number) => void;
|
|
67
|
+
scheduleDeadline?: (fn: () => void, ms: number) => () => void;
|
|
49
68
|
isDraining?: () => boolean;
|
|
69
|
+
isShutdownDraining?: () => boolean;
|
|
70
|
+
beginShutdownDrain?: () => boolean;
|
|
50
71
|
setDraining?: (value: boolean) => void;
|
|
51
72
|
getActiveTurnCount?: () => number;
|
|
52
73
|
listenPort?: () => number | undefined;
|
|
74
|
+
now?: () => number;
|
|
53
75
|
}
|
|
54
76
|
|
|
55
77
|
let restartIo: SystemRestartIo = {};
|
|
56
78
|
/** Prevents double-scheduling in the 200ms window before drainAndShutdown sets draining. */
|
|
57
79
|
let restartAccepted = false;
|
|
58
80
|
|
|
81
|
+
type RestartDrainOutcome = "completed" | "rejected" | "deadline";
|
|
82
|
+
type BoundedSettlementOutcome = "completed" | "rejected" | "deadline";
|
|
83
|
+
|
|
84
|
+
function waitForRestartDrain(
|
|
85
|
+
drainPromise: Promise<void>,
|
|
86
|
+
deadlineMs: number,
|
|
87
|
+
now: () => number,
|
|
88
|
+
scheduleDeadline: NonNullable<SystemRestartIo["scheduleDeadline"]>,
|
|
89
|
+
): Promise<RestartDrainOutcome> {
|
|
90
|
+
const remainingMs = Math.max(0, deadlineMs - now());
|
|
91
|
+
if (remainingMs === 0) {
|
|
92
|
+
// Observe any late rejection even though orchestration is already terminal.
|
|
93
|
+
void drainPromise.catch(() => {});
|
|
94
|
+
return Promise.resolve("deadline");
|
|
95
|
+
}
|
|
96
|
+
return new Promise<RestartDrainOutcome>((resolve) => {
|
|
97
|
+
let settled = false;
|
|
98
|
+
let cancelDeadline: (() => void) | undefined;
|
|
99
|
+
const finish = (outcome: RestartDrainOutcome) => {
|
|
100
|
+
if (settled) return;
|
|
101
|
+
settled = true;
|
|
102
|
+
cancelDeadline?.();
|
|
103
|
+
resolve(outcome);
|
|
104
|
+
};
|
|
105
|
+
cancelDeadline = scheduleDeadline(() => finish("deadline"), remainingMs);
|
|
106
|
+
if (settled) cancelDeadline();
|
|
107
|
+
void drainPromise.then(
|
|
108
|
+
() => finish("completed"),
|
|
109
|
+
() => finish("rejected"),
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function waitForBoundedSettlement(
|
|
115
|
+
promise: Promise<void>,
|
|
116
|
+
timeoutMs: number,
|
|
117
|
+
scheduleDeadline: NonNullable<SystemRestartIo["scheduleDeadline"]>,
|
|
118
|
+
): Promise<BoundedSettlementOutcome> {
|
|
119
|
+
return new Promise<BoundedSettlementOutcome>((resolve) => {
|
|
120
|
+
let settled = false;
|
|
121
|
+
let cancelDeadline: (() => void) | undefined;
|
|
122
|
+
const finish = (outcome: BoundedSettlementOutcome) => {
|
|
123
|
+
if (settled) return;
|
|
124
|
+
settled = true;
|
|
125
|
+
cancelDeadline?.();
|
|
126
|
+
resolve(outcome);
|
|
127
|
+
};
|
|
128
|
+
cancelDeadline = scheduleDeadline(() => finish("deadline"), timeoutMs);
|
|
129
|
+
if (settled) cancelDeadline();
|
|
130
|
+
void promise.then(
|
|
131
|
+
() => finish("completed"),
|
|
132
|
+
() => finish("rejected"),
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
59
137
|
/** Test seam — reset between tests. */
|
|
60
138
|
export function setSystemRestartIoForTests(io: SystemRestartIo = {}): void {
|
|
61
139
|
restartIo = io;
|
|
@@ -86,42 +164,180 @@ function spawnFailureCode(err: unknown): string {
|
|
|
86
164
|
return "spawn_failed";
|
|
87
165
|
}
|
|
88
166
|
|
|
89
|
-
function
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
167
|
+
function handoffError(code: string): NodeJS.ErrnoException {
|
|
168
|
+
const error = new Error(code) as NodeJS.ErrnoException;
|
|
169
|
+
error.code = code;
|
|
170
|
+
return error;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export async function waitForReplacementReady(
|
|
174
|
+
expectedPid: number | undefined,
|
|
175
|
+
parentPid: number,
|
|
176
|
+
expectedPort: number | undefined,
|
|
177
|
+
io: ReplacementReadinessIo = {},
|
|
178
|
+
): Promise<boolean> {
|
|
179
|
+
const findLive = io.findLive ?? findLiveProxy;
|
|
180
|
+
const now = io.now ?? Date.now;
|
|
181
|
+
const sleep = io.sleep ?? Bun.sleep;
|
|
182
|
+
const deadline = now() + REPLACEMENT_READY_TIMEOUT_MS;
|
|
183
|
+
while (now() < deadline) {
|
|
184
|
+
try {
|
|
185
|
+
const live = await findLive({
|
|
186
|
+
deadlineAt: deadline,
|
|
187
|
+
nowFn: now,
|
|
188
|
+
sleepFn: sleep,
|
|
189
|
+
});
|
|
190
|
+
// A probe that began within budget can still return after it. Never accept
|
|
191
|
+
// delayed health as proof once the shared absolute handoff budget expired.
|
|
192
|
+
if (now() >= deadline) return false;
|
|
193
|
+
if (
|
|
194
|
+
live
|
|
195
|
+
&& live.pid !== null
|
|
196
|
+
&& live.pid !== parentPid
|
|
197
|
+
&& (expectedPid === undefined || live.pid === expectedPid)
|
|
198
|
+
&& (expectedPort === undefined || live.port === expectedPort)
|
|
199
|
+
) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
} catch {
|
|
203
|
+
// A not-yet-bound replacement is indistinguishable from a transient
|
|
204
|
+
// liveness failure here; keep polling inside the one bounded window.
|
|
205
|
+
}
|
|
206
|
+
const remainingMs = deadline - now();
|
|
207
|
+
if (remainingMs <= 0) break;
|
|
208
|
+
await sleep(Math.min(REPLACEMENT_READY_POLL_MS, remainingMs));
|
|
93
209
|
}
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function spawnDetachedStart(
|
|
214
|
+
port?: number,
|
|
215
|
+
waitForHealthBeforeParentExit = true,
|
|
216
|
+
): Promise<void> {
|
|
217
|
+
const args = ["start"];
|
|
218
|
+
const expectedPort = typeof port === "number" && Number.isFinite(port) && port > 0 && port <= 65535
|
|
219
|
+
? Math.trunc(port)
|
|
220
|
+
: undefined;
|
|
221
|
+
if (expectedPort !== undefined) {
|
|
222
|
+
args.push("--port", String(expectedPort));
|
|
223
|
+
}
|
|
224
|
+
const launchArgs = selfLaunchArgv(args);
|
|
94
225
|
return new Promise<void>((resolve, reject) => {
|
|
95
226
|
let child: ReturnType<typeof spawn>;
|
|
96
227
|
try {
|
|
97
|
-
|
|
228
|
+
const env: NodeJS.ProcessEnv = { ...process.env };
|
|
229
|
+
delete env.OCX_SERVICE;
|
|
230
|
+
child = spawn(process.execPath, launchArgs, {
|
|
98
231
|
detached: true,
|
|
99
232
|
stdio: "ignore",
|
|
100
233
|
windowsHide: true,
|
|
101
|
-
env:
|
|
234
|
+
env: withProcessRuntimeProvenance(env),
|
|
102
235
|
});
|
|
103
236
|
} catch (err) {
|
|
104
237
|
reject(err);
|
|
105
238
|
return;
|
|
106
239
|
}
|
|
107
240
|
let settled = false;
|
|
108
|
-
const
|
|
241
|
+
const cleanup = () => {
|
|
242
|
+
child.off("error", onError);
|
|
243
|
+
child.off("exit", onExit);
|
|
244
|
+
child.off("spawn", onSpawn);
|
|
245
|
+
};
|
|
246
|
+
const finish = (error?: unknown) => {
|
|
109
247
|
if (settled) return;
|
|
110
248
|
settled = true;
|
|
111
|
-
|
|
249
|
+
cleanup();
|
|
250
|
+
if (error !== undefined) {
|
|
251
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
252
|
+
try { child.kill(); } catch { /* best-effort failed-start cleanup */ }
|
|
253
|
+
}
|
|
254
|
+
try { child.unref(); } catch { /* best-effort */ }
|
|
255
|
+
reject(error);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
child.unref();
|
|
259
|
+
resolve();
|
|
112
260
|
};
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
child.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
261
|
+
const onError = (err: Error) => { finish(err); };
|
|
262
|
+
const onExit = () => { finish(handoffError("child_exit")); };
|
|
263
|
+
const onSpawn = () => {
|
|
264
|
+
if (!waitForHealthBeforeParentExit) {
|
|
265
|
+
// A deadline may have been caused by native-main ownership cleanup.
|
|
266
|
+
// Let the ordinary child survive parent exit, which releases those OS locks.
|
|
267
|
+
finish();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
void waitForReplacementReady(child.pid, process.pid, expectedPort).then(
|
|
271
|
+
ready => {
|
|
272
|
+
if (!ready) {
|
|
273
|
+
console.warn(
|
|
274
|
+
"Drain-and-restart replacement is still alive after the readiness window; allowing it to continue after parent exit",
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
// Never kill a live ordinary start at its valid reclaim boundary. Parent
|
|
278
|
+
// exit is the final resource release the child may still be waiting for.
|
|
279
|
+
finish();
|
|
280
|
+
},
|
|
281
|
+
err => finish(err),
|
|
282
|
+
);
|
|
283
|
+
};
|
|
284
|
+
child.once("error", onError);
|
|
285
|
+
child.once("exit", onExit);
|
|
286
|
+
child.once("spawn", onSpawn);
|
|
122
287
|
});
|
|
123
288
|
}
|
|
124
289
|
|
|
290
|
+
async function completeDeferredParentExitHandoff(
|
|
291
|
+
io: SystemRestartIo,
|
|
292
|
+
exitProcess: (code: number) => void,
|
|
293
|
+
port: number | undefined,
|
|
294
|
+
phase: "deadline" | "listener-stop fallback",
|
|
295
|
+
): Promise<void> {
|
|
296
|
+
try {
|
|
297
|
+
await (io.spawnStart ?? spawnDetachedStart)(port, false);
|
|
298
|
+
} catch (err) {
|
|
299
|
+
console.warn(
|
|
300
|
+
`Drain-and-restart ${phase} spawn failed (${spawnFailureCode(err)}); exiting without replacement`,
|
|
301
|
+
);
|
|
302
|
+
delete process.env.OCX_SERVICE;
|
|
303
|
+
exitProcess(1);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
(io.markRecycling ?? markRecyclingForExit)();
|
|
307
|
+
exitProcess(0);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async function completeDeadlineRestartHandoff(
|
|
311
|
+
io: SystemRestartIo,
|
|
312
|
+
exitProcess: (code: number) => void,
|
|
313
|
+
port: number | undefined,
|
|
314
|
+
scheduleDeadline: NonNullable<SystemRestartIo["scheduleDeadline"]>,
|
|
315
|
+
): Promise<void> {
|
|
316
|
+
const supervised = (io.isSupervisedServiceChild ?? (() => isSupervisedServiceChild(io)))();
|
|
317
|
+
if (supervised) {
|
|
318
|
+
// Failure-only supervisors ignore exit(0); intentional non-zero triggers respawn.
|
|
319
|
+
exitProcess(1);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const stopPromise = Promise.resolve().then(
|
|
324
|
+
() => (io.stopListener ?? (() => stopServerListener()))(),
|
|
325
|
+
);
|
|
326
|
+
const stopOutcome = await waitForBoundedSettlement(
|
|
327
|
+
stopPromise,
|
|
328
|
+
DEADLINE_LISTENER_STOP_TIMEOUT_MS,
|
|
329
|
+
scheduleDeadline,
|
|
330
|
+
);
|
|
331
|
+
if (stopOutcome === "rejected") {
|
|
332
|
+
console.warn("Drain-and-restart deadline listener stop failed; continuing parent-exit handoff");
|
|
333
|
+
} else if (stopOutcome === "deadline") {
|
|
334
|
+
console.warn("Drain-and-restart deadline listener stop timed out; continuing parent-exit handoff");
|
|
335
|
+
}
|
|
336
|
+
// The ordinary child must survive parent exit: a failed/pending socket close
|
|
337
|
+
// or overdue cleanup is completed by process teardown, without a hidden mode.
|
|
338
|
+
await completeDeferredParentExitHandoff(io, exitProcess, port, "deadline");
|
|
339
|
+
}
|
|
340
|
+
|
|
125
341
|
/**
|
|
126
342
|
* Accept a drain-and-restart request. Returns immediately; the drain +
|
|
127
343
|
* respawn runs on a short timer so the HTTP response can flush first.
|
|
@@ -133,34 +349,74 @@ export function acceptSystemRestart(io: SystemRestartIo = restartIo): {
|
|
|
133
349
|
activeTurnCount: number;
|
|
134
350
|
drainTimeoutMs: number;
|
|
135
351
|
} {
|
|
136
|
-
const
|
|
352
|
+
const shutdownActive = io.isShutdownDraining
|
|
353
|
+
?? io.isDraining
|
|
354
|
+
?? isShutdownDraining;
|
|
355
|
+
const alreadyDraining = restartAccepted || shutdownActive();
|
|
137
356
|
const activeTurnCount = (io.getActiveTurnCount ?? getActiveTurnCount)();
|
|
138
357
|
const schedule = io.schedule ?? ((fn, ms) => { setTimeout(() => { void fn(); }, ms); });
|
|
139
358
|
|
|
140
359
|
if (!alreadyDraining) {
|
|
141
360
|
restartAccepted = true;
|
|
361
|
+
const now = io.now ?? Date.now;
|
|
362
|
+
const restartDeadlineMs = now() + MEMORY_DRAIN_RESTART_MS;
|
|
142
363
|
// Reject new data-plane traffic immediately (503), before the 200ms response-flush delay.
|
|
143
|
-
(io.
|
|
364
|
+
if (io.beginShutdownDrain) io.beginShutdownDrain();
|
|
365
|
+
else if (io.setDraining) io.setDraining(true);
|
|
366
|
+
else beginShutdownDrain();
|
|
144
367
|
schedule(async () => {
|
|
368
|
+
// Preserve the live binding before drainAndShutdown (or its deadline race)
|
|
369
|
+
// closes the listener and makes both the server ref and runtime metadata stale.
|
|
370
|
+
const restartPort = (io.listenPort ?? resolveListenPort)();
|
|
145
371
|
const drain = io.drainAndShutdown ?? drainAndShutdown;
|
|
146
|
-
|
|
372
|
+
const remainingMs = Math.max(0, restartDeadlineMs - now());
|
|
373
|
+
const drainPromise = Promise.resolve().then(() => drain(undefined, remainingMs));
|
|
374
|
+
const scheduleDeadline = io.scheduleDeadline ?? ((fn, ms) => {
|
|
375
|
+
const timer = setTimeout(fn, ms);
|
|
376
|
+
return () => clearTimeout(timer);
|
|
377
|
+
});
|
|
378
|
+
const drainOutcome = await waitForRestartDrain(drainPromise, restartDeadlineMs, now, scheduleDeadline);
|
|
379
|
+
const exitProcess = io.exitProcess ?? ((code: number) => { process.exit(code); });
|
|
380
|
+
if (drainOutcome === "deadline") {
|
|
381
|
+
console.warn("Drain-and-restart deadline expired; forcing terminal restart handoff");
|
|
382
|
+
await completeDeadlineRestartHandoff(io, exitProcess, restartPort, scheduleDeadline);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (drainOutcome === "rejected") {
|
|
386
|
+
// drainAndShutdown stops the listener in finally. Even if ancillary cleanup
|
|
387
|
+
// rejects, an accepted restart must still reach replacement or terminal exit.
|
|
388
|
+
console.warn("Drain-and-restart cleanup failed; continuing terminal restart handoff");
|
|
389
|
+
}
|
|
147
390
|
const supervised = (io.isSupervisedServiceChild ?? (() => isSupervisedServiceChild(io)))();
|
|
148
391
|
if (supervised) {
|
|
149
392
|
// Failure-only supervisors ignore exit(0); intentional non-zero triggers respawn.
|
|
150
393
|
(io.exitProcess ?? ((code: number) => { process.exit(code); }))(1);
|
|
151
394
|
return;
|
|
152
395
|
}
|
|
153
|
-
const port = (io.listenPort ?? resolveListenPort)();
|
|
154
|
-
const exitProcess = io.exitProcess ?? ((code: number) => { process.exit(code); });
|
|
155
396
|
try {
|
|
156
|
-
await (io.
|
|
397
|
+
await (io.stopListener ?? (() => stopServerListener()))();
|
|
398
|
+
} catch {
|
|
399
|
+
console.warn("Drain-and-restart listener stop failed; continuing parent-exit handoff");
|
|
400
|
+
await completeDeferredParentExitHandoff(
|
|
401
|
+
io,
|
|
402
|
+
exitProcess,
|
|
403
|
+
restartPort,
|
|
404
|
+
"listener-stop fallback",
|
|
405
|
+
);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
try {
|
|
409
|
+
// A rejected drain has uncertain cleanup ownership, so it uses the same
|
|
410
|
+
// parent-exit handoff as a deadline. Only a fully completed drain waits
|
|
411
|
+
// for replacement health in the old process.
|
|
412
|
+
await (io.spawnStart ?? spawnDetachedStart)(restartPort, drainOutcome === "completed");
|
|
157
413
|
} catch (err) {
|
|
158
414
|
console.warn(
|
|
159
415
|
`⚠️ Drain-and-restart spawn failed (${spawnFailureCode(err)}); exiting without replacement`,
|
|
160
416
|
);
|
|
161
417
|
// Listen socket is already stopped; do not markRecycling — no child to inherit fences.
|
|
162
|
-
//
|
|
163
|
-
//
|
|
418
|
+
// No replacement inherited the routing. Clear a stale service marker so
|
|
419
|
+
// this unsupervised parent restores clients after the failed handoff.
|
|
164
420
|
delete process.env.OCX_SERVICE;
|
|
165
421
|
exitProcess(1);
|
|
166
422
|
return;
|