@@ -14,13 +14,13 @@ import {
1414 hydrateConfig ,
1515 isSupportedOnboardingProvider ,
1616} from '@open-codesign/shared' ;
17- import { configDir , configPath , readConfig , writeConfig } from './config' ;
18- import { ipcMain , shell } from './electron-runtime' ;
17+ import { defaultConfigDir , readConfig , writeConfig } from './config' ;
18+ import { dialog , ipcMain , shell } from './electron-runtime' ;
1919import { type ClaudeCodeImport , readClaudeCodeSettings } from './imports/claude-code-config' ;
2020import { type CodexImport , readCodexConfig } from './imports/codex-config' ;
2121import { buildSecretRef , decryptSecret , migrateSecretMasks , tryBuildSecretRef } from './keychain' ;
2222import { prepareKeychain } from './keychain-ux' ;
23- import { getLogPath , getLogger } from './logger' ;
23+ import { defaultLogsDir , getLogger } from './logger' ;
2424import {
2525 type ProviderRow ,
2626 assertProviderHasStoredSecret ,
@@ -29,7 +29,15 @@ import {
2929 isKeylessProviderAllowed ,
3030 toProviderRows ,
3131} from './provider-settings' ;
32- import { buildAppPaths } from './storage-settings' ;
32+ import {
33+ type AppPaths ,
34+ type StorageKind ,
35+ buildAppPathsForLocations ,
36+ getDefaultUserDataDir ,
37+ patchForStorageKind ,
38+ readPersistedStorageLocations ,
39+ writeStorageLocations ,
40+ } from './storage-settings' ;
3341
3442const logger = getLogger ( 'settings-ipc' ) ;
3543
@@ -387,8 +395,42 @@ async function runSetActiveProvider(raw: unknown): Promise<OnboardingState> {
387395 return toState ( cachedConfig ) ;
388396}
389397
390- function runGetPaths ( ) {
391- return buildAppPaths ( configPath ( ) , getLogPath ( ) , configDir ( ) ) ;
398+ function defaultDataDir ( ) : string {
399+ return getDefaultUserDataDir ( ) ;
400+ }
401+
402+ function getStoragePathDefaults ( ) {
403+ return {
404+ configDir : defaultConfigDir ( ) ,
405+ logsDir : defaultLogsDir ( ) ,
406+ dataDir : defaultDataDir ( ) ,
407+ } ;
408+ }
409+
410+ async function runGetPaths ( ) : Promise < AppPaths > {
411+ const persisted = await readPersistedStorageLocations ( ) ;
412+ return buildAppPathsForLocations ( persisted , getStoragePathDefaults ( ) ) ;
413+ }
414+
415+ function parseStorageKind ( raw : unknown ) : StorageKind {
416+ if ( raw === 'config' || raw === 'logs' || raw === 'data' ) return raw ;
417+ throw new CodesignError ( 'storage kind must be "config", "logs", or "data"' , 'IPC_BAD_INPUT' ) ;
418+ }
419+
420+ async function runChooseStorageFolder ( raw : unknown ) : Promise < AppPaths > {
421+ const kind = parseStorageKind ( raw ) ;
422+ const result = await dialog . showOpenDialog ( {
423+ properties : [ 'openDirectory' , 'createDirectory' ] ,
424+ } ) ;
425+ if ( result . canceled || result . filePaths . length === 0 ) {
426+ return runGetPaths ( ) ;
427+ }
428+ const selected = result . filePaths [ 0 ] ;
429+ if ( selected === undefined || selected . trim ( ) . length === 0 ) {
430+ return runGetPaths ( ) ;
431+ }
432+ await writeStorageLocations ( patchForStorageKind ( kind , selected ) ) ;
433+ return runGetPaths ( ) ;
392434}
393435
394436async function runOpenFolder ( raw : unknown ) : Promise < void > {
@@ -636,7 +678,7 @@ async function runImportCodex(imported: CodexImport): Promise<OnboardingState> {
636678 for ( const entry of imported . providers ) {
637679 nextProviders [ entry . id ] = entry ;
638680 if ( entry . envKey !== undefined ) {
639- const envValue = process . env [ entry . envKey ] ;
681+ const envValue = process . env [ entry . envKey ] ?. trim ( ) ;
640682 if ( envValue !== undefined && envValue . length > 0 ) {
641683 const ref = tryBuildSecretRef ( envValue ) ;
642684 if ( ref !== null ) nextSecrets [ entry . id ] = ref ;
@@ -680,8 +722,9 @@ async function runImportClaudeCode(imported: ClaudeCodeImport): Promise<Onboardi
680722 }
681723 }
682724 nextProviders [ imported . provider . id ] = imported . provider ;
683- if ( imported . apiKey !== null ) {
684- const ref = tryBuildSecretRef ( imported . apiKey ) ;
725+ const importedApiKey = imported . apiKey ?. trim ( ) ;
726+ if ( importedApiKey !== undefined && importedApiKey . length > 0 ) {
727+ const ref = tryBuildSecretRef ( importedApiKey ) ;
685728 if ( ref !== null ) nextSecrets [ imported . provider . id ] = ref ;
686729 }
687730 const next = hydrateConfig ( {
@@ -891,7 +934,12 @@ export function registerOnboardingIpc(): void {
891934 async ( _e , raw : unknown ) : Promise < OnboardingState > => runSetActiveProvider ( raw ) ,
892935 ) ;
893936
894- ipcMain . handle ( 'settings:v1:get-paths' , ( ) => runGetPaths ( ) ) ;
937+ ipcMain . handle ( 'settings:v1:get-paths' , async ( ) : Promise < AppPaths > => runGetPaths ( ) ) ;
938+
939+ ipcMain . handle (
940+ 'settings:v1:choose-storage-folder' ,
941+ async ( _e , raw : unknown ) : Promise < AppPaths > => runChooseStorageFolder ( raw ) ,
942+ ) ;
895943
896944 ipcMain . handle (
897945 'settings:v1:open-folder' ,
@@ -929,11 +977,16 @@ export function registerOnboardingIpc(): void {
929977 } ,
930978 ) ;
931979
932- ipcMain . handle ( 'settings:get-paths' , ( ) => {
980+ ipcMain . handle ( 'settings:get-paths' , async ( ) : Promise < AppPaths > => {
933981 logger . warn ( 'legacy settings:get-paths channel used, schedule removal next minor' ) ;
934982 return runGetPaths ( ) ;
935983 } ) ;
936984
985+ ipcMain . handle ( 'settings:choose-storage-folder' , async ( _e , raw : unknown ) : Promise < AppPaths > => {
986+ logger . warn ( 'legacy settings:choose-storage-folder channel used, schedule removal next minor' ) ;
987+ return runChooseStorageFolder ( raw ) ;
988+ } ) ;
989+
937990 ipcMain . handle ( 'settings:open-folder' , async ( _e , raw : unknown ) => {
938991 logger . warn ( 'legacy settings:open-folder channel used, schedule removal next minor' ) ;
939992 return runOpenFolder ( raw ) ;
0 commit comments