diff --git a/README.md b/README.md index 34c5db1..a63684b 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ Chezmoi использует отдельный source dir `chezmoi/` внутр - **Git baseline** — `~/.gitconfig` с managed настройками, `~/.gitconfig.local` для персональных overrides - **Windows Terminal** — идемпотентный скрипт: PS7 по умолчанию, PS 5.1 как legacy, Azure Cloud Shell скрыт - **UTF-8** — `chcp 65001` + `Console.InputEncoding/OutputEncoding` только для pwsh 7, не для PS 5.1 +- **Codex Proxy shortcut** — Start Menu ярлык для запуска Codex GUI с proxy-переменными - **Extension points** — `~/.config/powershell/profile.extra.ps1` и `profile.d/*.ps1` для локальных добавок ### AI-инструменты (кросс-платформа) @@ -133,6 +134,17 @@ echo '127.0.0.1 hproxy.local' | sudo tee -a /etc/hosts **Windows pwsh** — `proxy_on` / `proxy_off` / `myip` работают аналогично bash-версиям. +**Codex GUI на Windows** — chezmoi создает Start Menu ярлык `Codex Proxy`, который запускает Codex Windows App с proxy-переменными: + +```powershell +HTTP_PROXY=http://hproxy.local:12334 +HTTPS_PROXY=http://hproxy.local:12334 +ALL_PROXY=socks5://hproxy.local:12334 +NO_PROXY=hproxy.local,localhost,127.0.0.1,::1,[::1],.concept-software.ru +``` + +Ярлык вызывает `~/.local/bin/start-codex-proxy.ps1`. Скрипт также добавляет эти переменные в `WSLENV` с флагом `/u`: это штатный мост Windows → WSL, чтобы дочерние WSL-сессии, запущенные из Codex GUI, получили тот же proxy environment. + ### Git baseline На всех платформах фиксируются настройки для предсказуемого поведения: @@ -196,6 +208,7 @@ echo '127.0.0.1 hproxy.local' | sudo tee -a /etc/hosts | `~/.env.secrets` | API-ключи, подгружается bash и VS Code Server | | `~/.bash_aliases` | Персональные алиасы bash | | `~/.gitconfig.local` | Персональные Git-настройки (`user.name`, `core.editor` и т.д.) | +| `~/.local/bin/start-codex-proxy.ps1` | Windows launcher для Codex GUI с proxy-переменными | | `~/.config/powershell/profile.extra.ps1` | Локальные дополнения к pwsh-профилю | | `~/.config/powershell/profile.d/*.ps1` | Фрагменты, загружаемые по алфавиту | | `~/.claude/settings.json` | Управляется Claude Code: `model`, `effortLevel`, «always allow» permissions | diff --git a/chezmoi/.chezmoiignore b/chezmoi/.chezmoiignore index 99f28bf..6cc1138 100644 --- a/chezmoi/.chezmoiignore +++ b/chezmoi/.chezmoiignore @@ -2,5 +2,6 @@ AppData/** Documents/** dot_config/** +dot_local/** dot_gitconfig {{ end }} diff --git a/chezmoi/.chezmoiscripts/run_30-create-codex-proxy-shortcut.ps1 b/chezmoi/.chezmoiscripts/run_30-create-codex-proxy-shortcut.ps1 new file mode 100644 index 0000000..0293587 --- /dev/null +++ b/chezmoi/.chezmoiscripts/run_30-create-codex-proxy-shortcut.ps1 @@ -0,0 +1,90 @@ +$ErrorActionPreference = 'Stop' + +if (-not ($IsWindows -or $PSVersionTable.PSEdition -eq 'Desktop')) { + return +} + +$LauncherPath = Join-Path $HOME '.local\bin\start-codex-proxy.ps1' +$ProgramsPath = [Environment]::GetFolderPath('Programs') +if ([string]::IsNullOrWhiteSpace($ProgramsPath)) { + Write-Warning 'Start Menu Programs folder was not found.' + return +} + +$ShortcutPath = Join-Path $ProgramsPath 'Codex Proxy.lnk' +$PwshCommand = Get-Command pwsh -ErrorAction SilentlyContinue +if ($null -ne $PwshCommand) { + $TargetPath = $PwshCommand.Source +} else { + $TargetPath = 'pwsh.exe' +} + +$Arguments = "-NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$LauncherPath`"" +$WorkingDirectory = $env:USERPROFILE +$IconLocation = "$TargetPath,0" + +function Get-CodexExecutable { + $Package = Get-AppxPackage -Name 'OpenAI.Codex' -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 +} + +$CodexExecutable = Get-CodexExecutable +if ($null -ne $CodexExecutable) { + $IconLocation = "$CodexExecutable,0" +} + +New-Item -ItemType Directory -Path (Split-Path -Parent $ShortcutPath) -Force | Out-Null + +$Shell = New-Object -ComObject WScript.Shell +$Shortcut = $Shell.CreateShortcut($ShortcutPath) + +$Changed = $false +if ($Shortcut.TargetPath -ne $TargetPath) { + $Shortcut.TargetPath = $TargetPath + $Changed = $true +} +if ($Shortcut.Arguments -ne $Arguments) { + $Shortcut.Arguments = $Arguments + $Changed = $true +} +if ($Shortcut.WorkingDirectory -ne $WorkingDirectory) { + $Shortcut.WorkingDirectory = $WorkingDirectory + $Changed = $true +} +if ($Shortcut.IconLocation -ne $IconLocation) { + $Shortcut.IconLocation = $IconLocation + $Changed = $true +} +if ($Shortcut.Description -ne 'Launch Codex with hproxy.local proxy environment') { + $Shortcut.Description = 'Launch Codex with hproxy.local proxy environment' + $Changed = $true +} + +if ($Changed -or -not (Test-Path -LiteralPath $ShortcutPath)) { + $Shortcut.Save() + Write-Host "Codex Proxy shortcut: updated $ShortcutPath" +} else { + Write-Host 'Codex Proxy shortcut: already up to date.' +} diff --git a/chezmoi/dot_local/bin/start-codex-proxy.ps1 b/chezmoi/dot_local/bin/start-codex-proxy.ps1 new file mode 100644 index 0000000..80bacd1 --- /dev/null +++ b/chezmoi/dot_local/bin/start-codex-proxy.ps1 @@ -0,0 +1,77 @@ +$ErrorActionPreference = 'Stop' + +$ProxyHostName = 'hproxy.local' +$ProxyPort = 12334 +$HttpProxy = "http://${ProxyHostName}:${ProxyPort}" +$SocksProxy = "socks5://${ProxyHostName}:${ProxyPort}" +$NoProxy = "${ProxyHostName},localhost,127.0.0.1,::1,[::1],.concept-software.ru" + +function Set-ProxyEnvironment { + $env:HTTP_PROXY = $HttpProxy + $env:HTTPS_PROXY = $HttpProxy + $env:ALL_PROXY = $SocksProxy + $env:NO_PROXY = $NoProxy + + $env:http_proxy = $HttpProxy + $env:https_proxy = $HttpProxy + $env:all_proxy = $SocksProxy + $env:no_proxy = $NoProxy +} + +function Add-WslEnvEntries { + $RequiredEntries = @( + 'HTTP_PROXY/u', + 'HTTPS_PROXY/u', + 'ALL_PROXY/u', + 'NO_PROXY/u', + 'http_proxy/u', + 'https_proxy/u', + 'all_proxy/u', + 'no_proxy/u' + ) + + $Entries = New-Object System.Collections.Generic.List[string] + if (-not [string]::IsNullOrWhiteSpace($env:WSLENV)) { + foreach ($Entry in ($env:WSLENV -split ':')) { + if (-not [string]::IsNullOrWhiteSpace($Entry) -and -not $Entries.Contains($Entry)) { + [void]$Entries.Add($Entry) + } + } + } + + foreach ($Entry in $RequiredEntries) { + if (-not $Entries.Contains($Entry)) { + [void]$Entries.Add($Entry) + } + } + + $env:WSLENV = [string]::Join(':', $Entries) +} + +function Get-CodexExecutable { + $Package = Get-AppxPackage -Name 'OpenAI.Codex' -ErrorAction SilentlyContinue | + Select-Object -First 1 + + if ($null -eq $Package) { + throw 'Codex Windows App is not installed. Expected AppX package: OpenAI.Codex.' + } + + $Manifest = Get-AppxPackageManifest $Package + $Application = @($Manifest.Package.Applications.Application) | Select-Object -First 1 + if ($null -eq $Application -or [string]::IsNullOrWhiteSpace($Application.Executable)) { + throw 'Codex Windows App manifest does not contain an executable entry.' + } + + $Executable = Join-Path $Package.InstallLocation ([string]$Application.Executable) + if (-not (Test-Path -LiteralPath $Executable)) { + throw "Codex Windows App executable was not found: $Executable" + } + + return $Executable +} + +Set-ProxyEnvironment +Add-WslEnvEntries + +$CodexExecutable = Get-CodexExecutable +Start-Process -FilePath $CodexExecutable