diff --git a/README.md b/README.md index b89f845..65855e6 100644 --- a/README.md +++ b/README.md @@ -109,10 +109,12 @@ Linux/Bash-интерфейс `proxy-client` поддерживает внешн приложение через системный идентификатор и передаёт ему параметры Chromium `--proxy-server` и `--proxy-bypass-list`. -`Claude Proxy` передаёт переменные прокси и параметры Electron -`--proxy-server` и `--proxy-bypass-list`, чтобы прокси применялся ко всему -трафику Claude Desktop. Если Claude уже запущен обычным способом, его нужно -полностью закрыть перед запуском через `Claude Proxy`. +`Claude Proxy` поддерживает как обычную установку в +`%LOCALAPPDATA%\AnthropicClaude`, так и пакет из Microsoft Store. В обоих +случаях он передаёт параметры Electron `--proxy-server` и +`--proxy-bypass-list`, чтобы прокси применялся ко всему трафику Claude Desktop. +Если Claude уже запущен обычным способом, его нужно полностью закрыть перед +запуском через `Claude Proxy`. ### Git baseline diff --git a/chezmoi/.chezmoiscripts/run_31-create-claude-proxy-shortcut.ps1 b/chezmoi/.chezmoiscripts/run_31-create-claude-proxy-shortcut.ps1 index d2b83e7..6ad74a7 100644 --- a/chezmoi/.chezmoiscripts/run_31-create-claude-proxy-shortcut.ps1 +++ b/chezmoi/.chezmoiscripts/run_31-create-claude-proxy-shortcut.ps1 @@ -24,8 +24,40 @@ if (Test-Path -LiteralPath $PwshAliasPath) { $Arguments = "-NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$LauncherPath`"" $WorkingDirectory = $env:USERPROFILE -$ClaudeExecutable = Join-Path $env:LOCALAPPDATA 'AnthropicClaude\claude.exe' -if (Test-Path -LiteralPath $ClaudeExecutable) { + +function Get-ClaudeIconExecutable { + $LegacyExecutable = Join-Path $env:LOCALAPPDATA 'AnthropicClaude\claude.exe' + if (Test-Path -LiteralPath $LegacyExecutable) { + return $LegacyExecutable + } + + $Package = Get-AppxPackage -Name 'Claude' -ErrorAction SilentlyContinue | + Select-Object -First 1 + if ($null -eq $Package) { + return $null + } + + try { + $Manifest = Get-AppxPackageManifest $Package + $Application = @($Manifest.Package.Applications.Application) | Select-Object -First 1 + if ($null -eq $Application -or [string]::IsNullOrWhiteSpace($Application.Executable)) { + return $null + } + + $Executable = Join-Path $Package.InstallLocation ([string]$Application.Executable) + if (Test-Path -LiteralPath $Executable) { + return $Executable + } + } + catch { + return $null + } + + return $null +} + +$ClaudeExecutable = Get-ClaudeIconExecutable +if ($null -ne $ClaudeExecutable) { $IconLocation = "$ClaudeExecutable,0" } else { $IconLocation = "$TargetPath,0" diff --git a/chezmoi/dot_local/bin/start-claude-proxy.ps1 b/chezmoi/dot_local/bin/start-claude-proxy.ps1 index 0afec83..d36886c 100644 --- a/chezmoi/dot_local/bin/start-claude-proxy.ps1 +++ b/chezmoi/dot_local/bin/start-claude-proxy.ps1 @@ -49,22 +49,125 @@ function Add-WslEnvEntries { $env:WSLENV = [string]::Join(':', $Entries) } -function Get-ClaudeExecutable { - $Executable = Join-Path $env:LOCALAPPDATA 'AnthropicClaude\claude.exe' - if (-not (Test-Path -LiteralPath $Executable)) { - throw "Claude Desktop executable was not found: $Executable" +function Get-ClaudeApplication { + $LegacyExecutable = Join-Path $env:LOCALAPPDATA 'AnthropicClaude\claude.exe' + if (Test-Path -LiteralPath $LegacyExecutable) { + return [PSCustomObject]@{ + Mode = 'Legacy' + Executable = $LegacyExecutable + AppUserModelId = $null + } } - return $Executable + $Package = Get-AppxPackage -Name 'Claude' -ErrorAction SilentlyContinue | + Select-Object -First 1 + + if ($null -eq $Package) { + throw "Claude Desktop не найден: проверены файл '$LegacyExecutable' и пакет 'Claude'." + } + + $Manifest = Get-AppxPackageManifest $Package + $Application = @($Manifest.Package.Applications.Application) | Select-Object -First 1 + if ($null -eq $Application -or [string]::IsNullOrWhiteSpace($Application.Executable)) { + throw "Манифест пакета Claude не содержит исполняемого файла." + } + + $Executable = Join-Path $Package.InstallLocation ([string]$Application.Executable) + if (-not (Test-Path -LiteralPath $Executable)) { + throw "Исполняемый файл пакета Claude не найден: $Executable" + } + + return [PSCustomObject]@{ + Mode = 'Packaged' + Executable = $Executable + AppUserModelId = "$($Package.PackageFamilyName)!$([string]$Application.Id)" + } +} + +function Start-ClaudePackagedApplication { + param( + [Parameter(Mandatory)] + [string]$AppUserModelId, + + [Parameter(Mandatory)] + [string]$Arguments + ) + + if (-not ('ClaudeProxyLauncher.ApplicationActivationManager' -as [type])) { + Add-Type -TypeDefinition @' +using System; +using System.Runtime.InteropServices; + +namespace ClaudeProxyLauncher +{ + [Flags] + public enum ActivateOptions : uint + { + None = 0 + } + + [ComImport] + [Guid("2e941141-7f97-4756-ba1d-9decde894a3d")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IApplicationActivationManager + { + [PreserveSig] + int ActivateApplication( + [MarshalAs(UnmanagedType.LPWStr)] string appUserModelId, + [MarshalAs(UnmanagedType.LPWStr)] string arguments, + ActivateOptions options, + out uint processId); + } + + [ComImport] + [Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")] + public class ApplicationActivationManager + { + } + + public static class ApplicationActivator + { + public static uint Activate(string appUserModelId, string arguments) + { + IApplicationActivationManager manager = + (IApplicationActivationManager)new ApplicationActivationManager(); + + uint processId; + int hResult = manager.ActivateApplication( + appUserModelId, + arguments, + ActivateOptions.None, + out processId); + + Marshal.ThrowExceptionForHR(hResult); + return processId; + } + } +} +'@ + } + + [void][ClaudeProxyLauncher.ApplicationActivator]::Activate( + $AppUserModelId, + $Arguments + ) } Set-ProxyEnvironment Add-WslEnvEntries -$ClaudeExecutable = Get-ClaudeExecutable -$ClaudeArguments = @( - "--proxy-server=${HttpProxy}", - "--proxy-bypass-list=${ProxyBypassList}" -) +$ClaudeApplication = Get-ClaudeApplication +$ProxyServerArgument = "--proxy-server=${HttpProxy}" +$ProxyBypassArgument = "--proxy-bypass-list=${ProxyBypassList}" -Start-Process -FilePath $ClaudeExecutable -ArgumentList $ClaudeArguments +if ($ClaudeApplication.Mode -eq 'Legacy') { + Start-Process -FilePath $ClaudeApplication.Executable -ArgumentList @( + $ProxyServerArgument, + $ProxyBypassArgument + ) +} else { + $ClaudeArguments = "${ProxyServerArgument} ${ProxyBypassArgument}" + Start-ClaudePackagedApplication ` + -AppUserModelId $ClaudeApplication.AppUserModelId ` + -Arguments $ClaudeArguments +}