codex-multi-auth 2.7.0 → 2.8.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 +9 -9
- package/README.md +435 -433
- package/dist/lib/cli.d.ts +2 -0
- package/dist/lib/cli.d.ts.map +1 -1
- package/dist/lib/codex-cli/writer.d.ts +51 -0
- package/dist/lib/codex-cli/writer.d.ts.map +1 -1
- package/dist/lib/codex-cli/writer.js +89 -8
- package/dist/lib/codex-manager/login-menu-actions.d.ts.map +1 -1
- package/dist/lib/codex-manager/login-menu-actions.js +12 -1
- package/dist/lib/codex-manager/login-menu-data.d.ts.map +1 -1
- package/dist/lib/codex-manager/login-menu-data.js +19 -8
- package/dist/lib/codex-manager/repair-commands.d.ts.map +1 -1
- package/dist/lib/codex-manager/repair-commands.js +57 -8
- package/dist/lib/forecast.d.ts.map +1 -1
- package/dist/lib/forecast.js +30 -4
- package/dist/lib/policy/runtime-policy.d.ts.map +1 -1
- package/dist/lib/policy/runtime-policy.js +12 -3
- package/dist/lib/quota-readiness.d.ts +1 -0
- package/dist/lib/quota-readiness.d.ts.map +1 -1
- package/dist/lib/quota-readiness.js +12 -2
- package/dist/lib/refresh-lease.d.ts +12 -0
- package/dist/lib/refresh-lease.d.ts.map +1 -1
- package/dist/lib/refresh-lease.js +24 -2
- package/dist/lib/refresh-queue.d.ts.map +1 -1
- package/dist/lib/refresh-queue.js +29 -3
- package/dist/lib/request/request-transformer.d.ts.map +1 -1
- package/dist/lib/request/request-transformer.js +13 -2
- package/dist/lib/request/response-handler.d.ts.map +1 -1
- package/dist/lib/request/response-handler.js +10 -1
- package/dist/lib/rotation.d.ts.map +1 -1
- package/dist/lib/rotation.js +8 -1
- package/dist/lib/runtime/account-check.d.ts +1 -1
- package/dist/lib/runtime/account-check.d.ts.map +1 -1
- package/dist/lib/runtime/account-check.js +8 -0
- package/dist/lib/runtime/first-run.d.ts +12 -6
- package/dist/lib/runtime/first-run.d.ts.map +1 -1
- package/dist/lib/runtime/first-run.js +140 -9
- package/dist/lib/runtime/rotation-storage-meta.d.ts.map +1 -1
- package/dist/lib/runtime/rotation-storage-meta.js +8 -2
- package/dist/lib/storage/account-port.d.ts +2 -0
- package/dist/lib/storage/account-port.d.ts.map +1 -1
- package/dist/lib/storage/account-port.js +1 -0
- package/dist/lib/storage/import-export.d.ts +1 -0
- package/dist/lib/storage/import-export.d.ts.map +1 -1
- package/dist/lib/storage/import-export.js +25 -0
- package/dist/lib/storage/project-migration.d.ts +1 -1
- package/dist/lib/storage/project-migration.d.ts.map +1 -1
- package/dist/lib/storage/project-migration.js +28 -2
- package/dist/lib/storage.d.ts +10 -0
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +16 -1
- package/dist/lib/ui/auth-menu-builder.d.ts +10 -0
- package/dist/lib/ui/auth-menu-builder.d.ts.map +1 -1
- package/dist/lib/ui/auth-menu-builder.js +29 -4
- package/package.json +1 -1
- package/scripts/codex.js +126 -13
|
@@ -24,6 +24,7 @@ export async function importAccountsSnapshot(params) {
|
|
|
24
24
|
imported: normalized,
|
|
25
25
|
maxAccounts: params.maxAccounts,
|
|
26
26
|
deduplicateAccounts: params.deduplicateAccounts,
|
|
27
|
+
findMatchingAccountIndex: params.findMatchingAccountIndex,
|
|
27
28
|
});
|
|
28
29
|
await persist(merged.newStorage);
|
|
29
30
|
return {
|
|
@@ -15,6 +15,7 @@ export declare function mergeImportedAccounts(params: {
|
|
|
15
15
|
imported: AccountStorageV3;
|
|
16
16
|
maxAccounts: number;
|
|
17
17
|
deduplicateAccounts: (accounts: AccountStorageV3["accounts"]) => AccountStorageV3["accounts"];
|
|
18
|
+
findMatchingAccountIndex: (accounts: AccountStorageV3["accounts"], candidate: AccountStorageV3["accounts"][number]) => number | undefined;
|
|
18
19
|
}): {
|
|
19
20
|
newStorage: AccountStorageV3;
|
|
20
21
|
imported: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-export.d.ts","sourceRoot":"","sources":["../../../lib/storage/import-export.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAsD1D,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9D,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACrE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuChB;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,gBAAgB,GAAG,IAAI,CAAC;CACrE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8C5B;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC7C,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,CACpB,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,KAClC,gBAAgB,CAAC,UAAU,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"import-export.d.ts","sourceRoot":"","sources":["../../../lib/storage/import-export.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAsD1D,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9D,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACrE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuChB;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,gBAAgB,GAAG,IAAI,CAAC;CACrE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8C5B;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC7C,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,CACpB,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,KAClC,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAGlC,wBAAwB,EAAE,CACzB,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,EACtC,SAAS,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAC3C,MAAM,GAAG,SAAS,CAAC;CACxB,GAAG;IACH,UAAU,EAAE,gBAAgB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB,CA6DA"}
|
|
@@ -127,6 +127,14 @@ export async function readImportFile(params) {
|
|
|
127
127
|
export function mergeImportedAccounts(params) {
|
|
128
128
|
const existingAccounts = params.existing?.accounts ?? [];
|
|
129
129
|
const existingActiveIndex = params.existing?.activeIndex ?? 0;
|
|
130
|
+
// Resolve the pinned account by IDENTITY before merging. The merged list is
|
|
131
|
+
// deduplicated below, which can move accounts to different positions, so a raw
|
|
132
|
+
// positional pin can end up selecting a DIFFERENT account (in range, wrong
|
|
133
|
+
// account) instead of the one the user pinned.
|
|
134
|
+
const existingPinnedIndex = params.existing?.pinnedAccountIndex;
|
|
135
|
+
const pinnedAccount = typeof existingPinnedIndex === "number"
|
|
136
|
+
? existingAccounts[existingPinnedIndex]
|
|
137
|
+
: undefined;
|
|
130
138
|
const merged = [...existingAccounts, ...params.imported.accounts];
|
|
131
139
|
if (merged.length > params.maxAccounts) {
|
|
132
140
|
const deduped = params.deduplicateAccounts(merged);
|
|
@@ -142,6 +150,23 @@ export function mergeImportedAccounts(params) {
|
|
|
142
150
|
activeIndex: existingActiveIndex,
|
|
143
151
|
activeIndexByFamily: params.existing?.activeIndexByFamily,
|
|
144
152
|
};
|
|
153
|
+
// Preserve the user's manual pin (#474) and affinity generation across import.
|
|
154
|
+
// Rebuilding storage from scratch here previously dropped a `switch <n>` pin
|
|
155
|
+
// and reset affinityGeneration to 0, which lets a running proxy holding a
|
|
156
|
+
// higher in-memory generation clobber a newer CLI pin. The pin is re-resolved
|
|
157
|
+
// against the deduplicated list by identity — a range check alone would happily
|
|
158
|
+
// keep an in-range index that dedupe has repointed at another account. When the
|
|
159
|
+
// pinned account no longer resolves (removed or ambiguous) the pin is dropped
|
|
160
|
+
// rather than left pointing somewhere arbitrary.
|
|
161
|
+
if (pinnedAccount) {
|
|
162
|
+
const remappedPinnedIndex = params.findMatchingAccountIndex(deduplicatedAccounts, pinnedAccount);
|
|
163
|
+
if (remappedPinnedIndex !== undefined) {
|
|
164
|
+
newStorage.pinnedAccountIndex = remappedPinnedIndex;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (typeof params.existing?.affinityGeneration === "number") {
|
|
168
|
+
newStorage.affinityGeneration = params.existing.affinityGeneration;
|
|
169
|
+
}
|
|
145
170
|
const importedCount = deduplicatedAccounts.length - deduplicatedExistingAccounts.length;
|
|
146
171
|
const skippedCount = params.imported.accounts.length - importedCount;
|
|
147
172
|
return {
|
|
@@ -6,5 +6,5 @@ export declare function loadNormalizedStorageFromPath(path: string, label: strin
|
|
|
6
6
|
}>;
|
|
7
7
|
logWarn: (message: string, details: Record<string, unknown>) => void;
|
|
8
8
|
}): Promise<AccountStorageV3 | null>;
|
|
9
|
-
export declare function mergeStorageForMigration(current: AccountStorageV3 | null, incoming: AccountStorageV3, normalizeAccountStorage: (value: unknown) => AccountStorageV3 | null): AccountStorageV3;
|
|
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
10
|
//# sourceMappingURL=project-migration.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-migration.d.ts","sourceRoot":"","sources":["../../../lib/storage/project-migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,wBAAsB,6BAA6B,CAClD,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IACL,oBAAoB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAC/C,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;QACpC,YAAY,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC,CAAC;IACH,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACrE,GACC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAoBlC;AAED,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,QAAQ,EAAE,gBAAgB,EAC1B,uBAAuB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,gBAAgB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"project-migration.d.ts","sourceRoot":"","sources":["../../../lib/storage/project-migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,wBAAsB,6BAA6B,CAClD,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IACL,oBAAoB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAC/C,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;QACpC,YAAY,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC,CAAC;IACH,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACrE,GACC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAoBlC;AAED,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,QAAQ,EAAE,gBAAgB,EAC1B,uBAAuB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,gBAAgB,GAAG,IAAI,EAIpE,wBAAwB,EAAE,CACzB,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,EACtC,SAAS,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAC3C,MAAM,GAAG,SAAS,GACrB,gBAAgB,CAuClB"}
|
|
@@ -20,18 +20,44 @@ export async function loadNormalizedStorageFromPath(path, label, deps) {
|
|
|
20
20
|
return null;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
export function mergeStorageForMigration(current, incoming, normalizeAccountStorage
|
|
23
|
+
export function mergeStorageForMigration(current, incoming, normalizeAccountStorage,
|
|
24
|
+
// Injected like `normalizeAccountStorage` rather than imported from
|
|
25
|
+
// ../storage.js, which would put this leaf module in a dependency cycle with
|
|
26
|
+
// the storage barrel.
|
|
27
|
+
findMatchingAccountIndex) {
|
|
24
28
|
if (!current) {
|
|
25
29
|
return incoming;
|
|
26
30
|
}
|
|
31
|
+
// Resolve the pinned account by IDENTITY before merging. normalizeAccountStorage
|
|
32
|
+
// deduplicates the merged list but only RANGE-validates the pin, so a raw
|
|
33
|
+
// positional pin that survives the range check can still end up pointing at a
|
|
34
|
+
// different account once dedupe shifts positions.
|
|
35
|
+
const pinnedAccount = typeof current.pinnedAccountIndex === "number"
|
|
36
|
+
? current.accounts[current.pinnedAccountIndex]
|
|
37
|
+
: undefined;
|
|
27
38
|
const merged = normalizeAccountStorage({
|
|
28
39
|
version: 3,
|
|
29
40
|
activeIndex: current.activeIndex,
|
|
30
41
|
activeIndexByFamily: current.activeIndexByFamily,
|
|
31
42
|
accounts: [...current.accounts, ...incoming.accounts],
|
|
43
|
+
// Carry the manual pin (#474) and affinity generation from the current
|
|
44
|
+
// storage through legacy-project migration; normalizeAccountStorage
|
|
45
|
+
// validates/clamps them against the merged account list. Omitting them
|
|
46
|
+
// dropped the pin and reset affinityGeneration to 0, which let a running
|
|
47
|
+
// proxy clobber a newer CLI pin.
|
|
48
|
+
pinnedAccountIndex: current.pinnedAccountIndex,
|
|
49
|
+
affinityGeneration: current.affinityGeneration,
|
|
32
50
|
});
|
|
33
51
|
if (!merged) {
|
|
34
52
|
return current;
|
|
35
53
|
}
|
|
36
|
-
|
|
54
|
+
if (!pinnedAccount) {
|
|
55
|
+
return merged;
|
|
56
|
+
}
|
|
57
|
+
// Re-point the pin at the account the user actually pinned; clear it when that
|
|
58
|
+
// account no longer resolves in the normalized list.
|
|
59
|
+
return {
|
|
60
|
+
...merged,
|
|
61
|
+
pinnedAccountIndex: findMatchingAccountIndex(merged.accounts, pinnedAccount),
|
|
62
|
+
};
|
|
37
63
|
}
|
package/dist/lib/storage.d.ts
CHANGED
|
@@ -35,6 +35,16 @@ type AccountMatchOptions = {
|
|
|
35
35
|
allowUniqueAccountIdFallbackWithoutEmail?: boolean;
|
|
36
36
|
};
|
|
37
37
|
export declare function findMatchingAccountIndex<T extends Pick<AccountLike, "accountId" | "email" | "refreshToken">>(accounts: readonly T[], candidate: Pick<AccountLike, "accountId" | "email" | "refreshToken">, options?: AccountMatchOptions): number | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Re-resolve a manual pin after the account list changes (deletion / auto-removal).
|
|
40
|
+
* `pinnedAccountIndex` is a POSITION, so once accounts are removed or reordered the
|
|
41
|
+
* raw index silently points at a DIFFERENT account — or out of range, which wedges
|
|
42
|
+
* the pool. Capture the pinned account BEFORE the change and pass it here to follow
|
|
43
|
+
* it by identity: returns its new index, or `undefined` when it is no longer present
|
|
44
|
+
* (the pin is cleared, never left dangling at a stale slot). See #474 — a manual pin
|
|
45
|
+
* must keep pointing at the account the user chose, or be dropped.
|
|
46
|
+
*/
|
|
47
|
+
export declare function reconcilePinnedAccountIndex(pinnedAccount: Pick<AccountLike, "accountId" | "email" | "refreshToken"> | undefined, nextAccounts: readonly Pick<AccountLike, "accountId" | "email" | "refreshToken">[]): number | undefined;
|
|
38
48
|
export declare function resolveAccountSelectionIndex<T extends Pick<AccountLike, "accountId" | "email" | "refreshToken">>(accounts: readonly T[], candidate: Pick<AccountLike, "accountId" | "email" | "refreshToken">, fallbackIndex?: number): number;
|
|
39
49
|
/**
|
|
40
50
|
* Removes duplicate accounts, keeping the most recently used entry for each
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"AA+BA,OAAO,EACN,KAAK,cAAc,EAGnB,KAAK,iBAAiB,EAEtB,MAAM,8BAA8B,CAAC;AAkBtC,OAAO,EAEN,KAAK,oBAAoB,EACzB,MAAM,qBAAqB,CAAC;AAe7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACN,sBAAsB,EACtB,cAAc,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,qBAAqB,EACrB,iBAAiB,GACjB,MAAM,uBAAuB,CAAC;AAa/B,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,wBAAwB,EACxB,uBAAuB,EACvB,gBAAgB,EAChB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,4BAA4B,CAAC;AA0CpC,YAAY,EACX,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,kBAAkB,GAClB,CAAC;AAcF,KAAK,WAAW,GAAG;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAiBF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE9D;AAuWD,wBAAgB,4BAA4B,IAAI,MAAM,CAErD;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CA4C/D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAO9D;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAMvC;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAarE;AAED,wBAAsB,yBAAyB,CAC9C,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAe3B;AAED,wBAAsB,iBAAiB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3B,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/storage.js
CHANGED
|
@@ -558,7 +558,7 @@ async function migrateLegacyProjectStorageIfNeeded(options) {
|
|
|
558
558
|
if (liveCurrentStorageAfterLegacyRead.exists) {
|
|
559
559
|
return liveCurrentStorageAfterLegacyRead.storage;
|
|
560
560
|
}
|
|
561
|
-
const mergedStorage = mergeStorageForMigration(targetStorage, legacyStorage, normalizeAccountStorage);
|
|
561
|
+
const mergedStorage = mergeStorageForMigration(targetStorage, legacyStorage, normalizeAccountStorage, findMatchingAccountIndex);
|
|
562
562
|
const fallbackStorage = targetStorage ?? legacyStorage;
|
|
563
563
|
if (commit) {
|
|
564
564
|
try {
|
|
@@ -722,6 +722,20 @@ export function findMatchingAccountIndex(accounts, candidate, options = {}) {
|
|
|
722
722
|
}
|
|
723
723
|
return findUniqueAccountIdMatchIndex(accounts, candidateRef, options);
|
|
724
724
|
}
|
|
725
|
+
/**
|
|
726
|
+
* Re-resolve a manual pin after the account list changes (deletion / auto-removal).
|
|
727
|
+
* `pinnedAccountIndex` is a POSITION, so once accounts are removed or reordered the
|
|
728
|
+
* raw index silently points at a DIFFERENT account — or out of range, which wedges
|
|
729
|
+
* the pool. Capture the pinned account BEFORE the change and pass it here to follow
|
|
730
|
+
* it by identity: returns its new index, or `undefined` when it is no longer present
|
|
731
|
+
* (the pin is cleared, never left dangling at a stale slot). See #474 — a manual pin
|
|
732
|
+
* must keep pointing at the account the user chose, or be dropped.
|
|
733
|
+
*/
|
|
734
|
+
export function reconcilePinnedAccountIndex(pinnedAccount, nextAccounts) {
|
|
735
|
+
if (!pinnedAccount)
|
|
736
|
+
return undefined;
|
|
737
|
+
return findMatchingAccountIndex(nextAccounts, pinnedAccount);
|
|
738
|
+
}
|
|
725
739
|
export function resolveAccountSelectionIndex(accounts, candidate, fallbackIndex = 0) {
|
|
726
740
|
if (accounts.length === 0)
|
|
727
741
|
return 0;
|
|
@@ -1707,6 +1721,7 @@ export async function importAccounts(filePath) {
|
|
|
1707
1721
|
mergeImportedAccounts,
|
|
1708
1722
|
maxAccounts: ACCOUNT_LIMITS.MAX_ACCOUNTS,
|
|
1709
1723
|
deduplicateAccounts,
|
|
1724
|
+
findMatchingAccountIndex,
|
|
1710
1725
|
logInfo: (message, details) => {
|
|
1711
1726
|
log.info(message, details);
|
|
1712
1727
|
},
|
|
@@ -17,6 +17,8 @@ export interface AccountInfo {
|
|
|
17
17
|
quota5hResetAtMs?: number;
|
|
18
18
|
quota7dLeftPercent?: number;
|
|
19
19
|
quota7dResetAtMs?: number;
|
|
20
|
+
quotaPrimaryWindowMinutes?: number;
|
|
21
|
+
quotaSecondaryWindowMinutes?: number;
|
|
20
22
|
quotaRateLimited?: boolean;
|
|
21
23
|
quotaExhausted?: boolean;
|
|
22
24
|
isCurrentAccount?: boolean;
|
|
@@ -84,6 +86,14 @@ export declare function accountTitle(account: AccountInfo): string;
|
|
|
84
86
|
export declare function accountSearchText(account: AccountInfo): string;
|
|
85
87
|
export declare function accountRowColor(account: AccountInfo): MenuItem<AuthMenuAction>["color"];
|
|
86
88
|
export declare function currentMarkerLabel(marker: AccountCurrentMarker): string;
|
|
89
|
+
/**
|
|
90
|
+
* Resolve a quota-window label from its duration in minutes, matching the
|
|
91
|
+
* data-driven labels used by the compact quota summary (`Nd`/`Nh`/`Nm`). Falls
|
|
92
|
+
* back to the positional label when the duration is unknown (e.g. quota entries
|
|
93
|
+
* cached before window durations were persisted), so Plus/Pro rows keep their
|
|
94
|
+
* familiar "5h"/"7d" labels while a Codex Business monthly window renders "30d".
|
|
95
|
+
*/
|
|
96
|
+
export declare function resolveQuotaWindowLabel(windowMinutes: number | undefined, fallbackLabel: string): string;
|
|
87
97
|
export declare function formatAccountHint(account: AccountInfo, ui: ReturnType<typeof getUiRuntimeOptions>): string;
|
|
88
98
|
export declare function authMenuFocusKey(action: AuthMenuAction): string;
|
|
89
99
|
//# sourceMappingURL=auth-menu-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-menu-builder.d.ts","sourceRoot":"","sources":["../../../lib/ui/auth-menu-builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAElF,MAAM,MAAM,aAAa,GACtB,QAAQ,GACR,IAAI,GACJ,iBAAiB,GACjB,cAAc,GACd,UAAU,GACV,UAAU,GACV,OAAO,GACP,SAAS,GACT,SAAS,CAAC;AAEb,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-menu-builder.d.ts","sourceRoot":"","sources":["../../../lib/ui/auth-menu-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -243,6 +243,25 @@ function formatQuotaPercent(leftPercent, ui) {
|
|
|
243
243
|
const tone = quotaToneFromLeftPercent(leftPercent);
|
|
244
244
|
return paintUiText(ui, percentText, tone);
|
|
245
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* Resolve a quota-window label from its duration in minutes, matching the
|
|
248
|
+
* data-driven labels used by the compact quota summary (`Nd`/`Nh`/`Nm`). Falls
|
|
249
|
+
* back to the positional label when the duration is unknown (e.g. quota entries
|
|
250
|
+
* cached before window durations were persisted), so Plus/Pro rows keep their
|
|
251
|
+
* familiar "5h"/"7d" labels while a Codex Business monthly window renders "30d".
|
|
252
|
+
*/
|
|
253
|
+
export function resolveQuotaWindowLabel(windowMinutes, fallbackLabel) {
|
|
254
|
+
if (typeof windowMinutes !== "number" ||
|
|
255
|
+
!Number.isFinite(windowMinutes) ||
|
|
256
|
+
windowMinutes <= 0) {
|
|
257
|
+
return fallbackLabel;
|
|
258
|
+
}
|
|
259
|
+
if (windowMinutes % 1440 === 0)
|
|
260
|
+
return `${windowMinutes / 1440}d`;
|
|
261
|
+
if (windowMinutes % 60 === 0)
|
|
262
|
+
return `${windowMinutes / 60}h`;
|
|
263
|
+
return `${windowMinutes}m`;
|
|
264
|
+
}
|
|
246
265
|
function formatQuotaWindow(label, leftPercent, resetAtMs, showCooldown, ui) {
|
|
247
266
|
const labelText = ui.v2Enabled ? paintUiText(ui, label, "muted") : label;
|
|
248
267
|
const bar = formatQuotaBar(leftPercent, ui);
|
|
@@ -263,14 +282,20 @@ function formatQuotaWindow(label, leftPercent, resetAtMs, showCooldown, ui) {
|
|
|
263
282
|
function formatQuotaSummary(account, ui) {
|
|
264
283
|
const summary = account.quotaSummary ?? "";
|
|
265
284
|
const showCooldown = account.showQuotaCooldown !== false;
|
|
266
|
-
|
|
267
|
-
|
|
285
|
+
// Resolve the window labels before parsing the summary: the summary string is
|
|
286
|
+
// produced by `formatAccountQuotaSummary`, which already labels its segments by
|
|
287
|
+
// duration, so a Business row reads "30d 18%, ..." and never "5h ...". Searching
|
|
288
|
+
// it for a literal "5h"/"7d" would find nothing and silently drop the bar.
|
|
289
|
+
const primaryLabel = resolveQuotaWindowLabel(account.quotaPrimaryWindowMinutes, "5h");
|
|
290
|
+
const secondaryLabel = resolveQuotaWindowLabel(account.quotaSecondaryWindowMinutes, "7d");
|
|
291
|
+
const left5h = normalizeQuotaPercent(account.quota5hLeftPercent) ?? parseLeftPercentFromSummary(summary, primaryLabel);
|
|
292
|
+
const left7d = normalizeQuotaPercent(account.quota7dLeftPercent) ?? parseLeftPercentFromSummary(summary, secondaryLabel);
|
|
268
293
|
const segments = [];
|
|
269
294
|
if (left5h !== null || typeof account.quota5hResetAtMs === "number") {
|
|
270
|
-
segments.push(formatQuotaWindow(
|
|
295
|
+
segments.push(formatQuotaWindow(primaryLabel, left5h, account.quota5hResetAtMs, showCooldown, ui));
|
|
271
296
|
}
|
|
272
297
|
if (left7d !== null || typeof account.quota7dResetAtMs === "number") {
|
|
273
|
-
segments.push(formatQuotaWindow(
|
|
298
|
+
segments.push(formatQuotaWindow(secondaryLabel, left7d, account.quota7dResetAtMs, showCooldown, ui));
|
|
274
299
|
}
|
|
275
300
|
if (account.quotaRateLimited || summary.toLowerCase().includes("rate-limited")) {
|
|
276
301
|
segments.push(ui.v2Enabled ? paintUiText(ui, "rate-limited", "danger") : `${ANSI.red}rate-limited${ANSI.reset}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-multi-auth",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Codex CLI multi-account OAuth manager with account switching, health checks, runtime rotation, diagnostics, and recovery tools for @openai/codex",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
package/scripts/codex.js
CHANGED
|
@@ -74,6 +74,10 @@ const APP_RUNTIME_HELPER_OWNER_PID_ENV =
|
|
|
74
74
|
"CODEX_MULTI_AUTH_APP_ROTATION_OWNER_PID";
|
|
75
75
|
const APP_RUNTIME_HELPER_REAL_CODEX_HOME_ENV =
|
|
76
76
|
"CODEX_MULTI_AUTH_REAL_CODEX_HOME";
|
|
77
|
+
const APP_RUNTIME_HELPER_USE_CANONICAL_HOME_ENV =
|
|
78
|
+
"CODEX_MULTI_AUTH_APP_ROTATION_USE_CANONICAL_HOME";
|
|
79
|
+
const APP_SERVER_CONFIG_ARGS_ENV =
|
|
80
|
+
"CODEX_MULTI_AUTH_APP_SERVER_CONFIG_ARGS_JSON";
|
|
77
81
|
const APP_RUNTIME_HELPER_STATUS_FILE =
|
|
78
82
|
RUNTIME_CONSTANTS.APP_RUNTIME_HELPER_STATUS_FILE;
|
|
79
83
|
const DEFAULT_APP_RUNTIME_HELPER_IDLE_MS = 12 * 60 * 60 * 1000;
|
|
@@ -1083,6 +1087,34 @@ async function loadRuntimeConfigTomlModule() {
|
|
|
1083
1087
|
}
|
|
1084
1088
|
}
|
|
1085
1089
|
|
|
1090
|
+
// Reconciles the persisted `cli_auth_credentials_store` in ~/.codex/config.toml
|
|
1091
|
+
// to "file" before forwarding.
|
|
1092
|
+
//
|
|
1093
|
+
// `buildForwardArgs` already appends `-c cli_auth_credentials_store="file"`, but
|
|
1094
|
+
// that only covers the process this wrapper spawns. Third-party front-ends
|
|
1095
|
+
// (CodexBar and friends) exec the official binary directly and read config.toml
|
|
1096
|
+
// instead, so a config still pointing at "keychain" keeps producing macOS login
|
|
1097
|
+
// keychain prompts (issue #641). Running the reconcile here self-heals a config
|
|
1098
|
+
// that something else flipped back — e.g. a fresh official `codex login`.
|
|
1099
|
+
//
|
|
1100
|
+
// Idempotent: the lib helper returns without writing when the value is already
|
|
1101
|
+
// "file", so this adds no write amplification on the common path.
|
|
1102
|
+
async function ensurePersistedCodexFileAuthStore() {
|
|
1103
|
+
const forceFileAuthStore = (process.env.CODEX_MULTI_AUTH_FORCE_FILE_AUTH_STORE ?? "1").trim() !== "0";
|
|
1104
|
+
if (!forceFileAuthStore) return;
|
|
1105
|
+
|
|
1106
|
+
try {
|
|
1107
|
+
const mod = await import("../dist/lib/codex-cli/writer.js");
|
|
1108
|
+
if (typeof mod.ensureCodexCliFileAuthStore !== "function") return;
|
|
1109
|
+
await mod.ensureCodexCliFileAuthStore();
|
|
1110
|
+
} catch (error) {
|
|
1111
|
+
if (isModuleNotFoundError(error)) return;
|
|
1112
|
+
// Best effort only. A read-only or locked config.toml (Windows
|
|
1113
|
+
// EPERM/EBUSY) must never block the wrapped command: the per-invocation
|
|
1114
|
+
// `-c` override still protects this run.
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1086
1118
|
async function autoSyncManagerActiveSelectionIfEnabled() {
|
|
1087
1119
|
const enabled = (process.env.CODEX_MULTI_AUTH_AUTO_SYNC_ON_STARTUP ?? "1").trim() !== "0";
|
|
1088
1120
|
if (!enabled) return;
|
|
@@ -3490,6 +3522,38 @@ function createRuntimeRotationProxyCodexHome(
|
|
|
3490
3522
|
};
|
|
3491
3523
|
}
|
|
3492
3524
|
|
|
3525
|
+
function createRuntimeRotationProxyCanonicalCodexHome(
|
|
3526
|
+
baseEnv,
|
|
3527
|
+
proxyBaseUrl,
|
|
3528
|
+
clientApiKey,
|
|
3529
|
+
configTomlModule,
|
|
3530
|
+
) {
|
|
3531
|
+
const originalCodexHome = resolveRuntimeRotationProxyOriginalCodexHome(baseEnv);
|
|
3532
|
+
const providerTable = `model_providers.${RUNTIME_ROTATION_PROXY_PROVIDER_ID}`;
|
|
3533
|
+
const configArgs = [
|
|
3534
|
+
`${providerTable}.name=${configTomlModule.tomlStringLiteral(APP_SERVER_ACCOUNT_DISPLAY_NAME)}`,
|
|
3535
|
+
`${providerTable}.base_url=${configTomlModule.tomlStringLiteral(proxyBaseUrl)}`,
|
|
3536
|
+
`${providerTable}.env_key=${configTomlModule.tomlStringLiteral("OPENAI_API_KEY")}`,
|
|
3537
|
+
`${providerTable}.requires_openai_auth=false`,
|
|
3538
|
+
`${providerTable}.wire_api=${configTomlModule.tomlStringLiteral("responses")}`,
|
|
3539
|
+
"disable_response_storage=false",
|
|
3540
|
+
].flatMap((assignment) => ["-c", assignment]);
|
|
3541
|
+
|
|
3542
|
+
return {
|
|
3543
|
+
args: configArgs,
|
|
3544
|
+
env: {
|
|
3545
|
+
...baseEnv,
|
|
3546
|
+
CODEX_HOME: originalCodexHome,
|
|
3547
|
+
OPENAI_API_KEY: clientApiKey,
|
|
3548
|
+
CODEX_MULTI_AUTH_DIR: resolveRuntimeRotationOriginalMultiAuthDir(
|
|
3549
|
+
originalCodexHome,
|
|
3550
|
+
baseEnv,
|
|
3551
|
+
),
|
|
3552
|
+
},
|
|
3553
|
+
cleanup: () => {},
|
|
3554
|
+
};
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3493
3557
|
function appendNodeImportOption(nodeOptions, preloadPath) {
|
|
3494
3558
|
const importOption = `--import=${pathToFileURL(preloadPath).href}`;
|
|
3495
3559
|
const trimmed = (nodeOptions ?? "").trim();
|
|
@@ -3504,15 +3568,26 @@ function createRuntimeRotationAppServerPreloadSource(wrapperScriptPath) {
|
|
|
3504
3568
|
"",
|
|
3505
3569
|
`const wrapperScriptPath = ${JSON.stringify(wrapperScriptPath)};`,
|
|
3506
3570
|
`const accountLabelEnv = ${JSON.stringify(APP_SERVER_ACCOUNT_LABEL_ENV)};`,
|
|
3571
|
+
`const configArgsEnv = ${JSON.stringify(APP_SERVER_CONFIG_ARGS_ENV)};`,
|
|
3572
|
+
"let configArgs = [];",
|
|
3573
|
+
"try {",
|
|
3574
|
+
' const parsed = JSON.parse(process.env[configArgsEnv] ?? "[]");',
|
|
3575
|
+
" if (Array.isArray(parsed)) {",
|
|
3576
|
+
' configArgs = parsed.filter((arg) => typeof arg === "string");',
|
|
3577
|
+
" }",
|
|
3578
|
+
"} catch {",
|
|
3579
|
+
" // Ignore malformed internal metadata and preserve app-server startup.",
|
|
3580
|
+
"}",
|
|
3507
3581
|
"const rawArgs = process.argv.slice(1);",
|
|
3508
3582
|
"const firstArg = rawArgs[0] ?? \"\";",
|
|
3509
3583
|
'if (basename(firstArg).toLowerCase() === "app-server") {',
|
|
3510
|
-
' const args = ["app-server", ...rawArgs.slice(1)];',
|
|
3584
|
+
' const args = ["app-server", ...rawArgs.slice(1), ...configArgs];',
|
|
3511
3585
|
" const env = {",
|
|
3512
3586
|
" ...process.env,",
|
|
3513
3587
|
' CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY: "0",',
|
|
3514
3588
|
" [accountLabelEnv]: \"1\",",
|
|
3515
3589
|
" };",
|
|
3590
|
+
" delete env[configArgsEnv];",
|
|
3516
3591
|
" const child = spawn(process.execPath, [wrapperScriptPath, ...args], {",
|
|
3517
3592
|
" stdio: \"inherit\",",
|
|
3518
3593
|
" env,",
|
|
@@ -3558,7 +3633,7 @@ function sweepStaleRuntimeRotationAppServerShimDirs(shimRootDir) {
|
|
|
3558
3633
|
}
|
|
3559
3634
|
}
|
|
3560
3635
|
|
|
3561
|
-
function installRuntimeRotationAppServerCliShim(forwardedEnv) {
|
|
3636
|
+
function installRuntimeRotationAppServerCliShim(forwardedEnv, configArgs = []) {
|
|
3562
3637
|
const shadowCodexHome = forwardedEnv.CODEX_HOME;
|
|
3563
3638
|
if (!shadowCodexHome) {
|
|
3564
3639
|
throw new Error("runtime app-server shim requires CODEX_HOME");
|
|
@@ -3615,6 +3690,11 @@ function installRuntimeRotationAppServerCliShim(forwardedEnv) {
|
|
|
3615
3690
|
);
|
|
3616
3691
|
forwardedEnv.CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY = "0";
|
|
3617
3692
|
forwardedEnv[APP_SERVER_ACCOUNT_LABEL_ENV] = "1";
|
|
3693
|
+
if (configArgs.length > 0) {
|
|
3694
|
+
forwardedEnv[APP_SERVER_CONFIG_ARGS_ENV] = JSON.stringify(configArgs);
|
|
3695
|
+
} else {
|
|
3696
|
+
delete forwardedEnv[APP_SERVER_CONFIG_ARGS_ENV];
|
|
3697
|
+
}
|
|
3618
3698
|
return shimDir;
|
|
3619
3699
|
}
|
|
3620
3700
|
|
|
@@ -3715,6 +3795,7 @@ function pickRuntimeRotationAppHelperEnv(env) {
|
|
|
3715
3795
|
"CODEX_MULTI_AUTH_REAL_CODEX_BIN",
|
|
3716
3796
|
"CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY",
|
|
3717
3797
|
APP_SERVER_ACCOUNT_LABEL_ENV,
|
|
3798
|
+
APP_SERVER_CONFIG_ARGS_ENV,
|
|
3718
3799
|
]) {
|
|
3719
3800
|
if (env[name]) {
|
|
3720
3801
|
picked[name] = env[name];
|
|
@@ -3776,7 +3857,7 @@ function createRuntimeRotationAppHelperStatus({
|
|
|
3776
3857
|
|
|
3777
3858
|
async function runRuntimeRotationAppHelper() {
|
|
3778
3859
|
let proxyServer = null;
|
|
3779
|
-
let
|
|
3860
|
+
let runtimeContext = null;
|
|
3780
3861
|
let appServerShimDir = null;
|
|
3781
3862
|
let statusTimer = null;
|
|
3782
3863
|
let closing = false;
|
|
@@ -3813,7 +3894,7 @@ async function runRuntimeRotationAppHelper() {
|
|
|
3813
3894
|
}
|
|
3814
3895
|
appServerShimDir = null;
|
|
3815
3896
|
}
|
|
3816
|
-
|
|
3897
|
+
runtimeContext?.cleanup?.();
|
|
3817
3898
|
} finally {
|
|
3818
3899
|
try {
|
|
3819
3900
|
await proxyServer?.close?.();
|
|
@@ -3844,13 +3925,33 @@ async function runRuntimeRotationAppHelper() {
|
|
|
3844
3925
|
}
|
|
3845
3926
|
const clientApiKey = createRuntimeRotationProxyClientApiKey();
|
|
3846
3927
|
proxyServer = await proxyModule.startRuntimeRotationProxy({ clientApiKey });
|
|
3847
|
-
|
|
3848
|
-
process.env
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3928
|
+
const useCanonicalHome =
|
|
3929
|
+
(process.env[APP_RUNTIME_HELPER_USE_CANONICAL_HOME_ENV] ?? "").trim() ===
|
|
3930
|
+
"1";
|
|
3931
|
+
runtimeContext = useCanonicalHome
|
|
3932
|
+
? createRuntimeRotationProxyCanonicalCodexHome(
|
|
3933
|
+
process.env,
|
|
3934
|
+
proxyServer.baseUrl,
|
|
3935
|
+
clientApiKey,
|
|
3936
|
+
configTomlModule,
|
|
3937
|
+
)
|
|
3938
|
+
: createRuntimeRotationProxyCodexHome(
|
|
3939
|
+
process.env,
|
|
3940
|
+
proxyServer.baseUrl,
|
|
3941
|
+
clientApiKey,
|
|
3942
|
+
configTomlModule,
|
|
3943
|
+
);
|
|
3944
|
+
const appServerConfigArgs = useCanonicalHome
|
|
3945
|
+
? [
|
|
3946
|
+
...(runtimeContext.args ?? []),
|
|
3947
|
+
"-c",
|
|
3948
|
+
`model_provider=${configTomlModule.tomlStringLiteral(RUNTIME_ROTATION_PROXY_PROVIDER_ID)}`,
|
|
3949
|
+
]
|
|
3950
|
+
: [];
|
|
3951
|
+
appServerShimDir = installRuntimeRotationAppServerCliShim(
|
|
3952
|
+
runtimeContext.env,
|
|
3953
|
+
appServerConfigArgs,
|
|
3852
3954
|
);
|
|
3853
|
-
appServerShimDir = installRuntimeRotationAppServerCliShim(shadowContext.env);
|
|
3854
3955
|
lastRequestCount = proxyServer.getStatus?.().totalRequests ?? 0;
|
|
3855
3956
|
publishStatus("running");
|
|
3856
3957
|
process.stdout.write(
|
|
@@ -3859,7 +3960,8 @@ async function runRuntimeRotationAppHelper() {
|
|
|
3859
3960
|
pid: process.pid,
|
|
3860
3961
|
baseUrl: proxyServer.baseUrl,
|
|
3861
3962
|
statusPath: resolveRuntimeRotationAppHelperStatusPath(),
|
|
3862
|
-
|
|
3963
|
+
args: runtimeContext.args ?? [],
|
|
3964
|
+
env: pickRuntimeRotationAppHelperEnv(runtimeContext.env),
|
|
3863
3965
|
})}\n`,
|
|
3864
3966
|
);
|
|
3865
3967
|
|
|
@@ -3920,7 +4022,7 @@ function stopRuntimeRotationAppHelper(helper) {
|
|
|
3920
4022
|
return waitForRuntimeRotationAppHelperExit(helper);
|
|
3921
4023
|
}
|
|
3922
4024
|
|
|
3923
|
-
function startRuntimeRotationAppHelper(baseContext) {
|
|
4025
|
+
function startRuntimeRotationAppHelper(baseContext, options = {}) {
|
|
3924
4026
|
const realCodexHome =
|
|
3925
4027
|
baseContext.originalCodexHome ??
|
|
3926
4028
|
resolveRuntimeRotationProxyOriginalCodexHome(baseContext.env);
|
|
@@ -3940,6 +4042,8 @@ function startRuntimeRotationAppHelper(baseContext) {
|
|
|
3940
4042
|
),
|
|
3941
4043
|
[APP_RUNTIME_HELPER_OWNER_PID_ENV]: String(process.pid),
|
|
3942
4044
|
[APP_RUNTIME_HELPER_REAL_CODEX_HOME_ENV]: realCodexHome,
|
|
4045
|
+
[APP_RUNTIME_HELPER_USE_CANONICAL_HOME_ENV]:
|
|
4046
|
+
options.useCanonicalHome === true ? "1" : "0",
|
|
3943
4047
|
},
|
|
3944
4048
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3945
4049
|
detached: true,
|
|
@@ -4005,8 +4109,14 @@ async function createRuntimeRotationAppHelperContext(
|
|
|
4005
4109
|
options = {},
|
|
4006
4110
|
) {
|
|
4007
4111
|
const startedAt = Date.now();
|
|
4008
|
-
const { helper, message } = await startRuntimeRotationAppHelper(
|
|
4112
|
+
const { helper, message } = await startRuntimeRotationAppHelper(
|
|
4113
|
+
baseContext,
|
|
4114
|
+
options,
|
|
4115
|
+
);
|
|
4009
4116
|
const helperEnv = message.env ?? {};
|
|
4117
|
+
const helperArgs = Array.isArray(message.args)
|
|
4118
|
+
? message.args.filter((arg) => typeof arg === "string")
|
|
4119
|
+
: [];
|
|
4010
4120
|
const detachGraceMs = resolveRuntimeRotationAppHelperDetachGraceMs(baseContext.env);
|
|
4011
4121
|
|
|
4012
4122
|
const cleanup = async ({ exitCode } = {}) => {
|
|
@@ -4023,6 +4133,7 @@ async function createRuntimeRotationAppHelperContext(
|
|
|
4023
4133
|
return {
|
|
4024
4134
|
args: [
|
|
4025
4135
|
...baseContext.args,
|
|
4136
|
+
...helperArgs,
|
|
4026
4137
|
"-c",
|
|
4027
4138
|
`model_provider=${configTomlModule.tomlStringLiteral(RUNTIME_ROTATION_PROXY_PROVIDER_ID)}`,
|
|
4028
4139
|
],
|
|
@@ -4063,6 +4174,7 @@ async function createRuntimeRotationProxyContextIfEnabled(
|
|
|
4063
4174
|
if (isCodexInteractiveTuiCommand(rawArgs)) {
|
|
4064
4175
|
return createRuntimeRotationAppHelperContext(baseContext, configTomlModule, {
|
|
4065
4176
|
detachOnExit: true,
|
|
4177
|
+
useCanonicalHome: true,
|
|
4066
4178
|
});
|
|
4067
4179
|
}
|
|
4068
4180
|
|
|
@@ -5045,6 +5157,7 @@ async function main() {
|
|
|
5045
5157
|
}
|
|
5046
5158
|
const forwardArgs = forcedAccount.forwardArgs;
|
|
5047
5159
|
|
|
5160
|
+
await ensurePersistedCodexFileAuthStore();
|
|
5048
5161
|
await autoSyncManagerActiveSelectionIfEnabled();
|
|
5049
5162
|
await maybePrintForwardStatusLine(forwardArgs);
|
|
5050
5163
|
maybeRefreshQuotaCacheInBackground();
|