# 01 — Внешний прокси и переносимый Bash-интерфейс **What to build:** Самостоятельный пользовательский пакет прокси, через который можно безопасно запускать команды с уже работающим внешним прокси, например Hiddify. Привычные Bash-команды переходят на единый CLI-контракт, но прежний сценарий без машинного конфига продолжает работать. **Blocked by:** None — can start immediately. **Status:** done - [x] CLI работает на Python 3.8+ без сторонних библиотек, ничего не устанавливает и не запускает без явной подкоманды и выдаёт понятную ошибку на более старом Python. - [x] Машинный INI явно различает типы `external` и `xray`, проверяет имя, адрес, порт и добавку к `NO_PROXY`; отсутствие файла сохраняет внешний прокси `hproxy.local:12334` без неявного переключения на другой тип. - [x] Канонический машинный INI содержит единственную секцию `[proxy]` и ровно по одному ключу `type`, `name`, `address`, `port`, `no_proxy_extra`: ```ini [proxy] type = external name = Hiddify address = hproxy.local port = 12334 no_proxy_extra = .example.internal,git.example.internal ``` Все ключи обязательны при наличии файла; `no_proxy_extra` может быть пустым. Неизвестные секции и ключи, повторы, пропуски, многострочные или содержащие NUL значения, пустые имя или адрес и порт вне диапазона 1–65535 отклоняются. Добавки к `NO_PROXY` задаются через запятую, окружающие пробелы удаляются, пустые элементы отклоняются. - [x] `address` принимает IPv4, IPv6 без квадратных скобок либо ASCII DNS-имя из корректных непустых меток; схема URL, встроенный порт, скобки, zone ID, пробелы, `/`, `@` и другие URL-разделители отклоняются. При формировании proxy-URL CLI сам заключает IPv6-литерал в квадратные скобки. - [x] Для типа `external` команды `status`, `env` и `run -- COMMAND ARG...` проверяют только настроенный адрес и порт; недоступный прокси запрещает запуск дочерней команды с понятным сообщением. - [x] До реализации управляемого процесса конфиг с `type=xray` обрабатывается безопасным отказом: `status`, `env`, `run` и `start` не считают один открытый порт доказательством управляемого Xray и не запускают дочернюю команду. - [x] `env` при успехе печатает только восемь разрешённых proxy-переменных в двух регистрах, а при ошибке не печатает частичный результат; базовый `NO_PROXY` включает loopback и узел прокси, затем дополняется машинной настройкой. - [x] Документированный `PROXY_PREFLIGHT_TIMEOUT` сохраняется как положительное число секунд с прежним значением по умолчанию `2` для проверок доступности из `status`, `env` и `run`; ошибочное значение даёт понятный отказ. - [x] `run` без искажений сохраняет аргументы и код возврата команды, передаёт proxy-переменные только дочернему процессу и возвращает отдельную понятную ошибку, если команда отсутствует в `PATH`. - [x] Переносимый Bash-модуль становится единственным владельцем `proxy_on`, `proxy_off`, `pclaude`, `pcodex`, `myip` и внутренних proxy-помощников; WSL-функция обновления `hproxy.local` остаётся независимой. - [x] Обычный запуск dotfiles подключает общий Bash-файл и переносимый proxy-модуль независимо: после установки доступны все пять proxy-команд и `update_hproxy`; подключение одного переносимого модуля без остальных dotfiles также предоставляет все пять proxy-команд. - [x] Bash-модуль принимает вывод `env` атомарно, проверяет белый список и наличие каждого из восьми ключей ровно один раз, не использует `eval` и при любом неверном выводе оставляет прежние восемь переменных без изменений; `proxy_on` и `proxy_off` больше не делают автоматический запрос внешнего IP. - [x] Автоматические тесты подтверждают прежний внешний Hiddify-сценарий, fail-fast, оба регистра переменных, настраиваемый `NO_PROXY`, отсутствие протечки окружения, обычное и самостоятельное подключение Bash-модуля, безопасный отказ для `type=xray` и атомарный разбор полного вывода `env`.