Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1d03235
fix: preserve settings write retry behavior
ndycode Mar 21, 2026
4bac0a1
test: cover settings persistence helpers
ndycode Mar 21, 2026
bd70b8c
test: cover settings retry semantics
ndycode Mar 21, 2026
2e961b9
chore: narrow settings read retry codes
ndycode Mar 21, 2026
764260f
fix: harden account snapshot inspection
ndycode Mar 21, 2026
fd4c6fe
docs: clarify account snapshot helper behavior
ndycode Mar 21, 2026
5ec8edc
fix: preserve snapshot exists semantics
ndycode Mar 21, 2026
c9d1ad0
test: expand account snapshot helper coverage
ndycode Mar 21, 2026
11e4b49
test: group account snapshot cases correctly
ndycode Mar 21, 2026
0f5ac55
test: clarify snapshot schema-error case
ndycode Mar 21, 2026
028f82b
fix: preserve locked snapshot visibility
ndycode Mar 21, 2026
c0e0b32
test: cover EPERM locked snapshot stats
ndycode Mar 21, 2026
8c77b78
fix: preserve snapshot metadata after lock
ndycode Mar 21, 2026
31ab94a
test: cover account snapshot metadata edges
ndycode Mar 21, 2026
1e8c9b0
test: cover dashboard formatters
ndycode Mar 22, 2026
54dfd76
fix: retry transient flagged storage reads
ndycode Mar 21, 2026
80a41ad
test: restore flagged storage integration coverage
ndycode Mar 21, 2026
57f62c9
fix: tighten flagged storage read retries
ndycode Mar 21, 2026
5c98f7e
test: cover non-retryable flagged reads
ndycode Mar 21, 2026
fb3861f
test: dedupe flagged retry coverage
ndycode Mar 21, 2026
85f6f54
Preserve storage save probe failures
ndycode Mar 22, 2026
6f3916e
Deduplicate flagged storage entry helpers
ndycode Mar 22, 2026
3954943
Harden clear entry wrapper tests
ndycode Mar 22, 2026
5836194
Add restore backup path wiring coverage
ndycode Mar 22, 2026
47bbd3a
Re-export flagged save entry facade
ndycode Mar 22, 2026
2aefb3d
Cover settings panel entry wrappers
ndycode Mar 22, 2026
0117df1
Share unified settings controller deps
ndycode Mar 22, 2026
a6e42ae
Fix storage import after unique replay
ndycode Mar 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lib/codex-manager/experimental-sync-target-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ export async function loadExperimentalSyncTargetEntry(params: {
"EBUSY",
"EPERM",
"EAGAIN",
"ENOTEMPTY",
"EACCES",
]),
maxAttempts: 4,
sleep: params.sleep,
Expand Down
2 changes: 1 addition & 1 deletion lib/codex-manager/settings-write-queue.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const SETTINGS_WRITE_MAX_ATTEMPTS = 4;
export const SETTINGS_WRITE_BASE_DELAY_MS = 50;
export const SETTINGS_WRITE_MAX_DELAY_MS = 1_000;
export const SETTINGS_WRITE_MAX_DELAY_MS = 30_000;
export const RETRYABLE_SETTINGS_WRITE_CODES = new Set([
"EBUSY",
"EPERM",
Expand Down
94 changes: 48 additions & 46 deletions lib/codex-manager/unified-settings-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,54 +10,56 @@ export type SettingsHubActionType =
| "backend"
| "back";

export type UnifiedSettingsControllerDeps = {
cloneDashboardSettings: (
settings: DashboardDisplaySettings,
) => DashboardDisplaySettings;
cloneBackendPluginConfig: (config: PluginConfig) => PluginConfig;
loadDashboardDisplaySettings: () => Promise<DashboardDisplaySettings>;
loadPluginConfig: () => PluginConfig;
applyUiThemeFromDashboardSettings: (
settings: DashboardDisplaySettings,
) => void;
promptSettingsHub: (
focus: SettingsHubActionType,
) => Promise<{ type: SettingsHubActionType } | null>;
configureDashboardDisplaySettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings>;
configureStatuslineSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings>;
promptBehaviorSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings | null>;
promptThemeSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings | null>;
dashboardSettingsEqual: (
left: DashboardDisplaySettings,
right: DashboardDisplaySettings,
) => boolean;
persistDashboardSettingsSelection: (
selected: DashboardDisplaySettings,
keys: readonly (keyof DashboardDisplaySettings)[],
scope: string,
) => Promise<DashboardDisplaySettings>;
promptExperimentalSettings: (
config: PluginConfig,
) => Promise<PluginConfig | null>;
backendSettingsEqual: (left: PluginConfig, right: PluginConfig) => boolean;
persistBackendConfigSelection: (
config: PluginConfig,
scope: string,
) => Promise<PluginConfig>;
configureBackendSettings: (config: PluginConfig) => Promise<PluginConfig>;
BEHAVIOR_PANEL_KEYS: readonly (keyof DashboardDisplaySettings)[];
THEME_PANEL_KEYS: readonly (keyof DashboardDisplaySettings)[];
};

export async function configureUnifiedSettingsController(
initialSettings: DashboardDisplaySettings | undefined,
deps: {
cloneDashboardSettings: (
settings: DashboardDisplaySettings,
) => DashboardDisplaySettings;
cloneBackendPluginConfig: (config: PluginConfig) => PluginConfig;
loadDashboardDisplaySettings: () => Promise<DashboardDisplaySettings>;
loadPluginConfig: () => PluginConfig;
applyUiThemeFromDashboardSettings: (
settings: DashboardDisplaySettings,
) => void;
promptSettingsHub: (
focus: SettingsHubActionType,
) => Promise<{ type: SettingsHubActionType } | null>;
configureDashboardDisplaySettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings>;
configureStatuslineSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings>;
promptBehaviorSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings | null>;
promptThemeSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings | null>;
dashboardSettingsEqual: (
left: DashboardDisplaySettings,
right: DashboardDisplaySettings,
) => boolean;
persistDashboardSettingsSelection: (
selected: DashboardDisplaySettings,
keys: readonly (keyof DashboardDisplaySettings)[],
scope: string,
) => Promise<DashboardDisplaySettings>;
promptExperimentalSettings: (
config: PluginConfig,
) => Promise<PluginConfig | null>;
backendSettingsEqual: (left: PluginConfig, right: PluginConfig) => boolean;
persistBackendConfigSelection: (
config: PluginConfig,
scope: string,
) => Promise<PluginConfig>;
configureBackendSettings: (config: PluginConfig) => Promise<PluginConfig>;
BEHAVIOR_PANEL_KEYS: readonly (keyof DashboardDisplaySettings)[];
THEME_PANEL_KEYS: readonly (keyof DashboardDisplaySettings)[];
},
deps: UnifiedSettingsControllerDeps,
): Promise<DashboardDisplaySettings> {
let current = deps.cloneDashboardSettings(
initialSettings ?? (await deps.loadDashboardDisplaySettings()),
Expand Down
103 changes: 5 additions & 98 deletions lib/codex-manager/unified-settings-entry.ts
Original file line number Diff line number Diff line change
@@ -1,109 +1,16 @@
import type { DashboardDisplaySettings } from "../dashboard-settings.js";
import type { PluginConfig } from "../types.js";
import type { SettingsHubActionType } from "./unified-settings-controller.js";
import type {
UnifiedSettingsControllerDeps,
} from "./unified-settings-controller.js";

export async function configureUnifiedSettingsEntry(
initialSettings: DashboardDisplaySettings | undefined,
deps: {
configureUnifiedSettingsController: (
initialSettings: DashboardDisplaySettings | undefined,
deps: {
cloneDashboardSettings: (
settings: DashboardDisplaySettings,
) => DashboardDisplaySettings;
cloneBackendPluginConfig: (config: PluginConfig) => PluginConfig;
loadDashboardDisplaySettings: () => Promise<DashboardDisplaySettings>;
loadPluginConfig: () => PluginConfig;
applyUiThemeFromDashboardSettings: (
settings: DashboardDisplaySettings,
) => void;
promptSettingsHub: (
focus: SettingsHubActionType,
) => Promise<{ type: SettingsHubActionType } | null>;
configureDashboardDisplaySettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings>;
configureStatuslineSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings>;
promptBehaviorSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings | null>;
promptThemeSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings | null>;
dashboardSettingsEqual: (
left: DashboardDisplaySettings,
right: DashboardDisplaySettings,
) => boolean;
persistDashboardSettingsSelection: (
selected: DashboardDisplaySettings,
keys: readonly (keyof DashboardDisplaySettings)[],
scope: string,
) => Promise<DashboardDisplaySettings>;
promptExperimentalSettings: (
config: PluginConfig,
) => Promise<PluginConfig | null>;
backendSettingsEqual: (
left: PluginConfig,
right: PluginConfig,
) => boolean;
persistBackendConfigSelection: (
config: PluginConfig,
scope: string,
) => Promise<PluginConfig>;
configureBackendSettings: (
config: PluginConfig,
) => Promise<PluginConfig>;
BEHAVIOR_PANEL_KEYS: readonly (keyof DashboardDisplaySettings)[];
THEME_PANEL_KEYS: readonly (keyof DashboardDisplaySettings)[];
},
deps: UnifiedSettingsControllerDeps,
) => Promise<DashboardDisplaySettings>;
cloneDashboardSettings: (
settings: DashboardDisplaySettings,
) => DashboardDisplaySettings;
cloneBackendPluginConfig: (config: PluginConfig) => PluginConfig;
loadDashboardDisplaySettings: () => Promise<DashboardDisplaySettings>;
loadPluginConfig: () => PluginConfig;
applyUiThemeFromDashboardSettings: (
settings: DashboardDisplaySettings,
) => void;
promptSettingsHub: (
focus: SettingsHubActionType,
) => Promise<{ type: SettingsHubActionType } | null>;
configureDashboardDisplaySettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings>;
configureStatuslineSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings>;
promptBehaviorSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings | null>;
promptThemeSettings: (
current: DashboardDisplaySettings,
) => Promise<DashboardDisplaySettings | null>;
dashboardSettingsEqual: (
left: DashboardDisplaySettings,
right: DashboardDisplaySettings,
) => boolean;
persistDashboardSettingsSelection: (
selected: DashboardDisplaySettings,
keys: readonly (keyof DashboardDisplaySettings)[],
scope: string,
) => Promise<DashboardDisplaySettings>;
promptExperimentalSettings: (
config: PluginConfig,
) => Promise<PluginConfig | null>;
backendSettingsEqual: (left: PluginConfig, right: PluginConfig) => boolean;
persistBackendConfigSelection: (
config: PluginConfig,
scope: string,
) => Promise<PluginConfig>;
configureBackendSettings: (config: PluginConfig) => Promise<PluginConfig>;
BEHAVIOR_PANEL_KEYS: readonly (keyof DashboardDisplaySettings)[];
THEME_PANEL_KEYS: readonly (keyof DashboardDisplaySettings)[];
},
} & UnifiedSettingsControllerDeps,
): Promise<DashboardDisplaySettings> {
return deps.configureUnifiedSettingsController(initialSettings, {
cloneDashboardSettings: deps.cloneDashboardSettings,
Expand Down
34 changes: 1 addition & 33 deletions lib/storage/account-port.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AccountStorageV3, FlaggedAccountStorageV1 } from "../storage.js";
import type { AccountStorageV3 } from "../storage.js";

export async function exportAccountsSnapshot(params: {
resolvedPath: string;
Expand Down Expand Up @@ -103,35 +103,3 @@ export async function importAccountsSnapshot(params: {
return result;
}

export async function saveFlaggedAccountsEntry(params: {
storage: FlaggedAccountStorageV1;
withStorageLock: <T>(fn: () => Promise<T>) => Promise<T>;
saveUnlocked: (storage: FlaggedAccountStorageV1) => Promise<void>;
}): Promise<void> {
return params.withStorageLock(async () => {
await params.saveUnlocked(params.storage);
});
}

export async function clearFlaggedAccountsEntry(params: {
path: string;
withStorageLock: <T>(fn: () => Promise<T>) => Promise<T>;
markerPath: string;
getBackupPaths: () => Promise<string[]>;
clearFlaggedAccountsOnDisk: (args: {
path: string;
markerPath: string;
backupPaths: string[];
logError: (message: string, details: Record<string, unknown>) => void;
}) => Promise<void>;
logError: (message: string, details: Record<string, unknown>) => void;
}): Promise<void> {
return params.withStorageLock(async () => {
await params.clearFlaggedAccountsOnDisk({
path: params.path,
markerPath: params.markerPath,
backupPaths: await params.getBackupPaths(),
logError: params.logError,
});
});
}
20 changes: 7 additions & 13 deletions lib/storage/account-save.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,13 @@ export async function saveAccountsToDisk(
await params.ensureGitignore();

if (params.looksLikeSyntheticFixtureStorage(storage)) {
try {
const existing = await params.loadExistingStorage();
if (
existing &&
existing.accounts.length > 0 &&
!params.looksLikeSyntheticFixtureStorage(existing)
) {
throw params.createSyntheticFixtureError();
}
} catch (error) {
if (error instanceof Error && error.message.includes("synthetic")) {
throw error;
}
const existing = await params.loadExistingStorage();
if (
existing &&
existing.accounts.length > 0 &&
!params.looksLikeSyntheticFixtureStorage(existing)
) {
throw params.createSyntheticFixtureError();
}
}

Expand Down
Loading