feat(kimi): добавлен запуск Kimi Desktop через прокси

- Зачем: Kimi Desktop по умолчанию ходит в сеть напрямую, а прокси нужен как для Codex и Claude.
- Что: start-kimi-proxy.ps1 запускает Kimi.exe с параметрами Electron --proxy-server и --proxy-bypass-list, run-скрипт chezmoi создаёт ярлык Kimi Proxy в меню "Пуск"; тест синхронизации списков обхода обобщён на все копии.
- Проверка: синтаксис скриптов проверен парсером PowerShell, tests/test_proxy_env_sync.py зелёный, запуск через ярлык проверен вручную.
This commit is contained in:
Dmitriy Dementiev committed 2026-10-23 14:10:59 +03:00
1 parent 4f034ea840
commit 5b2eef4881
4 files changed
+115 -1

No files matched your search

+7
View File
@@ -67,6 +67,7 @@ Chezmoi использует отдельный source dir `chezmoi/` внутр
- **UTF-8** - `chcp 65001` + `Console.InputEncoding/OutputEncoding` только для pwsh 7, не для PS 5.1 - **UTF-8** - `chcp 65001` + `Console.InputEncoding/OutputEncoding` только для pwsh 7, не для PS 5.1
- **Codex Proxy shortcut** - Start Menu ярлык для запуска Codex GUI с proxy-переменными - **Codex Proxy shortcut** - Start Menu ярлык для запуска Codex GUI с proxy-переменными
- **Claude Proxy** - ярлык меню "Пуск" для запуска Claude Desktop с переменными прокси - **Claude Proxy** - ярлык меню "Пуск" для запуска Claude Desktop с переменными прокси
- **Kimi Proxy** - ярлык меню "Пуск" для запуска Kimi Desktop с параметрами прокси Electron
- **Extension points** - `~/.config/powershell/profile.extra.ps1` и `profile.d/*.ps1` для локальных добавок - **Extension points** - `~/.config/powershell/profile.extra.ps1` и `profile.d/*.ps1` для локальных добавок
### AI-инструменты (кросс-платформа) ### AI-инструменты (кросс-платформа)
@@ -128,6 +129,11 @@ Codex и Claude Code могут брать прокси из своих наст
Если Claude уже запущен обычным способом, его нужно полностью закрыть перед Если Claude уже запущен обычным способом, его нужно полностью закрыть перед
запуском через `Claude Proxy`. запуском через `Claude Proxy`.
Ярлык `Kimi Proxy` запускает Kimi Desktop (`%LOCALAPPDATA%\Programs\Kimi\Kimi.exe`)
с теми же параметрами Electron `--proxy-server` и `--proxy-bypass-list`, что и
`Codex Proxy`. Если Kimi уже запущен, его нужно полностью закрыть перед запуском
через `Kimi Proxy`.
Список хостов, которые идут мимо прокси, продублирован в профилях Codex, Список хостов, которые идут мимо прокси, продублирован в профилях Codex,
PowerShell и VS Code: одного общего файла у Windows и WSL нет. Эталон - PowerShell и VS Code: одного общего файла у Windows и WSL нет. Эталон -
`DEFAULT_NO_PROXY_EXTRA` в `proxy-client/.local/bin/proxy-client`; меняя его, `DEFAULT_NO_PROXY_EXTRA` в `proxy-client/.local/bin/proxy-client`; меняя его,
@@ -212,6 +218,7 @@ PowerShell и VS Code: одного общего файла у Windows и WSL н
| `~/.local/bin/start-claude-proxy.ps1` | Скрипт запуска Claude Desktop для Windows с переменными прокси и параметрами Electron | | `~/.local/bin/start-claude-proxy.ps1` | Скрипт запуска Claude Desktop для Windows с переменными прокси и параметрами Electron |
| `~/.local/bin/start-claude-proxy.vbs` | Скрытый запуск PowerShell-скрипта без привязки Claude к видимому окну терминала | | `~/.local/bin/start-claude-proxy.vbs` | Скрытый запуск PowerShell-скрипта без привязки Claude к видимому окну терминала |
| `~/.local/bin/start-codex-proxy.ps1` | Запуск Codex для Windows через системный идентификатор; прокси Electron задается параметрами, а `codex.exe` читает `~/.codex/.env` | | `~/.local/bin/start-codex-proxy.ps1` | Запуск Codex для Windows через системный идентификатор; прокси Electron задается параметрами, а `codex.exe` читает `~/.codex/.env` |
| `~/.local/bin/start-kimi-proxy.ps1` | Запуск Kimi Desktop для Windows с параметрами прокси Electron |
| `~/.local/bin/start-chatgpt-proxy` | Запуск Linux-приложения ChatGPT через активную настройку `proxy-client` | | `~/.local/bin/start-chatgpt-proxy` | Запуск Linux-приложения ChatGPT через активную настройку `proxy-client` |
| `~/.local/share/applications/chatgpt-proxy.desktop` | Отдельный Linux-ярлык `ChatGPT Proxy`, не подменяющий штатный `ChatGPT` | | `~/.local/share/applications/chatgpt-proxy.desktop` | Отдельный Linux-ярлык `ChatGPT Proxy`, не подменяющий штатный `ChatGPT` |
| `~/.config/powershell/profile.extra.ps1` | Локальные дополнения к pwsh-профилю | | `~/.config/powershell/profile.extra.ps1` | Локальные дополнения к pwsh-профилю |
@@ -0,0 +1,66 @@
$ErrorActionPreference = 'Stop'
if (-not ($IsWindows -or $PSVersionTable.PSEdition -eq 'Desktop')) {
return
}
$LauncherPath = Join-Path $HOME '.local\bin\start-kimi-proxy.ps1'
$ProgramsPath = [Environment]::GetFolderPath('Programs')
if ([string]::IsNullOrWhiteSpace($ProgramsPath)) {
Write-Warning 'Start Menu Programs folder was not found.'
return
}
$ShortcutPath = Join-Path $ProgramsPath 'Kimi Proxy.lnk'
$PwshAliasPath = Join-Path $env:LOCALAPPDATA 'Microsoft\WindowsApps\pwsh.exe'
$PwshCommand = Get-Command pwsh -ErrorAction SilentlyContinue
if (Test-Path -LiteralPath $PwshAliasPath) {
$TargetPath = $PwshAliasPath
} elseif ($null -ne $PwshCommand) {
$TargetPath = $PwshCommand.Source
} else {
$TargetPath = 'pwsh.exe'
}
$Arguments = "-NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$LauncherPath`""
$WorkingDirectory = $env:USERPROFILE
$IconLocation = "$TargetPath,0"
$KimiExecutable = Join-Path $env:LOCALAPPDATA 'Programs\Kimi\Kimi.exe'
if (Test-Path -LiteralPath $KimiExecutable) {
$IconLocation = "$KimiExecutable,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 Kimi with hproxy.local proxy environment') {
$Shortcut.Description = 'Launch Kimi with hproxy.local proxy environment'
$Changed = $true
}
if ($Changed -or -not (Test-Path -LiteralPath $ShortcutPath)) {
$Shortcut.Save()
Write-Host "Kimi Proxy shortcut: updated $ShortcutPath"
} else {
Write-Host 'Kimi Proxy shortcut: already up to date.'
}
@@ -0,0 +1,38 @@
$ErrorActionPreference = 'Stop'
$ProxyHostName = 'hproxy.local'
$ProxyPort = 12334
$HttpProxy = "http://${ProxyHostName}:${ProxyPort}"
$ProxyBypassList = "${ProxyHostName};localhost;127.0.0.1;[::1];*.concept-software.ru;dementev.space;*.dementev.space"
function Get-KimiApplication {
$Executable = Join-Path $env:LOCALAPPDATA 'Programs\Kimi\Kimi.exe'
if (-not (Test-Path -LiteralPath $Executable)) {
throw "Kimi Desktop не найден: ожидался файл '$Executable'."
}
return $Executable
}
function Assert-KimiNotRunning {
param(
[Parameter(Mandatory)]
[string]$Executable
)
$RunningProcess = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |
Where-Object { $_.ExecutablePath -eq $Executable } |
Select-Object -First 1
if ($null -ne $RunningProcess) {
throw 'Kimi уже запущен. Полностью закройте приложение и повторно откройте ярлык Kimi Proxy.'
}
}
$KimiExecutable = Get-KimiApplication
Assert-KimiNotRunning -Executable $KimiExecutable
Start-Process -FilePath $KimiExecutable -ArgumentList @(
"--proxy-server=${HttpProxy}",
"--proxy-bypass-list=${ProxyBypassList}"
)
+4 -1
View File
@@ -38,6 +38,7 @@ COPIES = (
BYPASS_FILES = ( BYPASS_FILES = (
"chezmoi/dot_local/bin/start-claude-proxy.ps1", "chezmoi/dot_local/bin/start-claude-proxy.ps1",
"chezmoi/dot_local/bin/start-codex-proxy.ps1", "chezmoi/dot_local/bin/start-codex-proxy.ps1",
"chezmoi/dot_local/bin/start-kimi-proxy.ps1",
) )
BYPASS_RE = re.compile(r'^\$ProxyBypassList = "\$\{ProxyHostName\};(.+)"\s*$', re.M) BYPASS_RE = re.compile(r'^\$ProxyBypassList = "\$\{ProxyHostName\};(.+)"\s*$', re.M)
@@ -74,7 +75,9 @@ class NoProxySyncTest(unittest.TestCase):
match, "{}: не найден ProxyBypassList".format(relative_path) match, "{}: не найден ProxyBypassList".format(relative_path)
) )
values.append(match.group(1)) values.append(match.group(1))
self.assertEqual(values[0], values[1], "ProxyBypassList разошёлся") self.assertEqual(
len(set(values)), 1, "ProxyBypassList разошёлся между файлами"
)
if __name__ == "__main__": if __name__ == "__main__":