@@ -9,6 +9,9 @@ import java.nio.file.Path
99import java.nio.file.StandardCopyOption
1010import javax.swing.JFileChooser
1111import kotlin.io.path.exists
12+ import kotlin.io.path.isDirectory
13+ import kotlin.io.path.listDirectoryEntries
14+ import kotlin.io.path.name
1215import kotlin.io.path.readText
1316import kotlin.io.path.writeText
1417
@@ -68,14 +71,24 @@ class ClaudeDesktopProvider(private val logging: Logging, private val proxyJarMa
6871 val os = System .getProperty(" os.name" ).lowercase()
6972 val home = System .getProperty(" user.home" )
7073
71- val basePath = when {
72- os.contains(" win" ) -> Path .of(home, " AppData" , " Roaming" , " Claude" )
73- os.contains(" mac" ) || os.contains(" darwin" ) -> Path .of(home, " Library" , " Application Support" , " Claude" )
74- os.contains(" linux" ) -> Path .of(home, " .config" , " Claude" )
74+ val candidatePaths = when {
75+ os.contains(" win" ) -> windowsCandidatePaths(home)
76+ os.contains(" mac" ) || os.contains(" darwin" ) -> listOf (
77+ Path .of(home, " Library" , " Application Support" , " Claude" )
78+ )
79+ os.contains(" linux" ) -> listOf (Path .of(home, " .config" , " Claude" ))
7580 else -> return null
7681 }
7782
78- if (! basePath.exists()) return null
83+ val existingPaths = candidatePaths.filter { it.exists() && it.isDirectory() }
84+ val pathsWithConfig = existingPaths.filter { it.resolve(claudeConfigFileName).exists() }
85+ val preferredPaths = pathsWithConfig.ifEmpty { existingPaths }
86+ if (preferredPaths.size > 1 ) {
87+ logging.logToOutput(
88+ " Warning: multiple Claude Desktop config directories found; using ${preferredPaths.first()} : $preferredPaths "
89+ )
90+ }
91+ val basePath = preferredPaths.firstOrNull() ? : return null
7992
8093 val configFile = basePath.resolve(claudeConfigFileName)
8194 if (! configFile.exists()) {
@@ -85,6 +98,24 @@ class ClaudeDesktopProvider(private val logging: Logging, private val proxyJarMa
8598 return configFile
8699 }
87100
101+ internal fun windowsCandidatePaths (home : String ): List <Path > {
102+ val traditionalPath = Path .of(home, " AppData" , " Roaming" , " Claude" )
103+ val packagesDirectory = Path .of(home, " AppData" , " Local" , " Packages" )
104+ val storePaths = if (packagesDirectory.exists() && packagesDirectory.isDirectory()) {
105+ runCatching {
106+ packagesDirectory.listDirectoryEntries()
107+ .filter { it.isDirectory() && it.name.startsWith(" Claude_" ) }
108+ .map { it.resolve(" LocalCache" ).resolve(" Roaming" ).resolve(" Claude" ) }
109+ }.getOrElse { error ->
110+ logging.logToError(" Failed to inspect Windows Store Claude packages: ${error.message} " )
111+ emptyList()
112+ }
113+ } else {
114+ emptyList()
115+ }
116+ return listOf (traditionalPath) + storePaths
117+ }
118+
88119 private fun createDefaultConfig (path : Path ): Boolean {
89120 try {
90121 val defaultConfig = buildJsonObject {
@@ -146,4 +177,4 @@ class ManualProxyInstallerProvider(private val logging: Logging, private val pro
146177
147178 return " 代理 jar 已提取到 $destinationFile "
148179 }
149- }
180+ }
0 commit comments