1- import { promises as fs } from "node:fs" ;
21import { stdin as input , stdout as output } from "node:process" ;
32import { createInterface } from "node:readline/promises" ;
43import { loadPluginConfig , savePluginConfig } from "../config.js" ;
@@ -25,7 +24,6 @@ import { ANSI } from "../ui/ansi.js";
2524import { UI_COPY } from "../ui/copy.js" ;
2625import { getUiRuntimeOptions , setUiRuntimeOptions } from "../ui/runtime.js" ;
2726import { type MenuItem , select } from "../ui/select.js" ;
28- import { getUnifiedSettingsPath } from "../unified-settings.js" ;
2927import { sleep } from "../utils.js" ;
3028import {
3129 backendSettingsEqual ,
@@ -64,10 +62,11 @@ import {
6462 mapExperimentalStatusHotkey ,
6563} from "./experimental-settings-schema.js" ;
6664import {
67- RETRYABLE_SETTINGS_WRITE_CODES ,
68- SETTINGS_WRITE_MAX_ATTEMPTS ,
69- withQueuedRetry ,
70- } from "./settings-write-queue.js" ;
65+ readFileWithRetry ,
66+ resolvePluginConfigSavePathKey ,
67+ warnPersistFailure ,
68+ } from "./settings-persist-utils.js" ;
69+ import { withQueuedRetry } from "./settings-write-queue.js" ;
7170import { promptStatuslineSettingsPanel } from "./statusline-settings-panel.js" ;
7271import { promptThemeSettingsPanel } from "./theme-settings-panel.js" ;
7372
@@ -267,22 +266,6 @@ function mergeDashboardSettingsForKeys(
267266 return cloneDashboardSettings ( next ) ;
268267}
269268
270- function resolvePluginConfigSavePathKey ( ) : string {
271- const envPath = ( process . env . CODEX_MULTI_AUTH_CONFIG_PATH ?? "" ) . trim ( ) ;
272- return envPath . length > 0 ? envPath : getUnifiedSettingsPath ( ) ;
273- }
274-
275- function formatPersistError ( error : unknown ) : string {
276- if ( error instanceof Error ) return error . message ;
277- return String ( error ) ;
278- }
279-
280- function warnPersistFailure ( scope : string , error : unknown ) : void {
281- console . warn (
282- `Settings save failed (${ scope } ) after retries: ${ formatPersistError ( error ) } ` ,
283- ) ;
284- }
285-
286269async function persistDashboardSettingsSelection (
287270 selected : DashboardDisplaySettings ,
288271 keys : readonly DashboardSettingKey [ ] ,
@@ -308,27 +291,6 @@ async function persistDashboardSettingsSelection(
308291 }
309292}
310293
311- async function readFileWithRetry ( path : string ) : Promise < string > {
312- for ( let attempt = 0 ; ; attempt += 1 ) {
313- try {
314- return await fs . readFile ( path , "utf-8" ) ;
315- } catch ( error ) {
316- const code = ( error as NodeJS . ErrnoException ) . code ;
317- if ( code === "ENOENT" ) {
318- throw error ;
319- }
320- if (
321- ! code ||
322- ! RETRYABLE_SETTINGS_WRITE_CODES . has ( code ) ||
323- attempt >= SETTINGS_WRITE_MAX_ATTEMPTS - 1
324- ) {
325- throw error ;
326- }
327- await sleep ( 25 * 2 ** attempt ) ;
328- }
329- }
330- }
331-
332294async function persistBackendConfigSelection (
333295 selected : PluginConfig ,
334296 scope : string ,
@@ -1177,7 +1139,17 @@ async function loadExperimentalSyncTarget(): Promise<
11771139 }
11781140 try {
11791141 const raw = JSON . parse (
1180- await readFileWithRetry ( detection . descriptor . accountPath ) ,
1142+ await readFileWithRetry ( detection . descriptor . accountPath , {
1143+ retryableCodes : new Set ( [
1144+ "EBUSY" ,
1145+ "EPERM" ,
1146+ "EAGAIN" ,
1147+ "ENOTEMPTY" ,
1148+ "EACCES" ,
1149+ ] ) ,
1150+ maxAttempts : 4 ,
1151+ sleep,
1152+ } ) ,
11811153 ) ;
11821154 const normalized = normalizeAccountStorage ( raw ) ;
11831155 if ( ! normalized ) {
0 commit comments