



























@@ -1,5 +1,12 @@
1-import { readMiniMaxCliCredentialsCached } from "../cli-credentials.js";
2-import { EXTERNAL_CLI_SYNC_TTL_MS, MINIMAX_CLI_PROFILE_ID } from "./constants.js";
1+import {
2+readCodexCliCredentialsCached,
3+readMiniMaxCliCredentialsCached,
4+} from "../cli-credentials.js";
5+import {
6+EXTERNAL_CLI_SYNC_TTL_MS,
7+MINIMAX_CLI_PROFILE_ID,
8+OPENAI_CODEX_DEFAULT_PROFILE_ID,
9+} from "./constants.js";
310import { log } from "./constants.js";
411import {
512areOAuthCredentialsEquivalent,
@@ -29,6 +36,12 @@ type ExternalCliSyncProvider = {
2936profileId: string;
3037provider: string;
3138readCredentials: () => OAuthCredential | null;
39+// bootstrapOnly providers adopt the external CLI credential only to
40+// seed an empty slot; once a local OAuth credential exists for the
41+// profile, the local refresh token is treated as canonical and the
42+// CLI state must not replace or shadow it. Codex requires this to
43+// avoid clobbering a locally refreshed token with stale CLI state.
44+bootstrapOnly?: boolean;
3245};
33463447function normalizeAuthIdentityToken(value: string | undefined): string | undefined {
@@ -72,6 +85,12 @@ export function isSafeToUseExternalCliCredential(
7285}
73867487const EXTERNAL_CLI_SYNC_PROVIDERS: ExternalCliSyncProvider[] = [
88+{
89+profileId: OPENAI_CODEX_DEFAULT_PROFILE_ID,
90+provider: "openai-codex",
91+readCredentials: () => readCodexCliCredentialsCached({ ttlMs: EXTERNAL_CLI_SYNC_TTL_MS }),
92+bootstrapOnly: true,
93+},
7594{
7695profileId: MINIMAX_CLI_PROFILE_ID,
7796provider: "minimax-portal",
@@ -103,6 +122,13 @@ export function readExternalCliBootstrapCredential(params: {
103122if (!provider) {
104123return null;
105124}
125+// bootstrapOnly providers must not replace an existing local credential
126+// during runtime refresh. The oauth-manager only calls this hook when a
127+// local credential is already present, so returning null here keeps the
128+// locally stored refresh token canonical.
129+if (provider.bootstrapOnly) {
130+return null;
131+}
106132return provider.readCredentials();
107133}
108134@@ -132,6 +158,13 @@ export function resolveExternalCliAuthProfiles(
132158});
133159continue;
134160}
161+if (providerConfig.bootstrapOnly && existingOAuth) {
162+log.debug("kept local oauth over external cli bootstrap-only provider", {
163+profileId: providerConfig.profileId,
164+provider: providerConfig.provider,
165+});
166+continue;
167+}
135168if (existingOAuth && !isSafeToUseExternalCliCredential(existingOAuth, creds)) {
136169log.warn("refused external cli oauth bootstrap: identity mismatch", {
137170profileId: providerConfig.profileId,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。