@iislee/opencodex 2.11.0 → 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/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -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 +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -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 +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- 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 +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- 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 +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- 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 +618 -74
- package/src/adapters/identity.ts +39 -6
- 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 +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- 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 +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- 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 +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- 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 +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -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 +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- 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 +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/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- 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 +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -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 +80 -0
- package/src/codex/journal.ts +66 -4
- 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 +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 +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 +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 +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- 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 +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -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 +152 -29
- package/src/images/plan.ts +23 -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.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/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- 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 +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- 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/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- 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/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 +202 -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 +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -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/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- 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/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -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 +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -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 +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -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 +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- 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 +220 -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 +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- 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 +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- 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 +865 -181
- package/src/server/lifecycle.ts +284 -13
- 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 +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -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 +101 -32
- package/src/server/management/model-routes.ts +189 -131
- 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 +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- 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 +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 +288 -32
- 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 +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- 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 +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -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 +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -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 +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 +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -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 +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- 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 +845 -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 +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- 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 +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- 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 +9 -3
- 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 +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- 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,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared termination of surviving Windows scheduler launcher/wrapper processes.
|
|
3
|
+
*
|
|
4
|
+
* `schtasks /end` ends the task instance but often leaves wscript/cmd running the
|
|
5
|
+
* `:loop` batch, which brings the proxy back during a stop, a restart, or
|
|
6
|
+
* post-update reclaim. Both the service teardown path and the update job need
|
|
7
|
+
* that guarantee, and they used to carry a copy each.
|
|
8
|
+
*
|
|
9
|
+
* The copies drifted in both directions, which is why this module exists rather
|
|
10
|
+
* than a second careful implementation: the updater received the #1589 argv
|
|
11
|
+
* cleanup that service.ts missed, and service.ts received the canonical-path
|
|
12
|
+
* scoping the updater missed. One of those gaps could force-terminate a wrapper
|
|
13
|
+
* belonging to a DIFFERENT OpenCodex home.
|
|
14
|
+
*
|
|
15
|
+
* Matching is scoped to the CANONICAL paths of one installation, never a bare
|
|
16
|
+
* filename, and the path must appear as a COMPLETE command-line token
|
|
17
|
+
* (wscript.exe spawns the .vbs as an argument; cmd.exe /c runs the .cmd). A
|
|
18
|
+
* substring match is excluded: an unrelated process whose command line merely
|
|
19
|
+
* contains the filename, and a wrapper under another home whose path ends with
|
|
20
|
+
* the same name, must both survive.
|
|
21
|
+
*/
|
|
22
|
+
import { spawnSync } from "node:child_process";
|
|
23
|
+
|
|
24
|
+
import { resolveTrustedWindowsPowerShellExe } from "./windows-elevation";
|
|
25
|
+
|
|
26
|
+
/** Quote for PowerShell: single-quote the value and double any embedded quote. */
|
|
27
|
+
function quoteForPowerShell(value: string): string {
|
|
28
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The PowerShell that finds and stops the wrappers for exactly these paths.
|
|
33
|
+
* Exported for tests: the matching rule is the whole point of this module, and
|
|
34
|
+
* the spawn itself is best-effort and unobservable.
|
|
35
|
+
*/
|
|
36
|
+
export function windowsWrapperKillScript(paths: readonly string[]): string {
|
|
37
|
+
return [
|
|
38
|
+
`$pats = @(${paths.map(quoteForPowerShell).join(", ")});`,
|
|
39
|
+
"Get-CimInstance Win32_Process | Where-Object {",
|
|
40
|
+
" if ($_.ProcessId -eq $PID) { return $false };",
|
|
41
|
+
" $c = $_.CommandLine; if (-not $c) { return $false };",
|
|
42
|
+
" foreach ($p in $pats) {",
|
|
43
|
+
" $i = $c.IndexOf($p, [System.StringComparison]::OrdinalIgnoreCase);",
|
|
44
|
+
" if ($i -lt 0) { continue };",
|
|
45
|
+
" $before = if ($i -gt 0) { $c.Substring($i - 1, 1) } else { ' ' };",
|
|
46
|
+
" $end = $i + $p.Length;",
|
|
47
|
+
" $after = if ($end -lt $c.Length) { $c.Substring($end, 1) } else { ' ' };",
|
|
48
|
+
" if ($before -match '[\\s\"'']' -and $after -match '[\\s\"'']') { return $true };",
|
|
49
|
+
" };",
|
|
50
|
+
" $false",
|
|
51
|
+
"} | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }",
|
|
52
|
+
].join(" ");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Best-effort: never throws, never reports. A wrapper that survives is handled
|
|
57
|
+
* by the caller's own stop verification.
|
|
58
|
+
*/
|
|
59
|
+
export function killWindowsSchedulerWrappers(paths: {
|
|
60
|
+
scriptPath: string;
|
|
61
|
+
launcherPath: string;
|
|
62
|
+
}): void {
|
|
63
|
+
if (process.platform !== "win32") return;
|
|
64
|
+
try {
|
|
65
|
+
spawnSync(resolveTrustedWindowsPowerShellExe(), [
|
|
66
|
+
// No `-WindowStyle Hidden` here: Bun 1.3.14 can fail that direct CLI pair
|
|
67
|
+
// before the command runs (#1589). `windowsHide` below is sufficient.
|
|
68
|
+
"-NoProfile", "-NoLogo", "-NonInteractive",
|
|
69
|
+
"-Command", windowsWrapperKillScript([paths.scriptPath, paths.launcherPath]),
|
|
70
|
+
], { stdio: "ignore", timeout: 5000, windowsHide: true });
|
|
71
|
+
} catch { /* best-effort */ }
|
|
72
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decode bounded text emitted by Windows system tools.
|
|
3
|
+
*
|
|
4
|
+
* [Decision Log]
|
|
5
|
+
* - Purpose: preserve non-ASCII paths when a Windows tool writes the active
|
|
6
|
+
* legacy code page instead of UTF-8.
|
|
7
|
+
* - Existing constraint: generated service assets may be UTF-16, while
|
|
8
|
+
* redirected `schtasks` output follows the Windows locale on affected hosts.
|
|
9
|
+
* - Alternatives considered: replacement-character heuristics and a new
|
|
10
|
+
* iconv dependency. The former can reinterpret valid text; the latter widens
|
|
11
|
+
* the install/security surface for two small, already-supported codecs.
|
|
12
|
+
* - Choice: recognize UTF-16 first, accept only strict UTF-8 next, then use the
|
|
13
|
+
* locale-appropriate WHATWG decoder (CP949 through `euc-kr`, or Windows-1252
|
|
14
|
+
* only for locales that actually use that family). Unknown/unsupported
|
|
15
|
+
* locales fail back to the old replacement-preserving UTF-8 result instead
|
|
16
|
+
* of guessing another code page or throwing in diagnostics.
|
|
17
|
+
* - Impact: decoding stays dependency-free and bounded, but this deliberately
|
|
18
|
+
* does not guess arbitrary OEM code pages that the runtime cannot identify.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
function trimWindowsText(value: string): string {
|
|
22
|
+
return value.replace(/^\uFEFF/, "").trim();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function currentWindowsLocale(): string {
|
|
26
|
+
try {
|
|
27
|
+
return Intl.DateTimeFormat().resolvedOptions().locale;
|
|
28
|
+
} catch {
|
|
29
|
+
return "en-US";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function decodeStrict(buffer: Uint8Array, encoding: string): string | null {
|
|
34
|
+
try {
|
|
35
|
+
return trimWindowsText(new TextDecoder(encoding, { fatal: true }).decode(buffer));
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function decodeUtf16Be(buffer: Uint8Array): string {
|
|
42
|
+
const payloadLength = buffer.length - 2;
|
|
43
|
+
const swapped = Buffer.alloc(payloadLength - (payloadLength % 2));
|
|
44
|
+
for (let i = 2; i + 1 < buffer.length; i += 2) {
|
|
45
|
+
swapped[i - 2] = buffer[i + 1]!;
|
|
46
|
+
swapped[i - 1] = buffer[i]!;
|
|
47
|
+
}
|
|
48
|
+
return trimWindowsText(swapped.toString("utf16le"));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* CP949 is exposed by the Encoding Standard under the `euc-kr` label. Keep the
|
|
53
|
+
* Western fallback deliberately narrow: treating CP932, CP1250, or CP1251
|
|
54
|
+
* bytes as Windows-1252 can fabricate a different valid-looking filesystem
|
|
55
|
+
* path, which is worse than the previous replacement-character refusal.
|
|
56
|
+
*/
|
|
57
|
+
function legacyEncodingForLocale(locale: string): "euc-kr" | "windows-1252" | null {
|
|
58
|
+
const language = locale.trim().split(/[-_]/, 1)[0]?.toLowerCase();
|
|
59
|
+
if (language === "ko") return "euc-kr";
|
|
60
|
+
if (language && WINDOWS_1252_LANGUAGES.has(language)) return "windows-1252";
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const WINDOWS_1252_LANGUAGES = new Set([
|
|
65
|
+
"af", "br", "ca", "co", "cy", "da", "de", "en", "es", "eu", "fi", "fo", "fr",
|
|
66
|
+
"ga", "gd", "gl", "id", "is", "it", "lb", "ms", "nl", "no", "oc", "pt", "sq",
|
|
67
|
+
"sv", "sw",
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
export interface WindowsTextDecodeOptions {
|
|
71
|
+
/** Test seam and explicit locale override; production uses the active Intl locale. */
|
|
72
|
+
readonly locale?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function decodeWindowsTextBytes(
|
|
76
|
+
buffer: Uint8Array,
|
|
77
|
+
options: WindowsTextDecodeOptions = {},
|
|
78
|
+
): string {
|
|
79
|
+
if (buffer.length === 0) return "";
|
|
80
|
+
|
|
81
|
+
const bomUtf16Le = buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xfe;
|
|
82
|
+
const bomUtf16Be = buffer.length >= 2 && buffer[0] === 0xfe && buffer[1] === 0xff;
|
|
83
|
+
const looksUtf16Le = buffer.length >= 4
|
|
84
|
+
&& buffer[1] === 0x00
|
|
85
|
+
&& buffer[3] === 0x00
|
|
86
|
+
&& buffer[0] !== 0x00;
|
|
87
|
+
|
|
88
|
+
if (bomUtf16Le || looksUtf16Le) {
|
|
89
|
+
return trimWindowsText(Buffer.from(buffer).toString("utf16le"));
|
|
90
|
+
}
|
|
91
|
+
if (bomUtf16Be) return decodeUtf16Be(buffer);
|
|
92
|
+
|
|
93
|
+
const utf8 = decodeStrict(buffer, "utf-8");
|
|
94
|
+
if (utf8 !== null) return utf8;
|
|
95
|
+
|
|
96
|
+
const locale = options.locale ?? currentWindowsLocale();
|
|
97
|
+
const legacyEncoding = legacyEncodingForLocale(locale);
|
|
98
|
+
if (legacyEncoding !== null) {
|
|
99
|
+
const legacy = decodeStrict(buffer, legacyEncoding);
|
|
100
|
+
if (legacy !== null) return legacy;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Preserve the previous fail-soft behavior when the runtime lacks a codec or
|
|
104
|
+
// the bytes are malformed even for the selected Windows code page.
|
|
105
|
+
return trimWindowsText(new TextDecoder("utf-8").decode(buffer));
|
|
106
|
+
}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the effective Windows token to the locale-independent SID form that
|
|
3
|
+
* icacls accepts ("*S-1-..."). Environment values such as USERDOMAIN are not
|
|
4
|
+
* an authority for the current token: on workgroup machines USERDOMAIN may be
|
|
5
|
+
* the literal WORKGROUP even though the account belongs to the local computer.
|
|
6
|
+
*
|
|
7
|
+
* There is deliberately NO name-shaped fallback. A `DOMAIN\User` string has a
|
|
8
|
+
* valid shape, but shape is not evidence that the account is the current
|
|
9
|
+
* token's subject, and both environment variables are writable by whatever
|
|
10
|
+
* launched us. A wrong principal here is not cosmetic: `runIcacls` grants it
|
|
11
|
+
* Full Control and then removes inheritance, so a wrong grant either leaves a
|
|
12
|
+
* different account holding the secret or strands the file with no usable ACE.
|
|
13
|
+
* When the SID cannot be resolved, the caller declines to touch the ACL at all.
|
|
14
|
+
*
|
|
15
|
+
* Budget caveat: callers pass their REMAINING harden budget, which becomes the
|
|
16
|
+
* child process timeout. Trusted-executable resolution (a `GetSystemDirectoryW`
|
|
17
|
+
* FFI call) and spawn setup happen before that timeout starts, and the async
|
|
18
|
+
* timer only arms once `Bun.spawn` returns. Both are small in practice, but the
|
|
19
|
+
* lookup is not bounded by the deadline to the microsecond. Tightening that
|
|
20
|
+
* would mean passing an absolute deadline through the runner interface.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { existsSync } from "node:fs";
|
|
24
|
+
import { win32 as windowsPath } from "node:path";
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
resolveTrustedWindowsPowerShellExe,
|
|
28
|
+
WindowsSystemDirectoryFfiUnavailableError,
|
|
29
|
+
} from "./windows-elevation";
|
|
30
|
+
|
|
31
|
+
const SID_PATTERN = /^S-1-(?:\d+-)+\d+$/i;
|
|
32
|
+
const SID_EXPRESSION =
|
|
33
|
+
"[System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value";
|
|
34
|
+
const DEFAULT_WINDOWS_ARM64_POWERSHELL = windowsPath.join(
|
|
35
|
+
"C:\\Windows\\System32",
|
|
36
|
+
"WindowsPowerShell",
|
|
37
|
+
"v1.0",
|
|
38
|
+
"powershell.exe",
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
type PrincipalExecutableResolution = Readonly<{
|
|
42
|
+
platform: NodeJS.Platform;
|
|
43
|
+
arch: string;
|
|
44
|
+
resolveTrusted: () => string;
|
|
45
|
+
pathExists: (path: string) => boolean;
|
|
46
|
+
}>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Bun's Windows ARM64 build cannot currently execute the `bun:ffi` call used
|
|
50
|
+
* by the general System32 resolver. The ACL identity lookup has a narrower
|
|
51
|
+
* authority than the elevation helpers: it starts one non-elevated PowerShell
|
|
52
|
+
* command and accepts only a SID-shaped result. Keep its fallback equally
|
|
53
|
+
* narrow by using the fixed, OS-protected default installation path only.
|
|
54
|
+
*
|
|
55
|
+
* Environment and PATH lookup are deliberately absent. A Windows installation
|
|
56
|
+
* outside C:\\Windows keeps failing closed rather than executing a binary chosen
|
|
57
|
+
* by caller-controlled `SystemRoot`, `WINDIR`, or `PATH` values.
|
|
58
|
+
*/
|
|
59
|
+
function resolveWindowsPrincipalPowerShellExecutable(
|
|
60
|
+
resolution: PrincipalExecutableResolution = {
|
|
61
|
+
platform: process.platform,
|
|
62
|
+
arch: process.arch,
|
|
63
|
+
resolveTrusted: resolveTrustedWindowsPowerShellExe,
|
|
64
|
+
pathExists: existsSync,
|
|
65
|
+
},
|
|
66
|
+
): string {
|
|
67
|
+
try {
|
|
68
|
+
return resolution.resolveTrusted();
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (
|
|
71
|
+
!(error instanceof WindowsSystemDirectoryFfiUnavailableError) ||
|
|
72
|
+
resolution.platform !== "win32" ||
|
|
73
|
+
resolution.arch !== "arm64" ||
|
|
74
|
+
!resolution.pathExists(DEFAULT_WINDOWS_ARM64_POWERSHELL)
|
|
75
|
+
) {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
return DEFAULT_WINDOWS_ARM64_POWERSHELL;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Test-only dependency-injected view of the Windows ARM64 executable boundary. */
|
|
83
|
+
export function resolveWindowsPrincipalPowerShellExecutableForTests(
|
|
84
|
+
resolution: PrincipalExecutableResolution,
|
|
85
|
+
): string {
|
|
86
|
+
return resolveWindowsPrincipalPowerShellExecutable(resolution);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface WindowsPrincipalLookupResult {
|
|
90
|
+
success: boolean;
|
|
91
|
+
exitCode: number | null;
|
|
92
|
+
timedOut: boolean;
|
|
93
|
+
stdout: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type WindowsPrincipalRunner = (
|
|
97
|
+
timeoutMs: number,
|
|
98
|
+
) => WindowsPrincipalLookupResult;
|
|
99
|
+
|
|
100
|
+
export type AsyncWindowsPrincipalRunner = (
|
|
101
|
+
timeoutMs: number,
|
|
102
|
+
) => Promise<WindowsPrincipalLookupResult>;
|
|
103
|
+
|
|
104
|
+
const POWERSHELL_ARGS = [
|
|
105
|
+
"-NoLogo",
|
|
106
|
+
"-NoProfile",
|
|
107
|
+
"-NonInteractive",
|
|
108
|
+
"-Command",
|
|
109
|
+
SID_EXPRESSION,
|
|
110
|
+
] as const;
|
|
111
|
+
|
|
112
|
+
function windowsPrincipalPowerShellCommand(): string[] {
|
|
113
|
+
return [resolveWindowsPrincipalPowerShellExecutable(), ...POWERSHELL_ARGS];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Test-only readback of the exact trusted executable and static arguments. */
|
|
117
|
+
export function windowsPrincipalPowerShellCommandForTests(): string[] {
|
|
118
|
+
return windowsPrincipalPowerShellCommand();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function defaultWindowsPrincipalRunner(timeoutMs: number): WindowsPrincipalLookupResult {
|
|
122
|
+
const result = Bun.spawnSync(windowsPrincipalPowerShellCommand(), {
|
|
123
|
+
stdin: "ignore",
|
|
124
|
+
stdout: "pipe",
|
|
125
|
+
stderr: "ignore",
|
|
126
|
+
timeout: Math.max(1, timeoutMs),
|
|
127
|
+
windowsHide: true,
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
success: result.success,
|
|
131
|
+
exitCode: result.exitCode,
|
|
132
|
+
timedOut: result.exitedDueToTimeout ?? false,
|
|
133
|
+
stdout: result.stdout ? result.stdout.toString() : "",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function defaultAsyncWindowsPrincipalRunner(
|
|
138
|
+
timeoutMs: number,
|
|
139
|
+
): Promise<WindowsPrincipalLookupResult> {
|
|
140
|
+
const proc = Bun.spawn(windowsPrincipalPowerShellCommand(), {
|
|
141
|
+
stdin: "ignore",
|
|
142
|
+
stdout: "pipe",
|
|
143
|
+
stderr: "ignore",
|
|
144
|
+
windowsHide: true,
|
|
145
|
+
});
|
|
146
|
+
let timedOut = false;
|
|
147
|
+
const timer = setTimeout(() => {
|
|
148
|
+
timedOut = true;
|
|
149
|
+
try { proc.kill(); } catch { /* already exited */ }
|
|
150
|
+
}, Math.max(1, timeoutMs));
|
|
151
|
+
let exitCode: number | null = null;
|
|
152
|
+
try {
|
|
153
|
+
exitCode = await proc.exited;
|
|
154
|
+
} finally {
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
}
|
|
157
|
+
const stdout = proc.stdout
|
|
158
|
+
? await new Response(proc.stdout).text().catch(() => "")
|
|
159
|
+
: "";
|
|
160
|
+
return {
|
|
161
|
+
success: !timedOut && exitCode === 0,
|
|
162
|
+
exitCode: timedOut ? null : exitCode,
|
|
163
|
+
timedOut,
|
|
164
|
+
stdout,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let principalRunner: WindowsPrincipalRunner = defaultWindowsPrincipalRunner;
|
|
169
|
+
let asyncPrincipalRunner: AsyncWindowsPrincipalRunner = defaultAsyncWindowsPrincipalRunner;
|
|
170
|
+
let cachedPrincipal: string | null = null;
|
|
171
|
+
let asyncLookupInFlight: Promise<string> | null = null;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* POSIX CI drives the Windows ACL branch through `setPlatformForTests("win32")`,
|
|
175
|
+
* on hosts that have neither System32 nor PowerShell. Those runs need SOME
|
|
176
|
+
* principal, so this seam supplies a synthetic one.
|
|
177
|
+
*
|
|
178
|
+
* It lives here rather than in `windows-secret-acl.ts` for one reason that is
|
|
179
|
+
* not cosmetic: an explicitly injected runner must be able to beat it. When the
|
|
180
|
+
* synthetic value was chosen first, in the ACL module, a test could not inject a
|
|
181
|
+
* lookup FAILURE on POSIX at all — so the fail-closed and memo-isolation cases
|
|
182
|
+
* were guarded with `if (process.platform !== "win32") return;` and never ran
|
|
183
|
+
* outside Windows. Resolution order below is what makes those cases executable
|
|
184
|
+
* on every runner.
|
|
185
|
+
*/
|
|
186
|
+
let syntheticPrincipalForTests: string | null = null;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Test seam: supply the principal used when no runner was injected and the host
|
|
190
|
+
* is not really Windows. Pass null to disable.
|
|
191
|
+
*/
|
|
192
|
+
export function setSyntheticWindowsPrincipalForTests(principal: string | null): void {
|
|
193
|
+
syntheticPrincipalForTests = principal;
|
|
194
|
+
cachedPrincipal = null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** True when an explicit runner override is installed and must take precedence. */
|
|
198
|
+
function hasSyncRunnerOverride(): boolean {
|
|
199
|
+
return principalRunner !== defaultWindowsPrincipalRunner;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function hasAsyncRunnerOverride(): boolean {
|
|
203
|
+
return asyncPrincipalRunner !== defaultAsyncWindowsPrincipalRunner;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function identityError(reason: string): NodeJS.ErrnoException {
|
|
207
|
+
const error = new Error(`Windows effective-account SID lookup ${reason}`) as NodeJS.ErrnoException;
|
|
208
|
+
// Keep identity lookup failures distinct from icacls timeouts. In particular,
|
|
209
|
+
// they must not populate windows-secret-acl's destination timeout memo.
|
|
210
|
+
error.code = "EACLIDENTITY";
|
|
211
|
+
return error;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function principalFromResult(result: WindowsPrincipalLookupResult): string {
|
|
215
|
+
if (!result.success) {
|
|
216
|
+
throw identityError(result.timedOut
|
|
217
|
+
? "timed out"
|
|
218
|
+
: `exited ${result.exitCode ?? "null"}`);
|
|
219
|
+
}
|
|
220
|
+
const sid = result.stdout.trim();
|
|
221
|
+
if (!SID_PATTERN.test(sid)) {
|
|
222
|
+
throw identityError(sid ? "returned an invalid SID" : "returned an empty SID");
|
|
223
|
+
}
|
|
224
|
+
return `*${sid.toUpperCase()}`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Resolve and process-cache the effective token SID for synchronous ACL paths. */
|
|
228
|
+
export function resolveCurrentWindowsPrincipal(timeoutMs: number): string {
|
|
229
|
+
// Order matters: an explicitly injected runner outranks the synthetic value,
|
|
230
|
+
// so a test can inject a FAILURE on a POSIX host. See the seam comment above.
|
|
231
|
+
if (hasSyncRunnerOverride()) {
|
|
232
|
+
if (cachedPrincipal) return cachedPrincipal;
|
|
233
|
+
if (timeoutMs <= 0) throw identityError("had no remaining deadline");
|
|
234
|
+
let overridden: WindowsPrincipalLookupResult;
|
|
235
|
+
try {
|
|
236
|
+
overridden = principalRunner(timeoutMs);
|
|
237
|
+
} catch {
|
|
238
|
+
throw identityError("could not start");
|
|
239
|
+
}
|
|
240
|
+
const principal = principalFromResult(overridden);
|
|
241
|
+
cachedPrincipal = principal;
|
|
242
|
+
return principal;
|
|
243
|
+
}
|
|
244
|
+
if (cachedPrincipal) return cachedPrincipal;
|
|
245
|
+
if (syntheticPrincipalForTests) return syntheticPrincipalForTests;
|
|
246
|
+
if (timeoutMs <= 0) throw identityError("had no remaining deadline");
|
|
247
|
+
let result: WindowsPrincipalLookupResult;
|
|
248
|
+
try {
|
|
249
|
+
result = principalRunner(timeoutMs);
|
|
250
|
+
} catch {
|
|
251
|
+
throw identityError("could not start");
|
|
252
|
+
}
|
|
253
|
+
const principal = principalFromResult(result);
|
|
254
|
+
cachedPrincipal = principal;
|
|
255
|
+
return principal;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function waitForExistingLookup(
|
|
259
|
+
lookup: Promise<string>,
|
|
260
|
+
timeoutMs: number,
|
|
261
|
+
): Promise<string> {
|
|
262
|
+
if (timeoutMs <= 0) throw identityError("had no remaining deadline");
|
|
263
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
264
|
+
try {
|
|
265
|
+
return await Promise.race([
|
|
266
|
+
lookup,
|
|
267
|
+
new Promise<never>((_, reject) => {
|
|
268
|
+
timer = setTimeout(
|
|
269
|
+
() => reject(identityError("timed out while awaiting the shared lookup")),
|
|
270
|
+
Math.max(1, timeoutMs),
|
|
271
|
+
);
|
|
272
|
+
}),
|
|
273
|
+
]);
|
|
274
|
+
} finally {
|
|
275
|
+
if (timer) clearTimeout(timer);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Async counterpart. Concurrent callers share one owned child lookup; a later
|
|
281
|
+
* caller may exhaust its own budget without cancelling the lookup owned by the
|
|
282
|
+
* first caller. The first caller owns that child and its process timeout; a
|
|
283
|
+
* later, longer budget deliberately does not extend an already-running child.
|
|
284
|
+
*/
|
|
285
|
+
export async function resolveCurrentWindowsPrincipalAsync(timeoutMs: number): Promise<string> {
|
|
286
|
+
const overridden = hasAsyncRunnerOverride();
|
|
287
|
+
if (cachedPrincipal) return cachedPrincipal;
|
|
288
|
+
if (asyncLookupInFlight) return waitForExistingLookup(asyncLookupInFlight, timeoutMs);
|
|
289
|
+
// Same precedence rule as the sync path: an injected runner beats the synthetic.
|
|
290
|
+
if (!overridden && syntheticPrincipalForTests) return syntheticPrincipalForTests;
|
|
291
|
+
if (timeoutMs <= 0) throw identityError("had no remaining deadline");
|
|
292
|
+
|
|
293
|
+
const lookup = (async (): Promise<string> => {
|
|
294
|
+
let result: WindowsPrincipalLookupResult;
|
|
295
|
+
try {
|
|
296
|
+
result = await asyncPrincipalRunner(timeoutMs);
|
|
297
|
+
} catch {
|
|
298
|
+
throw identityError("could not start");
|
|
299
|
+
}
|
|
300
|
+
const principal = principalFromResult(result);
|
|
301
|
+
cachedPrincipal = principal;
|
|
302
|
+
return principal;
|
|
303
|
+
})();
|
|
304
|
+
asyncLookupInFlight = lookup;
|
|
305
|
+
try {
|
|
306
|
+
return await lookup;
|
|
307
|
+
} finally {
|
|
308
|
+
if (asyncLookupInFlight === lookup) asyncLookupInFlight = null;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** Test seam: replace the sync resolver process and clear its successful cache. */
|
|
313
|
+
export function setWindowsPrincipalRunnerForTests(
|
|
314
|
+
runner: WindowsPrincipalRunner | null,
|
|
315
|
+
): void {
|
|
316
|
+
if (asyncLookupInFlight) {
|
|
317
|
+
throw new Error("Cannot replace the Windows principal runner while a lookup is in flight.");
|
|
318
|
+
}
|
|
319
|
+
principalRunner = runner ?? defaultWindowsPrincipalRunner;
|
|
320
|
+
cachedPrincipal = null;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/** Test seam: replace the async resolver process and clear its successful cache. */
|
|
324
|
+
export function setAsyncWindowsPrincipalRunnerForTests(
|
|
325
|
+
runner: AsyncWindowsPrincipalRunner | null,
|
|
326
|
+
): void {
|
|
327
|
+
if (asyncLookupInFlight) {
|
|
328
|
+
throw new Error("Cannot replace the Windows principal runner while a lookup is in flight.");
|
|
329
|
+
}
|
|
330
|
+
asyncPrincipalRunner = runner ?? defaultAsyncWindowsPrincipalRunner;
|
|
331
|
+
cachedPrincipal = null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** Test seam: clear only process-local principal state. */
|
|
335
|
+
export function resetWindowsPrincipalForTests(): void {
|
|
336
|
+
if (asyncLookupInFlight) {
|
|
337
|
+
throw new Error("Cannot reset the Windows principal while a lookup is in flight.");
|
|
338
|
+
}
|
|
339
|
+
cachedPrincipal = null;
|
|
340
|
+
syntheticPrincipalForTests = null;
|
|
341
|
+
}
|
package/src/lib/winsw.ts
CHANGED
|
@@ -17,10 +17,11 @@ import { createHash } from "node:crypto";
|
|
|
17
17
|
import { execFileSync } from "node:child_process";
|
|
18
18
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
19
19
|
import { homedir } from "node:os";
|
|
20
|
-
import { join, resolve } from "node:path";
|
|
20
|
+
import { join, resolve, win32 } from "node:path";
|
|
21
21
|
import { expandUserPath, getConfigDir, loadConfig } from "../config";
|
|
22
22
|
import { recordOwnedConfigPath } from "./config-ownership";
|
|
23
|
-
import {
|
|
23
|
+
import { BUN_RUNTIME_PATH_ENV, BUN_RUNTIME_SOURCE_ENV, durableBunRuntime } from "./bun-runtime";
|
|
24
|
+
import type { BunRuntimeSource } from "./bun-runtime";
|
|
24
25
|
import { serviceApiTokenFilePath } from "./service-secrets";
|
|
25
26
|
|
|
26
27
|
export const WINSW_VERSION = "2.12.0";
|
|
@@ -62,8 +63,15 @@ function currentCodexHomeAbsolute(): string {
|
|
|
62
63
|
return raw ? resolve(expandUserPath(raw)) : join(homedir(), ".codex");
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
function windowsServicePathAbsolute(raw: string): string {
|
|
67
|
+
const expanded = expandUserPath(raw);
|
|
68
|
+
return win32.isAbsolute(expanded) ? win32.normalize(expanded) : resolve(expanded);
|
|
69
|
+
}
|
|
70
|
+
|
|
65
71
|
export interface WinswEntry {
|
|
66
72
|
bun: string;
|
|
73
|
+
/** Provenance of `bun`, resolved together with it so the two can never disagree. */
|
|
74
|
+
bunRuntimeSource: BunRuntimeSource;
|
|
67
75
|
cli: string;
|
|
68
76
|
}
|
|
69
77
|
|
|
@@ -95,9 +103,12 @@ export function buildWinswXml(entry: WinswEntry, env: NodeJS.ProcessEnv = proces
|
|
|
95
103
|
const aclTimeout = env.OPENCODEX_ACL_TIMEOUT_MS?.trim();
|
|
96
104
|
const envLines = [
|
|
97
105
|
` <env name="OCX_SERVICE" value="1"/>`,
|
|
106
|
+
` <env name="${BUN_RUNTIME_SOURCE_ENV}" value="${xmlEscape(entry.bunRuntimeSource)}"/>`,
|
|
107
|
+
` <env name="${BUN_RUNTIME_PATH_ENV}" value="${xmlEscape(entry.bun)}"/>`,
|
|
98
108
|
` <env name="OCX_API_TOKEN_FILE" value="${xmlEscape(serviceApiTokenFilePath())}"/>`,
|
|
99
109
|
` <env name="PATH" value="${xmlEscape(env.PATH ?? "")}"/>`,
|
|
100
110
|
env.CODEX_HOME?.trim() ? ` <env name="CODEX_HOME" value="${xmlEscape(currentCodexHomeAbsolute())}"/>` : null,
|
|
111
|
+
env.CODEX_SQLITE_HOME?.trim() ? ` <env name="CODEX_SQLITE_HOME" value="${xmlEscape(windowsServicePathAbsolute(env.CODEX_SQLITE_HOME.trim()))}"/>` : null,
|
|
101
112
|
` <env name="OPENCODEX_HOME" value="${xmlEscape(getConfigDir())}"/>`,
|
|
102
113
|
aclTimeout ? ` <env name="OPENCODEX_ACL_TIMEOUT_MS" value="${xmlEscape(aclTimeout)}"/>` : null,
|
|
103
114
|
].filter((line): line is string => Boolean(line));
|
|
@@ -323,7 +334,23 @@ export async function installWinswService(entry: WinswEntry, deps: WinswInstallD
|
|
|
323
334
|
}
|
|
324
335
|
|
|
325
336
|
export function startWinswService(): void { runWinsw(["start"]); }
|
|
326
|
-
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Stop the native service and prove it is no longer running. `stopwait` can fail both
|
|
340
|
+
* for the benign already-stopped case and for real access/timeout failures, so a bare
|
|
341
|
+
* catch cannot decide whether it is safe for lifecycle callers to continue. Re-read
|
|
342
|
+
* SCM state and only accept the two states that cannot still own the proxy listener.
|
|
343
|
+
*/
|
|
344
|
+
export function stopWinswService(): void {
|
|
345
|
+
try { runWinsw(["stopwait"]); } catch { /* classify by verified state below */ }
|
|
346
|
+
const status = statusWinswRaw();
|
|
347
|
+
if (status === "stopped" || status === "nonexistent") return;
|
|
348
|
+
if (status === "unknown") {
|
|
349
|
+
throw new Error("Native service stop could not be verified.");
|
|
350
|
+
}
|
|
351
|
+
throw new Error("Native service is still running after stop.");
|
|
352
|
+
}
|
|
353
|
+
|
|
327
354
|
export function uninstallWinswService(): void {
|
|
328
355
|
if (!existsSync(winswExePath())) {
|
|
329
356
|
// The binary is gone but the SCM registration can outlive it (quarantine, partial
|
|
@@ -363,7 +390,7 @@ export function winswStatusSummary(): string {
|
|
|
363
390
|
if (status === "nonexistent") {
|
|
364
391
|
// A stale SCM service can outlive a deleted exe; surface the repair path.
|
|
365
392
|
return existsSync(winswXmlPath()) && !existsSync(winswExePath())
|
|
366
|
-
? "native assets present but WinSW binary missing — run 'ocx service
|
|
393
|
+
? "native assets present but WinSW binary missing — run 'ocx service repair'"
|
|
367
394
|
: "";
|
|
368
395
|
}
|
|
369
396
|
return `native (WinSW ${WINSW_VERSION}): ${status}`;
|
|
@@ -371,5 +398,6 @@ export function winswStatusSummary(): string {
|
|
|
371
398
|
|
|
372
399
|
/** Default entry mirrors the Task Scheduler baking: durable Bun + cli.ts. */
|
|
373
400
|
export function defaultWinswEntry(cliDir: string): WinswEntry {
|
|
374
|
-
|
|
401
|
+
const runtime = durableBunRuntime();
|
|
402
|
+
return { bun: runtime.path, bunRuntimeSource: runtime.source, cli: join(cliDir, "cli", "index.ts") };
|
|
375
403
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { validateAntigravityImportCredential } from "../google-antigravity";
|
|
2
|
+
import { upsertCredentialByIdentity } from "../store";
|
|
3
|
+
import type { OAuthCredentials } from "../types";
|
|
4
|
+
import {
|
|
5
|
+
ACCOUNT_IMPORT_FORMAT,
|
|
6
|
+
ACCOUNT_IMPORT_MAX_EMAIL_LENGTH,
|
|
7
|
+
ACCOUNT_IMPORT_PROVIDER,
|
|
8
|
+
throwIfAccountImportAborted,
|
|
9
|
+
type AccountImportAdapter,
|
|
10
|
+
type CockpitAccountRecord,
|
|
11
|
+
type ValidatedAntigravityCredential,
|
|
12
|
+
} from "./types";
|
|
13
|
+
|
|
14
|
+
export interface AntigravityImportAdapterDeps {
|
|
15
|
+
validate(refreshToken: string, signal?: AbortSignal): Promise<ValidatedAntigravityCredential>;
|
|
16
|
+
upsert(credential: OAuthCredentials): Promise<"inserted" | "updated">;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function safeProviderEmail(value: unknown): string | null {
|
|
20
|
+
if (typeof value !== "string") return null;
|
|
21
|
+
const normalized = value.toLowerCase();
|
|
22
|
+
if (
|
|
23
|
+
normalized.length === 0
|
|
24
|
+
|| normalized.length > ACCOUNT_IMPORT_MAX_EMAIL_LENGTH
|
|
25
|
+
|| normalized !== normalized.trim()
|
|
26
|
+
|| /[\x00-\x20\x7f]/.test(normalized)
|
|
27
|
+
) return null;
|
|
28
|
+
return normalized;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function createAntigravityAccountImportAdapter(
|
|
32
|
+
deps: AntigravityImportAdapterDeps = {
|
|
33
|
+
validate: validateAntigravityImportCredential,
|
|
34
|
+
upsert: credential => upsertCredentialByIdentity(ACCOUNT_IMPORT_PROVIDER, credential),
|
|
35
|
+
},
|
|
36
|
+
): AccountImportAdapter {
|
|
37
|
+
return {
|
|
38
|
+
provider: ACCOUNT_IMPORT_PROVIDER,
|
|
39
|
+
format: ACCOUNT_IMPORT_FORMAT,
|
|
40
|
+
async importRecord(record: CockpitAccountRecord, signal?: AbortSignal) {
|
|
41
|
+
throwIfAccountImportAborted(signal);
|
|
42
|
+
let credential: ValidatedAntigravityCredential;
|
|
43
|
+
try {
|
|
44
|
+
credential = await deps.validate(record.refreshToken, signal);
|
|
45
|
+
} catch {
|
|
46
|
+
throwIfAccountImportAborted(signal);
|
|
47
|
+
return { status: "failed", code: "credential_rejected" };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
throwIfAccountImportAborted(signal);
|
|
51
|
+
|
|
52
|
+
const providerEmail = safeProviderEmail(credential.email);
|
|
53
|
+
if (!providerEmail) return { status: "failed", code: "credential_rejected" };
|
|
54
|
+
if (providerEmail !== record.email) return { status: "failed", code: "identity_mismatch" };
|
|
55
|
+
if (typeof credential.projectId !== "string" || credential.projectId.length === 0) {
|
|
56
|
+
return { status: "failed", code: "missing_project" };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
throwIfAccountImportAborted(signal);
|
|
60
|
+
try {
|
|
61
|
+
const disposition = await deps.upsert({
|
|
62
|
+
...credential,
|
|
63
|
+
email: providerEmail,
|
|
64
|
+
source: "credential-file",
|
|
65
|
+
});
|
|
66
|
+
return disposition === "updated"
|
|
67
|
+
? { status: "updated", code: "updated" }
|
|
68
|
+
: { status: "imported", code: "imported" };
|
|
69
|
+
} catch {
|
|
70
|
+
return { status: "failed", code: "persist_failed" };
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|