feat(proxy): добавлены pclaude/pcodex для явного запуска через прокси

- Зачем:
  - claude/codex должны ходить через hproxy.local, а ручной proxy_on легко забыть; нужны явные команды, которые не стартуют молча при недоступном прокси.
- Что:
  - bash: добавлены _proxy_export/_proxy_reachable/_proxy_run и pclaude/pcodex; proxy_on рефакторен на единый источник правды без смены поведения.
  - powershell: добавлены Get-ProxyEndpoint/Set-ProxyEnv/Test-ProxyReachable/Invoke-WithProxy и pclaude/pcodex; proxy_on рефакторен аналогично.
  - таймаут pre-flight вынесен в PROXY_PREFLIGHT_TIMEOUT (дефолт 2 c).
  - добавлен tests/test_proxy_launchers.sh (fail-fast, изоляция env, проброс кода, аргументы, регресс proxy_on).
- Проверка:
  - bash tests/test_proxy_launchers.sh.
This commit is contained in:
Dmitry Dementiev committed 2026-05-19 14:28:41 +03:00
1 parent 84e577bc97
commit d5559867bd
3 files changed
+249 -18

No files matched your search

+49 -11
View File
@@ -23,20 +23,58 @@ update_hproxy() {
echo "✅ hproxy.local -> $(getent hosts hproxy.local 2>/dev/null | awk '{print $1}')"
}
# Удобные функции-переключатели для терминала
# NO_PROXY: ::1 и [::1] нужны, т.к. localhost в dual-stack Linux резолвится в IPv6,
# и без них локальные MCP/loopback-соединения (chroma-mcp, claude-mem worker и т.п.)
# уходят в SOCKS5 через hproxy.local. Дублируем в lower-case no_proxy для Python-стека.
proxy_on() {
local no_proxy_list="hproxy.local,localhost,127.0.0.1,::1,[::1],.concept-software.ru"
export HTTP_PROXY="http://hproxy.local:12334"
export HTTPS_PROXY="http://hproxy.local:12334"
export ALL_PROXY="socks5://hproxy.local:12334"
export NO_PROXY="$no_proxy_list"
# Единый источник правды для прокси-эндпоинта (не экспортируется; идемпотентно
# при повторном source). NO_PROXY: ::1 и [::1] нужны, т.к. localhost в dual-stack
# Linux резолвится в IPv6, и без них локальные MCP/loopback-соединения
# (chroma-mcp, claude-mem worker и т.п.) уходят в SOCKS5 через hproxy.local.
: "${_PROXY_HOST:=hproxy.local}"
: "${_PROXY_PORT:=12334}"
: "${_PROXY_NO_PROXY:=hproxy.local,localhost,127.0.0.1,::1,[::1],.concept-software.ru}"
# Внутренний: экспортирует proxy-env (+ lower-case дубли для Python-стека).
# Единственное место, где формируются значения переменных.
_proxy_export() {
export HTTP_PROXY="http://${_PROXY_HOST}:${_PROXY_PORT}"
export HTTPS_PROXY="http://${_PROXY_HOST}:${_PROXY_PORT}"
export ALL_PROXY="socks5://${_PROXY_HOST}:${_PROXY_PORT}"
export NO_PROXY="$_PROXY_NO_PROXY"
export http_proxy="$HTTP_PROXY"
export https_proxy="$HTTPS_PROXY"
export all_proxy="$ALL_PROXY"
export no_proxy="$no_proxy_list"
export no_proxy="$_PROXY_NO_PROXY"
}
# Внутренний: fail-fast проверка доступности прокси (только reachability —
# не доказательство, что трафик реально проксируется). Таймаут покрывает и
# медленный DNS-резолв; при зависании — отказ запуска (безопасный отказ).
_proxy_reachable() {
timeout "${PROXY_PREFLIGHT_TIMEOUT:-2}" \
bash -c "exec 3<>/dev/tcp/${_PROXY_HOST}/${_PROXY_PORT}" 2>/dev/null
}
# Внутренний: запуск команды с proxy-env. Pre-flight, затем subshell+exec —
# env виден только дочернему процессу, не протекает в родительский shell,
# код возврата пробрасывается.
_proxy_run() {
local cmd="$1"; shift
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "❌ Команда не найдена в PATH: $cmd" >&2
return 127
fi
if ! _proxy_reachable; then
echo "❌ Прокси ${_PROXY_HOST}:${_PROXY_PORT} недоступен — запуск '$cmd' отменён." >&2
return 1
fi
# exec и так резолвит через PATH в обход функций/алиасов.
( _proxy_export; exec "$cmd" "$@" )
}
pclaude() { _proxy_run claude "$@"; }
pcodex() { _proxy_run codex "$@"; }
# Удобные функции-переключатели для терминала.
proxy_on() {
_proxy_export
echo "✅ Proxy enabled. Checking route..."
# Подставляем результат выполнения curl прямо в строку
echo "🌍 Current IP: $(curl -s --max-time 3 https://ifconfig.me)"