codex-multi-auth 2.17.0 → 2.17.3
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 +9 -9
- package/LICENSE +21 -21
- package/README.md +142 -484
- package/assets/codex-multi-auth-icon.svg +39 -39
- package/assets/readme-hero.svg +31 -31
- package/config/README.md +31 -31
- package/config/codex-legacy.json +1221 -1221
- package/config/codex-modern.json +423 -423
- package/config/minimal-codex.json +15 -15
- 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 +1 -8
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/accounts.js +7 -19
- 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 +1 -2
- package/dist/lib/codex-manager/commands/forecast.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/forecast.js +2 -2
- 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/health-check.js +1 -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-menu-data.d.ts.map +1 -1
- package/dist/lib/codex-manager/login-menu-data.js +7 -3
- 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 +7 -2
- package/dist/lib/codex-manager/quota-cache-helpers.d.ts.map +1 -1
- package/dist/lib/codex-manager/quota-cache-helpers.js +34 -19
- 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/repair-commands.js +1 -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 +0 -1
- package/dist/lib/context-budget-guard.d.ts +0 -1
- package/dist/lib/context-budget-response.d.ts +0 -1
- package/dist/lib/context-budget-response.js +8 -8
- package/dist/lib/context-overflow.d.ts +0 -1
- package/dist/lib/context-overflow.js +10 -10
- 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/oauth-success.html +125 -125
- 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 +0 -1
- 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-host-bridge.js +138 -138
- package/dist/lib/prompts/codex.d.ts +0 -1
- package/dist/lib/prompts/codex.js +79 -79
- 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 +7 -4
- package/dist/lib/quota-cache.d.ts.map +1 -1
- package/dist/lib/quota-cache.js +117 -61
- package/dist/lib/quota-probe.d.ts +0 -1
- package/dist/lib/quota-probe.js +5 -2
- package/dist/lib/quota-readiness.d.ts +7 -3
- package/dist/lib/quota-readiness.d.ts.map +1 -1
- package/dist/lib/quota-readiness.js +25 -4
- 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/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/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 +0 -1
- 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 +0 -1
- package/dist/lib/request/request-transformer.js +50 -25
- 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-bind.d.ts.map +1 -1
- package/dist/lib/runtime/app-bind.js +10 -2
- 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 +5 -2
- package/dist/lib/runtime/automatic-account-checks.d.ts.map +1 -1
- package/dist/lib/runtime/automatic-account-checks.js +29 -2
- package/dist/lib/runtime/automatic-subscription-checks.d.ts +1 -2
- package/dist/lib/runtime/automatic-subscription-checks.d.ts.map +1 -1
- package/dist/lib/runtime/automatic-subscription-checks.js +13 -16
- 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 +2 -3
- 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 +136 -3
- 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 +10 -3
- package/dist/lib/storage/pending-auth.d.ts.map +1 -1
- package/dist/lib/storage/pending-auth.js +33 -9
- 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 +15 -0
- package/dist/lib/storage/record-identity.d.ts.map +1 -0
- package/dist/lib/storage/record-identity.js +16 -0
- 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 +0 -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 +0 -1
- 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/node_modules/@codex-ai/plugin/dist/index.d.ts +2 -2
- package/node_modules/@codex-ai/plugin/dist/index.js +2 -2
- package/node_modules/@codex-ai/plugin/dist/tool.d.ts +42 -42
- package/node_modules/@codex-ai/plugin/dist/tool.js +29 -29
- package/node_modules/@codex-ai/plugin/package.json +9 -9
- package/node_modules/@codex-ai/sdk/dist/index.d.ts +4 -4
- package/node_modules/@codex-ai/sdk/dist/index.js +2 -2
- package/node_modules/@codex-ai/sdk/package.json +8 -8
- package/package.json +206 -200
- package/scripts/codex-app-launcher.js +653 -653
- package/scripts/codex-app-router.js +373 -373
- package/scripts/codex-bin-resolver.js +332 -313
- package/scripts/codex-multi-auth.js +65 -59
- package/scripts/codex-routing.js +62 -62
- package/scripts/codex.js +6923 -6642
- package/scripts/install-codex-auth-utils.js +213 -213
- package/scripts/mcodex.js +367 -367
- package/scripts/postinstall.js +114 -114
- package/scripts/preuninstall.js +265 -265
- package/skills/codex-auth-setup/SKILL.md +73 -0
- package/vendor/codex-ai-plugin/dist/index.d.ts +2 -2
- package/vendor/codex-ai-plugin/dist/index.js +2 -2
- package/vendor/codex-ai-plugin/dist/tool.d.ts +42 -42
- package/vendor/codex-ai-plugin/dist/tool.js +29 -29
- package/vendor/codex-ai-plugin/package.json +9 -9
- package/vendor/codex-ai-sdk/dist/index.d.ts +4 -4
- package/vendor/codex-ai-sdk/dist/index.js +2 -2
- package/vendor/codex-ai-sdk/package.json +8 -8
|
@@ -18,4 +18,3 @@ export declare function toAccountIdentityRef(account: Pick<AccountLike, "account
|
|
|
18
18
|
export declare function getAccountIdentityKey(account: Pick<AccountLike, "accountId" | "email" | "refreshToken">): string | undefined;
|
|
19
19
|
export declare function getRuntimeAccountIdentityKey(account: Pick<RuntimeAccountLike, "accountId" | "email" | "index">): string | number | undefined;
|
|
20
20
|
export {};
|
|
21
|
-
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stamp `updatedAt` for a per-key governance entry with a hybrid logical
|
|
3
|
+
* floor: when the wall clock regressed below the timestamp the entry being
|
|
4
|
+
* overwritten already carries, stamp `prior + 1` instead of `now`. Every
|
|
5
|
+
* upsert-only store merges with `updatedAt >=`, so a backward clock jump
|
|
6
|
+
* would otherwise stamp a semantically-newer write below its own
|
|
7
|
+
* predecessor and the merge would silently drop it. Equal or forward wall
|
|
8
|
+
* times pass through unchanged — ties already resolve to the caller's
|
|
9
|
+
* write under `>=`.
|
|
10
|
+
*
|
|
11
|
+
* `prior` is the entry the writer saw, which can trail the freshest on-disk
|
|
12
|
+
* entry when a concurrent writer lands between the caller's load and its
|
|
13
|
+
* save; baseline-aware save merges re-apply this same floor against the
|
|
14
|
+
* on-disk entry at merge time so the edit still cannot be lost.
|
|
15
|
+
*/
|
|
16
|
+
export declare function stampUpdatedAt(now: number, prior: number | undefined): number;
|
|
17
|
+
/**
|
|
18
|
+
* Serialize `task` behind the previous write queued for `path`, so same-file
|
|
19
|
+
* writers inside this process run one at a time in submission order. A failed
|
|
20
|
+
* predecessor never blocks or fails successors. Re-entrant for the same path
|
|
21
|
+
* within one async context.
|
|
22
|
+
*
|
|
23
|
+
* This is the per-path generalization of the module-local `writeQueue`
|
|
24
|
+
* variables the governance stores used to keep by hand.
|
|
25
|
+
*/
|
|
26
|
+
export declare function withJsonStoreWriteQueue<T>(path: string, task: () => Promise<T>): Promise<T>;
|
|
27
|
+
/** Test helper: drop queued-write bookkeeping (all paths, or one when given). */
|
|
28
|
+
export declare function resetJsonStoreWriteQueuesForTests(path?: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Stat `filePath` for its mtime with bounded transient-FS retry (the save
|
|
31
|
+
* path is Windows-sensitive: a single transient EBUSY/EPERM/EAGAIN from an
|
|
32
|
+
* AV/indexer lock must not abort the whole save). ENOENT returns `null`
|
|
33
|
+
* immediately; on exhaustion the last failure surfaces so the caller treats
|
|
34
|
+
* it as a real save error rather than a phantom missing file.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getJsonStoreFileMtimeMs(filePath: string): Promise<number | null>;
|
|
37
|
+
/**
|
|
38
|
+
* The `ESTALE` signal used by the CAS retry loop: the file's mtime moved
|
|
39
|
+
* between the caller's stat and its write, so the attempt must re-read and
|
|
40
|
+
* re-merge against the latest on-disk state instead of clobbering it.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createJsonStoreStaleError(filePath: string): NodeJS.ErrnoException;
|
|
43
|
+
/**
|
|
44
|
+
* Throw `ESTALE` when `filePath`'s current mtime differs from
|
|
45
|
+
* `expectedMtimeMs` (`null` means "file must still be absent"). Writers that
|
|
46
|
+
* keep their own temp+rename flow call this just before the rename, matching
|
|
47
|
+
* {@link writeJsonStoreFileAtomicWithRetry}'s inline check.
|
|
48
|
+
*/
|
|
49
|
+
export declare function assertJsonStoreFileMtimeUnchanged(filePath: string, expectedMtimeMs: number | null): Promise<void>;
|
|
50
|
+
export interface JsonStoreAtomicWriteOptions {
|
|
51
|
+
/**
|
|
52
|
+
* When present (including explicit `null` = "expect the file to be
|
|
53
|
+
* absent"), compare-and-swap guard: abort with `ESTALE` if the target's
|
|
54
|
+
* mtime moved since the caller read it, so the caller can re-read and
|
|
55
|
+
* merge instead of clobbering a concurrent write. Omit the key entirely
|
|
56
|
+
* to skip the check.
|
|
57
|
+
*/
|
|
58
|
+
expectedMtimeMs?: number | null;
|
|
59
|
+
/** Temp file mode (and therefore the final file's mode when created). */
|
|
60
|
+
mode?: number;
|
|
61
|
+
/** fsync the temp file before rename so a crash/power-loss cannot leave a truncated store. */
|
|
62
|
+
fsync?: boolean;
|
|
63
|
+
/** Rename retry codes; defaults to EBUSY/EPERM. */
|
|
64
|
+
retryableCodes?: ReadonlySet<string>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Atomic JSON write: serialize `payload` pretty-printed with a trailing
|
|
68
|
+
* newline to a crypto-random sibling temp file, then rename it over
|
|
69
|
+
* `filePath` with bounded transient-FS retry. Optionally CAS-checks the
|
|
70
|
+
* target mtime first and fsyncs the temp file; on failure the temp is
|
|
71
|
+
* removed best-effort.
|
|
72
|
+
*/
|
|
73
|
+
export declare function writeJsonStoreFileAtomicWithRetry(filePath: string, payload: unknown, options?: JsonStoreAtomicWriteOptions): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Run `task`, retrying `ESTALE` CAS aborts so each attempt can re-read and
|
|
76
|
+
* re-merge against the latest on-disk state (matches the config save loop:
|
|
77
|
+
* 3 attempts, immediate retry, ESTALE-only).
|
|
78
|
+
*/
|
|
79
|
+
export declare function withJsonStoreCasRetry<T>(task: () => Promise<T>): Promise<T>;
|
|
80
|
+
export interface JsonStoreFileLockOptions {
|
|
81
|
+
/**
|
|
82
|
+
* How long to wait for a lock held by a LIVE foreign process before
|
|
83
|
+
* failing with `ELOCKTIMEOUT` (default 10s). A crashed holder's lock is
|
|
84
|
+
* reclaimed as soon as its dead PID is observed; a live holder is never
|
|
85
|
+
* evicted — including a reused PID, which fails closed here rather than
|
|
86
|
+
* risking two writers in the critical section.
|
|
87
|
+
*/
|
|
88
|
+
waitTimeoutMs?: number;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Cross-process mutex for a JSON store file, delegated to the proven
|
|
92
|
+
* candidate-directory transaction lock in lib/storage/file-lock.ts: each
|
|
93
|
+
* acquirer stages `<path>.write-lock.candidate-*` containing its unique
|
|
94
|
+
* `<host>.<pid>.<uuid>` owner file, then publishes it with a single atomic
|
|
95
|
+
* `rename` (which only succeeds while the lock directory is absent or empty,
|
|
96
|
+
* so there is no ownerless acquisition window). A crashed holder's lock is
|
|
97
|
+
* recovered by unlinking exactly that dead owner's unique filename and
|
|
98
|
+
* removing the directory only while it is still empty — an `rmdir` can never
|
|
99
|
+
* erase a lock that was republished in the meantime, so takeover can never
|
|
100
|
+
* delete another owner's live lock. Waiters on a live holder retry inside
|
|
101
|
+
* `waitTimeoutMs` (default 10s), then this wrapper surfaces the exhaustion
|
|
102
|
+
* as `ELOCKTIMEOUT`. Re-entrant for the same resolved path within one async
|
|
103
|
+
* context.
|
|
104
|
+
*/
|
|
105
|
+
export declare function withJsonStoreFileLock<T>(targetPath: string, task: () => Promise<T>, options?: JsonStoreFileLockOptions): Promise<T>;
|
|
@@ -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
|
|
@@ -3,6 +3,7 @@ export declare function getPendingAuthPath(storagePath: string): string;
|
|
|
3
3
|
/** Record a rotated credential beside the account pool. */
|
|
4
4
|
export declare function recordPendingAuth(storagePath: string, auth: {
|
|
5
5
|
priorRefreshToken: string;
|
|
6
|
+
recordId?: string;
|
|
6
7
|
refreshToken: string;
|
|
7
8
|
accessToken: string;
|
|
8
9
|
expiresAt: number;
|
|
@@ -10,8 +11,14 @@ export declare function recordPendingAuth(storagePath: string, auth: {
|
|
|
10
11
|
}): Promise<void>;
|
|
11
12
|
/** Overlay pending rotated credentials on rows that still hold the spent token. */
|
|
12
13
|
export declare function applyPendingAuth(storagePath: string, storage: AccountStorageV3 | null): Promise<AccountStorageV3 | null>;
|
|
13
|
-
/**
|
|
14
|
-
|
|
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>;
|
|
15
23
|
/** Coordinate resets with pending credential writers, including Windows rename locks. */
|
|
16
24
|
export declare function clearPendingAuth(storagePath: string): Promise<void>;
|
|
17
|
-
//# sourceMappingURL=pending-auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pending-auth.d.ts","sourceRoot":"","sources":["../../../lib/storage/pending-auth.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"pending-auth.d.ts","sourceRoot":"","sources":["../../../lib/storage/pending-auth.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AA0B1D,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAmCD,2DAA2D;AAC3D,wBAAsB,iBAAiB,CACtC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9H,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED,mFAAmF;AACnF,wBAAsB,gBAAgB,CACrC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAC9B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA6BlC;AAED,mGAAmG;AACnG,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlG;AAED,yFAAyF;AACzF,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGzE"}
|
|
@@ -17,6 +17,7 @@ import { getIntentionalResetMarkerPath } from "./backup-paths.js";
|
|
|
17
17
|
const entrySchema = z.object({
|
|
18
18
|
/** sha256 of the spent refresh token: identifies the row without storing it. */
|
|
19
19
|
prior: z.string().regex(/^[0-9a-f]{64}$/),
|
|
20
|
+
recordId: z.string().trim().min(1).optional(),
|
|
20
21
|
refreshToken: z.string().min(1),
|
|
21
22
|
accessToken: z.string().min(1),
|
|
22
23
|
expiresAt: z.number(),
|
|
@@ -78,15 +79,17 @@ export async function recordPendingAuth(storagePath, auth) {
|
|
|
78
79
|
}
|
|
79
80
|
const prior = hash(auth.priorRefreshToken);
|
|
80
81
|
const entries = (await read(path)).filter((entry) => entry.prior !== prior && entry.prior !== hash(auth.refreshToken));
|
|
81
|
-
// Rotating a token that is itself only journaled:
|
|
82
|
-
//
|
|
83
|
-
//
|
|
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.
|
|
84
88
|
const chained = entries.find((entry) => entry.refreshToken === auth.priorRefreshToken);
|
|
85
|
-
const current = chained ?? { prior, refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at };
|
|
86
89
|
if (chained)
|
|
87
|
-
Object.assign(chained, { refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at });
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
Object.assign(chained, { recordId: chained.recordId ?? auth.recordId, refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at });
|
|
91
|
+
const current = { prior, recordId: auth.recordId, refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at };
|
|
92
|
+
entries.push(current);
|
|
90
93
|
const excess = entries.length - MAX_ENTRIES;
|
|
91
94
|
if (excess > 0) {
|
|
92
95
|
// Drop the oldest other entries, never the credential being recorded now.
|
|
@@ -120,6 +123,7 @@ export async function applyPendingAuth(storagePath, storage) {
|
|
|
120
123
|
const entry = account.refreshToken ? entries.find((item) => item.prior === hash(account.refreshToken)) : undefined;
|
|
121
124
|
if (!entry)
|
|
122
125
|
continue;
|
|
126
|
+
account.recordId ??= entry.recordId;
|
|
123
127
|
account.refreshToken = entry.refreshToken;
|
|
124
128
|
account.accessToken = entry.accessToken;
|
|
125
129
|
account.expiresAt = entry.expiresAt;
|
|
@@ -132,14 +136,34 @@ export async function applyPendingAuth(storagePath, storage) {
|
|
|
132
136
|
}
|
|
133
137
|
return storage;
|
|
134
138
|
}
|
|
135
|
-
/**
|
|
136
|
-
|
|
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) {
|
|
137
148
|
const path = getPendingAuthPath(storagePath);
|
|
138
149
|
const current = await read(path);
|
|
139
150
|
if (!current.length)
|
|
140
151
|
return;
|
|
141
152
|
await withFileTransactionLock(path, async () => {
|
|
142
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
|
+
}
|
|
143
167
|
const entries = await read(path);
|
|
144
168
|
const remaining = entries.filter((entry) => spent.has(entry.prior));
|
|
145
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
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Derive a legacy record identity before its first persisted token rotation. */
|
|
2
|
+
export declare function deriveAccountRecordId(account: {
|
|
3
|
+
accountId?: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
refreshToken: string;
|
|
6
|
+
addedAt: number;
|
|
7
|
+
}): string;
|
|
8
|
+
/** Resolve the persisted identity, or derive it for a legacy row. */
|
|
9
|
+
export declare function resolveAccountRecordId(account: {
|
|
10
|
+
recordId?: string;
|
|
11
|
+
accountId?: string;
|
|
12
|
+
email?: string;
|
|
13
|
+
refreshToken: string;
|
|
14
|
+
addedAt: number;
|
|
15
|
+
}): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-identity.d.ts","sourceRoot":"","sources":["../../../lib/storage/record-identity.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE;IACR,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CAChB,GACC,MAAM,CAQR;AAED,qEAAqE;AACrE,wBAAgB,sBAAsB,CACrC,OAAO,EAAE;IACR,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CAChB,GACC,MAAM,CAGR"}
|