@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,143 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
import type {
|
|
3
|
+
PublicArtifactV1,
|
|
4
|
+
PublicEvidenceBundleUnsignedV1,
|
|
5
|
+
PublicEvidenceBundleV1,
|
|
6
|
+
PublicEvidenceRecordV1,
|
|
7
|
+
PublicEvidenceSubjectV1,
|
|
8
|
+
} from "./types";
|
|
9
|
+
import { PublicEvidenceValidationError } from "./validate";
|
|
10
|
+
|
|
11
|
+
const FORBIDDEN_PUBLIC_STRING_PATTERNS: ReadonlyArray<{ label: string; pattern: RegExp }> = [
|
|
12
|
+
{ label: "URL", pattern: /(?:https?|file):\/\//i },
|
|
13
|
+
{
|
|
14
|
+
label: "local path",
|
|
15
|
+
pattern:
|
|
16
|
+
/(?:[A-Za-z]:[\\/]|\\\\[A-Za-z0-9._-]+\\|(?:^|[\s"'([{=:])\/(?:Users|home|root|tmp|var|opt|private|etc|mnt|media|srv|usr|dev|run|Library|System|Applications|Volumes|bin|sbin|lib|lib64|proc|sys|boot|Network|cores|nix|snap|app)(?:\/|$))/i,
|
|
17
|
+
},
|
|
18
|
+
{ label: "email", pattern: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i },
|
|
19
|
+
{ label: "IP address", pattern: /\b(?:\d{1,3}\.){3}\d{1,3}\b|\[[0-9a-f:]{2,}\]/i },
|
|
20
|
+
{ label: "query string", pattern: /[?&][A-Za-z0-9_.~-]+=/ },
|
|
21
|
+
{ label: "authorization/header material", pattern: /\b(?:authorization|proxy-authorization|cookie|set-cookie|x-api-key|api[_-]?key|bearer)\b/i },
|
|
22
|
+
{ label: "credential", pattern: /\b(?:sk-[A-Za-z0-9_-]{8,}|gh[opusr]_[A-Za-z0-9]{8,}|github_pat_[A-Za-z0-9_]{8,}|AKIA[0-9A-Z]{12,})\b/ },
|
|
23
|
+
{ label: "private key", pattern: /-----BEGIN [^-]*PRIVATE KEY-----/i },
|
|
24
|
+
{ label: "local request/decision/Fabric id", pattern: /\b(?:request|decision|fabric)_[A-Za-z0-9_-]{6,}\b/i },
|
|
25
|
+
{ label: "account/project/tenant context", pattern: /\b(?:account|tenant|project|organization|deployment)[=:][^\s]+/i },
|
|
26
|
+
{ label: "precise timestamp", pattern: /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/ },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const PUBLIC_TEXT_ARTIFACT_MEDIA_TYPES = new Set([
|
|
30
|
+
"application/json",
|
|
31
|
+
"application/json; charset=utf-8",
|
|
32
|
+
"text/markdown",
|
|
33
|
+
"text/markdown; charset=utf-8",
|
|
34
|
+
"text/plain",
|
|
35
|
+
"text/plain; charset=utf-8",
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
function containsIpLiteral(value: string): boolean {
|
|
39
|
+
if (isIP(value) !== 0) return true;
|
|
40
|
+
for (const candidate of value.match(/[0-9A-Fa-f:]{2,}/g) ?? []) {
|
|
41
|
+
if (candidate.includes(":") && isIP(candidate) === 6) return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function assertPrivacySafeString(value: string, field: string): void {
|
|
47
|
+
// `PUBLIC_IDENTIFIER` intentionally permits `:` for reviewed identifiers, so use
|
|
48
|
+
// Node's IP parser to validate colon-bearing candidates instead of rejecting them
|
|
49
|
+
// with a broad regex. This catches both whole-string and embedded IPv6 literals.
|
|
50
|
+
if (containsIpLiteral(value)) {
|
|
51
|
+
throw new PublicEvidenceValidationError(
|
|
52
|
+
"privacy_rejected",
|
|
53
|
+
`${field} contains forbidden IP address material`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
for (const { label, pattern } of FORBIDDEN_PUBLIC_STRING_PATTERNS) {
|
|
57
|
+
if (pattern.test(value)) {
|
|
58
|
+
throw new PublicEvidenceValidationError(
|
|
59
|
+
"privacy_rejected",
|
|
60
|
+
`${field} contains forbidden ${label} material`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function scanSubject(subject: PublicEvidenceSubjectV1, field: string): void {
|
|
67
|
+
if (subject.subjectKind === "protocol") {
|
|
68
|
+
assertPrivacySafeString(subject.compatibilityVersion, `${field}.compatibilityVersion`);
|
|
69
|
+
assertPrivacySafeString(subject.adapterFamily, `${field}.adapterFamily`);
|
|
70
|
+
assertPrivacySafeString(subject.inboundProtocol, `${field}.inboundProtocol`);
|
|
71
|
+
assertPrivacySafeString(subject.upstreamProtocol, `${field}.upstreamProtocol`);
|
|
72
|
+
assertPrivacySafeString(subject.surface, `${field}.surface`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (subject.subjectKind === "route") {
|
|
76
|
+
assertPrivacySafeString(subject.providerId, `${field}.providerId`);
|
|
77
|
+
assertPrivacySafeString(subject.modelId, `${field}.modelId`);
|
|
78
|
+
assertPrivacySafeString(subject.adapterFamily, `${field}.adapterFamily`);
|
|
79
|
+
assertPrivacySafeString(subject.compatibilityVersion, `${field}.compatibilityVersion`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
scanSubject(subject.route, `${field}.route`);
|
|
83
|
+
assertPrivacySafeString(subject.taskClassId, `${field}.taskClassId`);
|
|
84
|
+
assertPrivacySafeString(subject.taskClassVersion, `${field}.taskClassVersion`);
|
|
85
|
+
assertPrivacySafeString(subject.fabricCompatibilityVersion, `${field}.fabricCompatibilityVersion`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function scanArtifact(artifact: PublicArtifactV1, index: number): void {
|
|
89
|
+
const field = `bundle.artifacts[${index}]`;
|
|
90
|
+
assertPrivacySafeString(artifact.artifactClass, `${field}.artifactClass`);
|
|
91
|
+
assertPrivacySafeString(artifact.mediaType, `${field}.mediaType`);
|
|
92
|
+
|
|
93
|
+
if (!PUBLIC_TEXT_ARTIFACT_MEDIA_TYPES.has(artifact.mediaType.toLowerCase())) {
|
|
94
|
+
throw new PublicEvidenceValidationError(
|
|
95
|
+
"privacy_rejected",
|
|
96
|
+
`${field}.mediaType is not in the closed public text-artifact set`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
if (typeof artifact.contentBase64 !== "string") {
|
|
100
|
+
throw new PublicEvidenceValidationError("privacy_rejected", `${field}.contentBase64 is invalid`);
|
|
101
|
+
}
|
|
102
|
+
const bytes = Buffer.from(artifact.contentBase64, "base64");
|
|
103
|
+
if (bytes.toString("base64") !== artifact.contentBase64 || bytes.byteLength !== artifact.byteCount) {
|
|
104
|
+
throw new PublicEvidenceValidationError(
|
|
105
|
+
"privacy_rejected",
|
|
106
|
+
`${field}.contentBase64 is non-canonical or does not match byteCount`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
let text: string;
|
|
110
|
+
try {
|
|
111
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
112
|
+
} catch {
|
|
113
|
+
throw new PublicEvidenceValidationError("privacy_rejected", `${field} is not valid UTF-8 text`);
|
|
114
|
+
}
|
|
115
|
+
assertPrivacySafeString(text, `${field}.content`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function validatePublicEvidenceRecordPrivacy(record: PublicEvidenceRecordV1): void {
|
|
119
|
+
assertPrivacySafeString(record.suiteId, "record.suiteId");
|
|
120
|
+
assertPrivacySafeString(record.suiteVersion, "record.suiteVersion");
|
|
121
|
+
assertPrivacySafeString(record.scenarioId, "record.scenarioId");
|
|
122
|
+
assertPrivacySafeString(record.scenarioVersion, "record.scenarioVersion");
|
|
123
|
+
scanSubject(record.subject, "record.subject");
|
|
124
|
+
for (const [index, assertion] of record.assertions.entries()) {
|
|
125
|
+
assertPrivacySafeString(assertion.id, `record.assertions[${index}].id`);
|
|
126
|
+
}
|
|
127
|
+
for (const [index, incident] of (record.incidentRefs ?? []).entries()) {
|
|
128
|
+
assertPrivacySafeString(incident.corpusId, `record.incidentRefs[${index}].corpusId`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Second-pass CL-10 export privacy boundary. Hashes, signatures and publisher public-key
|
|
134
|
+
* bytes are intentionally not pattern-scanned; every human-semantic public string and
|
|
135
|
+
* every final text artifact byte is scanned before local signing/storage or import.
|
|
136
|
+
*/
|
|
137
|
+
export function validatePublicEvidencePrivacy(
|
|
138
|
+
bundle: PublicEvidenceBundleUnsignedV1 | PublicEvidenceBundleV1,
|
|
139
|
+
): void {
|
|
140
|
+
assertPrivacySafeString(bundle.createdDayUtc, "bundle.createdDayUtc");
|
|
141
|
+
for (const record of bundle.records) validatePublicEvidenceRecordPrivacy(record);
|
|
142
|
+
for (const [index, artifact] of bundle.artifacts.entries()) scanArtifact(artifact, index);
|
|
143
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
closeSync,
|
|
4
|
+
constants as fsConstants,
|
|
5
|
+
fsyncSync,
|
|
6
|
+
linkSync,
|
|
7
|
+
lstatSync,
|
|
8
|
+
openSync,
|
|
9
|
+
readdirSync,
|
|
10
|
+
unlinkSync,
|
|
11
|
+
writeSync,
|
|
12
|
+
} from "node:fs";
|
|
13
|
+
import type { Stats } from "node:fs";
|
|
14
|
+
import { basename, dirname, join } from "node:path";
|
|
15
|
+
|
|
16
|
+
export type PrivateFileCommitFault = "before_publish" | "parent_directory_sync" | null;
|
|
17
|
+
let privateFileCommitFaultForTests: PrivateFileCommitFault = null;
|
|
18
|
+
let privateFileCleanupSyncFaultForTests = false;
|
|
19
|
+
const PRIVATE_STAGE_RE = /^\..+\.(\d+)\.[0-9a-f-]{36}\.tmp$/;
|
|
20
|
+
export const PRIVATE_FILE_STAGE_RETENTION_MS = 24 * 60 * 60 * 1000;
|
|
21
|
+
|
|
22
|
+
export interface PrivateFilePublishOptions {
|
|
23
|
+
/** Validate or harden the empty stage before caller-controlled bytes are written. */
|
|
24
|
+
prepareStage?: (stagePath: string) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function cleanup(path: string): void {
|
|
28
|
+
try { unlinkSync(path); } catch { /* absent/already removed */ }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function pidDefinitelyDead(pid: number): boolean {
|
|
32
|
+
try {
|
|
33
|
+
process.kill(pid, 0);
|
|
34
|
+
return false;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return (error as NodeJS.ErrnoException).code === "ESRCH";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function staleTempPrefix(finalPath: string): string {
|
|
41
|
+
return `.${basename(finalPath)}.`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function fsyncParentBestEffort(path: string): void {
|
|
45
|
+
if (process.platform === "win32") return;
|
|
46
|
+
let fd: number | null = null;
|
|
47
|
+
try {
|
|
48
|
+
fd = openSync(dirname(path), fsConstants.O_RDONLY);
|
|
49
|
+
fsyncSync(fd);
|
|
50
|
+
} catch {
|
|
51
|
+
// Cleanup durability is best-effort after unlink. Publication and crash-witness
|
|
52
|
+
// retirement use the strict path below and never swallow POSIX failures.
|
|
53
|
+
} finally {
|
|
54
|
+
if (fd !== null) closeSync(fd);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function fsyncParentStrict(path: string): void {
|
|
59
|
+
if (process.platform === "win32") return;
|
|
60
|
+
let fd: number | null = null;
|
|
61
|
+
try {
|
|
62
|
+
fd = openSync(dirname(path), fsConstants.O_RDONLY);
|
|
63
|
+
fsyncSync(fd);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
const code = (error as NodeJS.ErrnoException).code ?? "unknown";
|
|
66
|
+
const wrapped = new Error(`private-file parent directory sync failed (${code})`);
|
|
67
|
+
(wrapped as Error & { cause?: unknown }).cause = error;
|
|
68
|
+
throw wrapped;
|
|
69
|
+
} finally {
|
|
70
|
+
if (fd !== null) closeSync(fd);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function fsyncParentForPublication(path: string): void {
|
|
75
|
+
// Node does not provide a portable directory-fsync contract on Windows. The
|
|
76
|
+
// exclusive hard-link publication remains atomic there, while POSIX requires
|
|
77
|
+
// the parent directory sync before publication is reported as durable.
|
|
78
|
+
if (process.platform === "win32") return;
|
|
79
|
+
if (privateFileCommitFaultForTests === "parent_directory_sync") {
|
|
80
|
+
throw new Error("synthetic private-file parent directory sync failure");
|
|
81
|
+
}
|
|
82
|
+
fsyncParentStrict(path);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function isPrivateFileStageName(name: string): boolean {
|
|
86
|
+
return PRIVATE_STAGE_RE.test(name);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isPrivateRegularStage(stats: Stats): boolean {
|
|
90
|
+
return stats.isFile() && !stats.isSymbolicLink();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function shouldReclaimPrivateFileStage(dir: string, name: string, nowMs: number): boolean {
|
|
94
|
+
const match = PRIVATE_STAGE_RE.exec(name);
|
|
95
|
+
if (!match) return false;
|
|
96
|
+
const pid = Number(match[1]);
|
|
97
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
98
|
+
|
|
99
|
+
let stats: Stats;
|
|
100
|
+
try {
|
|
101
|
+
stats = lstatSync(join(dir, name));
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return false;
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
if (!isPrivateRegularStage(stats)) return false;
|
|
107
|
+
|
|
108
|
+
const expired = nowMs - stats.mtimeMs > PRIVATE_FILE_STAGE_RETENTION_MS;
|
|
109
|
+
const dead = pid !== process.pid && pidDefinitelyDead(pid);
|
|
110
|
+
return expired || dead;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Reclaim private-file stages whose writer is dead or whose crash witness is past the retention window. */
|
|
114
|
+
export function cleanupStalePrivateFileStagesInDir(dir: string): void {
|
|
115
|
+
let names: string[];
|
|
116
|
+
try {
|
|
117
|
+
names = readdirSync(dir);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return;
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
const nowMs = Date.now();
|
|
123
|
+
const reclaimable = names.filter((name) => shouldReclaimPrivateFileStage(dir, name, nowMs));
|
|
124
|
+
if (reclaimable.length === 0) return;
|
|
125
|
+
|
|
126
|
+
// A stale stage can be the hard-link witness for a final name that was linked
|
|
127
|
+
// before a crash or directory-sync failure. Make that final directory entry
|
|
128
|
+
// durable before removing any such witness.
|
|
129
|
+
if (process.platform !== "win32" && privateFileCleanupSyncFaultForTests) {
|
|
130
|
+
throw new Error("synthetic private-file cleanup parent directory sync failure");
|
|
131
|
+
}
|
|
132
|
+
fsyncParentStrict(join(dir, "."));
|
|
133
|
+
|
|
134
|
+
let changed = false;
|
|
135
|
+
for (const name of reclaimable) {
|
|
136
|
+
try {
|
|
137
|
+
unlinkSync(join(dir, name));
|
|
138
|
+
changed = true;
|
|
139
|
+
} catch {
|
|
140
|
+
// Another cleanup or writer may have removed it after enumeration.
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (changed) fsyncParentBestEffort(join(dir, "."));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Reclaim staging links from dead writers or expired crash witnesses. */
|
|
147
|
+
export function cleanupStalePrivateFileStages(finalPath: string): void {
|
|
148
|
+
cleanupStalePrivateFileStagesInDir(dirname(finalPath));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Remove only stage links that already reference the durable final inode. */
|
|
152
|
+
function cleanupPublishedPrivateFileStages(finalPath: string): void {
|
|
153
|
+
let finalStats;
|
|
154
|
+
try {
|
|
155
|
+
finalStats = lstatSync(finalPath);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return;
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
if (!finalStats.isFile() || finalStats.isSymbolicLink()) return;
|
|
161
|
+
|
|
162
|
+
const dir = dirname(finalPath);
|
|
163
|
+
const prefix = staleTempPrefix(finalPath);
|
|
164
|
+
let changed = false;
|
|
165
|
+
for (const name of readdirSync(dir)) {
|
|
166
|
+
if (!name.startsWith(prefix) || !PRIVATE_STAGE_RE.test(name)) continue;
|
|
167
|
+
const stagePath = join(dir, name);
|
|
168
|
+
try {
|
|
169
|
+
const stageStats = lstatSync(stagePath);
|
|
170
|
+
if (!stageStats.isFile() || stageStats.isSymbolicLink()) continue;
|
|
171
|
+
if (stageStats.dev !== finalStats.dev || stageStats.ino !== finalStats.ino) continue;
|
|
172
|
+
unlinkSync(stagePath);
|
|
173
|
+
changed = true;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (changed) fsyncParentBestEffort(finalPath);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function writeAll(fd: number, bytes: Uint8Array): void {
|
|
182
|
+
let offset = 0;
|
|
183
|
+
while (offset < bytes.byteLength) {
|
|
184
|
+
const count = writeSync(fd, bytes, offset, bytes.byteLength - offset);
|
|
185
|
+
if (count <= 0) throw new Error("private file write made no progress");
|
|
186
|
+
offset += count;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Publish immutable mode-0600 bytes without ever exposing a partially-written final path.
|
|
192
|
+
* The caller owns EEXIST comparison semantics because some objects are idempotent and
|
|
193
|
+
* others are identity conflicts. Staging files are target-scoped and stale stages from
|
|
194
|
+
* definitely-dead writers are reclaimed on the next read or publication attempt.
|
|
195
|
+
*/
|
|
196
|
+
export function publishPrivateFileExclusive(
|
|
197
|
+
finalPath: string,
|
|
198
|
+
bytes: Uint8Array,
|
|
199
|
+
options: PrivateFilePublishOptions = {},
|
|
200
|
+
): { created: boolean } {
|
|
201
|
+
cleanupStalePrivateFileStages(finalPath);
|
|
202
|
+
const tempPath = join(
|
|
203
|
+
dirname(finalPath),
|
|
204
|
+
`${staleTempPrefix(finalPath)}${process.pid}.${randomUUID()}.tmp`,
|
|
205
|
+
);
|
|
206
|
+
let fd: number | null = null;
|
|
207
|
+
let preservePublishedStage = false;
|
|
208
|
+
try {
|
|
209
|
+
fd = openSync(tempPath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, 0o600);
|
|
210
|
+
// Secret callers can harden the empty stage before any sensitive bytes exist.
|
|
211
|
+
// A failure here can therefore leave at most an empty cleanup witness.
|
|
212
|
+
options.prepareStage?.(tempPath);
|
|
213
|
+
writeAll(fd, bytes);
|
|
214
|
+
fsyncSync(fd);
|
|
215
|
+
closeSync(fd);
|
|
216
|
+
fd = null;
|
|
217
|
+
|
|
218
|
+
if (privateFileCommitFaultForTests === "before_publish") {
|
|
219
|
+
throw new Error("synthetic private-file commit failure before publish");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
linkSync(tempPath, finalPath);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
if ((error as NodeJS.ErrnoException).code === "EEXIST") {
|
|
226
|
+
// A prior publication may have linked the final entry but failed while
|
|
227
|
+
// syncing the parent directory. Re-sync before reporting idempotent success,
|
|
228
|
+
// then remove only stages that are hard links to that durable final inode.
|
|
229
|
+
fsyncParentForPublication(finalPath);
|
|
230
|
+
cleanupPublishedPrivateFileStages(finalPath);
|
|
231
|
+
return { created: false };
|
|
232
|
+
}
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
fsyncParentForPublication(finalPath);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
// The final name exists, but POSIX durability was not established. Keep this
|
|
239
|
+
// exact hard-link stage so a retry can re-sync and then identify it by inode.
|
|
240
|
+
preservePublishedStage = true;
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
return { created: true };
|
|
244
|
+
} finally {
|
|
245
|
+
if (fd !== null) closeSync(fd);
|
|
246
|
+
if (!preservePublishedStage) {
|
|
247
|
+
cleanup(tempPath);
|
|
248
|
+
fsyncParentBestEffort(finalPath);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Test-only fault seam at the atomic publication point. Import this module directly in tests. */
|
|
254
|
+
export function setPrivateFileCommitFaultForTests(fault: PrivateFileCommitFault): void {
|
|
255
|
+
privateFileCommitFaultForTests = fault;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** Test-only fault seam for strict stale-stage cleanup durability. */
|
|
259
|
+
export function setPrivateFileCleanupSyncFaultForTests(enabled: boolean): void {
|
|
260
|
+
privateFileCleanupSyncFaultForTests = enabled;
|
|
261
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { CompatibilityVerdict } from "../constants";
|
|
2
|
+
import type { ObservationEvent, ProtocolSubjectV1 } from "../events/types";
|
|
3
|
+
import { validatePublicEvidenceAuthorities } from "./community-authority";
|
|
4
|
+
import { publicEvidenceId } from "./ids";
|
|
5
|
+
import { validatePublicEvidenceRecordPrivacy } from "./privacy";
|
|
6
|
+
import { publicUtcDay } from "./time";
|
|
7
|
+
import {
|
|
8
|
+
PUBLIC_ADAPTER_FAMILIES,
|
|
9
|
+
type PublicAdapterFamily,
|
|
10
|
+
type PublicEvidenceProjectionResult,
|
|
11
|
+
type PublicEvidenceRecordV1,
|
|
12
|
+
type PublicIncidentRefV1,
|
|
13
|
+
type PublicProtocolSubjectV1,
|
|
14
|
+
} from "./types";
|
|
15
|
+
import {
|
|
16
|
+
isPublicIncidentRef,
|
|
17
|
+
PublicEvidenceValidationError,
|
|
18
|
+
validatePublicEvidenceRecord,
|
|
19
|
+
} from "./validate";
|
|
20
|
+
|
|
21
|
+
const PROJECTOR_INVARIANT_ERROR_CODES = new Set([
|
|
22
|
+
"subject_id_mismatch",
|
|
23
|
+
"record_id_mismatch",
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
export interface ProjectPublicEvidenceRecordInput {
|
|
27
|
+
observation: ObservationEvent;
|
|
28
|
+
verdict: CompatibilityVerdict;
|
|
29
|
+
incidentRefs?: string[];
|
|
30
|
+
publicArtifactRefs?: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function asPublicAdapterFamily(value: string): PublicAdapterFamily | undefined {
|
|
34
|
+
return (PUBLIC_ADAPTER_FAMILIES as readonly string[]).includes(value)
|
|
35
|
+
? value as PublicAdapterFamily
|
|
36
|
+
: undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function projectProtocolSubject(subject: ProtocolSubjectV1): PublicProtocolSubjectV1 | undefined {
|
|
40
|
+
const adapterFamily = asPublicAdapterFamily(subject.effectiveAdapter);
|
|
41
|
+
if (!adapterFamily) return undefined;
|
|
42
|
+
return {
|
|
43
|
+
subjectKind: "protocol",
|
|
44
|
+
compatibilityVersion: subject.opencodexCompatibilityVersion,
|
|
45
|
+
adapterFamily,
|
|
46
|
+
inboundProtocol: subject.inboundProtocol,
|
|
47
|
+
upstreamProtocol: subject.upstreamProtocol,
|
|
48
|
+
surface: subject.surface,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function projectIncidentRefs(values: string[] | undefined): PublicIncidentRefV1[] | undefined {
|
|
53
|
+
if (values === undefined) return undefined;
|
|
54
|
+
if (values.some((value) => !isPublicIncidentRef(value))) return undefined;
|
|
55
|
+
return values.map((corpusId) => ({ corpusId }));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Project one local observation into the closed public V1 record shape and apply the
|
|
60
|
+
* complete reviewed authority/privacy boundary before exposing it as exportable.
|
|
61
|
+
*
|
|
62
|
+
* Route and task observations deliberately fail closed here. Persisted RouteSubjectV1
|
|
63
|
+
* contains installation-salted provider-instance and endpoint identity, so the exact
|
|
64
|
+
* public/default route cannot be proven from ledger bytes alone. Dropping those fields
|
|
65
|
+
* would broaden a private exact route into a misleading public claim.
|
|
66
|
+
*/
|
|
67
|
+
export function projectPublicEvidenceRecord(
|
|
68
|
+
input: ProjectPublicEvidenceRecordInput,
|
|
69
|
+
): PublicEvidenceProjectionResult {
|
|
70
|
+
const { observation } = input;
|
|
71
|
+
|
|
72
|
+
if (observation.evidenceLayer === "live_route_compatibility" || observation.evidenceLayer === "task_effectiveness") {
|
|
73
|
+
return { status: "not_exportable", reason: "private_route_identity" };
|
|
74
|
+
}
|
|
75
|
+
if (observation.evidenceLayer !== "protocol_conformance" || observation.subject.subjectKind !== "protocol") {
|
|
76
|
+
return { status: "not_exportable", reason: "unsupported_subject" };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const subject = projectProtocolSubject(observation.subject);
|
|
80
|
+
if (!subject) return { status: "not_exportable", reason: "unsupported_adapter_family" };
|
|
81
|
+
|
|
82
|
+
const incidentRefs = projectIncidentRefs(input.incidentRefs);
|
|
83
|
+
if (input.incidentRefs !== undefined && incidentRefs === undefined) {
|
|
84
|
+
return { status: "not_exportable", reason: "unsafe_public_field" };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const subjectId = publicEvidenceId("subject", subject);
|
|
89
|
+
const withoutRecordId: Omit<PublicEvidenceRecordV1, "recordId"> = {
|
|
90
|
+
subjectId,
|
|
91
|
+
evidenceLayer: "protocol_conformance",
|
|
92
|
+
suiteId: observation.suiteId,
|
|
93
|
+
suiteVersion: observation.suiteVersion,
|
|
94
|
+
scenarioId: observation.scenarioId,
|
|
95
|
+
scenarioVersion: observation.scenarioVersion,
|
|
96
|
+
verdict: input.verdict,
|
|
97
|
+
observedDayUtc: publicUtcDay(observation.completedAt),
|
|
98
|
+
subject,
|
|
99
|
+
assertions: observation.assertions.map((assertion) => ({
|
|
100
|
+
id: assertion.id,
|
|
101
|
+
required: assertion.required,
|
|
102
|
+
passed: assertion.passed,
|
|
103
|
+
})),
|
|
104
|
+
...(incidentRefs !== undefined ? { incidentRefs } : {}),
|
|
105
|
+
...(input.publicArtifactRefs !== undefined ? { artifactRefs: [...input.publicArtifactRefs] } : {}),
|
|
106
|
+
};
|
|
107
|
+
const record = validatePublicEvidenceRecord({
|
|
108
|
+
recordId: publicEvidenceId("record", withoutRecordId),
|
|
109
|
+
...withoutRecordId,
|
|
110
|
+
});
|
|
111
|
+
validatePublicEvidenceAuthorities([record]);
|
|
112
|
+
validatePublicEvidenceRecordPrivacy(record);
|
|
113
|
+
return { status: "exportable", record };
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if (error instanceof PublicEvidenceValidationError) {
|
|
116
|
+
if (PROJECTOR_INVARIANT_ERROR_CODES.has(error.code)) throw error;
|
|
117
|
+
return { status: "not_exportable", reason: "unsafe_public_field", detailCode: error.code };
|
|
118
|
+
}
|
|
119
|
+
if (error instanceof TypeError && error.message.startsWith("jcsStringify:")) {
|
|
120
|
+
return { status: "not_exportable", reason: "unsafe_public_field" };
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type PublicEvidencePurgeFaultForTests =
|
|
2
|
+
| "before_export_delete"
|
|
3
|
+
| "export_directory_sync"
|
|
4
|
+
| null;
|
|
5
|
+
|
|
6
|
+
let purgeFaultForTests: PublicEvidencePurgeFaultForTests = null;
|
|
7
|
+
|
|
8
|
+
/** Arms the internal deterministic fault seam and returns a scoped restore handle. */
|
|
9
|
+
export function setPublicEvidencePurgeFaultForTests(
|
|
10
|
+
fault: PublicEvidencePurgeFaultForTests,
|
|
11
|
+
): () => void {
|
|
12
|
+
const previous = purgeFaultForTests;
|
|
13
|
+
purgeFaultForTests = fault;
|
|
14
|
+
return () => {
|
|
15
|
+
purgeFaultForTests = previous;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function publicEvidencePurgeFaultForTests(): PublicEvidencePurgeFaultForTests {
|
|
20
|
+
return purgeFaultForTests;
|
|
21
|
+
}
|