diff --git a/src/main/library-path-config.ts b/src/main/library-path-config.ts index 30a15be..ab0ea3f 100644 --- a/src/main/library-path-config.ts +++ b/src/main/library-path-config.ts @@ -56,6 +56,12 @@ export function applyLibraryPathToPythonEnvironment( * Normal desktop launches instead keep the selected path in config.json so * the backend can re-read a Settings change on the next manual scan without * requiring a process restart. + * + * Failure statuses (invalid-config, write-failed) still export the resolved + * fallback as DLC_DIR: the backend has NO built-in default (_get_dlc_dir + * returns None), so removing the env var when config.json cannot own the + * path would strand the user with an empty library and only a console warn. + * Config-owned dynamic behaviour applies exactly when config.json is usable. */ export function prepareLibraryPathForPython( configDir: string, @@ -79,6 +85,7 @@ export function prepareLibraryPathForPython( if (!isPlainObject(parsed)) { return { status: 'invalid-config', + environmentDlcDir: resolvedDlcDir, error: 'config.json is not a JSON object', }; } @@ -86,6 +93,7 @@ export function prepareLibraryPathForPython( } catch (err) { return { status: 'invalid-config', + environmentDlcDir: resolvedDlcDir, error: err instanceof Error ? err.message : String(err), }; } @@ -97,12 +105,14 @@ export function prepareLibraryPathForPython( } return { status: 'invalid-config', + environmentDlcDir: resolvedDlcDir, error: 'config.json dlc_dir is not an existing directory', }; } if (configured !== undefined && configured !== null && configured !== '') { return { status: 'invalid-config', + environmentDlcDir: resolvedDlcDir, error: 'config.json dlc_dir is not a string', }; } @@ -120,6 +130,7 @@ export function prepareLibraryPathForPython( } catch { /* best-effort temporary-file cleanup */ } return { status: 'write-failed', + environmentDlcDir: resolvedDlcDir, error: err instanceof Error ? err.message : String(err), }; } diff --git a/tests/library-path-config.test.js b/tests/library-path-config.test.js index fa9981b..051df4d 100644 --- a/tests/library-path-config.test.js +++ b/tests/library-path-config.test.js @@ -134,6 +134,49 @@ test('a corrupt config is never overwritten during bootstrap', () => { assert.equal(fs.readFileSync(configFile, 'utf8'), '{broken'); }); +test('invalid-config exports the resolved fallback so the backend keeps a library', () => { + // The backend has no built-in default (_get_dlc_dir returns None): with + // the env var deleted AND config.json unusable, scans and starter + // seeding would silently skip. Failure statuses must keep the pre-#117 + // env fallback. + const configDir = tmpConfigDir(); + const configFile = path.join(configDir, 'config.json'); + fs.writeFileSync(configFile, JSON.stringify({ dlc_dir: path.join(configDir, 'gone') })); + + const result = prepareLibraryPathForPython(configDir, 'C:\\Default Songs'); + + assert.equal(result.status, 'invalid-config'); + assert.equal(result.environmentDlcDir, 'C:\\Default Songs'); + + const environment = {}; + applyLibraryPathToPythonEnvironment(environment, result); + assert.deepEqual(environment, { DLC_DIR: 'C:\\Default Songs' }); +}); + +test('corrupt config exports the resolved fallback without being overwritten', () => { + const configDir = tmpConfigDir(); + const configFile = path.join(configDir, 'config.json'); + fs.writeFileSync(configFile, '{broken'); + + const result = prepareLibraryPathForPython(configDir, 'C:\\Default Songs'); + + assert.equal(result.status, 'invalid-config'); + assert.equal(result.environmentDlcDir, 'C:\\Default Songs'); + assert.equal(fs.readFileSync(configFile, 'utf8'), '{broken'); +}); + +test('write-failed exports the resolved fallback so the backend keeps a library', () => { + // Force the config write to fail by making config.json's parent a file. + const root = tmpConfigDir(); + const configDir = path.join(root, 'not-a-dir'); + fs.writeFileSync(configDir, 'x'); + + const result = prepareLibraryPathForPython(configDir, 'C:\\Default Songs'); + + assert.equal(result.status, 'write-failed'); + assert.equal(result.environmentDlcDir, 'C:\\Default Songs'); +}); + test('Python environment omits DLC_DIR when config owns the library path', () => { const environment = { DLC_DIR: 'C:\\Stale Parent Value', KEEP: 'yes' };