codex-multi-auth 2.17.2 → 2.18.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/.codex-plugin/plugin.json +1 -1
- package/README.md +86 -425
- package/config/README.md +1 -1
- package/config/codex-legacy.json +12 -212
- package/config/codex-modern.json +4 -80
- package/config/minimal-codex.json +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/lib/account-policy.d.ts +18 -2
- package/dist/lib/account-policy.js +97 -40
- package/dist/lib/accounts/rate-limits.d.ts +0 -1
- package/dist/lib/accounts.d.ts +0 -1
- package/dist/lib/accounts.js +4 -5
- package/dist/lib/api-route-store.d.ts +0 -1
- package/dist/lib/audit.d.ts +0 -1
- package/dist/lib/audit.js +43 -12
- package/dist/lib/auth/account-access.d.ts +0 -1
- package/dist/lib/auth/account-access.js +5 -1
- package/dist/lib/auth/auth.d.ts +4 -3
- package/dist/lib/auth/auth.js +220 -28
- package/dist/lib/auth/browser.d.ts +0 -1
- package/dist/lib/auth/callback-guidance.d.ts +0 -1
- package/dist/lib/auth/device-auth.d.ts +0 -1
- package/dist/lib/auth/index.d.ts +0 -1
- package/dist/lib/auth/org-override.d.ts +0 -1
- package/dist/lib/auth/server.d.ts +1 -2
- package/dist/lib/auth/server.js +100 -53
- package/dist/lib/auth/token-utils.d.ts +0 -1
- package/dist/lib/auth-rate-limit.d.ts +0 -1
- package/dist/lib/budget-guard.d.ts +16 -2
- package/dist/lib/budget-guard.js +123 -43
- package/dist/lib/capability-policy.d.ts +0 -1
- package/dist/lib/circuit-breaker.d.ts +20 -1
- package/dist/lib/circuit-breaker.js +24 -5
- package/dist/lib/cli.d.ts +0 -1
- package/dist/lib/codex-cli/index.d.ts +0 -1
- package/dist/lib/codex-cli/observability.d.ts +0 -1
- package/dist/lib/codex-cli/state.d.ts +0 -1
- package/dist/lib/codex-cli/sync.d.ts +0 -1
- package/dist/lib/codex-cli/writer.d.ts +0 -1
- package/dist/lib/codex-manager/account-credentials.d.ts +0 -1
- package/dist/lib/codex-manager/account-manager-commands.d.ts +0 -1
- package/dist/lib/codex-manager/account-pool-write.d.ts +0 -1
- package/dist/lib/codex-manager/active-account-sync.d.ts +6 -0
- package/dist/lib/codex-manager/active-account-sync.js +336 -0
- package/dist/lib/codex-manager/api-login-menu.d.ts +0 -1
- package/dist/lib/codex-manager/backend-category-entry.d.ts +0 -1
- package/dist/lib/codex-manager/backend-category-helpers.d.ts +0 -1
- package/dist/lib/codex-manager/backend-category-prompt.d.ts +0 -1
- package/dist/lib/codex-manager/backend-settings-controller.d.ts +0 -1
- package/dist/lib/codex-manager/backend-settings-entry.d.ts +0 -1
- package/dist/lib/codex-manager/backend-settings-helpers.d.ts +0 -1
- package/dist/lib/codex-manager/backend-settings-prompt.d.ts +0 -1
- package/dist/lib/codex-manager/backend-settings-schema.d.ts +0 -1
- package/dist/lib/codex-manager/behavior-settings-panel.d.ts +0 -1
- package/dist/lib/codex-manager/commands/account.d.ts +8 -3
- package/dist/lib/codex-manager/commands/account.js +46 -34
- package/dist/lib/codex-manager/commands/best.d.ts +0 -1
- package/dist/lib/codex-manager/commands/bridge.d.ts +0 -1
- package/dist/lib/codex-manager/commands/budget.d.ts +8 -3
- package/dist/lib/codex-manager/commands/budget.js +6 -4
- package/dist/lib/codex-manager/commands/check.d.ts +0 -1
- package/dist/lib/codex-manager/commands/config-explain.d.ts +0 -1
- package/dist/lib/codex-manager/commands/debug-bundle.d.ts +0 -1
- package/dist/lib/codex-manager/commands/forecast.d.ts +0 -1
- package/dist/lib/codex-manager/commands/history.d.ts +0 -1
- package/dist/lib/codex-manager/commands/init-config.d.ts +0 -1
- package/dist/lib/codex-manager/commands/integrations.d.ts +0 -1
- package/dist/lib/codex-manager/commands/limits.d.ts +0 -1
- package/dist/lib/codex-manager/commands/models.d.ts +0 -1
- package/dist/lib/codex-manager/commands/monitor.d.ts +0 -1
- package/dist/lib/codex-manager/commands/report.d.ts +0 -1
- package/dist/lib/codex-manager/commands/resets.d.ts +0 -1
- package/dist/lib/codex-manager/commands/resets.js +9 -1
- package/dist/lib/codex-manager/commands/rotation.d.ts +0 -1
- package/dist/lib/codex-manager/commands/status.d.ts +0 -1
- package/dist/lib/codex-manager/commands/switch.d.ts +0 -1
- package/dist/lib/codex-manager/commands/uninstall.d.ts +0 -1
- package/dist/lib/codex-manager/commands/unpin.d.ts +0 -1
- package/dist/lib/codex-manager/commands/usage.d.ts +0 -1
- package/dist/lib/codex-manager/commands/verify.d.ts +0 -1
- package/dist/lib/codex-manager/commands/why-selected.d.ts +0 -1
- package/dist/lib/codex-manager/commands/workspace.d.ts +0 -1
- package/dist/lib/codex-manager/dashboard-display-panel.d.ts +0 -1
- package/dist/lib/codex-manager/dashboard-formatters.d.ts +0 -1
- package/dist/lib/codex-manager/dashboard-settings-controller.d.ts +0 -1
- package/dist/lib/codex-manager/dashboard-settings-data.d.ts +0 -1
- package/dist/lib/codex-manager/dashboard-settings-entry.d.ts +0 -1
- package/dist/lib/codex-manager/experimental-settings-entry.d.ts +0 -1
- package/dist/lib/codex-manager/experimental-settings-prompt.d.ts +0 -1
- package/dist/lib/codex-manager/experimental-settings-schema.d.ts +0 -1
- package/dist/lib/codex-manager/experimental-sync-target-entry.d.ts +0 -1
- package/dist/lib/codex-manager/experimental-sync-target.d.ts +0 -1
- package/dist/lib/codex-manager/forecast-report-shared.d.ts +0 -1
- package/dist/lib/codex-manager/formatters/account-formatters.d.ts +0 -1
- package/dist/lib/codex-manager/formatters/index.d.ts +0 -1
- package/dist/lib/codex-manager/formatters/model-formatters.d.ts +0 -1
- package/dist/lib/codex-manager/formatters/quota-formatters.d.ts +0 -1
- package/dist/lib/codex-manager/formatters/text-style.d.ts +0 -1
- package/dist/lib/codex-manager/health-check.d.ts +0 -1
- package/dist/lib/codex-manager/help.d.ts +0 -1
- package/dist/lib/codex-manager/login-action-panel.d.ts +0 -1
- package/dist/lib/codex-manager/login-flow.d.ts +0 -1
- package/dist/lib/codex-manager/login-menu-actions.d.ts +0 -1
- package/dist/lib/codex-manager/login-menu-data.d.ts +0 -1
- package/dist/lib/codex-manager/login-oauth.d.ts +0 -1
- package/dist/lib/codex-manager/login-workspace-choice.d.ts +0 -1
- package/dist/lib/codex-manager/manual-callback.d.ts +0 -1
- package/dist/lib/codex-manager/persist-selected-account.d.ts +0 -1
- package/dist/lib/codex-manager/quota-cache-helpers.d.ts +0 -1
- package/dist/lib/codex-manager/rate-limit-markers.d.ts +0 -1
- package/dist/lib/codex-manager/repair-commands.d.ts +0 -1
- package/dist/lib/codex-manager/settings-hub/backend.d.ts +0 -1
- package/dist/lib/codex-manager/settings-hub/dashboard.d.ts +0 -1
- package/dist/lib/codex-manager/settings-hub/experimental.d.ts +0 -1
- package/dist/lib/codex-manager/settings-hub/index.d.ts +0 -1
- package/dist/lib/codex-manager/settings-hub/shared.d.ts +0 -1
- package/dist/lib/codex-manager/settings-hub-entry.d.ts +0 -1
- package/dist/lib/codex-manager/settings-hub-menu.d.ts +0 -1
- package/dist/lib/codex-manager/settings-hub-prompt.d.ts +0 -1
- package/dist/lib/codex-manager/settings-hub.d.ts +0 -1
- package/dist/lib/codex-manager/settings-panels.d.ts +0 -1
- package/dist/lib/codex-manager/settings-persist-utils.d.ts +0 -1
- package/dist/lib/codex-manager/settings-preview.d.ts +0 -1
- package/dist/lib/codex-manager/settings-write-queue.d.ts +0 -1
- package/dist/lib/codex-manager/statusline-settings-panel.d.ts +0 -1
- package/dist/lib/codex-manager/theme-settings-panel.d.ts +0 -1
- package/dist/lib/codex-manager/unified-settings-controller.d.ts +0 -1
- package/dist/lib/codex-manager/unified-settings-entry.d.ts +0 -1
- package/dist/lib/codex-manager.d.ts +1 -2
- package/dist/lib/codex-manager.js +5 -95
- package/dist/lib/concurrency.d.ts +0 -1
- package/dist/lib/config-schema.d.ts +0 -1
- package/dist/lib/config.d.ts +0 -1
- package/dist/lib/config.js +46 -241
- package/dist/lib/constants.d.ts +0 -1
- package/dist/lib/context-budget/model-context-windows.d.ts +1 -2
- package/dist/lib/context-budget/model-context-windows.js +10 -13
- package/dist/lib/context-budget-guard.d.ts +0 -1
- package/dist/lib/context-budget-response.d.ts +0 -1
- package/dist/lib/context-overflow.d.ts +0 -1
- package/dist/lib/dashboard-settings.d.ts +0 -1
- package/dist/lib/entitlement-cache.d.ts +0 -1
- package/dist/lib/env-parsing.d.ts +13 -1
- package/dist/lib/env-parsing.js +21 -0
- package/dist/lib/errors.d.ts +0 -1
- package/dist/lib/forecast.d.ts +0 -1
- package/dist/lib/fs-retry.d.ts +0 -1
- package/dist/lib/health.d.ts +0 -1
- package/dist/lib/index.d.ts +0 -1
- package/dist/lib/integration-generators.d.ts +0 -1
- package/dist/lib/live-account-sync.d.ts +0 -1
- package/dist/lib/local-bridge.d.ts +0 -1
- package/dist/lib/local-bridge.js +4 -1
- package/dist/lib/local-client-tokens.d.ts +0 -1
- package/dist/lib/local-client-tokens.js +125 -30
- package/dist/lib/logger.d.ts +0 -1
- package/dist/lib/logger.js +11 -1
- package/dist/lib/model-capability-matrix.d.ts +0 -1
- package/dist/lib/model-route-policy.d.ts +1 -2
- package/dist/lib/named-backup-export.d.ts +0 -1
- package/dist/lib/oc-chatgpt-import-adapter.d.ts +0 -1
- package/dist/lib/oc-chatgpt-orchestrator.d.ts +0 -1
- package/dist/lib/oc-chatgpt-target-detection.d.ts +3 -3
- package/dist/lib/oc-chatgpt-target-detection.js +40 -13
- package/dist/lib/parallel-probe.d.ts +0 -1
- package/dist/lib/policy/runtime-policy-cache.d.ts +80 -0
- package/dist/lib/policy/runtime-policy-cache.js +310 -0
- package/dist/lib/policy/runtime-policy.d.ts +1 -2
- package/dist/lib/policy/runtime-policy.js +46 -19
- package/dist/lib/preemptive-quota-scheduler.d.ts +0 -1
- package/dist/lib/proactive-refresh.d.ts +0 -1
- package/dist/lib/prompts/codex-host-bridge.d.ts +0 -1
- package/dist/lib/prompts/codex.d.ts +0 -1
- package/dist/lib/prompts/fetch-utils.d.ts +0 -1
- package/dist/lib/prompts/host-codex-prompt.d.ts +0 -1
- package/dist/lib/quota-cache.d.ts +0 -1
- package/dist/lib/quota-cache.js +60 -36
- package/dist/lib/quota-probe.d.ts +0 -1
- package/dist/lib/quota-probe.js +5 -2
- package/dist/lib/quota-readiness.d.ts +0 -1
- package/dist/lib/recovery/constants.d.ts +0 -1
- package/dist/lib/recovery/storage.d.ts +0 -1
- package/dist/lib/recovery/types.d.ts +0 -1
- package/dist/lib/recovery.d.ts +0 -1
- package/dist/lib/redaction.d.ts +0 -1
- package/dist/lib/refresh-guardian.d.ts +0 -1
- package/dist/lib/refresh-lease.d.ts +0 -1
- package/dist/lib/refresh-queue.d.ts +0 -1
- package/dist/lib/request/client-cancellation.d.ts +0 -1
- package/dist/lib/request/error-classification.d.ts +0 -1
- package/dist/lib/request/error-classification.js +41 -52
- package/dist/lib/request/failover-config.d.ts +0 -1
- package/dist/lib/request/failure-policy.d.ts +0 -1
- package/dist/lib/request/fetch-helpers.d.ts +0 -1
- package/dist/lib/request/fetch-helpers.js +1 -1
- package/dist/lib/request/headers.d.ts +0 -1
- package/dist/lib/request/helpers/input-utils.d.ts +0 -1
- package/dist/lib/request/helpers/input-utils.js +88 -34
- package/dist/lib/request/helpers/model-map.d.ts +2 -3
- package/dist/lib/request/helpers/model-map.js +120 -78
- package/dist/lib/request/helpers/tool-utils.d.ts +0 -1
- package/dist/lib/request/helpers/tool-utils.js +421 -4
- package/dist/lib/request/index.d.ts +0 -1
- package/dist/lib/request/rate-limit-backoff.d.ts +0 -1
- package/dist/lib/request/rate-limit-decision.d.ts +0 -1
- package/dist/lib/request/request-attempt-budget.d.ts +0 -1
- package/dist/lib/request/request-init.d.ts +0 -1
- package/dist/lib/request/request-resilience.d.ts +0 -1
- package/dist/lib/request/request-transformer.d.ts +1 -2
- package/dist/lib/request/request-transformer.js +51 -26
- package/dist/lib/request/response-compaction.d.ts +0 -1
- package/dist/lib/request/response-handler.d.ts +0 -1
- package/dist/lib/request/response-metadata.d.ts +0 -1
- package/dist/lib/request/response-outcome.d.ts +0 -1
- package/dist/lib/request/stream-failover-runtime.d.ts +0 -1
- package/dist/lib/request/stream-failover.d.ts +0 -1
- package/dist/lib/request/stream-failover.js +28 -4
- package/dist/lib/request/token-refresh.d.ts +0 -1
- package/dist/lib/request/url-rewriting.d.ts +0 -1
- package/dist/lib/request/wait-utils.d.ts +0 -1
- package/dist/lib/rotation.d.ts +0 -1
- package/dist/lib/routing-mutex.d.ts +0 -1
- package/dist/lib/routing-profiles.d.ts +16 -2
- package/dist/lib/routing-profiles.js +119 -44
- package/dist/lib/runtime/account-check-helpers.d.ts +0 -1
- package/dist/lib/runtime/account-check-types.d.ts +0 -1
- package/dist/lib/runtime/account-check.d.ts +0 -1
- package/dist/lib/runtime/account-manager-cache-entry.d.ts +0 -1
- package/dist/lib/runtime/account-manager-cache.d.ts +0 -1
- package/dist/lib/runtime/account-model-catalog.d.ts +1 -2
- package/dist/lib/runtime/account-pool.d.ts +0 -1
- package/dist/lib/runtime/account-reset-credits.d.ts +0 -1
- package/dist/lib/runtime/account-reset-credits.js +8 -2
- package/dist/lib/runtime/account-scope.d.ts +0 -1
- package/dist/lib/runtime/account-select-event.d.ts +0 -1
- package/dist/lib/runtime/account-selection.d.ts +0 -1
- package/dist/lib/runtime/account-state.d.ts +0 -1
- package/dist/lib/runtime/account-status.d.ts +0 -1
- package/dist/lib/runtime/account-storage-scope-entry.d.ts +0 -1
- package/dist/lib/runtime/api-model-capabilities.d.ts +0 -1
- package/dist/lib/runtime/api-model-runtime.d.ts +0 -1
- package/dist/lib/runtime/app-bind.d.ts +0 -1
- package/dist/lib/runtime/app-helper-selection.d.ts +0 -1
- package/dist/lib/runtime/auth-facade.d.ts +0 -1
- package/dist/lib/runtime/automatic-account-checks.d.ts +0 -1
- package/dist/lib/runtime/automatic-subscription-checks.d.ts +0 -1
- package/dist/lib/runtime/browser-oauth-flow.d.ts +0 -1
- package/dist/lib/runtime/capability-boost.d.ts +0 -1
- package/dist/lib/runtime/catalog-capabilities.d.ts +0 -1
- package/dist/lib/runtime/config-toml.d.ts +0 -1
- package/dist/lib/runtime/context-budget-settings.d.ts +0 -1
- package/dist/lib/runtime/event-handler.d.ts +0 -1
- package/dist/lib/runtime/first-run.d.ts +0 -1
- package/dist/lib/runtime/flagged-verify-types.d.ts +0 -1
- package/dist/lib/runtime/hydrate-emails.d.ts +0 -1
- package/dist/lib/runtime/inference-activity.d.ts +0 -1
- package/dist/lib/runtime/live-sync-entry.d.ts +0 -1
- package/dist/lib/runtime/live-sync.d.ts +0 -1
- package/dist/lib/runtime/loader-setup.d.ts +0 -1
- package/dist/lib/runtime/login-menu-accounts.d.ts +0 -1
- package/dist/lib/runtime/manual-oauth-flow.d.ts +0 -1
- package/dist/lib/runtime/model-discovery-status.d.ts +0 -1
- package/dist/lib/runtime/native-account-storage.d.ts +0 -1
- package/dist/lib/runtime/native-account-sync.d.ts +0 -1
- package/dist/lib/runtime/native-binding-lock.d.ts +0 -1
- package/dist/lib/runtime/native-client-auth.d.ts +0 -1
- package/dist/lib/runtime/native-provider-config.d.ts +0 -1
- package/dist/lib/runtime/native-rate-limits.d.ts +2 -1
- package/dist/lib/runtime/native-rate-limits.js +23 -6
- package/dist/lib/runtime/preemptive-quota.d.ts +0 -1
- package/dist/lib/runtime/quota-headers.d.ts +0 -1
- package/dist/lib/runtime/quota-probe.d.ts +0 -1
- package/dist/lib/runtime/quota-settings.d.ts +0 -1
- package/dist/lib/runtime/refresh-guardian-entry.d.ts +0 -1
- package/dist/lib/runtime/refresh-guardian.d.ts +0 -1
- package/dist/lib/runtime/request-init.d.ts +0 -1
- package/dist/lib/runtime/reset-credit-routing.d.ts +0 -1
- package/dist/lib/runtime/reset-credits.d.ts +0 -1
- package/dist/lib/runtime/response-output-history.d.ts +0 -1
- package/dist/lib/runtime/responses-websocket.d.ts +0 -1
- package/dist/lib/runtime/resume-picker.d.ts +0 -1
- package/dist/lib/runtime/rotation-account-selection.d.ts +0 -1
- package/dist/lib/runtime/rotation-proxy-state.d.ts +0 -1
- package/dist/lib/runtime/rotation-server-types.d.ts +0 -1
- package/dist/lib/runtime/rotation-storage-meta.d.ts +0 -1
- package/dist/lib/runtime/rotation-token-refresh.d.ts +0 -1
- package/dist/lib/runtime/runtime-capability-failures.d.ts +0 -1
- package/dist/lib/runtime/runtime-current-account.d.ts +0 -1
- package/dist/lib/runtime/runtime-observability.d.ts +0 -1
- package/dist/lib/runtime/runtime-services.d.ts +0 -1
- package/dist/lib/runtime/session-affinity-entry.d.ts +0 -1
- package/dist/lib/runtime/session-recovery.d.ts +0 -1
- package/dist/lib/runtime/status-marker.d.ts +0 -1
- package/dist/lib/runtime/storage-scope.d.ts +0 -1
- package/dist/lib/runtime/subscription-first-use.d.ts +0 -1
- package/dist/lib/runtime/subscription-quota-event.d.ts +0 -1
- package/dist/lib/runtime/subscription-quota-order.d.ts +0 -1
- package/dist/lib/runtime/toast.d.ts +0 -1
- package/dist/lib/runtime/ui-runtime-entry.d.ts +0 -1
- package/dist/lib/runtime/ui-runtime.d.ts +0 -1
- package/dist/lib/runtime/verify-flagged.d.ts +0 -1
- package/dist/lib/runtime/workspace-model-scopes.d.ts +0 -1
- package/dist/lib/runtime-constants.d.ts +0 -1
- package/dist/lib/runtime-paths.d.ts +0 -1
- package/dist/lib/runtime-rotation-proxy.d.ts +1 -1
- package/dist/lib/runtime-rotation-proxy.js +133 -0
- package/dist/lib/schemas.d.ts +35 -13
- package/dist/lib/schemas.js +19 -2
- package/dist/lib/session-affinity.d.ts +0 -1
- package/dist/lib/shutdown.d.ts +0 -1
- package/dist/lib/storage/account-clear-entry.d.ts +0 -1
- package/dist/lib/storage/account-clear.d.ts +0 -1
- package/dist/lib/storage/account-match-utils.d.ts +0 -1
- package/dist/lib/storage/account-persistence.d.ts +0 -1
- package/dist/lib/storage/account-port.d.ts +0 -1
- package/dist/lib/storage/account-save-entry.d.ts +0 -1
- package/dist/lib/storage/account-save.d.ts +9 -2
- package/dist/lib/storage/account-save.js +4 -1
- package/dist/lib/storage/account-snapshot.d.ts +0 -1
- package/dist/lib/storage/backup-metadata-builder.d.ts +0 -1
- package/dist/lib/storage/backup-metadata.d.ts +0 -1
- package/dist/lib/storage/backup-paths.d.ts +0 -1
- package/dist/lib/storage/backup-restore.d.ts +0 -1
- package/dist/lib/storage/cache-artifacts.d.ts +0 -1
- package/dist/lib/storage/credential-sidecars.d.ts +0 -1
- package/dist/lib/storage/error-hints.d.ts +0 -1
- package/dist/lib/storage/file-lock.d.ts +0 -1
- package/dist/lib/storage/file-lock.js +33 -1
- package/dist/lib/storage/file-paths.d.ts +0 -1
- package/dist/lib/storage/fixture-guards.d.ts +0 -1
- package/dist/lib/storage/flagged-entry.d.ts +0 -1
- package/dist/lib/storage/flagged-load-entry.d.ts +0 -1
- package/dist/lib/storage/flagged-save-entry.d.ts +0 -1
- package/dist/lib/storage/flagged-storage-file.d.ts +0 -1
- package/dist/lib/storage/flagged-storage-io.d.ts +0 -1
- package/dist/lib/storage/flagged-storage.d.ts +0 -1
- package/dist/lib/storage/gitignore.d.ts +0 -1
- package/dist/lib/storage/hash.d.ts +0 -1
- package/dist/lib/storage/health.d.ts +0 -1
- package/dist/lib/storage/identity.d.ts +0 -1
- package/dist/lib/storage/import-export.d.ts +0 -1
- package/dist/lib/storage/json-store-lock.d.ts +105 -0
- package/dist/lib/storage/json-store-lock.js +259 -0
- package/dist/lib/storage/metadata-section.d.ts +0 -1
- package/dist/lib/storage/migrations.d.ts +0 -1
- package/dist/lib/storage/migrations.js +31 -18
- package/dist/lib/storage/named-backup-entry.d.ts +0 -1
- package/dist/lib/storage/named-backups-entry.d.ts +0 -1
- package/dist/lib/storage/named-backups.d.ts +0 -1
- package/dist/lib/storage/path-state.d.ts +0 -1
- package/dist/lib/storage/paths.d.ts +0 -1
- package/dist/lib/storage/pending-auth.d.ts +9 -3
- package/dist/lib/storage/pending-auth.js +30 -8
- package/dist/lib/storage/project-migration.d.ts +0 -1
- package/dist/lib/storage/public-types.d.ts +0 -1
- package/dist/lib/storage/record-identity.d.ts +0 -1
- package/dist/lib/storage/record-utils.d.ts +0 -1
- package/dist/lib/storage/restore-assessment.d.ts +0 -1
- package/dist/lib/storage/restore-backup-entry.d.ts +0 -1
- package/dist/lib/storage/restore-metadata.d.ts +0 -1
- package/dist/lib/storage/save-retry.d.ts +0 -1
- package/dist/lib/storage/snapshot-inspectors.d.ts +0 -1
- package/dist/lib/storage/snapshot-merge.d.ts +0 -1
- package/dist/lib/storage/storage-parser.d.ts +2 -1
- package/dist/lib/storage/storage-parser.js +10 -2
- package/dist/lib/storage/transactions.d.ts +0 -1
- package/dist/lib/storage.d.ts +15 -2
- package/dist/lib/storage.js +612 -25
- package/dist/lib/synthetic-response.d.ts +0 -1
- package/dist/lib/table-formatter.d.ts +0 -1
- package/dist/lib/temp-path.d.ts +0 -1
- package/dist/lib/tools/hashline-tools.d.ts +0 -1
- package/dist/lib/types.d.ts +0 -1
- package/dist/lib/ui/ansi.d.ts +0 -1
- package/dist/lib/ui/auth-menu-builder.d.ts +0 -1
- package/dist/lib/ui/auth-menu.d.ts +0 -1
- package/dist/lib/ui/check-progress.d.ts +0 -1
- package/dist/lib/ui/confirm.d.ts +0 -1
- package/dist/lib/ui/display-width.d.ts +0 -1
- package/dist/lib/ui/format.d.ts +0 -1
- package/dist/lib/ui/index.d.ts +0 -1
- package/dist/lib/ui/runtime.d.ts +0 -1
- package/dist/lib/ui/select.d.ts +0 -1
- package/dist/lib/ui/theme.d.ts +0 -1
- package/dist/lib/ui/ui-copy.d.ts +1 -2
- package/dist/lib/ui/ui-copy.js +1 -1
- package/dist/lib/unified-settings.d.ts +13 -11
- package/dist/lib/unified-settings.js +22 -14
- package/dist/lib/update-notice.d.ts +0 -1
- package/dist/lib/usage/index.d.ts +0 -1
- package/dist/lib/usage/ledger.d.ts +0 -1
- package/dist/lib/usage/pricing.d.ts +1 -2
- package/dist/lib/usage/pricing.js +41 -16
- package/dist/lib/usage/redaction.d.ts +0 -1
- package/dist/lib/usage/stream-usage-deferral.d.ts +0 -1
- package/dist/lib/usage/types.d.ts +0 -1
- package/dist/lib/usage/usage-extraction.d.ts +0 -1
- package/dist/lib/utils.d.ts +21 -1
- package/dist/lib/utils.js +31 -0
- package/dist/lib/wsl.d.ts +0 -1
- package/package.json +11 -5
- package/scripts/codex-bin-resolver.js +20 -1
- package/scripts/codex-multi-auth.js +7 -1
- package/scripts/codex.js +385 -89
- package/skills/codex-auth-setup/SKILL.md +73 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { withRetry } from "../fs-retry.js";
|
|
5
|
+
import { tempPathFor } from "../temp-path.js";
|
|
6
|
+
import { withFileTransactionLock } from "./file-lock.js";
|
|
7
|
+
/**
|
|
8
|
+
* Shared concurrency machinery for the file-backed governance JSON stores
|
|
9
|
+
* (config, unified settings, budget guards, routing profiles, account
|
|
10
|
+
* policies, local client tokens, quota cache).
|
|
11
|
+
*
|
|
12
|
+
* Three cooperating guards, extracted from lib/config.ts's save path so every
|
|
13
|
+
* store gets the same semantics instead of each re-deriving a subset:
|
|
14
|
+
*
|
|
15
|
+
* 1. {@link withJsonStoreWriteQueue} — a per-path in-process promise queue
|
|
16
|
+
* that serializes writers inside this process (replaces each store's
|
|
17
|
+
* hand-rolled `writeQueue` module variable).
|
|
18
|
+
* 2. {@link withJsonStoreFileLock} — a cross-process lock directory
|
|
19
|
+
* (`<path>.write-lock`) delegated to {@link withFileTransactionLock}: a
|
|
20
|
+
* pre-populated candidate directory is published by atomic rename, and a
|
|
21
|
+
* crashed holder's lock is recovered only when its owner PID is dead —
|
|
22
|
+
* live holders are NEVER evicted, so a takeover can never unlink a newly
|
|
23
|
+
* acquired lock (the stale-check→unlink TOCTOU that a single lockfile
|
|
24
|
+
* cannot close: POSIX has no delete-if-unchanged primitive, and renaming
|
|
25
|
+
* the file aside leaves an empty path another `wx` create can claim).
|
|
26
|
+
* The promise queue only serializes THIS process; the lock directory
|
|
27
|
+
* closes the read→check→merge→rename TOCTOU window against OTHER
|
|
28
|
+
* processes. Re-entrant within one async context so a nested write on the
|
|
29
|
+
* same path cannot deadlock itself.
|
|
30
|
+
* 3. mtime compare-and-swap — {@link getJsonStoreFileMtimeMs} /
|
|
31
|
+
* {@link assertJsonStoreFileMtimeUnchanged} /
|
|
32
|
+
* {@link writeJsonStoreFileAtomicWithRetry} plus
|
|
33
|
+
* {@link withJsonStoreCasRetry}: each attempt re-stats, re-reads, and
|
|
34
|
+
* re-merges against the latest on-disk state before writing, aborting with
|
|
35
|
+
* `ESTALE` when another writer moved the file under us. This stays on as a
|
|
36
|
+
* second-line guard for writers that do not take the lockfile.
|
|
37
|
+
*
|
|
38
|
+
* Storage layer: this module sits below the governance stores (which live in
|
|
39
|
+
* lib/ root) and below lib/config.ts; it must only depend on leaf utilities.
|
|
40
|
+
*/
|
|
41
|
+
const JSON_STORE_WRITE_RETRY_CODES = new Set(["EBUSY", "EPERM"]);
|
|
42
|
+
const JSON_STORE_READ_RETRY_CODES = new Set(["EBUSY", "EPERM", "EAGAIN"]);
|
|
43
|
+
const JSON_STORE_CAS_MAX_ATTEMPTS = 3;
|
|
44
|
+
/**
|
|
45
|
+
* Stamp `updatedAt` for a per-key governance entry with a hybrid logical
|
|
46
|
+
* floor: when the wall clock regressed below the timestamp the entry being
|
|
47
|
+
* overwritten already carries, stamp `prior + 1` instead of `now`. Every
|
|
48
|
+
* upsert-only store merges with `updatedAt >=`, so a backward clock jump
|
|
49
|
+
* would otherwise stamp a semantically-newer write below its own
|
|
50
|
+
* predecessor and the merge would silently drop it. Equal or forward wall
|
|
51
|
+
* times pass through unchanged — ties already resolve to the caller's
|
|
52
|
+
* write under `>=`.
|
|
53
|
+
*
|
|
54
|
+
* `prior` is the entry the writer saw, which can trail the freshest on-disk
|
|
55
|
+
* entry when a concurrent writer lands between the caller's load and its
|
|
56
|
+
* save; baseline-aware save merges re-apply this same floor against the
|
|
57
|
+
* on-disk entry at merge time so the edit still cannot be lost.
|
|
58
|
+
*/
|
|
59
|
+
export function stampUpdatedAt(now, prior) {
|
|
60
|
+
return typeof prior === "number" && Number.isFinite(prior) && now < prior
|
|
61
|
+
? prior + 1
|
|
62
|
+
: now;
|
|
63
|
+
}
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// 1. Per-path in-process write queue
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
const jsonStoreWriteQueues = new Map();
|
|
68
|
+
// Async-local re-entrancy map for the write queue (keyed by the raw path
|
|
69
|
+
// string, matching the queue key): a nested withJsonStoreWriteQueue on the
|
|
70
|
+
// same path inside one async context runs inside the outer critical section
|
|
71
|
+
// instead of deadlocking on its own queue slot — e.g. config.ts wraps
|
|
72
|
+
// saveUnifiedPluginConfig (which queues on settings.json) in an outer queue
|
|
73
|
+
// for the same path.
|
|
74
|
+
const jsonStoreQueueLeases = new AsyncLocalStorage();
|
|
75
|
+
/**
|
|
76
|
+
* Serialize `task` behind the previous write queued for `path`, so same-file
|
|
77
|
+
* writers inside this process run one at a time in submission order. A failed
|
|
78
|
+
* predecessor never blocks or fails successors. Re-entrant for the same path
|
|
79
|
+
* within one async context.
|
|
80
|
+
*
|
|
81
|
+
* This is the per-path generalization of the module-local `writeQueue`
|
|
82
|
+
* variables the governance stores used to keep by hand.
|
|
83
|
+
*/
|
|
84
|
+
export async function withJsonStoreWriteQueue(path, task) {
|
|
85
|
+
const held = jsonStoreQueueLeases.getStore();
|
|
86
|
+
if (held?.get(path)?.active) {
|
|
87
|
+
return task();
|
|
88
|
+
}
|
|
89
|
+
const previous = jsonStoreWriteQueues.get(path) ?? Promise.resolve();
|
|
90
|
+
const lease = { active: true };
|
|
91
|
+
const context = new Map(held);
|
|
92
|
+
context.set(path, lease);
|
|
93
|
+
const queued = previous.catch(() => { }).then(async () => {
|
|
94
|
+
try {
|
|
95
|
+
return await jsonStoreQueueLeases.run(context, task);
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
lease.active = false;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
// Store the settled (never-rejecting) wrapper so successors chain cleanly;
|
|
102
|
+
// keep the reference for the same-object check below.
|
|
103
|
+
const stored = queued.then(() => undefined, () => undefined);
|
|
104
|
+
jsonStoreWriteQueues.set(path, stored);
|
|
105
|
+
try {
|
|
106
|
+
return await queued;
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
if (jsonStoreWriteQueues.get(path) === stored) {
|
|
110
|
+
jsonStoreWriteQueues.delete(path);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Test helper: drop queued-write bookkeeping (all paths, or one when given). */
|
|
115
|
+
export function resetJsonStoreWriteQueuesForTests(path) {
|
|
116
|
+
if (path !== undefined) {
|
|
117
|
+
jsonStoreWriteQueues.delete(path);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
jsonStoreWriteQueues.clear();
|
|
121
|
+
}
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// 2. mtime compare-and-swap + atomic JSON write
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
/**
|
|
126
|
+
* Stat `filePath` for its mtime with bounded transient-FS retry (the save
|
|
127
|
+
* path is Windows-sensitive: a single transient EBUSY/EPERM/EAGAIN from an
|
|
128
|
+
* AV/indexer lock must not abort the whole save). ENOENT returns `null`
|
|
129
|
+
* immediately; on exhaustion the last failure surfaces so the caller treats
|
|
130
|
+
* it as a real save error rather than a phantom missing file.
|
|
131
|
+
*/
|
|
132
|
+
export async function getJsonStoreFileMtimeMs(filePath) {
|
|
133
|
+
return withRetry(async () => {
|
|
134
|
+
try {
|
|
135
|
+
return (await fs.stat(filePath)).mtimeMs;
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (error?.code === "ENOENT") {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}, {
|
|
144
|
+
maxAttempts: 5,
|
|
145
|
+
backoffMs: (attempt) => 10 * 2 ** (attempt - 1),
|
|
146
|
+
retryableCodes: JSON_STORE_READ_RETRY_CODES,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The `ESTALE` signal used by the CAS retry loop: the file's mtime moved
|
|
151
|
+
* between the caller's stat and its write, so the attempt must re-read and
|
|
152
|
+
* re-merge against the latest on-disk state instead of clobbering it.
|
|
153
|
+
*/
|
|
154
|
+
export function createJsonStoreStaleError(filePath) {
|
|
155
|
+
const staleError = new Error(`JSON store at ${filePath} changed on disk during save; retrying with latest state.`);
|
|
156
|
+
staleError.code = "ESTALE";
|
|
157
|
+
return staleError;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Throw `ESTALE` when `filePath`'s current mtime differs from
|
|
161
|
+
* `expectedMtimeMs` (`null` means "file must still be absent"). Writers that
|
|
162
|
+
* keep their own temp+rename flow call this just before the rename, matching
|
|
163
|
+
* {@link writeJsonStoreFileAtomicWithRetry}'s inline check.
|
|
164
|
+
*/
|
|
165
|
+
export async function assertJsonStoreFileMtimeUnchanged(filePath, expectedMtimeMs) {
|
|
166
|
+
const currentMtimeMs = await getJsonStoreFileMtimeMs(filePath);
|
|
167
|
+
if (currentMtimeMs !== expectedMtimeMs) {
|
|
168
|
+
throw createJsonStoreStaleError(filePath);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Atomic JSON write: serialize `payload` pretty-printed with a trailing
|
|
173
|
+
* newline to a crypto-random sibling temp file, then rename it over
|
|
174
|
+
* `filePath` with bounded transient-FS retry. Optionally CAS-checks the
|
|
175
|
+
* target mtime first and fsyncs the temp file; on failure the temp is
|
|
176
|
+
* removed best-effort.
|
|
177
|
+
*/
|
|
178
|
+
export async function writeJsonStoreFileAtomicWithRetry(filePath, payload, options) {
|
|
179
|
+
const tempPath = tempPathFor(filePath);
|
|
180
|
+
await fs.mkdir(dirname(filePath), { recursive: true });
|
|
181
|
+
const handle = await fs.open(tempPath, "w", options?.mode);
|
|
182
|
+
try {
|
|
183
|
+
await handle.writeFile(`${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
184
|
+
if (options?.fsync) {
|
|
185
|
+
await handle.sync();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
await handle.close();
|
|
190
|
+
}
|
|
191
|
+
let renamed = false;
|
|
192
|
+
try {
|
|
193
|
+
if (options && "expectedMtimeMs" in options) {
|
|
194
|
+
await assertJsonStoreFileMtimeUnchanged(filePath, options.expectedMtimeMs ?? null);
|
|
195
|
+
}
|
|
196
|
+
await withRetry(() => fs.rename(tempPath, filePath), {
|
|
197
|
+
maxAttempts: 5,
|
|
198
|
+
backoffMs: (attempt) => 10 * 2 ** (attempt - 1),
|
|
199
|
+
retryableCodes: options?.retryableCodes ?? JSON_STORE_WRITE_RETRY_CODES,
|
|
200
|
+
});
|
|
201
|
+
renamed = true;
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
if (!renamed) {
|
|
205
|
+
try {
|
|
206
|
+
await fs.unlink(tempPath);
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// Best-effort temp cleanup.
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Run `task`, retrying `ESTALE` CAS aborts so each attempt can re-read and
|
|
216
|
+
* re-merge against the latest on-disk state (matches the config save loop:
|
|
217
|
+
* 3 attempts, immediate retry, ESTALE-only).
|
|
218
|
+
*/
|
|
219
|
+
export async function withJsonStoreCasRetry(task) {
|
|
220
|
+
return withRetry(task, {
|
|
221
|
+
maxAttempts: JSON_STORE_CAS_MAX_ATTEMPTS,
|
|
222
|
+
backoffMs: 0,
|
|
223
|
+
retryableCodes: ["ESTALE"],
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
// 3. Cross-process lockfile
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
const JSON_STORE_LOCK_WAIT_TIMEOUT_MS = 10_000;
|
|
230
|
+
/**
|
|
231
|
+
* Cross-process mutex for a JSON store file, delegated to the proven
|
|
232
|
+
* candidate-directory transaction lock in lib/storage/file-lock.ts: each
|
|
233
|
+
* acquirer stages `<path>.write-lock.candidate-*` containing its unique
|
|
234
|
+
* `<host>.<pid>.<uuid>` owner file, then publishes it with a single atomic
|
|
235
|
+
* `rename` (which only succeeds while the lock directory is absent or empty,
|
|
236
|
+
* so there is no ownerless acquisition window). A crashed holder's lock is
|
|
237
|
+
* recovered by unlinking exactly that dead owner's unique filename and
|
|
238
|
+
* removing the directory only while it is still empty — an `rmdir` can never
|
|
239
|
+
* erase a lock that was republished in the meantime, so takeover can never
|
|
240
|
+
* delete another owner's live lock. Waiters on a live holder retry inside
|
|
241
|
+
* `waitTimeoutMs` (default 10s), then this wrapper surfaces the exhaustion
|
|
242
|
+
* as `ELOCKTIMEOUT`. Re-entrant for the same resolved path within one async
|
|
243
|
+
* context.
|
|
244
|
+
*/
|
|
245
|
+
export async function withJsonStoreFileLock(targetPath, task, options) {
|
|
246
|
+
try {
|
|
247
|
+
return await withFileTransactionLock(targetPath, task, {
|
|
248
|
+
waitMs: options?.waitTimeoutMs ?? JSON_STORE_LOCK_WAIT_TIMEOUT_MS,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
if (error?.code === "ELOCKED") {
|
|
253
|
+
const timeoutError = new Error(`Timed out acquiring JSON store lock at ${targetPath}.`);
|
|
254
|
+
timeoutError.code = "ELOCKTIMEOUT";
|
|
255
|
+
throw timeoutError;
|
|
256
|
+
}
|
|
257
|
+
throw error;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
@@ -7,38 +7,51 @@
|
|
|
7
7
|
* ./public-types.ts.
|
|
8
8
|
*/
|
|
9
9
|
import { MODEL_FAMILIES } from "../request/helpers/model-map.js";
|
|
10
|
+
import { isRecord } from "./record-utils.js";
|
|
10
11
|
function nowMs() {
|
|
11
12
|
return Date.now();
|
|
12
13
|
}
|
|
13
14
|
export function migrateV1ToV3(v1) {
|
|
14
15
|
const now = nowMs();
|
|
16
|
+
const rawActiveIndexByFamily = isRecord(v1.activeIndexByFamily)
|
|
17
|
+
? v1
|
|
18
|
+
.activeIndexByFamily
|
|
19
|
+
: {};
|
|
15
20
|
return {
|
|
16
21
|
version: 3,
|
|
17
|
-
accounts: v1.accounts
|
|
22
|
+
accounts: v1.accounts
|
|
23
|
+
.filter((account) => account !== null && typeof account === "object")
|
|
24
|
+
.map((account) => {
|
|
25
|
+
const { rateLimitResetTime, rateLimitResetTimes: existingResets, ...passthrough } = account;
|
|
26
|
+
// A pre-existing V3 map wins per key; the legacy scalar only fills
|
|
27
|
+
// families the map does not already cover.
|
|
18
28
|
const rateLimitResetTimes = {};
|
|
19
|
-
if (
|
|
29
|
+
if (isRecord(existingResets)) {
|
|
30
|
+
for (const [family, value] of Object.entries(existingResets)) {
|
|
31
|
+
if (typeof value === "number") {
|
|
32
|
+
rateLimitResetTimes[family] = value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (typeof rateLimitResetTime === "number" && rateLimitResetTime > now) {
|
|
20
37
|
for (const family of MODEL_FAMILIES) {
|
|
21
|
-
rateLimitResetTimes[family]
|
|
38
|
+
rateLimitResetTimes[family] ??= rateLimitResetTime;
|
|
22
39
|
}
|
|
23
40
|
}
|
|
24
41
|
return {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
refreshToken: account.refreshToken,
|
|
30
|
-
accessToken: account.accessToken,
|
|
31
|
-
expiresAt: account.expiresAt,
|
|
32
|
-
enabled: account.enabled,
|
|
33
|
-
addedAt: account.addedAt,
|
|
34
|
-
lastUsed: account.lastUsed,
|
|
35
|
-
lastSwitchReason: account.lastSwitchReason,
|
|
36
|
-
rateLimitResetTimes: Object.keys(rateLimitResetTimes).length > 0 ? rateLimitResetTimes : undefined,
|
|
37
|
-
coolingDownUntil: account.coolingDownUntil,
|
|
38
|
-
cooldownReason: account.cooldownReason,
|
|
42
|
+
...passthrough,
|
|
43
|
+
rateLimitResetTimes: Object.keys(rateLimitResetTimes).length > 0
|
|
44
|
+
? rateLimitResetTimes
|
|
45
|
+
: undefined,
|
|
39
46
|
};
|
|
40
47
|
}),
|
|
41
48
|
activeIndex: v1.activeIndex,
|
|
42
|
-
activeIndexByFamily: Object.fromEntries(MODEL_FAMILIES.map((family) =>
|
|
49
|
+
activeIndexByFamily: Object.fromEntries(MODEL_FAMILIES.map((family) => {
|
|
50
|
+
const perFamily = rawActiveIndexByFamily[family];
|
|
51
|
+
return [
|
|
52
|
+
family,
|
|
53
|
+
typeof perFamily === "number" ? perFamily : v1.activeIndex,
|
|
54
|
+
];
|
|
55
|
+
})),
|
|
43
56
|
};
|
|
44
57
|
}
|
|
@@ -12,4 +12,3 @@ export declare function exportNamedBackupEntry(params: {
|
|
|
12
12
|
getStoragePath: () => string;
|
|
13
13
|
exportAccounts: (filePath: string, force?: boolean, beforeCommit?: (resolvedPath: string) => Promise<void> | void) => Promise<void>;
|
|
14
14
|
}): Promise<string>;
|
|
15
|
-
//# sourceMappingURL=named-backup-entry.d.ts.map
|
|
@@ -10,4 +10,3 @@ export declare function setStoragePathDirectState(state: StoragePathState): void
|
|
|
10
10
|
export declare function runWithStoragePathState<T>(state: StoragePathState, fn: () => T | Promise<T>): Promise<T>;
|
|
11
11
|
/** Temporarily use the shared pool without mutating the caller or sibling async scopes. */
|
|
12
12
|
export declare function runWithGlobalStoragePath<T>(fn: () => T | Promise<T>): Promise<T>;
|
|
13
|
-
//# sourceMappingURL=path-state.d.ts.map
|
|
@@ -59,4 +59,3 @@ export declare function resolveProjectStorageIdentityRoot(projectRoot: string):
|
|
|
59
59
|
export declare function isProjectDirectory(dir: string): boolean;
|
|
60
60
|
export declare function findProjectRoot(startDir: string): string | null;
|
|
61
61
|
export declare function resolvePath(filePath: string): string;
|
|
62
|
-
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -11,8 +11,14 @@ export declare function recordPendingAuth(storagePath: string, auth: {
|
|
|
11
11
|
}): Promise<void>;
|
|
12
12
|
/** Overlay pending rotated credentials on rows that still hold the spent token. */
|
|
13
13
|
export declare function applyPendingAuth(storagePath: string, storage: AccountStorageV3 | null): Promise<AccountStorageV3 | null>;
|
|
14
|
-
/**
|
|
15
|
-
|
|
14
|
+
/**
|
|
15
|
+
* After a save, drop entries whose spent token is no longer in any restorable
|
|
16
|
+
* state. `saved` is the primary content just persisted; callers may also
|
|
17
|
+
* supply `restorableRefreshTokens` — refresh tokens still present in recovery
|
|
18
|
+
* sources (rotating/discovered backups, a WAL payload) — since a restore can
|
|
19
|
+
* resurface a spent token, its entry must survive until no source holds it.
|
|
20
|
+
* A scan failure keeps every entry: retention is the safe direction.
|
|
21
|
+
*/
|
|
22
|
+
export declare function prunePendingAuth(storagePath: string, saved: AccountStorageV3, restorableRefreshTokens?: () => Promise<Iterable<string>>): Promise<void>;
|
|
16
23
|
/** Coordinate resets with pending credential writers, including Windows rename locks. */
|
|
17
24
|
export declare function clearPendingAuth(storagePath: string): Promise<void>;
|
|
18
|
-
//# sourceMappingURL=pending-auth.d.ts.map
|
|
@@ -79,15 +79,17 @@ export async function recordPendingAuth(storagePath, auth) {
|
|
|
79
79
|
}
|
|
80
80
|
const prior = hash(auth.priorRefreshToken);
|
|
81
81
|
const entries = (await read(path)).filter((entry) => entry.prior !== prior && entry.prior !== hash(auth.refreshToken));
|
|
82
|
-
// Rotating a token that is itself only journaled:
|
|
83
|
-
//
|
|
84
|
-
//
|
|
82
|
+
// Rotating a token that is itself only journaled: extend that entry to the
|
|
83
|
+
// newest credential, but ALSO keep an entry keyed by the token this
|
|
84
|
+
// rotation just spent. A backup slot or WAL can still hold that
|
|
85
|
+
// intermediate token, and pruning now keeps entries whose spent token any
|
|
86
|
+
// recovery source can surface — a stale-snapshot restore then self-heals
|
|
87
|
+
// straight to the newest credential instead of reviving a spent token.
|
|
85
88
|
const chained = entries.find((entry) => entry.refreshToken === auth.priorRefreshToken);
|
|
86
|
-
const current = chained ?? { prior, recordId: auth.recordId, refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at };
|
|
87
89
|
if (chained)
|
|
88
90
|
Object.assign(chained, { recordId: chained.recordId ?? auth.recordId, refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at });
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
const current = { prior, recordId: auth.recordId, refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at };
|
|
92
|
+
entries.push(current);
|
|
91
93
|
const excess = entries.length - MAX_ENTRIES;
|
|
92
94
|
if (excess > 0) {
|
|
93
95
|
// Drop the oldest other entries, never the credential being recorded now.
|
|
@@ -134,14 +136,34 @@ export async function applyPendingAuth(storagePath, storage) {
|
|
|
134
136
|
}
|
|
135
137
|
return storage;
|
|
136
138
|
}
|
|
137
|
-
/**
|
|
138
|
-
|
|
139
|
+
/**
|
|
140
|
+
* After a save, drop entries whose spent token is no longer in any restorable
|
|
141
|
+
* state. `saved` is the primary content just persisted; callers may also
|
|
142
|
+
* supply `restorableRefreshTokens` — refresh tokens still present in recovery
|
|
143
|
+
* sources (rotating/discovered backups, a WAL payload) — since a restore can
|
|
144
|
+
* resurface a spent token, its entry must survive until no source holds it.
|
|
145
|
+
* A scan failure keeps every entry: retention is the safe direction.
|
|
146
|
+
*/
|
|
147
|
+
export async function prunePendingAuth(storagePath, saved, restorableRefreshTokens) {
|
|
139
148
|
const path = getPendingAuthPath(storagePath);
|
|
140
149
|
const current = await read(path);
|
|
141
150
|
if (!current.length)
|
|
142
151
|
return;
|
|
143
152
|
await withFileTransactionLock(path, async () => {
|
|
144
153
|
const spent = new Set(saved.accounts.map((account) => hash(account.refreshToken)));
|
|
154
|
+
if (restorableRefreshTokens) {
|
|
155
|
+
try {
|
|
156
|
+
for (const token of await restorableRefreshTokens()) {
|
|
157
|
+
spent.add(hash(token));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
log.warn("Recovery-source scan failed; keeping all pending rotated credentials", {
|
|
162
|
+
code: typeof error.code === "string" && /^[A-Z_]{1,40}$/.test(error.code ?? "") ? error.code : "UNKNOWN",
|
|
163
|
+
});
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
145
167
|
const entries = await read(path);
|
|
146
168
|
const remaining = entries.filter((entry) => spent.has(entry.prior));
|
|
147
169
|
if (remaining.length !== entries.length)
|
|
@@ -7,4 +7,3 @@ export declare function loadNormalizedStorageFromPath(path: string, label: strin
|
|
|
7
7
|
logWarn: (message: string, details: Record<string, unknown>) => void;
|
|
8
8
|
}): Promise<AccountStorageV3 | null>;
|
|
9
9
|
export declare function mergeStorageForMigration(current: AccountStorageV3 | null, incoming: AccountStorageV3, normalizeAccountStorage: (value: unknown) => AccountStorageV3 | null, findMatchingAccountIndex: (accounts: AccountStorageV3["accounts"], candidate: AccountStorageV3["accounts"][number]) => number | undefined): AccountStorageV3;
|
|
10
|
-
//# sourceMappingURL=project-migration.d.ts.map
|
|
@@ -7,4 +7,3 @@ type AccountStorageWithMetadata = AccountStorageV3 & {
|
|
|
7
7
|
export declare function createEmptyStorageWithRestoreMetadata(restoreEligible: boolean, restoreReason: RestoreReason): AccountStorageWithMetadata;
|
|
8
8
|
export declare function withRestoreMetadata(storage: AccountStorageV3, restoreEligible: boolean, restoreReason: RestoreReason): AccountStorageWithMetadata;
|
|
9
9
|
export {};
|
|
10
|
-
//# sourceMappingURL=restore-metadata.d.ts.map
|
|
@@ -7,4 +7,3 @@
|
|
|
7
7
|
import type { AccountStorageV3 } from "./public-types.js";
|
|
8
8
|
export declare function isRetryableStorageWriteError(error: unknown): boolean;
|
|
9
9
|
export declare function saveAccountsWithRetry(storage: AccountStorageV3, saveAccounts: (storage: AccountStorageV3) => Promise<void>): Promise<void>;
|
|
10
|
-
//# sourceMappingURL=save-retry.d.ts.map
|
|
@@ -19,4 +19,3 @@ export declare function describeFlaggedSnapshot(path: string, kind: BackupSnapsh
|
|
|
19
19
|
loadFlaggedAccountsFromPath: (path: string) => Promise<FlaggedAccountStorageV1>;
|
|
20
20
|
logWarn?: (message: string, meta: Record<string, unknown>) => void;
|
|
21
21
|
}): Promise<BackupSnapshotMetadata>;
|
|
22
|
-
//# sourceMappingURL=snapshot-inspectors.d.ts.map
|
|
@@ -13,4 +13,3 @@ export declare function mergeAccountSnapshot(base: AccountStorageV3 | null, curr
|
|
|
13
13
|
/** Save observations independently of unresolved user-edit conflicts. Inventory stays disk-owned. */
|
|
14
14
|
export declare function mergeAccountRuntimeObservations(base: AccountStorageV3, current: AccountStorageV3, local: AccountStorageV3): AccountStorageV3;
|
|
15
15
|
export {};
|
|
16
|
-
//# sourceMappingURL=snapshot-merge.d.ts.map
|
|
@@ -28,5 +28,6 @@ export declare function loadAccountsFromPath(path: string, deps: {
|
|
|
28
28
|
normalized: AccountStorageV3 | null;
|
|
29
29
|
storedVersion: unknown;
|
|
30
30
|
schemaErrors: string[];
|
|
31
|
+
/** sha256 of the exact bytes read, for cheap unchanged-content checks. */
|
|
32
|
+
contentSha256: string;
|
|
31
33
|
}>;
|
|
32
|
-
//# sourceMappingURL=storage-parser.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import { AnyAccountStorageSchema, getValidationErrors, safeParseJson, } from "../schemas.js";
|
|
3
3
|
import { withFileOperationRetry } from "../fs-retry.js";
|
|
4
|
+
import { computeSha256 } from "./hash.js";
|
|
4
5
|
export function parseAndNormalizeStorage(data, normalizeAccountStorage, isRecord) {
|
|
5
6
|
const schemaErrors = getValidationErrors(AnyAccountStorageSchema, data);
|
|
6
7
|
const normalized = normalizeAccountStorage(data);
|
|
@@ -33,18 +34,25 @@ export async function loadAccountsFromPath(path, deps) {
|
|
|
33
34
|
// unchanged; JSON.parse runs outside the retry, so the SyntaxError → recovery
|
|
34
35
|
// contract documented above is also preserved.
|
|
35
36
|
const content = await withFileOperationRetry(() => fs.readFile(path, "utf-8"));
|
|
37
|
+
const contentSha256 = computeSha256(content);
|
|
36
38
|
// Run the Zod-guarded JSON boundary first. Returns null on either a
|
|
37
39
|
// `SyntaxError` or a schema mismatch; we disambiguate below so the
|
|
38
40
|
// `SyntaxError` contract keeps propagating to callers that rely on it
|
|
39
41
|
// for WAL / backup recovery.
|
|
40
42
|
const validated = safeParseJson(content, AnyAccountStorageSchema, "storage-parser.loadAccountsFromPath");
|
|
41
43
|
if (validated !== null) {
|
|
42
|
-
return
|
|
44
|
+
return {
|
|
45
|
+
...parseAndNormalizeStorage(validated, deps.normalizeAccountStorage, deps.isRecord),
|
|
46
|
+
contentSha256,
|
|
47
|
+
};
|
|
43
48
|
}
|
|
44
49
|
// `validated === null`: either SyntaxError or schema mismatch.
|
|
45
50
|
// A raw JSON.parse distinguishes them: SyntaxError propagates to preserve
|
|
46
51
|
// existing recovery semantics; otherwise fall through to the TS normalizer
|
|
47
52
|
// (legacy unknown-shape path, surfaced via `schemaErrors`).
|
|
48
53
|
const data = JSON.parse(content);
|
|
49
|
-
return
|
|
54
|
+
return {
|
|
55
|
+
...parseAndNormalizeStorage(data, deps.normalizeAccountStorage, deps.isRecord),
|
|
56
|
+
contentSha256,
|
|
57
|
+
};
|
|
50
58
|
}
|
|
@@ -29,4 +29,3 @@ export declare function withAccountAndFlaggedStorageTransaction<T>(handler: (cur
|
|
|
29
29
|
cloneAccountStorageForPersistence: (storage: AccountStorageV3 | null | undefined) => AccountStorageV3;
|
|
30
30
|
logRollbackError: (error: unknown, rollbackError: unknown) => void;
|
|
31
31
|
}): Promise<T>;
|
|
32
|
-
//# sourceMappingURL=transactions.d.ts.map
|
package/dist/lib/storage.d.ts
CHANGED
|
@@ -156,7 +156,21 @@ export declare function withFlaggedStorageTransaction<T>(handler: (current: Flag
|
|
|
156
156
|
* @param storage - Account storage data to save
|
|
157
157
|
* @throws StorageError with platform-aware hints on failure
|
|
158
158
|
*/
|
|
159
|
-
/**
|
|
159
|
+
/**
|
|
160
|
+
* Clone a loaded working snapshot without losing its optimistic-concurrency baseline.
|
|
161
|
+
*
|
|
162
|
+
* Baseline contract: `saveAccounts` only runs the three-way merge
|
|
163
|
+
* (`mergeAccountSnapshot` against a fresh `loadPrimaryAccountsForMerge` read)
|
|
164
|
+
* when the saved object is registered in `loadedAccountSnapshots` — and that
|
|
165
|
+
* WeakMap is keyed by OBJECT IDENTITY, so registration does not survive
|
|
166
|
+
* `structuredClone`, `JSON.parse(JSON.stringify(...))`, spread copies, or
|
|
167
|
+
* manual reconstruction. A baseline-less save writes the object as-is
|
|
168
|
+
* (last-writer-wins): concurrent changes are neither merged nor flagged with
|
|
169
|
+
* ESTALE, and when the primary on disk differs from the state this process
|
|
170
|
+
* last read or wrote the save additionally emits a one-time baseline-less
|
|
171
|
+
* overwrite warning. Use this helper — or mutate the loaded object in place —
|
|
172
|
+
* to keep the merge armed.
|
|
173
|
+
*/
|
|
160
174
|
export declare function cloneTrackedAccountStorage(storage: AccountStorageV3): AccountStorageV3;
|
|
161
175
|
export declare function saveAccounts(storage: AccountStorageV3): Promise<void>;
|
|
162
176
|
/**
|
|
@@ -185,4 +199,3 @@ export declare function importAccounts(filePath: string): Promise<{
|
|
|
185
199
|
total: number;
|
|
186
200
|
skipped: number;
|
|
187
201
|
}>;
|
|
188
|
-
//# sourceMappingURL=storage.d.ts.map
|