@yansigit/opencodex 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/LICENSE +21 -0
- package/README.md +303 -0
- package/assets/architecture.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/claude-code-models.gif +0 -0
- package/assets/codex-app-picker.png +0 -0
- package/bin/ocx.mjs +587 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
- package/gui/dist/assets/index-CGoDO3uO.css +1 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/icons.svg +24 -0
- package/gui/dist/index.html +25 -0
- package/gui/dist/logo.png +0 -0
- package/gui/dist/provider-icons/alibaba-color.svg +1 -0
- package/gui/dist/provider-icons/antigravity-color.svg +1 -0
- package/gui/dist/provider-icons/claude-color.svg +1 -0
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -0
- package/gui/dist/provider-icons/cursor-color.svg +2 -0
- package/gui/dist/provider-icons/deepseek-color.svg +1 -0
- package/gui/dist/provider-icons/discord.svg +1 -0
- package/gui/dist/provider-icons/firepass-color.svg +1 -0
- package/gui/dist/provider-icons/fireworks-color.svg +1 -0
- package/gui/dist/provider-icons/gemini-color.svg +1 -0
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
- package/gui/dist/provider-icons/grok.svg +1 -0
- package/gui/dist/provider-icons/groq-color.svg +1 -0
- package/gui/dist/provider-icons/huggingface-color.svg +1 -0
- package/gui/dist/provider-icons/kimi-color.svg +1 -0
- package/gui/dist/provider-icons/kiro-color.svg +15 -0
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
- package/gui/dist/provider-icons/mistral-color.svg +1 -0
- package/gui/dist/provider-icons/moonshot-color.svg +1 -0
- package/gui/dist/provider-icons/nvidia-color.svg +1 -0
- package/gui/dist/provider-icons/ollama-color.svg +1 -0
- package/gui/dist/provider-icons/openai.svg +1 -0
- package/gui/dist/provider-icons/opencode.svg +2 -0
- package/gui/dist/provider-icons/openrouter-color.svg +1 -0
- package/gui/dist/provider-icons/pi.svg +21 -0
- package/gui/dist/provider-icons/qianfan-color.svg +1 -0
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
- package/gui/dist/provider-icons/telegram.svg +1 -0
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/vllm-color.svg +1 -0
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
- package/package.json +108 -0
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic-image-guard.ts +251 -0
- package/src/adapters/anthropic-image-normalize.ts +518 -0
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +1327 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +121 -0
- package/src/adapters/client-fingerprint.ts +65 -0
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +288 -0
- package/src/adapters/cursor/discovery.ts +333 -0
- package/src/adapters/cursor/effort-map.ts +151 -0
- package/src/adapters/cursor/exec-policy.ts +88 -0
- package/src/adapters/cursor/framing.ts +250 -0
- package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +269 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1653 -0
- package/src/adapters/cursor/mcp-config.ts +42 -0
- package/src/adapters/cursor/mcp-manager.ts +333 -0
- package/src/adapters/cursor/message-mapper.ts +49 -0
- package/src/adapters/cursor/native-exec-common.ts +76 -0
- package/src/adapters/cursor/native-exec-desktop.ts +184 -0
- package/src/adapters/cursor/native-exec-fs.ts +332 -0
- package/src/adapters/cursor/native-exec-mcp.ts +153 -0
- package/src/adapters/cursor/native-exec-network.ts +43 -0
- package/src/adapters/cursor/native-exec-shell.ts +547 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +663 -0
- package/src/adapters/cursor/protobuf-events.ts +1381 -0
- package/src/adapters/cursor/protobuf-request.ts +1032 -0
- package/src/adapters/cursor/request-builder.ts +461 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +735 -0
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +79 -0
- package/src/adapters/cursor/types.ts +79 -0
- package/src/adapters/cursor.ts +322 -0
- package/src/adapters/google-antigravity-hosts.ts +48 -0
- package/src/adapters/google-antigravity-replay.ts +827 -0
- package/src/adapters/google-antigravity-tools.ts +105 -0
- package/src/adapters/google-antigravity-wire.ts +141 -0
- package/src/adapters/google-errors.ts +92 -0
- package/src/adapters/google-http.ts +460 -0
- package/src/adapters/google-tool-schema.ts +238 -0
- package/src/adapters/google-truncation.ts +24 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +1377 -0
- package/src/adapters/identity.ts +77 -0
- package/src/adapters/image.ts +23 -0
- package/src/adapters/kiro-constants.ts +16 -0
- package/src/adapters/kiro-errors.ts +208 -0
- package/src/adapters/kiro-events.ts +197 -0
- package/src/adapters/kiro-images.ts +129 -0
- package/src/adapters/kiro-retry.ts +312 -0
- package/src/adapters/kiro-thinking.ts +112 -0
- package/src/adapters/kiro-tool-fallback.ts +36 -0
- package/src/adapters/kiro-tools.ts +224 -0
- package/src/adapters/kiro-truncation.ts +33 -0
- package/src/adapters/kiro-wire.ts +129 -0
- package/src/adapters/kiro.ts +1936 -0
- package/src/adapters/mimo-free.ts +280 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1980 -0
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1911 -0
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +154 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +1986 -0
- package/src/chat/inbound.ts +319 -0
- package/src/chat/outbound.ts +821 -0
- package/src/claude/agents-inject.ts +266 -0
- package/src/claude/alias.ts +149 -0
- package/src/claude/auth-detect.ts +229 -0
- package/src/claude/auth-mode-migration.ts +32 -0
- package/src/claude/auth-mode.ts +62 -0
- package/src/claude/context-windows.ts +205 -0
- package/src/claude/desktop-3p-guard.ts +35 -0
- package/src/claude/desktop-3p-paths.ts +84 -0
- package/src/claude/desktop-3p.ts +615 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +107 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +578 -0
- package/src/claude/model-info.ts +174 -0
- package/src/claude/outbound.ts +926 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +302 -0
- package/src/cli/account-auth.ts +250 -0
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +737 -0
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +299 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +290 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +213 -0
- package/src/cli/claude.ts +355 -0
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +47 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +127 -0
- package/src/cli/config-command.ts +209 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/dispatch.ts +585 -0
- package/src/cli/doctor.ts +1202 -0
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +213 -0
- package/src/cli/help.ts +101 -0
- package/src/cli/index.ts +973 -0
- package/src/cli/init.ts +211 -0
- package/src/cli/integrations.ts +260 -0
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +245 -0
- package/src/cli/models.ts +422 -0
- package/src/cli/observe.ts +206 -0
- package/src/cli/opencode.ts +588 -0
- package/src/cli/provider-replit.ts +232 -0
- package/src/cli/provider-runtime.ts +179 -0
- package/src/cli/provider.ts +492 -0
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +422 -0
- package/src/cli/replit-gateway-key-input.ts +138 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +328 -0
- package/src/cli/star-prompt.ts +211 -0
- package/src/cli/status-oauth.ts +78 -0
- package/src/cli/status.ts +328 -0
- package/src/cli/system-command.ts +112 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +199 -0
- package/src/cli/v2.ts +268 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +1704 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +47 -0
- package/src/codex/account-lifecycle.ts +172 -0
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +195 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-runtime-state.ts +31 -0
- package/src/codex/account-store.ts +544 -0
- package/src/codex/account-usability.ts +43 -0
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/agent-roles-sync.ts +225 -0
- package/src/codex/agent-roles.ts +238 -0
- package/src/codex/app-server-processes.ts +1143 -0
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +2147 -0
- package/src/codex/auth-collision.ts +109 -0
- package/src/codex/auth-context.ts +665 -0
- package/src/codex/autostart-health.ts +156 -0
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +436 -0
- package/src/codex/catalog/bundled.ts +549 -0
- package/src/codex/catalog/effort.ts +446 -0
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +664 -0
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +650 -0
- package/src/codex/catalog/provider-fetch.ts +2064 -0
- package/src/codex/catalog/sync.ts +1883 -0
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +14 -0
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/data/upstream-models.json +830 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +1566 -0
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +108 -0
- package/src/codex/history-provider.ts +979 -0
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1733 -0
- package/src/codex/injected-marker.ts +106 -0
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +225 -0
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +56 -0
- package/src/codex/main-account.ts +68 -0
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +273 -0
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +144 -0
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +295 -0
- package/src/codex/project-config-warnings.ts +425 -0
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +573 -0
- package/src/codex/refresh.ts +62 -0
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +1888 -0
- package/src/codex/runtime.ts +659 -0
- package/src/codex/shim.ts +2170 -0
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +784 -0
- package/src/codex/sync.ts +319 -0
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +298 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +160 -0
- package/src/combos/index.ts +45 -0
- package/src/combos/request.ts +94 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +398 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +4041 -0
- package/src/fork/register.ts +3 -0
- package/src/generated/compatibility-version.json +3116 -0
- package/src/generated/model-metadata.ts +106 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +530 -0
- package/src/grok/inspect.ts +45 -0
- package/src/grok/status.ts +121 -0
- package/src/grok/sync.ts +66 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +149 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +955 -0
- package/src/images/plan.ts +143 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/index.ts +22 -0
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/abort.ts +146 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/admission.ts +83 -0
- package/src/lib/app-owned-memory-stores.ts +195 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +346 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +184 -0
- package/src/lib/bun-stream-caps.ts +130 -0
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +364 -0
- package/src/lib/crash-guard.ts +344 -0
- package/src/lib/debug-log-buffer.ts +83 -0
- package/src/lib/debug-settings.ts +108 -0
- package/src/lib/debug.ts +31 -0
- package/src/lib/destination-policy.ts +380 -0
- package/src/lib/errors.ts +406 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/open-url.ts +25 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +270 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +168 -0
- package/src/lib/provider-outbound.ts +210 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +521 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +25 -0
- package/src/lib/shadow-call.ts +61 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +364 -0
- package/src/lib/state-store-registrations.ts +119 -0
- package/src/lib/state-store-sweeper.ts +184 -0
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/test-home-guard.ts +90 -0
- package/src/lib/token-estimate.ts +86 -0
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +400 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +392 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-atomic-replace.ts +156 -0
- package/src/lib/windows-elevation.ts +773 -0
- package/src/lib/windows-secret-acl.ts +854 -0
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +403 -0
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic-routing.ts +594 -0
- package/src/oauth/anthropic.ts +188 -0
- package/src/oauth/antigravity-routing.ts +151 -0
- package/src/oauth/callback-server.ts +300 -0
- package/src/oauth/chatgpt.ts +161 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +252 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +262 -0
- package/src/oauth/health.ts +407 -0
- package/src/oauth/index.ts +1504 -0
- package/src/oauth/key-providers.ts +124 -0
- package/src/oauth/kimi.ts +227 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +621 -0
- package/src/oauth/local-token-detect.ts +130 -0
- package/src/oauth/log.ts +50 -0
- package/src/oauth/login-cli.ts +223 -0
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +728 -0
- package/src/oauth/token-guardian.ts +309 -0
- package/src/oauth/types.ts +62 -0
- package/src/oauth/xai.ts +241 -0
- package/src/providers/alibaba-region-backup.ts +75 -0
- package/src/providers/alibaba-region-migration.ts +156 -0
- package/src/providers/alibaba-region-startup.ts +36 -0
- package/src/providers/antigravity-models.ts +695 -0
- package/src/providers/antigravity-quota.ts +216 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +74 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +82 -0
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +586 -0
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +187 -0
- package/src/providers/github-copilot-transport.ts +56 -0
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +271 -0
- package/src/providers/kiro-models.ts +67 -0
- package/src/providers/label.ts +19 -0
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +449 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +243 -0
- package/src/providers/openai-tier-startup.ts +56 -0
- package/src/providers/openai-tiers.ts +423 -0
- package/src/providers/openai-virtual-models.ts +83 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +185 -0
- package/src/providers/quota.ts +2345 -0
- package/src/providers/registry.ts +2918 -0
- package/src/providers/replit/constants.ts +27 -0
- package/src/providers/replit/derive.ts +85 -0
- package/src/providers/replit/headers.ts +28 -0
- package/src/providers/replit/origin.ts +55 -0
- package/src/providers/replit/pair-install-response.ts +72 -0
- package/src/providers/replit/probe.ts +199 -0
- package/src/providers/replit/setup.ts +350 -0
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +103 -0
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +148 -0
- package/src/reasoning-effort.ts +183 -0
- package/src/responses/compaction.ts +142 -0
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +838 -0
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +165 -0
- package/src/responses/spill-store.ts +459 -0
- package/src/responses/state.ts +1433 -0
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +761 -0
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +53 -0
- package/src/server/auth-cors.ts +751 -0
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +442 -0
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +1030 -0
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +190 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +152 -0
- package/src/server/image-retry.ts +42 -0
- package/src/server/images.ts +568 -0
- package/src/server/index.ts +1813 -0
- package/src/server/lifecycle.ts +498 -0
- package/src/server/live.ts +717 -0
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +1433 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +193 -0
- package/src/server/management/body.ts +41 -0
- package/src/server/management/combo-routes.ts +263 -0
- package/src/server/management/config-routes.ts +835 -0
- package/src/server/management/context.ts +113 -0
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +586 -0
- package/src/server/management/model-routes.ts +560 -0
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +637 -0
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +1033 -0
- package/src/server/management/replit-provider-routes.ts +86 -0
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +385 -0
- package/src/server/management/shared.ts +286 -0
- package/src/server/management/sidebar-routes.ts +106 -0
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +435 -0
- package/src/server/management/system-routes.ts +194 -0
- package/src/server/management/usage-summary-cache.ts +94 -0
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +314 -0
- package/src/server/management-auth.ts +482 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +156 -0
- package/src/server/proxy-liveness.ts +328 -0
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +353 -0
- package/src/server/relay.ts +1209 -0
- package/src/server/request-decompress.ts +239 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1259 -0
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +551 -0
- package/src/server/responses/compact.ts +771 -0
- package/src/server/responses/core.ts +5389 -0
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +331 -0
- package/src/server/responses/fetch-helpers.ts +232 -0
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +78 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +251 -0
- package/src/server/responses/upstream-error.ts +53 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-image-gen-repair.ts +132 -0
- package/src/server/responses-item-id-repair.ts +272 -0
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +25 -0
- package/src/server/search.ts +201 -0
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +263 -0
- package/src/server/startup-action-control.ts +315 -0
- package/src/server/startup-health-cache.ts +131 -0
- package/src/server/system-env.ts +484 -0
- package/src/server/windows-tcp-drop.ts +184 -0
- package/src/server/windows-tray-control.ts +41 -0
- package/src/server/ws-bridge.ts +472 -0
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +3575 -0
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/stall-timeout.ts +20 -0
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +3085 -0
- package/src/storage/policy-job.ts +457 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +59 -0
- package/src/storage/policy.ts +527 -0
- package/src/storage/restore-job.ts +299 -0
- package/src/storage/restore-worker.ts +58 -0
- package/src/storage/scanner.ts +238 -0
- package/src/storage/storage-mutation-coordinator.ts +139 -0
- package/src/storage/worker-lifecycle.ts +215 -0
- package/src/tray/assets/opencodex-tray-offline.ico +0 -0
- package/src/tray/assets/opencodex-tray-online.ico +0 -0
- package/src/tray/assets/opencodex-tray-warning.ico +0 -0
- package/src/tray/assets/opencodex-tray.png +0 -0
- package/src/tray/windows-tray.ps1 +364 -0
- package/src/tray/windows.ts +757 -0
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +876 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +106 -0
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +415 -0
- package/src/update/job.ts +1887 -0
- package/src/update/notify.ts +263 -0
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/update/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +625 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +416 -0
- package/src/usage/log.ts +1223 -0
- package/src/usage/summary.ts +753 -0
- package/src/usage/totals.ts +14 -0
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +189 -0
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +131 -0
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +681 -0
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +195 -0
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +113 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +331 -0
- package/src/web-search/loop.ts +896 -0
- package/src/web-search/parse.ts +315 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/synthetic-tool.ts +47 -0
- package/src/web-search/xai-executor.ts +219 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reclaim a listen port after stop/update so restart can stay on the configured
|
|
3
|
+
* port instead of hopping to an ephemeral one (Windows CLOSE_WAIT / leftover ocx).
|
|
4
|
+
*
|
|
5
|
+
* Killing is never the default. A process may be killed only when the caller
|
|
6
|
+
* sets `killOcxHolders` and either supplies a non-empty `onlyKillPids` allowlist
|
|
7
|
+
* (trusted teardown PIDs, including allowlisted holders that fail ocx revalidate)
|
|
8
|
+
* or enables `killAllOcxOnPort` for revalidated ocx listeners. Unknown foreign
|
|
9
|
+
* (non-ocx, non-allowlisted) processes are never killed.
|
|
10
|
+
*/
|
|
11
|
+
import { execFileSync } from "node:child_process";
|
|
12
|
+
import { verifyPidIdentity } from "../config";
|
|
13
|
+
import { isProcessAlive, killProxy } from "../lib/process-control";
|
|
14
|
+
import { isPortAvailable, type WaitForPortOptions } from "./ports";
|
|
15
|
+
import { dropWindowsTcpRowsForLocalPort } from "./windows-tcp-drop";
|
|
16
|
+
|
|
17
|
+
export type ListenPidScan =
|
|
18
|
+
| { ok: true; pids: number[] }
|
|
19
|
+
| { ok: false; error?: string };
|
|
20
|
+
|
|
21
|
+
export type ReclaimListenPortOptions = WaitForPortOptions & {
|
|
22
|
+
/**
|
|
23
|
+
* When true AND `onlyKillPids` is a non-empty allowlist, those PIDs may be
|
|
24
|
+
* killed after revalidation. Default false — never kill without an allowlist.
|
|
25
|
+
* When {@link killAllOcxOnPort} is also true, any ocx listener on this port
|
|
26
|
+
* may be killed even if it is not in `onlyKillPids`.
|
|
27
|
+
*/
|
|
28
|
+
killOcxHolders?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Explicit PIDs the caller just stopped / hard-killed. An omitted or empty
|
|
31
|
+
* list means no process may be killed — unless {@link killAllOcxOnPort} is set.
|
|
32
|
+
*/
|
|
33
|
+
onlyKillPids?: number[];
|
|
34
|
+
/**
|
|
35
|
+
* When true with `killOcxHolders`, every live ocx listener on this port may be
|
|
36
|
+
* killed (re-checked each scan). Used by post-update restart so a Windows
|
|
37
|
+
* service wrapper that respawns a *new* bun PID mid-reclaim cannot stay
|
|
38
|
+
* protected just because it was absent from the pre-wait allowlist snapshot.
|
|
39
|
+
* Never kills foreign (non-ocx) processes — only allowlisted teardown PIDs
|
|
40
|
+
* and revalidated ocx listeners.
|
|
41
|
+
*/
|
|
42
|
+
killAllOcxOnPort?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* On Windows, force-delete IPv4 TCP rows for this local port via SetTcpEntry.
|
|
45
|
+
* Default true on win32. Never kills foreign processes, never runs while a
|
|
46
|
+
* live foreign / protected ocx listener owns the port, and never runs when
|
|
47
|
+
* the listener scan failed.
|
|
48
|
+
*/
|
|
49
|
+
dropTcpRows?: boolean;
|
|
50
|
+
/** How often to scan for listen PIDs / attempt TCB drop (ms). Default 500. */
|
|
51
|
+
scanIntervalMs?: number;
|
|
52
|
+
listListenPidsFn?: (port: number) => ListenPidScan | number[];
|
|
53
|
+
isAliveFn?: (pid: number) => boolean;
|
|
54
|
+
verifyOcxFn?: (pid: number) => number | null;
|
|
55
|
+
killFn?: (pid: number) => void;
|
|
56
|
+
dropTcpFn?: (port: number) => number | { dropped: number; skippedIpv6: number };
|
|
57
|
+
isAvailableFn?: (port: number, hostname?: string) => Promise<boolean>;
|
|
58
|
+
sleepMs?: (ms: number) => Promise<void>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Parse `netstat -ano` (Windows) / `netstat -anlp` listen lines for a port.
|
|
63
|
+
* Exported for unit tests.
|
|
64
|
+
*/
|
|
65
|
+
export function parseListenPidsFromNetstat(output: string, port: number): number[] {
|
|
66
|
+
const pids = new Set<number>();
|
|
67
|
+
const portSuffix = `:${port}`;
|
|
68
|
+
for (const rawLine of output.split(/\r?\n/)) {
|
|
69
|
+
const line = rawLine.trim();
|
|
70
|
+
if (!/^TCP\b/i.test(line) && !/^tcp\b/i.test(line)) continue;
|
|
71
|
+
const parts = line.split(/\s+/);
|
|
72
|
+
// Prefer the first address token that ends with :port (local), not a later foreign one.
|
|
73
|
+
const localIdx = parts.findIndex(part => part.endsWith(portSuffix) || part.endsWith(`]:${port}`));
|
|
74
|
+
if (localIdx < 0) continue;
|
|
75
|
+
const foreign = parts[localIdx + 1] ?? "";
|
|
76
|
+
// Locale-safe listen detection: English LISTEN*, or unbound foreign wildcard
|
|
77
|
+
// (German ABHÖREN still shows 0.0.0.0:0 / *:*).
|
|
78
|
+
const listenWord = /\bLISTEN/i.test(line);
|
|
79
|
+
const wildcardForeign = /^(0\.0\.0\.0|::|\*|\[::\]):0$/.test(foreign) || foreign === "*:*";
|
|
80
|
+
if (!listenWord && !wildcardForeign) continue;
|
|
81
|
+
const last = parts[parts.length - 1] ?? "";
|
|
82
|
+
const winPid = /^\d+$/.test(last) ? Number(last) : NaN;
|
|
83
|
+
const unixPid = /^(\d+)(?:\/\S*)?$/.exec(last);
|
|
84
|
+
const pid = Number.isSafeInteger(winPid) && winPid > 0
|
|
85
|
+
? winPid
|
|
86
|
+
: unixPid
|
|
87
|
+
? Number(unixPid[1])
|
|
88
|
+
: NaN;
|
|
89
|
+
if (Number.isSafeInteger(pid) && pid > 0) pids.add(pid);
|
|
90
|
+
}
|
|
91
|
+
return [...pids];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function normalizeListenPidScan(result: ListenPidScan | number[]): ListenPidScan {
|
|
95
|
+
if (Array.isArray(result)) return { ok: true, pids: result };
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Prefer English netstat states; fall back to the UI-locale table. */
|
|
100
|
+
function readWindowsNetstatAno(): string {
|
|
101
|
+
const netstat = `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\netstat.exe`;
|
|
102
|
+
const cmd = `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\cmd.exe`;
|
|
103
|
+
try {
|
|
104
|
+
// chcp 437 forces English LISTENING/ESTABLISHED labels on localized Windows.
|
|
105
|
+
return execFileSync(cmd, ["/d", "/c", `chcp 437>nul & "${netstat}" -ano -p tcp`], {
|
|
106
|
+
encoding: "utf-8",
|
|
107
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
108
|
+
timeout: 5000,
|
|
109
|
+
windowsHide: true,
|
|
110
|
+
});
|
|
111
|
+
} catch {
|
|
112
|
+
return execFileSync(netstat, ["-ano", "-p", "tcp"], {
|
|
113
|
+
encoding: "utf-8",
|
|
114
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
115
|
+
timeout: 4000,
|
|
116
|
+
windowsHide: true,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Scan for PIDs currently LISTENing on `port`.
|
|
123
|
+
* Distinguishes probe failure (`ok: false`) from a successful empty result.
|
|
124
|
+
*/
|
|
125
|
+
export function scanListenPids(port: number): ListenPidScan {
|
|
126
|
+
if (!Number.isFinite(port) || port <= 0 || port > 65535) {
|
|
127
|
+
return { ok: false, error: "invalid port" };
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
if (process.platform === "win32") {
|
|
131
|
+
return { ok: true, pids: parseListenPidsFromNetstat(readWindowsNetstatAno(), port) };
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const output = execFileSync("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t"], {
|
|
135
|
+
encoding: "utf-8",
|
|
136
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
137
|
+
timeout: 3000,
|
|
138
|
+
});
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
pids: output
|
|
142
|
+
.split(/\r?\n/)
|
|
143
|
+
.map(line => Number(line.trim()))
|
|
144
|
+
.filter(pid => Number.isSafeInteger(pid) && pid > 0),
|
|
145
|
+
};
|
|
146
|
+
} catch (lsofErr) {
|
|
147
|
+
try {
|
|
148
|
+
const output = execFileSync("netstat", ["-anlp"], {
|
|
149
|
+
encoding: "utf-8",
|
|
150
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
151
|
+
timeout: 3000,
|
|
152
|
+
});
|
|
153
|
+
return { ok: true, pids: parseListenPidsFromNetstat(output, Math.trunc(port)) };
|
|
154
|
+
} catch (netstatErr) {
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
error: `lsof/netstat unavailable: ${String(lsofErr)} / ${String(netstatErr)}`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} catch (error) {
|
|
162
|
+
return { ok: false, error: String(error) };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Best-effort PIDs currently LISTENing on `port`. Empty on probe failure. */
|
|
167
|
+
export function listListenPids(port: number): number[] {
|
|
168
|
+
const scan = scanListenPids(port);
|
|
169
|
+
return scan.ok ? scan.pids : [];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Wait until `port` can bind.
|
|
174
|
+
* Never kills a process unless `killOcxHolders === true` and either
|
|
175
|
+
* `onlyKillPids` is a non-empty allowlist or `killAllOcxOnPort` is set — then
|
|
176
|
+
* revalidates immediately before each kill.
|
|
177
|
+
* Never kills foreign processes. Never drops TCP rows while a live foreign or
|
|
178
|
+
* protected ocx listener owns the port, or when the listener scan failed.
|
|
179
|
+
*/
|
|
180
|
+
export async function reclaimListenPort(
|
|
181
|
+
port: number,
|
|
182
|
+
hostname = "127.0.0.1",
|
|
183
|
+
opts: ReclaimListenPortOptions = {},
|
|
184
|
+
): Promise<boolean> {
|
|
185
|
+
const timeoutMs = opts.timeoutMs ?? 30_000;
|
|
186
|
+
const intervalMs = opts.intervalMs ?? 100;
|
|
187
|
+
const scanIntervalMs = opts.scanIntervalMs ?? 500;
|
|
188
|
+
const allowedKillPids = new Set(
|
|
189
|
+
(opts.onlyKillPids ?? []).filter(pid => Number.isSafeInteger(pid) && pid > 0),
|
|
190
|
+
);
|
|
191
|
+
const killAllOcx = opts.killAllOcxOnPort === true;
|
|
192
|
+
const mayKill = opts.killOcxHolders === true
|
|
193
|
+
&& (allowedKillPids.size > 0 || killAllOcx);
|
|
194
|
+
const dropTcpRows = opts.dropTcpRows ?? process.platform === "win32";
|
|
195
|
+
const listFn = opts.listListenPidsFn ?? scanListenPids;
|
|
196
|
+
const isAliveFn = opts.isAliveFn ?? isProcessAlive;
|
|
197
|
+
const verifyOcxFn = opts.verifyOcxFn ?? verifyPidIdentity;
|
|
198
|
+
const killFn = opts.killFn ?? killProxy;
|
|
199
|
+
const dropTcpFn = opts.dropTcpFn ?? dropWindowsTcpRowsForLocalPort;
|
|
200
|
+
const isAvailableFn = opts.isAvailableFn ?? isPortAvailable;
|
|
201
|
+
const sleep = opts.sleepMs ?? ((ms: number) => new Promise<void>(resolve => setTimeout(resolve, ms)));
|
|
202
|
+
|
|
203
|
+
const deadline = Date.now() + timeoutMs;
|
|
204
|
+
let lastScan = 0;
|
|
205
|
+
const killed = new Set<number>();
|
|
206
|
+
|
|
207
|
+
for (;;) {
|
|
208
|
+
if (await isAvailableFn(port, hostname)) return true;
|
|
209
|
+
if (Date.now() >= deadline) return false;
|
|
210
|
+
|
|
211
|
+
if (Date.now() - lastScan >= scanIntervalMs) {
|
|
212
|
+
lastScan = Date.now();
|
|
213
|
+
|
|
214
|
+
const scan = normalizeListenPidScan(listFn(port));
|
|
215
|
+
if (!scan.ok) {
|
|
216
|
+
// Failed probe ≠ empty listeners: do not kill and do not reset TCP rows.
|
|
217
|
+
await sleep(intervalMs);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
let foreignLive = false;
|
|
222
|
+
let protectedOcxListener = false;
|
|
223
|
+
|
|
224
|
+
for (const pid of scan.pids) {
|
|
225
|
+
if (pid === process.pid) continue;
|
|
226
|
+
if (!isAliveFn(pid)) {
|
|
227
|
+
// Clear "already tried" so a later respawn that reuses this PID slot
|
|
228
|
+
// is not skipped (Windows service :loop / npm rename respawns).
|
|
229
|
+
killed.delete(pid);
|
|
230
|
+
continue; // Windows may still list a dead owner briefly
|
|
231
|
+
}
|
|
232
|
+
const isOcx = verifyOcxFn(pid) === pid;
|
|
233
|
+
const allowlisted = allowedKillPids.has(pid);
|
|
234
|
+
// Pre-update PIDs can fail verify while still LISTENing (dead owner still
|
|
235
|
+
// listed, or cmdline probe raced). Allowlisted teardown PIDs may be killed;
|
|
236
|
+
// unknown foreign claimants must remain fail-closed.
|
|
237
|
+
if (!isOcx) {
|
|
238
|
+
if (mayKill && allowlisted) {
|
|
239
|
+
if (!killed.has(pid)) {
|
|
240
|
+
try {
|
|
241
|
+
killFn(pid);
|
|
242
|
+
killed.add(pid);
|
|
243
|
+
} catch {
|
|
244
|
+
// Kill failed: never SetTcpEntry while the process may still own the port.
|
|
245
|
+
protectedOcxListener = true;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (!isAliveFn(pid)) killed.delete(pid);
|
|
249
|
+
else protectedOcxListener = true;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
foreignLive = true;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const mayKillThis = allowlisted || killAllOcx;
|
|
256
|
+
if (!mayKill || !mayKillThis) {
|
|
257
|
+
// Healthy / intentional ocx proxy — never steal its port.
|
|
258
|
+
protectedOcxListener = true;
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (!killed.has(pid)) {
|
|
262
|
+
// Revalidate immediately before termination.
|
|
263
|
+
if (isAliveFn(pid) && verifyOcxFn(pid) === pid && mayKillThis) {
|
|
264
|
+
try {
|
|
265
|
+
killFn(pid);
|
|
266
|
+
killed.add(pid);
|
|
267
|
+
} catch {
|
|
268
|
+
// Kill failed: keep waiting and never reset this listener's TCP rows.
|
|
269
|
+
protectedOcxListener = true;
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
// Revalidation failed while the allowlisted listener is still listed live.
|
|
273
|
+
protectedOcxListener = true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// Respawning supervisors (Windows service :loop) mint a new PID after each
|
|
277
|
+
// kill — clear the per-PID "already tried" bit once the process is gone so a
|
|
278
|
+
// later child with a reused slot is not skipped, and keep reclaiming while live.
|
|
279
|
+
if (!isAliveFn(pid)) {
|
|
280
|
+
killed.delete(pid);
|
|
281
|
+
} else {
|
|
282
|
+
protectedOcxListener = true;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (foreignLive || protectedOcxListener) {
|
|
287
|
+
// Foreign app or an unprotected live ocx listener owns the port: never
|
|
288
|
+
// SetTcpEntry-reset their sockets, and fail reclaim once the deadline hits.
|
|
289
|
+
await sleep(intervalMs);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// After hard-kill, browsers often keep ESTABLISHED/CLOSE_WAIT to the dead listener.
|
|
294
|
+
// Reset those IPv4 TCBs (and ghost LISTEN rows) so the configured port can bind again —
|
|
295
|
+
// without killing the browser process. Only safe when no live foreign/protected listener remains.
|
|
296
|
+
if (dropTcpRows) {
|
|
297
|
+
try {
|
|
298
|
+
dropTcpFn(port);
|
|
299
|
+
} catch {
|
|
300
|
+
/* access denied / unsupported — keep waiting */
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
await sleep(intervalMs);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { createServer } from "node:net";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* True when an error means "this port/address is already bound" — the only bind failure
|
|
5
|
+
* that is safe to answer with a retry on another port. Bun/Node surface it as
|
|
6
|
+
* `code: "EADDRINUSE"` or an EADDRINUSE / "address in use" message depending on the API.
|
|
7
|
+
*/
|
|
8
|
+
export function isAddrInUse(err: unknown): boolean {
|
|
9
|
+
if (!err || typeof err !== "object") return false;
|
|
10
|
+
const { code, message } = err as { code?: unknown; message?: unknown };
|
|
11
|
+
if (code === "EADDRINUSE") return true;
|
|
12
|
+
const text = typeof message === "string" ? message.toLowerCase() : "";
|
|
13
|
+
return text.includes("eaddrinuse") || text.includes("in use");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function isPortAvailable(port: number, hostname = "127.0.0.1"): Promise<boolean> {
|
|
17
|
+
return await new Promise(resolve => {
|
|
18
|
+
const server = createServer();
|
|
19
|
+
// Fail closed: EACCES / EADDRNOTAVAIL / EPERM / unknown listen errors mean the
|
|
20
|
+
// requested bind is not available. Only the listening event reports free.
|
|
21
|
+
server.once("error", () => resolve(false));
|
|
22
|
+
server.once("listening", () => {
|
|
23
|
+
server.close(() => resolve(true));
|
|
24
|
+
});
|
|
25
|
+
server.listen({ port, host: hostname });
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type WaitForPortOptions = {
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
intervalMs?: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** Poll until `port` accepts a bind, or until the timeout elapses. */
|
|
35
|
+
export async function waitForPortAvailable(
|
|
36
|
+
port: number,
|
|
37
|
+
hostname = "127.0.0.1",
|
|
38
|
+
opts: WaitForPortOptions = {},
|
|
39
|
+
): Promise<boolean> {
|
|
40
|
+
const timeoutMs = opts.timeoutMs ?? 5000;
|
|
41
|
+
const intervalMs = opts.intervalMs ?? 50;
|
|
42
|
+
const deadline = Date.now() + timeoutMs;
|
|
43
|
+
for (;;) {
|
|
44
|
+
if (await isPortAvailable(port, hostname)) return true;
|
|
45
|
+
if (Date.now() >= deadline) return false;
|
|
46
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type FindAvailablePortOptions = {
|
|
51
|
+
/** How long to keep retrying the preferred port before falling back to an ephemeral port. */
|
|
52
|
+
preferRetryMs?: number;
|
|
53
|
+
preferRetryIntervalMs?: number;
|
|
54
|
+
/**
|
|
55
|
+
* When false, never bind `port: 0` — prefer-retry then throw if the preferred port
|
|
56
|
+
* stays busy. Used for explicit `ocx start --port N` and service-baked pins so an
|
|
57
|
+
* update restart cannot hop to a random ephemeral listener (PR #152 gap).
|
|
58
|
+
*/
|
|
59
|
+
allowEphemeralFallback?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* A port this selection must never return, even when it is free (#1102).
|
|
62
|
+
*
|
|
63
|
+
* The unauthenticated loopback listener binds a fixed port from config. If the public
|
|
64
|
+
* listener took that port first — via an explicit `--port`, a `config.port` of 0, or the
|
|
65
|
+
* ephemeral fallback happening to land on it — the loopback bind would then fail with
|
|
66
|
+
* EADDRINUSE, and the startup transaction would roll back a public listener that had
|
|
67
|
+
* nothing wrong with it. Excluding the port here fails the right thing at the right time.
|
|
68
|
+
*/
|
|
69
|
+
reservedPort?: number;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export class PortUnavailableError extends Error {
|
|
73
|
+
readonly port: number;
|
|
74
|
+
constructor(port: number, hostname: string) {
|
|
75
|
+
super(`Port ${port} on ${hostname} is still busy after prefer-retry; refusing ephemeral fallback.`);
|
|
76
|
+
this.name = "PortUnavailableError";
|
|
77
|
+
this.port = port;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function findAvailablePort(
|
|
82
|
+
preferredPort: number,
|
|
83
|
+
hostname = "127.0.0.1",
|
|
84
|
+
opts: FindAvailablePortOptions = {},
|
|
85
|
+
): Promise<number> {
|
|
86
|
+
const preferRetryMs = opts.preferRetryMs ?? 0;
|
|
87
|
+
const allowEphemeral = opts.allowEphemeralFallback !== false;
|
|
88
|
+
const reserved = opts.reservedPort;
|
|
89
|
+
// An explicit preference for the reserved port is a configuration mistake, not a busy
|
|
90
|
+
// socket: retrying or hopping would hide it. Refuse before probing anything.
|
|
91
|
+
if (reserved !== undefined && preferredPort === reserved) {
|
|
92
|
+
throw new PortUnavailableError(preferredPort, hostname);
|
|
93
|
+
}
|
|
94
|
+
// Port 0 asks the OS to select an ephemeral port. Resolve it to that concrete
|
|
95
|
+
// port here so callers never persist or advertise an unusable `:0` endpoint.
|
|
96
|
+
if (preferredPort > 0 && preferRetryMs > 0) {
|
|
97
|
+
if (await waitForPortAvailable(preferredPort, hostname, {
|
|
98
|
+
timeoutMs: preferRetryMs,
|
|
99
|
+
intervalMs: opts.preferRetryIntervalMs ?? 50,
|
|
100
|
+
})) {
|
|
101
|
+
return preferredPort;
|
|
102
|
+
}
|
|
103
|
+
} else if (preferredPort > 0 && (await isPortAvailable(preferredPort, hostname))) {
|
|
104
|
+
return preferredPort;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!allowEphemeral) {
|
|
108
|
+
throw new PortUnavailableError(preferredPort, hostname);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Bounded, not recursive. The OS can hand back the reserved port, and a redraw practically
|
|
112
|
+
// always differs — but "practically always" is not a termination argument, and an unbounded
|
|
113
|
+
// async recursion has no way to stop if the assumption is ever wrong.
|
|
114
|
+
for (let attempt = 0; attempt < EPHEMERAL_REDRAW_LIMIT; attempt += 1) {
|
|
115
|
+
const port = await allocateEphemeralPort(hostname);
|
|
116
|
+
if (port !== reserved) return port;
|
|
117
|
+
}
|
|
118
|
+
throw new Error("failed to allocate an available port");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** How many times an ephemeral draw may come back reserved before we give up. */
|
|
122
|
+
const EPHEMERAL_REDRAW_LIMIT = 8;
|
|
123
|
+
|
|
124
|
+
/** Test seam: replace the OS ephemeral allocator so the redraw path is reachable. */
|
|
125
|
+
let ephemeralAllocator: ((hostname: string) => Promise<number>) | null = null;
|
|
126
|
+
|
|
127
|
+
export function setEphemeralPortAllocatorForTests(
|
|
128
|
+
allocator: ((hostname: string) => Promise<number>) | null,
|
|
129
|
+
): void {
|
|
130
|
+
ephemeralAllocator = allocator;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async function allocateEphemeralPort(hostname: string): Promise<number> {
|
|
134
|
+
if (ephemeralAllocator) return ephemeralAllocator(hostname);
|
|
135
|
+
return await new Promise<number>((resolve, reject) => {
|
|
136
|
+
const server = createServer();
|
|
137
|
+
server.once("error", reject);
|
|
138
|
+
server.once("listening", () => {
|
|
139
|
+
const address = server.address();
|
|
140
|
+
const port = typeof address === "object" && address ? address.port : 0;
|
|
141
|
+
server.close(() => {
|
|
142
|
+
if (port > 0) resolve(port);
|
|
143
|
+
else reject(new Error("failed to allocate an available port"));
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
server.listen({ port: 0, host: hostname });
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function shouldPersistSelectedPort(
|
|
151
|
+
configPort: number | undefined,
|
|
152
|
+
selectedPort: number,
|
|
153
|
+
preferredPort: number,
|
|
154
|
+
): boolean {
|
|
155
|
+
return selectedPort === preferredPort && configPort !== selectedPort;
|
|
156
|
+
}
|