@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,353 @@
|
|
|
1
|
+
import { replayLabLedger } from "../ledger/store";
|
|
2
|
+
import { labLedgerPath } from "../paths";
|
|
3
|
+
import { queryLabEvents, queryLabVerdicts } from "../query";
|
|
4
|
+
import type { ObservationEvent } from "../events/types";
|
|
5
|
+
import {
|
|
6
|
+
importCommunityEvidenceBundle,
|
|
7
|
+
listCommunityEvidence,
|
|
8
|
+
} from "./community";
|
|
9
|
+
import { readPrivateRegularFile } from "./file-safety";
|
|
10
|
+
import { withPublicEvidenceMutationLock } from "./mutation-lock";
|
|
11
|
+
import { recordLocalPublicOrigin } from "./origin";
|
|
12
|
+
import type { ProjectPublicEvidenceRecordInput } from "./project";
|
|
13
|
+
import { projectPublicEvidenceRecord } from "./project";
|
|
14
|
+
import {
|
|
15
|
+
signPublicEvidenceBundle,
|
|
16
|
+
verifyPublicEvidenceBundle,
|
|
17
|
+
} from "./signature";
|
|
18
|
+
import { storePublicEvidenceBundle } from "./storage";
|
|
19
|
+
import { parseStrictPublicJson } from "./strict-json";
|
|
20
|
+
import { publicUtcDay } from "./time";
|
|
21
|
+
import { PUBLIC_EVIDENCE_BUNDLE_SCHEMA_VERSION, PUBLIC_EXPORT_POLICY_VERSION } from "./types";
|
|
22
|
+
import type {
|
|
23
|
+
PublicEvidenceBundleV1,
|
|
24
|
+
PublicEvidencePreviewBundleV1,
|
|
25
|
+
PublicEvidenceRecordV1,
|
|
26
|
+
PublicProjectionNotExportableReason,
|
|
27
|
+
} from "./types";
|
|
28
|
+
import { PublicEvidenceValidationError } from "./validate";
|
|
29
|
+
|
|
30
|
+
const MAX_OPERATOR_EVENTS = 256;
|
|
31
|
+
const MAX_PUBLIC_FILE_BYTES = 2 * 1024 * 1024;
|
|
32
|
+
const EMPTY_PREVIEW_DAY = "1970-01-01";
|
|
33
|
+
const PRIVATE_STORAGE_LOCATOR = "<private>";
|
|
34
|
+
|
|
35
|
+
export interface ProjectPublicEvidenceInput {
|
|
36
|
+
records: ProjectPublicEvidenceRecordInput[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function projectPublicEvidence(input: ProjectPublicEvidenceInput): {
|
|
40
|
+
bundle: PublicEvidencePreviewBundleV1;
|
|
41
|
+
excluded: Array<{ index: number; reason: PublicProjectionNotExportableReason }>;
|
|
42
|
+
} {
|
|
43
|
+
const records: PublicEvidenceRecordV1[] = [];
|
|
44
|
+
const excluded: Array<{ index: number; reason: PublicProjectionNotExportableReason }> = [];
|
|
45
|
+
let latestExportableCompletedAt: number | null = null;
|
|
46
|
+
|
|
47
|
+
input.records.forEach((recordInput, index) => {
|
|
48
|
+
const projected = projectPublicEvidenceRecord(recordInput);
|
|
49
|
+
if (projected.status !== "exportable") {
|
|
50
|
+
excluded.push({ index, reason: projected.reason });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
records.push(projected.record);
|
|
54
|
+
latestExportableCompletedAt = Math.max(
|
|
55
|
+
latestExportableCompletedAt ?? recordInput.observation.completedAt,
|
|
56
|
+
recordInput.observation.completedAt,
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
records.sort((a, b) => a.recordId < b.recordId ? -1 : a.recordId > b.recordId ? 1 : 0);
|
|
60
|
+
return {
|
|
61
|
+
bundle: {
|
|
62
|
+
schemaVersion: PUBLIC_EVIDENCE_BUNDLE_SCHEMA_VERSION,
|
|
63
|
+
exportPolicyVersion: PUBLIC_EXPORT_POLICY_VERSION,
|
|
64
|
+
createdDayUtc: latestExportableCompletedAt === null
|
|
65
|
+
? EMPTY_PREVIEW_DAY
|
|
66
|
+
: publicUtcDay(latestExportableCompletedAt),
|
|
67
|
+
records,
|
|
68
|
+
artifacts: [],
|
|
69
|
+
},
|
|
70
|
+
excluded,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type PublicOperatorExclusionReason =
|
|
75
|
+
| PublicProjectionNotExportableReason
|
|
76
|
+
| "event_not_found"
|
|
77
|
+
| "not_observation"
|
|
78
|
+
| "event_excluded"
|
|
79
|
+
| "no_canonical_verdict";
|
|
80
|
+
|
|
81
|
+
export interface PublicOperatorExclusionV1 {
|
|
82
|
+
selectionIndex: number;
|
|
83
|
+
reason: PublicOperatorExclusionReason;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface LocalPublicPreviewV1 {
|
|
87
|
+
bundle: PublicEvidencePreviewBundleV1;
|
|
88
|
+
excluded: PublicOperatorExclusionV1[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface LocalPublicExportV1 {
|
|
92
|
+
bundle: PublicEvidenceBundleV1;
|
|
93
|
+
stored: { path: typeof PRIVATE_STORAGE_LOCATOR; created: boolean };
|
|
94
|
+
excluded: PublicOperatorExclusionV1[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export type PublicVerificationSummaryV1 =
|
|
98
|
+
| { status: "cryptographically_valid"; bundleId: string; publisherKeyId: string; locallyVerified: false }
|
|
99
|
+
| { status: "schema_rejected" | "digest_invalid" | "signature_invalid"; locallyVerified: false };
|
|
100
|
+
|
|
101
|
+
function assertOperatorEventIds(eventIds: readonly string[]): Array<{ eventId: string; selectionIndex: number }> {
|
|
102
|
+
if (eventIds.length === 0 || eventIds.length > MAX_OPERATOR_EVENTS) {
|
|
103
|
+
throw new PublicEvidenceValidationError(
|
|
104
|
+
"public_selection_limit",
|
|
105
|
+
`public evidence selection must contain 1..${MAX_OPERATOR_EVENTS} event ids`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
const unique: Array<{ eventId: string; selectionIndex: number }> = [];
|
|
109
|
+
const seen = new Set<string>();
|
|
110
|
+
for (const [selectionIndex, eventId] of eventIds.entries()) {
|
|
111
|
+
if (!/^[0-9a-f]{64}$/.test(eventId)) {
|
|
112
|
+
throw new PublicEvidenceValidationError(
|
|
113
|
+
"public_selection_event_id",
|
|
114
|
+
"public evidence event ids must be lowercase sha256 hex",
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (seen.has(eventId)) continue;
|
|
118
|
+
seen.add(eventId);
|
|
119
|
+
unique.push({ eventId, selectionIndex });
|
|
120
|
+
}
|
|
121
|
+
return unique;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function projectedObservationState(
|
|
125
|
+
eventIds: readonly string[],
|
|
126
|
+
configDir?: string,
|
|
127
|
+
): Map<string, { excluded: boolean }> {
|
|
128
|
+
const pending = new Set(eventIds);
|
|
129
|
+
const state = new Map<string, { excluded: boolean }>();
|
|
130
|
+
let cursor: string | undefined;
|
|
131
|
+
|
|
132
|
+
while (pending.size > 0) {
|
|
133
|
+
const page = queryLabEvents({ eventKind: "observation" }, cursor, 200, configDir);
|
|
134
|
+
for (const row of page.items) {
|
|
135
|
+
if (!pending.has(row.eventId)) continue;
|
|
136
|
+
state.set(row.eventId, { excluded: row.excluded });
|
|
137
|
+
pending.delete(row.eventId);
|
|
138
|
+
}
|
|
139
|
+
if (!page.hasMore || !page.nextCursor) break;
|
|
140
|
+
cursor = page.nextCursor;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return state;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function canonicalVerdictsForObservations(
|
|
147
|
+
observations: readonly ObservationEvent[],
|
|
148
|
+
configDir?: string,
|
|
149
|
+
): Map<string, ProjectPublicEvidenceRecordInput["verdict"]> {
|
|
150
|
+
const verdictByEventId = new Map<string, ProjectPublicEvidenceRecordInput["verdict"]>();
|
|
151
|
+
const groups = new Map<string, {
|
|
152
|
+
subjectId: string;
|
|
153
|
+
evidenceLayer: ObservationEvent["evidenceLayer"];
|
|
154
|
+
suiteId: string;
|
|
155
|
+
observations: ObservationEvent[];
|
|
156
|
+
}>();
|
|
157
|
+
|
|
158
|
+
for (const observation of observations) {
|
|
159
|
+
const key = `${observation.subjectId}\0${observation.evidenceLayer}\0${observation.suiteId}`;
|
|
160
|
+
const existing = groups.get(key);
|
|
161
|
+
if (existing) existing.observations.push(observation);
|
|
162
|
+
else groups.set(key, {
|
|
163
|
+
subjectId: observation.subjectId,
|
|
164
|
+
evidenceLayer: observation.evidenceLayer,
|
|
165
|
+
suiteId: observation.suiteId,
|
|
166
|
+
observations: [observation],
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for (const group of groups.values()) {
|
|
171
|
+
const pending = new Map(group.observations.map((observation) => [observation.eventId, observation] as const));
|
|
172
|
+
let cursor: string | undefined;
|
|
173
|
+
while (pending.size > 0) {
|
|
174
|
+
const page = queryLabVerdicts({
|
|
175
|
+
subjectId: group.subjectId,
|
|
176
|
+
layer: group.evidenceLayer,
|
|
177
|
+
suiteId: group.suiteId,
|
|
178
|
+
}, cursor, 200, configDir);
|
|
179
|
+
for (const row of page.items) {
|
|
180
|
+
for (const eventId of row.contributingEventIds) {
|
|
181
|
+
const observation = pending.get(eventId);
|
|
182
|
+
if (!observation) continue;
|
|
183
|
+
if (
|
|
184
|
+
row.subjectId !== observation.subjectId
|
|
185
|
+
|| row.evidenceLayer !== observation.evidenceLayer
|
|
186
|
+
|| row.suiteId !== observation.suiteId
|
|
187
|
+
|| row.suiteVersion !== observation.suiteVersion
|
|
188
|
+
) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
verdictByEventId.set(eventId, row.verdict);
|
|
192
|
+
pending.delete(eventId);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (!page.hasMore || !page.nextCursor) break;
|
|
196
|
+
cursor = page.nextCursor;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return verdictByEventId;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function previewLocalPublicEvidence(
|
|
204
|
+
input: { eventIds: readonly string[] },
|
|
205
|
+
configDir?: string,
|
|
206
|
+
): LocalPublicPreviewV1 {
|
|
207
|
+
const selections = assertOperatorEventIds(input.eventIds);
|
|
208
|
+
const replay = replayLabLedger(labLedgerPath(configDir));
|
|
209
|
+
const byId = new Map(replay.events.map((event) => [event.eventId, event] as const));
|
|
210
|
+
const observationSelections: Array<{ observation: ObservationEvent; selectionIndex: number }> = [];
|
|
211
|
+
const excluded: PublicOperatorExclusionV1[] = [];
|
|
212
|
+
|
|
213
|
+
for (const { eventId, selectionIndex } of selections) {
|
|
214
|
+
const event = byId.get(eventId);
|
|
215
|
+
if (!event) {
|
|
216
|
+
excluded.push({ selectionIndex, reason: "event_not_found" });
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (event.eventKind !== "observation") {
|
|
220
|
+
excluded.push({ selectionIndex, reason: "not_observation" });
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
observationSelections.push({ observation: event, selectionIndex });
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (observationSelections.length === 0) {
|
|
227
|
+
throw new PublicEvidenceValidationError("public_selection_empty", "public evidence selection contains no observation events");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const projectionByEventId = projectedObservationState(
|
|
231
|
+
observationSelections.map(({ observation }) => observation.eventId),
|
|
232
|
+
configDir,
|
|
233
|
+
);
|
|
234
|
+
const candidates: Array<{ observation: ObservationEvent; selectionIndex: number }> = [];
|
|
235
|
+
for (const candidate of observationSelections) {
|
|
236
|
+
const projectedEvent = projectionByEventId.get(candidate.observation.eventId);
|
|
237
|
+
if (!projectedEvent) {
|
|
238
|
+
excluded.push({ selectionIndex: candidate.selectionIndex, reason: "event_not_found" });
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (projectedEvent.excluded) {
|
|
242
|
+
excluded.push({ selectionIndex: candidate.selectionIndex, reason: "event_excluded" });
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
candidates.push(candidate);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const verdictByEventId = canonicalVerdictsForObservations(
|
|
249
|
+
candidates.map((candidate) => candidate.observation),
|
|
250
|
+
configDir,
|
|
251
|
+
);
|
|
252
|
+
const projectInputs: ProjectPublicEvidenceRecordInput[] = [];
|
|
253
|
+
const projectSelectionIndices: number[] = [];
|
|
254
|
+
for (const { observation, selectionIndex } of candidates) {
|
|
255
|
+
const verdict = verdictByEventId.get(observation.eventId);
|
|
256
|
+
if (!verdict) {
|
|
257
|
+
excluded.push({ selectionIndex, reason: "no_canonical_verdict" });
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
projectInputs.push({ observation, verdict });
|
|
261
|
+
projectSelectionIndices.push(selectionIndex);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const projected = projectPublicEvidence({ records: projectInputs });
|
|
265
|
+
for (const row of projected.excluded) {
|
|
266
|
+
excluded.push({ selectionIndex: projectSelectionIndices[row.index]!, reason: row.reason });
|
|
267
|
+
}
|
|
268
|
+
excluded.sort((a, b) => a.selectionIndex - b.selectionIndex);
|
|
269
|
+
return { bundle: projected.bundle, excluded };
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function exportLocalPublicEvidence(
|
|
273
|
+
input: { eventIds: readonly string[] },
|
|
274
|
+
configDir?: string,
|
|
275
|
+
): LocalPublicExportV1 {
|
|
276
|
+
const preview = previewLocalPublicEvidence(input, configDir);
|
|
277
|
+
if (preview.bundle.records.length === 0) {
|
|
278
|
+
throw new PublicEvidenceValidationError("public_export_empty", "selected events produced no exportable public evidence records");
|
|
279
|
+
}
|
|
280
|
+
const bundle = signPublicEvidenceBundle({
|
|
281
|
+
records: preview.bundle.records,
|
|
282
|
+
artifacts: preview.bundle.artifacts,
|
|
283
|
+
createdDayUtc: preview.bundle.createdDayUtc,
|
|
284
|
+
configDir,
|
|
285
|
+
});
|
|
286
|
+
return withPublicEvidenceMutationLock(configDir, () => {
|
|
287
|
+
// Commit purge-owned provenance first. If export publication later fails or the
|
|
288
|
+
// process crashes, an orphan marker is conservative and can be reclaimed later;
|
|
289
|
+
// the inverse state, a durable export without provenance, is not acceptable.
|
|
290
|
+
recordLocalPublicOrigin({ publisherKeyId: bundle.publisher.keyId, bundleId: bundle.bundleId }, configDir);
|
|
291
|
+
const stored = storePublicEvidenceBundle(bundle, configDir);
|
|
292
|
+
return {
|
|
293
|
+
bundle,
|
|
294
|
+
stored: { path: PRIVATE_STORAGE_LOCATOR, created: stored.created },
|
|
295
|
+
excluded: preview.excluded,
|
|
296
|
+
};
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function summarizePublicEvidenceVerification(raw: unknown): PublicVerificationSummaryV1 {
|
|
301
|
+
const result = verifyPublicEvidenceBundle(raw as PublicEvidenceBundleV1);
|
|
302
|
+
if (result.status !== "cryptographically_valid") {
|
|
303
|
+
return { status: result.status, locallyVerified: false };
|
|
304
|
+
}
|
|
305
|
+
const bundle = raw as PublicEvidenceBundleV1;
|
|
306
|
+
return {
|
|
307
|
+
status: "cryptographically_valid",
|
|
308
|
+
bundleId: bundle.bundleId,
|
|
309
|
+
publisherKeyId: bundle.publisher.keyId,
|
|
310
|
+
locallyVerified: false,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function readBoundedPublicFile(path: string): Buffer {
|
|
315
|
+
return readPrivateRegularFile(path, {
|
|
316
|
+
maxBytes: MAX_PUBLIC_FILE_BYTES,
|
|
317
|
+
errorCode: "public_file_unsafe",
|
|
318
|
+
errorMessage: "public evidence input must be a regular non-symlink file",
|
|
319
|
+
sizeErrorCode: "public_file_too_large",
|
|
320
|
+
sizeErrorMessage: "public evidence input exceeds 2 MiB",
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function parsePublicFile(path: string): unknown {
|
|
325
|
+
return parseStrictPublicJson(readBoundedPublicFile(path), "public evidence input", "public_file_json");
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export function verifyPublicEvidenceFile(path: string): PublicVerificationSummaryV1 {
|
|
329
|
+
return summarizePublicEvidenceVerification(parsePublicFile(path));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function finishCommunityImport(
|
|
333
|
+
stored: { path: string; created: boolean; bundleId: string; publisherKeyId: string },
|
|
334
|
+
) {
|
|
335
|
+
const { path: _privatePath, ...imported } = stored;
|
|
336
|
+
return { ...imported, trustClass: "community_untrusted_v1" as const, locallyVerified: false as const };
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export function importCommunityEvidenceFile(path: string, configDir?: string) {
|
|
340
|
+
return finishCommunityImport(importCommunityEvidenceBundle(readBoundedPublicFile(path), configDir));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function importCommunityEvidenceValue(raw: unknown, configDir?: string) {
|
|
344
|
+
return finishCommunityImport(importCommunityEvidenceBundle(raw, configDir));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export function listCommunityEvidenceContext(configDir?: string) {
|
|
348
|
+
return {
|
|
349
|
+
evidence: listCommunityEvidence(configDir),
|
|
350
|
+
trustClass: "community_untrusted_v1" as const,
|
|
351
|
+
locallyVerified: false as const,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { ensureLabDirs, labPublicOriginDir } from "../paths";
|
|
4
|
+
import { readPrivateRegularFile } from "./file-safety";
|
|
5
|
+
import { cleanupStalePrivateFileStagesInDir, isPrivateFileStageName } from "./private-file";
|
|
6
|
+
import { parseStrictPublicJson } from "./strict-json";
|
|
7
|
+
|
|
8
|
+
const MAX_ORIGIN_BYTES = 1024;
|
|
9
|
+
const ORIGIN_RE = /^origin-([0-9a-f]{64})-([0-9a-f]{64})\.json$/;
|
|
10
|
+
|
|
11
|
+
export interface PurgeOriginIdentity {
|
|
12
|
+
publisherKeyId: string;
|
|
13
|
+
bundleId: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface PurgeOriginRecovery {
|
|
17
|
+
identities: PurgeOriginIdentity[];
|
|
18
|
+
skipped: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Purge must salvage each provenance marker independently. A corrupt marker is untrusted
|
|
23
|
+
* and skipped, but it cannot hide later valid markers that are needed to classify local
|
|
24
|
+
* community copies after the export or publisher key is unavailable. The operational
|
|
25
|
+
* 1024-marker quota is deliberately not a read cutoff here: recovery must inspect every
|
|
26
|
+
* valid-format marker present after a race/crash instead of silently losing provenance.
|
|
27
|
+
*/
|
|
28
|
+
export function recoverPublicOriginsForPurge(configDir?: string): PurgeOriginRecovery {
|
|
29
|
+
ensureLabDirs(configDir);
|
|
30
|
+
const dir = labPublicOriginDir(configDir);
|
|
31
|
+
cleanupStalePrivateFileStagesInDir(dir);
|
|
32
|
+
const names = readdirSync(dir)
|
|
33
|
+
.filter((name) => !isPrivateFileStageName(name) && ORIGIN_RE.test(name))
|
|
34
|
+
.sort();
|
|
35
|
+
const identities: PurgeOriginIdentity[] = [];
|
|
36
|
+
let skipped = 0;
|
|
37
|
+
|
|
38
|
+
for (const name of names) {
|
|
39
|
+
const match = ORIGIN_RE.exec(name)!;
|
|
40
|
+
const expected = { publisherKeyId: match[1]!, bundleId: match[2]! };
|
|
41
|
+
try {
|
|
42
|
+
const raw = parseStrictPublicJson(
|
|
43
|
+
readPrivateRegularFile(join(dir, name), {
|
|
44
|
+
maxBytes: MAX_ORIGIN_BYTES,
|
|
45
|
+
errorCode: "public_origin_unsafe",
|
|
46
|
+
errorMessage: "public origin marker is unsafe during purge",
|
|
47
|
+
sizeErrorCode: "public_origin_unsafe",
|
|
48
|
+
sizeErrorMessage: "public origin marker exceeds its size bound",
|
|
49
|
+
requireMode600: true,
|
|
50
|
+
}),
|
|
51
|
+
"public origin marker during purge",
|
|
52
|
+
"public_origin_json",
|
|
53
|
+
);
|
|
54
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
55
|
+
skipped += 1;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const row = raw as Record<string, unknown>;
|
|
59
|
+
if (
|
|
60
|
+
Object.keys(row).sort().join(",") !== "bundleId,publisherKeyId,schemaVersion"
|
|
61
|
+
|| row.schemaVersion !== "public_origin_v1"
|
|
62
|
+
|| row.publisherKeyId !== expected.publisherKeyId
|
|
63
|
+
|| row.bundleId !== expected.bundleId
|
|
64
|
+
) {
|
|
65
|
+
skipped += 1;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
identities.push(expected);
|
|
69
|
+
} catch {
|
|
70
|
+
skipped += 1;
|
|
71
|
+
// Salvage continues with the next marker.
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { identities, skipped };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function listValidPublicOriginsForPurge(configDir?: string): PurgeOriginIdentity[] {
|
|
78
|
+
return recoverPublicOriginsForPurge(configDir).identities;
|
|
79
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { lstatSync, readdirSync, unlinkSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { jcsStringify } from "../digest";
|
|
4
|
+
import { ensureLabDirs, labCommunityDir, labExportDir, labPublicOriginDir } from "../paths";
|
|
5
|
+
import { communityBundleFileName } from "./community-files";
|
|
6
|
+
import { readPrivateRegularFile } from "./file-safety";
|
|
7
|
+
import {
|
|
8
|
+
cleanupStalePrivateFileStagesInDir,
|
|
9
|
+
isPrivateFileStageName,
|
|
10
|
+
publishPrivateFileExclusive,
|
|
11
|
+
} from "./private-file";
|
|
12
|
+
import { parseStrictPublicJson } from "./strict-json";
|
|
13
|
+
import { PublicEvidenceValidationError } from "./validate";
|
|
14
|
+
|
|
15
|
+
// The community cache itself is capped at 512 files. Keeping twice that many origin
|
|
16
|
+
// markers leaves headroom for in-flight/local exports while allowing unreferenced
|
|
17
|
+
// provenance to be reclaimed instead of permanently locking future exports.
|
|
18
|
+
const MAX_ORIGINS = 1024;
|
|
19
|
+
const MAX_ORIGIN_BYTES = 1024;
|
|
20
|
+
const ORIGIN_RE = /^origin-([0-9a-f]{64})-([0-9a-f]{64})\.json$/;
|
|
21
|
+
|
|
22
|
+
export interface PublicOriginIdentityV1 {
|
|
23
|
+
publisherKeyId: string;
|
|
24
|
+
bundleId: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function originPath(identity: PublicOriginIdentityV1, configDir?: string): string {
|
|
28
|
+
if (!/^[0-9a-f]{64}$/.test(identity.publisherKeyId) || !/^[0-9a-f]{64}$/.test(identity.bundleId)) {
|
|
29
|
+
throw new PublicEvidenceValidationError("public_origin_id", "public origin identity is invalid");
|
|
30
|
+
}
|
|
31
|
+
return join(
|
|
32
|
+
labPublicOriginDir(configDir),
|
|
33
|
+
`origin-${identity.publisherKeyId}-${identity.bundleId}.json`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function originBody(identity: PublicOriginIdentityV1): Buffer {
|
|
38
|
+
return Buffer.from(jcsStringify({
|
|
39
|
+
schemaVersion: "public_origin_v1",
|
|
40
|
+
publisherKeyId: identity.publisherKeyId,
|
|
41
|
+
bundleId: identity.bundleId,
|
|
42
|
+
}), "utf8");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function readOrigin(path: string, expected?: PublicOriginIdentityV1): PublicOriginIdentityV1 {
|
|
46
|
+
const bytes = readPrivateRegularFile(path, {
|
|
47
|
+
maxBytes: MAX_ORIGIN_BYTES,
|
|
48
|
+
errorCode: "public_origin_unsafe",
|
|
49
|
+
errorMessage: "public origin marker is not a private regular file with 0600 permissions",
|
|
50
|
+
sizeErrorCode: "public_origin_unsafe",
|
|
51
|
+
sizeErrorMessage: "public origin marker exceeds its size bound",
|
|
52
|
+
requireMode600: true,
|
|
53
|
+
});
|
|
54
|
+
const raw = parseStrictPublicJson(bytes, "public origin marker", "public_origin_json");
|
|
55
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
56
|
+
throw new PublicEvidenceValidationError("public_origin_json", "public origin marker must be an object");
|
|
57
|
+
}
|
|
58
|
+
const row = raw as Record<string, unknown>;
|
|
59
|
+
if (Object.keys(row).sort().join(",") !== "bundleId,publisherKeyId,schemaVersion"
|
|
60
|
+
|| row.schemaVersion !== "public_origin_v1"
|
|
61
|
+
|| typeof row.publisherKeyId !== "string"
|
|
62
|
+
|| typeof row.bundleId !== "string"
|
|
63
|
+
|| !/^[0-9a-f]{64}$/.test(row.publisherKeyId)
|
|
64
|
+
|| !/^[0-9a-f]{64}$/.test(row.bundleId)) {
|
|
65
|
+
throw new PublicEvidenceValidationError("public_origin_json", "public origin marker schema is invalid");
|
|
66
|
+
}
|
|
67
|
+
const identity = { publisherKeyId: row.publisherKeyId, bundleId: row.bundleId };
|
|
68
|
+
if (expected && (identity.publisherKeyId !== expected.publisherKeyId || identity.bundleId !== expected.bundleId)) {
|
|
69
|
+
throw new PublicEvidenceValidationError("public_origin_conflict", "public origin marker identity mismatch");
|
|
70
|
+
}
|
|
71
|
+
return identity;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Marker names only. Quota accounting, reclaim, and listing must agree on this set. */
|
|
75
|
+
function originNames(dir: string): string[] {
|
|
76
|
+
cleanupStalePrivateFileStagesInDir(dir);
|
|
77
|
+
return readdirSync(dir)
|
|
78
|
+
.filter((name) => !isPrivateFileStageName(name) && ORIGIN_RE.test(name))
|
|
79
|
+
.sort();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function foreignOriginNames(dir: string): string[] {
|
|
83
|
+
return readdirSync(dir)
|
|
84
|
+
.filter((name) => !isPrivateFileStageName(name) && !ORIGIN_RE.test(name))
|
|
85
|
+
.sort();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function pathExistsConservatively(path: string): boolean {
|
|
89
|
+
try {
|
|
90
|
+
lstatSync(path);
|
|
91
|
+
return true;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return false;
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function communityBundlePath(identity: PublicOriginIdentityV1, configDir?: string): string {
|
|
99
|
+
return join(
|
|
100
|
+
labCommunityDir(configDir),
|
|
101
|
+
communityBundleFileName(identity.publisherKeyId, identity.bundleId),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function localExportPath(identity: PublicOriginIdentityV1, configDir?: string): string {
|
|
106
|
+
return join(labExportDir(configDir), `${identity.bundleId}.json`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Origin markers exist to recover local provenance for community copies when the export
|
|
111
|
+
* or publisher key is later unavailable. A marker is reclaimable only when neither the
|
|
112
|
+
* exact community copy nor its matching local export still exists.
|
|
113
|
+
*/
|
|
114
|
+
function reclaimUnreferencedOrigins(
|
|
115
|
+
dir: string,
|
|
116
|
+
preservePath: string,
|
|
117
|
+
configDir?: string,
|
|
118
|
+
): void {
|
|
119
|
+
for (const name of originNames(dir)) {
|
|
120
|
+
const match = ORIGIN_RE.exec(name)!;
|
|
121
|
+
const path = join(dir, name);
|
|
122
|
+
if (path === preservePath) continue;
|
|
123
|
+
const identity = { publisherKeyId: match[1]!, bundleId: match[2]! };
|
|
124
|
+
if (pathExistsConservatively(communityBundlePath(identity, configDir))) continue;
|
|
125
|
+
if (pathExistsConservatively(localExportPath(identity, configDir))) continue;
|
|
126
|
+
try {
|
|
127
|
+
unlinkSync(path);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function recordLocalPublicOrigin(identity: PublicOriginIdentityV1, configDir?: string): void {
|
|
135
|
+
ensureLabDirs(configDir);
|
|
136
|
+
const dir = labPublicOriginDir(configDir);
|
|
137
|
+
const path = originPath(identity, configDir);
|
|
138
|
+
try {
|
|
139
|
+
readOrigin(path, identity);
|
|
140
|
+
return;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error instanceof PublicEvidenceValidationError) throw error;
|
|
143
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let names = originNames(dir);
|
|
147
|
+
if (names.length >= MAX_ORIGINS) {
|
|
148
|
+
reclaimUnreferencedOrigins(dir, path, configDir);
|
|
149
|
+
names = originNames(dir);
|
|
150
|
+
}
|
|
151
|
+
if (names.length >= MAX_ORIGINS) {
|
|
152
|
+
throw new PublicEvidenceValidationError("public_origin_bound", "public origin marker bound exceeded");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const bytes = originBody(identity);
|
|
156
|
+
const published = publishPrivateFileExclusive(path, bytes);
|
|
157
|
+
if (!published.created) {
|
|
158
|
+
readOrigin(path, identity);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Separate CLI processes can both observe one free slot before either publishes.
|
|
163
|
+
// Reclaim unreferenced history after publication, then remove only this call's marker
|
|
164
|
+
// if the directory still cannot converge inside the hard cap.
|
|
165
|
+
if (originNames(dir).length > MAX_ORIGINS) {
|
|
166
|
+
reclaimUnreferencedOrigins(dir, path, configDir);
|
|
167
|
+
if (originNames(dir).length > MAX_ORIGINS) {
|
|
168
|
+
try { unlinkSync(path); } catch { /* preserve the quota failure */ }
|
|
169
|
+
throw new PublicEvidenceValidationError("public_origin_bound", "public origin marker bound exceeded");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function listLocalPublicOrigins(configDir?: string): PublicOriginIdentityV1[] {
|
|
175
|
+
ensureLabDirs(configDir);
|
|
176
|
+
const dir = labPublicOriginDir(configDir);
|
|
177
|
+
const names = originNames(dir);
|
|
178
|
+
if (names.length > MAX_ORIGINS) {
|
|
179
|
+
throw new PublicEvidenceValidationError("public_origin_bound", "public origin marker bound exceeded");
|
|
180
|
+
}
|
|
181
|
+
if (foreignOriginNames(dir).length > 0) {
|
|
182
|
+
throw new PublicEvidenceValidationError("public_origin_unsafe", "unexpected public origin marker entry");
|
|
183
|
+
}
|
|
184
|
+
const identities: PublicOriginIdentityV1[] = [];
|
|
185
|
+
for (const name of names) {
|
|
186
|
+
const match = ORIGIN_RE.exec(name)!;
|
|
187
|
+
const expected = { publisherKeyId: match[1]!, bundleId: match[2]! };
|
|
188
|
+
identities.push(readOrigin(join(dir, name), expected));
|
|
189
|
+
}
|
|
190
|
+
return identities;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function clearLocalPublicOrigins(configDir?: string): void {
|
|
194
|
+
ensureLabDirs(configDir);
|
|
195
|
+
const dir = labPublicOriginDir(configDir);
|
|
196
|
+
cleanupStalePrivateFileStagesInDir(dir);
|
|
197
|
+
for (const name of readdirSync(dir)) {
|
|
198
|
+
if (!ORIGIN_RE.test(name)) continue;
|
|
199
|
+
try { unlinkSync(join(dir, name)); } catch (error) {
|
|
200
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|