@iislee/opencodex 2.11.0 → 2.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/README.md +117 -22
- package/bin/ocx.mjs +245 -88
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-Be1sDpWw.css +1 -0
- package/gui/dist/assets/index-D4OKgUV4.js +114 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +21 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +475 -62
- package/src/adapters/base.ts +82 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +637 -0
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/catalog.ts +541 -0
- package/src/adapters/cursor/checkpoint-store.ts +308 -0
- package/src/adapters/cursor/cursor-errors.ts +144 -6
- package/src/adapters/cursor/discovery.ts +122 -14
- package/src/adapters/cursor/effort-map.ts +106 -4
- package/src/adapters/cursor/envelope-echo.ts +290 -0
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +180 -59
- package/src/adapters/cursor/live-transport.ts +623 -170
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-desktop.ts +23 -0
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +5 -3
- package/src/adapters/cursor/native-exec.ts +121 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +447 -75
- package/src/adapters/cursor/request-builder.ts +271 -35
- package/src/adapters/cursor/tool-definitions.ts +252 -12
- package/src/adapters/cursor/tool-result-normalize.ts +115 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +48 -1
- package/src/adapters/cursor.ts +336 -39
- package/src/adapters/exec-tool-result-normalize.ts +99 -0
- package/src/adapters/google-antigravity-replay.ts +713 -41
- package/src/adapters/google-antigravity-wire.ts +48 -10
- package/src/adapters/google-errors.ts +44 -12
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +742 -86
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +27 -0
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +65 -17
- package/src/adapters/kiro.ts +270 -73
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1377 -344
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1164 -64
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +105 -21
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/adapters/xai-web-search.ts +186 -0
- package/src/bridge.ts +512 -92
- package/src/chat/inbound.ts +57 -20
- package/src/chat/outbound.ts +97 -33
- package/src/claude/agents-inject.ts +40 -10
- package/src/claude/context-windows.ts +37 -14
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +88 -21
- package/src/cli/access.ts +46 -3
- package/src/cli/account-api.ts +150 -19
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +648 -28
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +97 -19
- package/src/cli/agent.ts +53 -2
- package/src/cli/alias.ts +66 -0
- package/src/cli/capabilities-command.ts +94 -0
- package/src/cli/capabilities.ts +496 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +60 -15
- package/src/cli/claude.ts +129 -35
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +821 -0
- package/src/cli/doctor.ts +440 -56
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +34 -274
- package/src/cli/index.ts +417 -528
- package/src/cli/init.ts +5 -17
- package/src/cli/inspect.ts +230 -0
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +130 -2
- package/src/cli/models.ts +118 -16
- package/src/cli/observe.ts +123 -11
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +34 -3
- package/src/cli/provider.ts +25 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +476 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +57 -10
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +51 -4
- package/src/cli/storage.ts +234 -0
- package/src/cli/system-command.ts +16 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/usage-report.ts +184 -0
- package/src/cli/v2.ts +137 -18
- package/src/cli/version-skew.ts +46 -0
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1442 -23
- package/src/clients/effective-status.ts +30 -2
- package/src/clients/probes/cline.ts +81 -0
- package/src/codex/account-label.ts +35 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +84 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +570 -107
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +893 -246
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +348 -32
- package/src/codex/autostart-health.ts +24 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +86 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +138 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +555 -45
- package/src/codex/catalog/native-models.ts +75 -0
- package/src/codex/catalog/parsing.ts +269 -30
- package/src/codex/catalog/provider-fetch.ts +1626 -144
- package/src/codex/catalog/sync.ts +1576 -187
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +386 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +676 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/desktop-app-restart.ts +355 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +436 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +30 -24
- package/src/codex/history-provider.ts +1016 -235
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +223 -0
- package/src/codex/inject-coordination.ts +373 -0
- package/src/codex/inject.ts +1114 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +81 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +524 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +360 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +622 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +675 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +1313 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +264 -21
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +514 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1065 -31
- package/src/codex/subagent-model-fallback.ts +437 -43
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +720 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +47 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +91 -9
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +121 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +309 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config/provider-validation.ts +177 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +1713 -709
- package/src/generated/compatibility-version.json +3324 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +157 -33
- package/src/images/plan.ts +24 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership-policy.ts +160 -0
- package/src/integrations/ownership.ts +155 -0
- package/src/integrations/registry.ts +166 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +433 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +715 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/admin-secrets.ts +24 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +167 -11
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +26 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +80 -5
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/package-tree-integrity.ts +101 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +6 -2
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +15 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +253 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +30 -4
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/cline.ts +203 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +462 -71
- package/src/oauth/key-providers.ts +25 -0
- package/src/oauth/kimi.ts +25 -3
- package/src/oauth/kiro.ts +95 -6
- package/src/oauth/local-token-detect.ts +13 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +133 -26
- package/src/oauth/token-guardian.ts +9 -3
- package/src/oauth/types.ts +15 -0
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/auto-compact-budget.ts +65 -0
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +176 -0
- package/src/providers/context-cap.ts +26 -8
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +281 -6
- package/src/providers/fastwire.ts +507 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +35 -2
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/new-model-policy.ts +146 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +30 -0
- package/src/providers/quota.ts +1379 -40
- package/src/providers/registry.ts +1545 -112
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +94 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +32 -4
- package/src/reasoning-effort.ts +68 -3
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +384 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +435 -0
- package/src/responses/parser.ts +225 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +504 -0
- package/src/responses/schema.ts +12 -2
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +659 -31
- package/src/responses/thought-signature-replay.ts +364 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/responses/turn-termination.ts +107 -0
- package/src/router.ts +405 -31
- package/src/routing/analytics.ts +379 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +155 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +289 -48
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +154 -72
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +445 -0
- package/src/server/claude-messages.ts +160 -44
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +1021 -190
- package/src/server/lifecycle.ts +336 -14
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +433 -116
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +64 -25
- package/src/server/management/config-routes.ts +511 -51
- package/src/server/management/context.ts +89 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +127 -52
- package/src/server/management/model-routes.ts +461 -133
- package/src/server/management/model-rows.ts +167 -0
- package/src/server/management/native-integration-routes.ts +770 -0
- package/src/server/management/oauth-account-routes.ts +90 -8
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +836 -159
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/route-registry.ts +332 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +289 -33
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +126 -23
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +161 -10
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +221 -54
- package/src/server/relay.ts +479 -87
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log-conversation.ts +51 -0
- package/src/server/request-log.ts +298 -31
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/codex-auth-error.ts +55 -0
- package/src/server/responses/collaboration.ts +239 -36
- package/src/server/responses/combo-stream-preflight.ts +178 -0
- package/src/server/responses/compact.ts +444 -72
- package/src/server/responses/core.ts +3579 -436
- package/src/server/responses/empty-completion-guard.ts +333 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +89 -99
- package/src/server/responses/input-admission.ts +187 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +343 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +381 -0
- package/src/server/responses-custom-tool-repair.ts +363 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +363 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +376 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +319 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +53 -40
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1153 -94
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/policy-job.ts +14 -4
- package/src/storage/policy.ts +88 -23
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +911 -0
- package/src/types/provider.ts +614 -0
- package/src/types/request.ts +397 -0
- package/src/types/tools.ts +236 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +107 -1237
- package/src/update/index.ts +37 -23
- package/src/update/job.ts +445 -68
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +266 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +287 -16
- package/src/usage/log.ts +666 -50
- package/src/usage/summary.ts +388 -17
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +27 -16
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +119 -0
- package/src/web-search/executor.ts +21 -6
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +284 -54
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one place that decides whether a sidecar may treat ChatGPT or Anthropic
|
|
3
|
+
* auth as PRESENT (#2188). Web-search and vision consumed two hand-rolled
|
|
4
|
+
* copies of the Anthropic predicate and no Codex-login predicate at all —
|
|
5
|
+
* provider presence was standing in for "logged in", which let a fresh install
|
|
6
|
+
* with the built-in forward provider but no credential offer Luna as a
|
|
7
|
+
* describer it could never run.
|
|
8
|
+
*
|
|
9
|
+
* Both flags are request-context-free: they read config plus the stored
|
|
10
|
+
* account state, never headers. Per-request usability (exact accounts,
|
|
11
|
+
* generation fences) stays in resolveFirstUsableOpenAiSidecar and the
|
|
12
|
+
* executors; this module only answers "is this side worth offering at all?".
|
|
13
|
+
*/
|
|
14
|
+
import type { OcxConfig, OcxProviderConfig } from "../types";
|
|
15
|
+
import { listOpenAiForwardSidecarCandidates } from "../providers/openai-sidecar";
|
|
16
|
+
import { OPENAI_CODEX_PROVIDER_ID } from "../providers/openai-tiers";
|
|
17
|
+
import { isCodexAccountUsable } from "../codex/account-usability";
|
|
18
|
+
import { MAIN_CODEX_ACCOUNT_ID, isSelectableCodexPoolAccount } from "../codex/account-id";
|
|
19
|
+
import { getAccountSet } from "../oauth/store";
|
|
20
|
+
|
|
21
|
+
export interface SidecarAuthState {
|
|
22
|
+
/** ChatGPT login usable: canonical forward provider AND a live stored credential. */
|
|
23
|
+
isCodexAuth: boolean;
|
|
24
|
+
/** Enabled anthropic-adapter OAuth provider whose active account is not marked for reauth. */
|
|
25
|
+
isAnthropicAuth: boolean;
|
|
26
|
+
/** The provider an Anthropic-side executor would dispatch through, when isAnthropicAuth. */
|
|
27
|
+
anthropicProviderName?: string;
|
|
28
|
+
anthropicProvider?: OcxProviderConfig;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Fixed auth-slot models (#2188): logged-in sides keep these candidates even
|
|
33
|
+
* when the picker hides or disables them. The slot is the LOGIN's entitlement,
|
|
34
|
+
* not the catalog's.
|
|
35
|
+
*/
|
|
36
|
+
export const AUTH_SLOT_MODELS = {
|
|
37
|
+
codex: "gpt-5.6-luna",
|
|
38
|
+
anthropic: "claude-haiku-4-5",
|
|
39
|
+
} as const;
|
|
40
|
+
|
|
41
|
+
export interface SidecarAuthSlot {
|
|
42
|
+
provider: string;
|
|
43
|
+
id: string;
|
|
44
|
+
slot: keyof typeof AUTH_SLOT_MODELS;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Login-shaped, not provider-shaped: a forward provider with no credential is NOT Codex auth. */
|
|
48
|
+
function hasUsableCodexLogin(config: OcxConfig): boolean {
|
|
49
|
+
if (listOpenAiForwardSidecarCandidates(config).length === 0) return false;
|
|
50
|
+
if (isCodexAccountUsable(config, MAIN_CODEX_ACCOUNT_ID)) return true;
|
|
51
|
+
return (config.codexAccounts ?? []).some(account =>
|
|
52
|
+
isSelectableCodexPoolAccount(account) && isCodexAccountUsable(config, account.id));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The predicate previously duplicated as findAnthropicSidecarProvider
|
|
57
|
+
* (web-search) and findAnthropicVisionProvider (vision): first enabled
|
|
58
|
+
* anthropic-adapter OAuth provider whose ACTIVE stored account holds a usable
|
|
59
|
+
* credential. getAccountSet + needsReauth, not getCredential — a terminally
|
|
60
|
+
* invalid account must not present as auth (audit F1).
|
|
61
|
+
*/
|
|
62
|
+
function findAnthropicAuthProvider(
|
|
63
|
+
config: OcxConfig,
|
|
64
|
+
): { providerName: string; provider: OcxProviderConfig } | undefined {
|
|
65
|
+
for (const [providerName, provider] of Object.entries(config.providers)) {
|
|
66
|
+
if (provider.disabled === true) continue;
|
|
67
|
+
if (provider.adapter !== "anthropic" || provider.authMode !== "oauth") continue;
|
|
68
|
+
const set = getAccountSet(providerName);
|
|
69
|
+
const active = set?.accounts.find(account => account.id === set.activeAccountId);
|
|
70
|
+
if (active && active.needsReauth !== true) return { providerName, provider };
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function resolveSidecarAuth(config: OcxConfig): SidecarAuthState {
|
|
76
|
+
const anthropic = findAnthropicAuthProvider(config);
|
|
77
|
+
return {
|
|
78
|
+
isCodexAuth: hasUsableCodexLogin(config),
|
|
79
|
+
isAnthropicAuth: anthropic !== undefined,
|
|
80
|
+
...(anthropic ? { anthropicProviderName: anthropic.providerName, anthropicProvider: anthropic.provider } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The auth-entitled fixed candidates. Emitted regardless of picker visibility. */
|
|
85
|
+
export function sidecarAuthSlots(auth: SidecarAuthState): SidecarAuthSlot[] {
|
|
86
|
+
const slots: SidecarAuthSlot[] = [];
|
|
87
|
+
if (auth.isCodexAuth) slots.push({ provider: OPENAI_CODEX_PROVIDER_ID, id: AUTH_SLOT_MODELS.codex, slot: "codex" });
|
|
88
|
+
if (auth.isAnthropicAuth && auth.anthropicProviderName) {
|
|
89
|
+
slots.push({ provider: auth.anthropicProviderName, id: AUTH_SLOT_MODELS.anthropic, slot: "anthropic" });
|
|
90
|
+
}
|
|
91
|
+
return slots;
|
|
92
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The unified picker-visibility candidate set both sidecars consume (#2188).
|
|
3
|
+
*
|
|
4
|
+
* Rule 1 (picker): a model may be OFFERED as a sidecar backend only if the
|
|
5
|
+
* management picker would show it — the same `listManagementModelRows` rows
|
|
6
|
+
* the GUI Models tab renders, minus disabled rows. Rule 1's only exception is
|
|
7
|
+
* the auth slots: a logged-in side keeps its fixed slot model (Luna/Haiku)
|
|
8
|
+
* even when the picker hides it, because the slot is the login's entitlement.
|
|
9
|
+
*
|
|
10
|
+
* Vision additionally applies rule 2 (− provably text-only); web-search
|
|
11
|
+
* applies its own rule 2 (∩ probed backend with an executor) in
|
|
12
|
+
* src/web-search/backends.ts. Both start from THIS set so the two sidecars
|
|
13
|
+
* cannot diverge on what "visible" means.
|
|
14
|
+
*/
|
|
15
|
+
import type { OcxConfig } from "../types";
|
|
16
|
+
import { listManagementModelRows } from "../server/management/model-rows";
|
|
17
|
+
import { modelAcceptsImageInput, type VisionCandidateModel } from "../vision/eligibility";
|
|
18
|
+
import { sidecarAuthSlots, type SidecarAuthState } from "./auth";
|
|
19
|
+
|
|
20
|
+
export interface SidecarCandidate {
|
|
21
|
+
provider: string;
|
|
22
|
+
id: string;
|
|
23
|
+
native?: boolean;
|
|
24
|
+
inputModalities?: string[];
|
|
25
|
+
/** True when this row is an auth-slot entitlement rather than a picker row. */
|
|
26
|
+
authSlot?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* (picker-visible rows) ∪ (auth slots). De-duplicated by provider+id with the
|
|
31
|
+
* auth-slot flag winning, so a slot model that is ALSO picker-visible still
|
|
32
|
+
* reads as slot-backed. A catalog outage degrades to slots only — the settings
|
|
33
|
+
* routes must not 500 and must keep the logged-in floor populated.
|
|
34
|
+
*/
|
|
35
|
+
export async function pickerVisibleSidecarCandidates(
|
|
36
|
+
config: OcxConfig,
|
|
37
|
+
auth: SidecarAuthState,
|
|
38
|
+
): Promise<SidecarCandidate[]> {
|
|
39
|
+
let rows: Awaited<ReturnType<typeof listManagementModelRows>> = [];
|
|
40
|
+
try { rows = await listManagementModelRows(config); } catch { rows = []; }
|
|
41
|
+
const byKey = new Map<string, SidecarCandidate>();
|
|
42
|
+
for (const row of rows) {
|
|
43
|
+
if (row.disabled === true) continue;
|
|
44
|
+
byKey.set(`${row.provider}/${row.id}`, {
|
|
45
|
+
provider: row.provider,
|
|
46
|
+
id: row.id,
|
|
47
|
+
...(row.inputModalities ? { inputModalities: row.inputModalities } : {}),
|
|
48
|
+
...(row.native ? { native: true } : {}),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
for (const slot of sidecarAuthSlots(auth)) {
|
|
52
|
+
byKey.set(`${slot.provider}/${slot.id}`, {
|
|
53
|
+
provider: slot.provider,
|
|
54
|
+
id: slot.id,
|
|
55
|
+
// Slot models are known image-capable; their only exclusion path is the
|
|
56
|
+
// provider's explicit consumer list (same stance as baselineCandidate).
|
|
57
|
+
inputModalities: ["text", "image"],
|
|
58
|
+
authSlot: true,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return [...byKey.values()];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Rule 2 for vision: drop rows PROVABLY text-only. Unknown stays eligible —
|
|
66
|
+
* the picker filter (rule 1) already bounded the set, so permissive-unknown
|
|
67
|
+
* no longer expands to the whole catalog.
|
|
68
|
+
*/
|
|
69
|
+
export function visionSidecarCandidates(
|
|
70
|
+
config: Pick<OcxConfig, "providers">,
|
|
71
|
+
all: readonly SidecarCandidate[],
|
|
72
|
+
): SidecarCandidate[] {
|
|
73
|
+
return all.filter(candidate => modelAcceptsImageInput(config, toVisionCandidate(candidate)) !== false);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function toVisionCandidate(candidate: SidecarCandidate): VisionCandidateModel {
|
|
77
|
+
return {
|
|
78
|
+
provider: candidate.provider,
|
|
79
|
+
id: candidate.id,
|
|
80
|
+
...(candidate.inputModalities ? { inputModalities: candidate.inputModalities } : {}),
|
|
81
|
+
...(candidate.native ? { native: true } : {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
package/src/storage/cleanup.ts
CHANGED
|
@@ -1091,7 +1091,7 @@ function writeSatelliteBackup(
|
|
|
1091
1091
|
throw new Error("test_fail_satellite_backup_replace");
|
|
1092
1092
|
}
|
|
1093
1093
|
try {
|
|
1094
|
-
renameAtomicFile(tmp, dest);
|
|
1094
|
+
renameAtomicFile(tmp, dest, undefined, "storage-cleanup");
|
|
1095
1095
|
} catch (error) {
|
|
1096
1096
|
try { unlinkSync(tmp); } catch { /* */ }
|
|
1097
1097
|
throw error;
|
|
@@ -2435,7 +2435,7 @@ function writeRestorePending(
|
|
|
2435
2435
|
throw new Error("test_fail_pending_rename");
|
|
2436
2436
|
}
|
|
2437
2437
|
try {
|
|
2438
|
-
|
|
2438
|
+
renameAtomicFile(tmp, dest, undefined, "storage-cleanup");
|
|
2439
2439
|
} catch (error) {
|
|
2440
2440
|
try { unlinkSync(tmp); } catch { /* */ }
|
|
2441
2441
|
throw error;
|
|
@@ -38,6 +38,7 @@ export interface PolicyJobOutcome {
|
|
|
38
38
|
freedBytes?: number;
|
|
39
39
|
removed?: number;
|
|
40
40
|
trashDir?: string;
|
|
41
|
+
metadataPersistenceError?: PolicyRunResult["metadataPersistenceError"];
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
export interface PolicyJobState {
|
|
@@ -238,6 +239,7 @@ export async function abortStorageCleanupPolicyJobAsync(): Promise<void> {
|
|
|
238
239
|
}
|
|
239
240
|
}
|
|
240
241
|
|
|
242
|
+
/** Project a run result into the bounded management-API job outcome. */
|
|
241
243
|
function outcomeFromResult(result: PolicyRunResult): PolicyJobOutcome {
|
|
242
244
|
return {
|
|
243
245
|
ok: result.ok,
|
|
@@ -248,18 +250,26 @@ function outcomeFromResult(result: PolicyRunResult): PolicyJobOutcome {
|
|
|
248
250
|
...(result.freedBytes !== undefined ? { freedBytes: result.freedBytes } : {}),
|
|
249
251
|
...(result.removed !== undefined ? { removed: result.removed } : {}),
|
|
250
252
|
...(result.trashDir ? { trashDir: result.trashDir } : {}),
|
|
253
|
+
...(result.metadataPersistenceError
|
|
254
|
+
? { metadataPersistenceError: result.metadataPersistenceError }
|
|
255
|
+
: {}),
|
|
251
256
|
};
|
|
252
257
|
}
|
|
253
258
|
|
|
259
|
+
/** Publish one completed evaluation without losing successful cleanup effects. */
|
|
254
260
|
function applyFinished(result: PolicyRunResult): void {
|
|
255
261
|
// Prefer the latest persisted policy over `result.policy`. The worker (or
|
|
256
262
|
// in-process run) already merged run metadata into disk; a concurrent PUT
|
|
257
263
|
// may also have landed after that write. Re-reading avoids applying a stale
|
|
258
264
|
// start-of-job snapshot when the run skipped without saving.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
265
|
+
// A best-effort fallback policy may predate concurrent edits; keep the current
|
|
266
|
+
// live config untouched when the durable metadata write did not land.
|
|
267
|
+
if (!result.metadataPersistenceError) {
|
|
268
|
+
try {
|
|
269
|
+
livePolicyApply?.(readStorageCleanupPolicyFromConfig());
|
|
270
|
+
} catch {
|
|
271
|
+
livePolicyApply?.(result.policy);
|
|
272
|
+
}
|
|
263
273
|
}
|
|
264
274
|
state = {
|
|
265
275
|
status: "idle",
|
package/src/storage/policy.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Privacy: logs never include host paths, digests of file contents, or secrets.
|
|
9
9
|
*/
|
|
10
10
|
import { resolveCodexHomeDir } from "../codex/home";
|
|
11
|
-
import { loadConfig, saveConfigPreservingClaudeCode } from "../config";
|
|
11
|
+
import { loadConfig, mutatePersistedConfig, saveConfigPreservingClaudeCode } from "../config";
|
|
12
12
|
import type { StorageCleanupPolicy } from "../types";
|
|
13
13
|
import {
|
|
14
14
|
computePreviewDigest,
|
|
@@ -38,6 +38,7 @@ export function setStorageCleanupPolicyLiveSink(
|
|
|
38
38
|
|
|
39
39
|
export type PolicySchedule = StorageCleanupPolicy["schedule"];
|
|
40
40
|
export type PolicyRunReason = "startup" | "schedule" | "manual";
|
|
41
|
+
export type PolicyMetadataPersistenceError = "missing" | "invalid" | "conflict" | "write_failed";
|
|
41
42
|
|
|
42
43
|
export type PolicySkipReason =
|
|
43
44
|
| "disabled"
|
|
@@ -54,6 +55,7 @@ export interface PolicyRunResult {
|
|
|
54
55
|
freedBytes?: number;
|
|
55
56
|
removed?: number;
|
|
56
57
|
trashDir?: string;
|
|
58
|
+
metadataPersistenceError?: PolicyMetadataPersistenceError;
|
|
57
59
|
policy: StorageCleanupPolicy;
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -399,6 +401,21 @@ export type PolicyRunMetadataPatch = {
|
|
|
399
401
|
lastRun?: StorageCleanupPolicy["lastRun"];
|
|
400
402
|
};
|
|
401
403
|
|
|
404
|
+
/** Apply only run-owned fields while preserving the supplied policy settings. */
|
|
405
|
+
function applyPolicyRunMetadata(
|
|
406
|
+
policy: StorageCleanupPolicy,
|
|
407
|
+
patch: PolicyRunMetadataPatch,
|
|
408
|
+
): StorageCleanupPolicy {
|
|
409
|
+
let next =
|
|
410
|
+
patch.nextRun === "defer_busy"
|
|
411
|
+
? deferBusy(policy, patch.now)
|
|
412
|
+
: advanceNextRun(policy, patch.now);
|
|
413
|
+
if (patch.lastRun) {
|
|
414
|
+
next = { ...next, lastRun: patch.lastRun };
|
|
415
|
+
}
|
|
416
|
+
return next;
|
|
417
|
+
}
|
|
418
|
+
|
|
402
419
|
/**
|
|
403
420
|
* Reload the latest persisted policy and write only run-owned metadata
|
|
404
421
|
* (`lastRun` / `nextRun`). Preserves concurrent edits to enabled, trigger,
|
|
@@ -410,17 +427,57 @@ export function commitPolicyRunMetadata(
|
|
|
410
427
|
patch: PolicyRunMetadataPatch,
|
|
411
428
|
): StorageCleanupPolicy {
|
|
412
429
|
const latest = normalizeStorageCleanupPolicy(load());
|
|
413
|
-
|
|
414
|
-
patch.nextRun === "defer_busy"
|
|
415
|
-
? deferBusy(latest, patch.now)
|
|
416
|
-
: advanceNextRun(latest, patch.now);
|
|
417
|
-
if (patch.lastRun) {
|
|
418
|
-
next = { ...next, lastRun: patch.lastRun };
|
|
419
|
-
}
|
|
430
|
+
const next = applyPolicyRunMetadata(latest, patch);
|
|
420
431
|
save(next);
|
|
421
432
|
return next;
|
|
422
433
|
}
|
|
423
434
|
|
|
435
|
+
type PolicyRunMetadataCommit = {
|
|
436
|
+
policy: StorageCleanupPolicy;
|
|
437
|
+
persistenceError?: PolicyMetadataPersistenceError;
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
/** Attach the durable metadata outcome without replacing cleanup status or metrics. */
|
|
441
|
+
function withMetadataCommit(
|
|
442
|
+
result: Omit<PolicyRunResult, "policy" | "metadataPersistenceError">,
|
|
443
|
+
committed: PolicyRunMetadataCommit,
|
|
444
|
+
): PolicyRunResult {
|
|
445
|
+
return {
|
|
446
|
+
...result,
|
|
447
|
+
policy: committed.policy,
|
|
448
|
+
...(committed.persistenceError ? { metadataPersistenceError: committed.persistenceError } : {}),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/** Recompute run-owned metadata from the latest config inside the mutation lock. */
|
|
453
|
+
function commitPolicyRunMetadataToConfig(
|
|
454
|
+
patch: PolicyRunMetadataPatch,
|
|
455
|
+
fallbackPolicy: StorageCleanupPolicy,
|
|
456
|
+
): PolicyRunMetadataCommit {
|
|
457
|
+
const unavailable = (reason: PolicyMetadataPersistenceError): PolicyRunMetadataCommit => {
|
|
458
|
+
console.warn(`[storage-policy] metadata_persist_failed reason=${reason}`);
|
|
459
|
+
return {
|
|
460
|
+
policy: applyPolicyRunMetadata(fallbackPolicy, patch),
|
|
461
|
+
persistenceError: reason,
|
|
462
|
+
};
|
|
463
|
+
};
|
|
464
|
+
try {
|
|
465
|
+
const outcome = mutatePersistedConfig(config => {
|
|
466
|
+
const next = applyPolicyRunMetadata(
|
|
467
|
+
normalizeStorageCleanupPolicy(config.storageCleanupPolicy),
|
|
468
|
+
patch,
|
|
469
|
+
);
|
|
470
|
+
config.storageCleanupPolicy = next;
|
|
471
|
+
return { changed: true, value: next };
|
|
472
|
+
});
|
|
473
|
+
if (outcome.status === "unavailable") return unavailable(outcome.reason);
|
|
474
|
+
livePolicySink?.(outcome.value);
|
|
475
|
+
return { policy: outcome.value };
|
|
476
|
+
} catch {
|
|
477
|
+
return unavailable("write_failed");
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
424
481
|
function logPolicyEvent(message: string): void {
|
|
425
482
|
console.log(`[storage-policy] ${message}`);
|
|
426
483
|
}
|
|
@@ -434,8 +491,14 @@ export function runStorageCleanupPolicy(deps: PolicyRunDeps): PolicyRunResult {
|
|
|
434
491
|
const load = deps.loadPolicy ?? readStorageCleanupPolicyFromConfig;
|
|
435
492
|
const save = deps.savePolicy ?? writeStorageCleanupPolicyToConfig;
|
|
436
493
|
const execute = deps.execute ?? executeArchivedCleanup;
|
|
437
|
-
|
|
438
494
|
const policy = normalizeStorageCleanupPolicy(load());
|
|
495
|
+
// Injected stores retain the existing load/save contract. The production path
|
|
496
|
+
// recomputes metadata from the latest persisted policy inside the config lock.
|
|
497
|
+
const commitMetadata = deps.loadPolicy !== undefined || deps.savePolicy !== undefined
|
|
498
|
+
? (patch: PolicyRunMetadataPatch): PolicyRunMetadataCommit => ({
|
|
499
|
+
policy: commitPolicyRunMetadata(load, save, patch),
|
|
500
|
+
})
|
|
501
|
+
: (patch: PolicyRunMetadataPatch) => commitPolicyRunMetadataToConfig(patch, policy);
|
|
439
502
|
|
|
440
503
|
if (typeof deps.holdAfterLoadMs === "number" && Number.isFinite(deps.holdAfterLoadMs) && deps.holdAfterLoadMs > 0) {
|
|
441
504
|
Bun.sleepSync(Math.floor(deps.holdAfterLoadMs));
|
|
@@ -451,15 +514,15 @@ export function runStorageCleanupPolicy(deps: PolicyRunDeps): PolicyRunResult {
|
|
|
451
514
|
|
|
452
515
|
const selection = selectPolicyPreview(policy, deps.codexHome);
|
|
453
516
|
if (selection.archivedBytes <= policy.trigger.archivedBytesOver) {
|
|
454
|
-
const
|
|
517
|
+
const committed = commitMetadata({ now, nextRun: "advance" });
|
|
455
518
|
logPolicyEvent("skip under_threshold");
|
|
456
|
-
return { ok: true, skipped: "under_threshold",
|
|
519
|
+
return withMetadataCommit({ ok: true, skipped: "under_threshold" }, committed);
|
|
457
520
|
}
|
|
458
521
|
|
|
459
522
|
if (selection.count === 0) {
|
|
460
|
-
const
|
|
523
|
+
const committed = commitMetadata({ now, nextRun: "advance" });
|
|
461
524
|
logPolicyEvent("skip nothing_selected");
|
|
462
|
-
return { ok: true, skipped: "nothing_selected",
|
|
525
|
+
return withMetadataCommit({ ok: true, skipped: "nothing_selected" }, committed);
|
|
463
526
|
}
|
|
464
527
|
|
|
465
528
|
const result = execute({
|
|
@@ -473,25 +536,28 @@ export function runStorageCleanupPolicy(deps: PolicyRunDeps): PolicyRunResult {
|
|
|
473
536
|
});
|
|
474
537
|
|
|
475
538
|
if (!result.ok && result.error === "codex_busy") {
|
|
476
|
-
const
|
|
539
|
+
const committed = commitMetadata({ now, nextRun: "defer_busy" });
|
|
477
540
|
logPolicyEvent("defer codex_busy");
|
|
478
|
-
return {
|
|
541
|
+
return withMetadataCommit({
|
|
542
|
+
ok: false,
|
|
543
|
+
deferred: "codex_busy",
|
|
544
|
+
error: "codex_busy",
|
|
545
|
+
}, committed);
|
|
479
546
|
}
|
|
480
547
|
|
|
481
548
|
if (!result.ok) {
|
|
482
549
|
// Non-busy failure: still advance schedule so we do not tight-loop.
|
|
483
|
-
const
|
|
550
|
+
const committed = commitMetadata({ now, nextRun: "advance" });
|
|
484
551
|
logPolicyEvent(`fail ${result.error ?? "cleanup_failed"}`);
|
|
485
|
-
return {
|
|
552
|
+
return withMetadataCommit({
|
|
486
553
|
ok: false,
|
|
487
554
|
error: result.error,
|
|
488
555
|
mode: result.mode,
|
|
489
556
|
...(result.trashDir ? { trashDir: result.trashDir } : {}),
|
|
490
|
-
|
|
491
|
-
};
|
|
557
|
+
}, committed);
|
|
492
558
|
}
|
|
493
559
|
|
|
494
|
-
const
|
|
560
|
+
const committed = commitMetadata({
|
|
495
561
|
now,
|
|
496
562
|
nextRun: "advance",
|
|
497
563
|
lastRun: {
|
|
@@ -503,14 +569,13 @@ export function runStorageCleanupPolicy(deps: PolicyRunDeps): PolicyRunResult {
|
|
|
503
569
|
logPolicyEvent(
|
|
504
570
|
`ok mode=${result.mode} removed=${result.count} freedBytes=${result.bytes}`,
|
|
505
571
|
);
|
|
506
|
-
return {
|
|
572
|
+
return withMetadataCommit({
|
|
507
573
|
ok: true,
|
|
508
574
|
mode: result.mode,
|
|
509
575
|
freedBytes: result.bytes,
|
|
510
576
|
removed: result.count,
|
|
511
577
|
...(result.trashDir ? { trashDir: result.trashDir } : {}),
|
|
512
|
-
|
|
513
|
-
};
|
|
578
|
+
}, committed);
|
|
514
579
|
}
|
|
515
580
|
|
|
516
581
|
/** Startup / schedule tick entry — swallows unexpected errors. */
|
package/src/storage/scanner.ts
CHANGED
|
@@ -16,7 +16,7 @@ const IMMUTABLE_READONLY_FLAGS = constants.SQLITE_OPEN_READONLY | constants.SQLI
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Read-only CODEX_HOME storage scanner — Phase 1 of the Storage page epic
|
|
19
|
-
* (devlog/
|
|
19
|
+
* (devlog/_fin/500_storage-page-session-cleanup). Pure measurement: sizes via
|
|
20
20
|
* fs.stat walks, DB row counts via immutable readonly opens that degrade to
|
|
21
21
|
* null on lock/corruption. Performs zero writes under CODEX_HOME.
|
|
22
22
|
*/
|
|
@@ -11,10 +11,9 @@
|
|
|
11
11
|
* time (so we cannot miss `self.close()` / early exit), stays in `liveWorkers`
|
|
12
12
|
* until that close settles, and `drainStorageWorkers()` joins every in-flight
|
|
13
13
|
* terminate. Spawns are serialized through `withStorageWorkerSpawnGate` so the
|
|
14
|
-
* next Worker cannot be created until prior threads have exited.
|
|
15
|
-
*
|
|
16
|
-
* (
|
|
17
|
-
* `bun test --isolate`).
|
|
14
|
+
* next Worker cannot be created until prior threads have exited. A post-close
|
|
15
|
+
* settle covers the OS/runtime join gap Bun does not expose on Windows, macOS,
|
|
16
|
+
* and Linux (including Bun 1.3.14 isolate crashes and Linux `epoll_ctl` reuse).
|
|
18
17
|
*/
|
|
19
18
|
|
|
20
19
|
import { createAdmissionGate, type AdmissionMetrics, type AdmissionReservation } from "../lib/admission";
|
|
@@ -52,15 +51,15 @@ let spawnCancelEpoch = 0;
|
|
|
52
51
|
/**
|
|
53
52
|
* OS-join gap after the `close` event on platforms where Bun's Worker reclaim
|
|
54
53
|
* races the isolate/file boundary (not a CI job-timeout bump).
|
|
55
|
-
* Windows GHA at 250ms and 750ms still left `workers_spawned(N)
|
|
56
|
-
* workers_terminated(N-1)` panics under isolate
|
|
57
|
-
*
|
|
58
|
-
*
|
|
54
|
+
* Windows GHA at 250ms and 750ms still left `workers_spawned(N)`
|
|
55
|
+
* `workers_terminated(N-1)` panics under isolate, so Windows keeps 1500ms.
|
|
56
|
+
* Darwin and Linux use a shorter settle for the balanced-count/epoll reclaim
|
|
57
|
+
* window seen on Bun 1.3.14.
|
|
59
58
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return
|
|
59
|
+
export function storageWorkerOsJoinSettleMs(platform = process.platform): number {
|
|
60
|
+
if (platform === "win32") return 1_500;
|
|
61
|
+
if (platform === "darwin" || platform === "linux") return 250;
|
|
62
|
+
return 0;
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
/** Invalidate spawn callbacks still waiting on the gate (reset / server drain). */
|
|
@@ -181,9 +180,10 @@ export function terminateStorageWorker(worker: Worker, timeoutMs = 5_000): Promi
|
|
|
181
180
|
// only forces `closed`, it does not prove the OS thread has exited.
|
|
182
181
|
// Callers that catch and continue (e.g. drainAndShutdown) still need
|
|
183
182
|
// that gap before the next isolate reclaim or server.stop.
|
|
184
|
-
|
|
183
|
+
const settleMs = storageWorkerOsJoinSettleMs();
|
|
184
|
+
if (settleMs > 0) {
|
|
185
185
|
await Bun.sleep(0);
|
|
186
|
-
await Bun.sleep(
|
|
186
|
+
await Bun.sleep(settleMs);
|
|
187
187
|
}
|
|
188
188
|
if (timedOut) {
|
|
189
189
|
throw new Error(`storage worker did not exit within ${timeoutMs}ms`);
|
|
@@ -3,6 +3,9 @@ param(
|
|
|
3
3
|
[Parameter(Mandatory = $true)][string]$CliPath,
|
|
4
4
|
[Parameter(Mandatory = $true)][string]$CodexHome,
|
|
5
5
|
[Parameter(Mandatory = $true)][string]$OpenCodexHome,
|
|
6
|
+
# Provenance of $BunPath, chosen when the tray entry was built. Optional so an
|
|
7
|
+
# already-installed launcher command from an older version still starts.
|
|
8
|
+
[ValidateSet("", "override", "bundled", "process")][string]$BunRuntimeSource = "",
|
|
6
9
|
[ValidateSet("Run", "Stop")][string]$Mode = "Run",
|
|
7
10
|
[int]$HostPid = 0
|
|
8
11
|
)
|
|
@@ -81,7 +84,7 @@ function ConvertTo-NativeArgument([string]$Value) {
|
|
|
81
84
|
return '"' + $Value + '"'
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
function Start-OcxCommand([string[]]$CommandArgs) {
|
|
87
|
+
function Start-OcxCommand([string[]]$CommandArgs, [switch]$TrackExit) {
|
|
85
88
|
try {
|
|
86
89
|
$allArgs = @($CliPath) + $CommandArgs
|
|
87
90
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
|
@@ -92,9 +95,17 @@ function Start-OcxCommand([string[]]$CommandArgs) {
|
|
|
92
95
|
$psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
|
|
93
96
|
$psi.EnvironmentVariables["CODEX_HOME"] = $CodexHome
|
|
94
97
|
$psi.EnvironmentVariables["OPENCODEX_HOME"] = $OpenCodexHome
|
|
98
|
+
if ($BunRuntimeSource) {
|
|
99
|
+
$psi.EnvironmentVariables["OCX_BUN_RUNTIME_SOURCE"] = $BunRuntimeSource
|
|
100
|
+
# Paired with the source so a later relaunch can tell the marker still describes
|
|
101
|
+
# this binary rather than one it merely inherited.
|
|
102
|
+
$psi.EnvironmentVariables["OCX_BUN_RUNTIME_PATH"] = $BunPath
|
|
103
|
+
}
|
|
95
104
|
$process = [System.Diagnostics.Process]::Start($psi)
|
|
96
|
-
if ($null -
|
|
105
|
+
if ($null -eq $process) { throw "Process did not start" }
|
|
97
106
|
Write-ActionLog "dispatched $($CommandArgs -join ' ')"
|
|
107
|
+
if ($TrackExit) { return $process }
|
|
108
|
+
$process.Dispose()
|
|
98
109
|
return $true
|
|
99
110
|
} catch {
|
|
100
111
|
Write-ActionLog "launch failed: $($_.Exception.GetType().Name)"
|
|
@@ -163,18 +174,40 @@ $script:pendingAction = $null
|
|
|
163
174
|
$script:pendingStarted = 0L
|
|
164
175
|
$script:pendingDeadline = 0L
|
|
165
176
|
$script:pendingOldProxyPid = $null
|
|
177
|
+
$script:pendingProcess = $null
|
|
166
178
|
|
|
167
179
|
function Set-PendingAction([string]$Action, [int]$TimeoutSeconds) {
|
|
180
|
+
if ($null -ne $script:pendingAction) {
|
|
181
|
+
Write-ActionLog "$Action ignored because $($script:pendingAction) is still pending"
|
|
182
|
+
return $false
|
|
183
|
+
}
|
|
184
|
+
if ($null -ne $script:pendingProcess) {
|
|
185
|
+
try {
|
|
186
|
+
$script:pendingProcess.Dispose()
|
|
187
|
+
} catch {
|
|
188
|
+
Write-ActionLog "pending process dispose failed: $($_.Exception.GetType().Name)"
|
|
189
|
+
}
|
|
190
|
+
$script:pendingProcess = $null
|
|
191
|
+
}
|
|
168
192
|
$script:pendingAction = $Action
|
|
169
193
|
$script:pendingStarted = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
|
|
170
194
|
$script:pendingDeadline = $script:pendingStarted + ($TimeoutSeconds * 1000)
|
|
171
195
|
$script:pendingOldProxyPid = $script:proxyPid
|
|
196
|
+
return $true
|
|
172
197
|
}
|
|
173
198
|
|
|
174
199
|
function Complete-PendingAction([bool]$Success) {
|
|
175
200
|
if ($null -eq $script:pendingAction) { return }
|
|
176
201
|
$action = $script:pendingAction
|
|
177
202
|
$script:pendingAction = $null
|
|
203
|
+
if ($null -ne $script:pendingProcess) {
|
|
204
|
+
try {
|
|
205
|
+
$script:pendingProcess.Dispose()
|
|
206
|
+
} catch {
|
|
207
|
+
Write-ActionLog "pending process dispose failed: $($_.Exception.GetType().Name)"
|
|
208
|
+
}
|
|
209
|
+
$script:pendingProcess = $null
|
|
210
|
+
}
|
|
178
211
|
if ($Success) {
|
|
179
212
|
Write-ActionLog "$action completed (port=$($script:port), pid=$($script:proxyPid))"
|
|
180
213
|
$notify.ShowBalloonTip(2500, "opencodex", "$action completed.", [System.Windows.Forms.ToolTipIcon]::Info)
|
|
@@ -217,6 +250,11 @@ function Update-TrayState {
|
|
|
217
250
|
$stopItem.Enabled = $false
|
|
218
251
|
$restartItem.Enabled = $false
|
|
219
252
|
}
|
|
253
|
+
if ($null -ne $script:pendingAction) {
|
|
254
|
+
$startItem.Enabled = $false
|
|
255
|
+
$stopItem.Enabled = $false
|
|
256
|
+
$restartItem.Enabled = $false
|
|
257
|
+
}
|
|
220
258
|
$heartbeat = @{ pid = $PID; timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() }
|
|
221
259
|
if ($HostPid -gt 0) { $heartbeat.hostPid = $HostPid }
|
|
222
260
|
$heartbeatJson = $heartbeat | ConvertTo-Json -Compress
|
|
@@ -228,26 +266,59 @@ function Update-TrayState {
|
|
|
228
266
|
$reached = ($script:pendingAction -eq "Start Proxy" -and $script:online) -or
|
|
229
267
|
($script:pendingAction -eq "Stop Proxy" -and -not $script:online) -or
|
|
230
268
|
($script:pendingAction -eq "Restart Proxy" -and $elapsed -gt 3000 -and $script:online -and $script:proxyPid -ne $script:pendingOldProxyPid)
|
|
231
|
-
|
|
269
|
+
$commandFailed = $false
|
|
270
|
+
if ($null -ne $script:pendingProcess) {
|
|
271
|
+
try {
|
|
272
|
+
$commandFailed = $script:pendingProcess.HasExited -and $script:pendingProcess.ExitCode -ne 0
|
|
273
|
+
} catch {
|
|
274
|
+
Write-ActionLog "pending process result inspection failed: $($_.Exception.GetType().Name)"
|
|
275
|
+
# If we cannot inspect the tracked command, we cannot prove it is still
|
|
276
|
+
# healthy. Fail the pending action instead of silently waiting for a later
|
|
277
|
+
# timeout and presenting an indeterminate process as success-capable.
|
|
278
|
+
$commandFailed = $true
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if ($commandFailed) { Complete-PendingAction $false }
|
|
282
|
+
elseif ($reached) { Complete-PendingAction $true }
|
|
232
283
|
elseif ($now -gt $script:pendingDeadline) { Complete-PendingAction $false }
|
|
233
284
|
}
|
|
234
285
|
}
|
|
235
286
|
|
|
236
287
|
$openItem.add_Click({ Start-OcxCommand @("gui") })
|
|
237
288
|
$startItem.add_Click({
|
|
289
|
+
if (-not (Set-PendingAction "Start Proxy" 75)) { return }
|
|
238
290
|
$statusItem.Text = "Proxy: Starting..."
|
|
239
|
-
|
|
240
|
-
|
|
291
|
+
# service start can spend 20s and the CLI then observes health for another 40s.
|
|
292
|
+
$startProcess = Start-OcxCommand @("__tray-start") -TrackExit
|
|
293
|
+
if ($startProcess -is [System.Diagnostics.Process]) {
|
|
294
|
+
$script:pendingProcess = $startProcess
|
|
295
|
+
} else {
|
|
296
|
+
Complete-PendingAction $false
|
|
297
|
+
}
|
|
241
298
|
})
|
|
242
299
|
$stopItem.add_Click({
|
|
300
|
+
if (-not (Set-PendingAction "Stop Proxy" 15)) { return }
|
|
243
301
|
$statusItem.Text = "Proxy: Stopping..."
|
|
244
|
-
|
|
245
|
-
if (
|
|
302
|
+
$stopProcess = Start-OcxCommand @("stop") -TrackExit
|
|
303
|
+
if ($stopProcess -is [System.Diagnostics.Process]) {
|
|
304
|
+
$script:pendingProcess = $stopProcess
|
|
305
|
+
} else {
|
|
306
|
+
Complete-PendingAction $false
|
|
307
|
+
}
|
|
246
308
|
})
|
|
247
309
|
$restartItem.add_Click({
|
|
310
|
+
if (-not (Set-PendingAction "Restart Proxy" 160)) { return }
|
|
248
311
|
$statusItem.Text = "Proxy: Restarting..."
|
|
249
|
-
|
|
250
|
-
|
|
312
|
+
# /api/system/restart may drain active work for 60s and then spend up to 70s
|
|
313
|
+
# handing off to an identity-verified replacement. The tray observes health/PID
|
|
314
|
+
# rather than the detached CLI exit, so keep a watchdog margin around that shared
|
|
315
|
+
# lifecycle budget. The CLI remains the lifecycle owner; the tray never kills.
|
|
316
|
+
$restartProcess = Start-OcxCommand @("__tray-restart") -TrackExit
|
|
317
|
+
if ($restartProcess -is [System.Diagnostics.Process]) {
|
|
318
|
+
$script:pendingProcess = $restartProcess
|
|
319
|
+
} else {
|
|
320
|
+
Complete-PendingAction $false
|
|
321
|
+
}
|
|
251
322
|
})
|
|
252
323
|
$logsItem.add_Click({
|
|
253
324
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
|
@@ -280,6 +351,9 @@ try {
|
|
|
280
351
|
$timer.Stop()
|
|
281
352
|
$timer.Dispose()
|
|
282
353
|
$notify.Visible = $false
|
|
354
|
+
if ($null -ne $script:pendingProcess) {
|
|
355
|
+
try { $script:pendingProcess.Dispose() } catch { $null = $_ }
|
|
356
|
+
}
|
|
283
357
|
$notify.Dispose()
|
|
284
358
|
foreach ($icon in $script:ownedIcons) { $icon.Dispose() }
|
|
285
359
|
$menu.Dispose()
|