Files
dotfiles/docs/specs/2026-07-15-proxy-client-design.md
T
ddadmin 6e431d875e refactor(proxy-client): переименован интерфейс прокси
- Зачем:
  - прежнее имя выпячивало Xray, хотя клиент поддерживает также внешний прокси, а два каталога конфигурации были неочевидны.
- Что:
  - пакет, CLI, конфигурация, состояние, тесты и документация переименованы в proxy-client.
  - машинный конфиг, профиль и два явных примера собраны в одном пользовательском каталоге.
  - свежая установка защищена от сворачивания каталога конфигурации внутрь репозитория.
- Проверка:
  - bash tests/test_proxy_client_full.sh.
  - bash tests/test_install.sh.
  - ручные start, status и xray run -test; незавершённая сетевая приёмка записана в handoff.
2026-07-21 09:31:21 -04:00

42 KiB
Raw Blame History

proxy-client для агентских CLI

Дата: 2026-07-15

Статус: реализация готова к ручной приёмке; публичное имя уточнено 2026-07-21

Проблема

На удалённых Linux-серверах нет GUI-клиента Hiddify. Перед запуском Claude Code или Codex приходится вручную запускать Xray и выставлять proxy-переменные. Переменные легко забыть, после чего агент стартует без прокси.

Нужны привычные команды pclaude и pcodex, которые не запускают агента, если явно настроенный прокси недоступен. Решение должно работать как часть этого репозитория и отдельно от остальных dotfiles.

Контекст

Существующий дизайн pclaude / pcodex задаёт важный контракт: proxy-переменные видны только дочернему процессу, аргументы и код возврата сохраняются, а недоступный прокси приводит к отказу до запуска агента.

Эта спецификация заменяет Linux-часть прежнего дизайна в вопросах расположения функций, источника настроек и вывода proxy_on/proxy_off. Windows-часть прежнего дизайна не меняется.

Сейчас Bash-функции жёстко используют внешний Hiddify на hproxy.local:12334. Принесённый прототип scripts/setup-xray-proxy.sh умеет установить и запустить Xray из готового JSON, но смешивает установку и запуск, не разбирает ссылки Hiddify и небезопасно ищет чужие процессы через pkill.

Xray принимает конфигурационные файлы, а не vless://-ссылки. При этом его SOCKS-вход принимает SOCKS и HTTP на одном порту, поэтому существующая схема proxy-переменных совместима с локальным Xray без второго порта. См. командную строку Xray и SOCKS-вход.

Цели

  • Дать headless Linux-серверу управляемый пользовательский Xray без systemd и прав root.
  • Сохранить явные pclaude и pcodex, которые нельзя случайно запустить через другой прокси или без настроенного прокси.
  • Принимать одну точечную VLESS-ссылку Hiddify и преобразовывать её в клиентский JSON Xray.
  • Сохранить совместимость Bash-функций с внешним Hiddify.
  • Позволить настраивать машинный NO_PROXY без правки файлов репозитория.
  • Поддержать выборочную установку после git clone: через stow, ручные симлинки или копирование.

Не входит в объём

  • Windows, PowerShell, Windows Codex launcher и VS Code Server.
  • systemd, автозапуск после перезагрузки, sudo, firewall, TUN и изменение системной маршрутизации.
  • Автоматический выбор между Xray и Hiddify или переход на запасной прокси.
  • Одновременное управление несколькими профилями одного Unix-пользователя.
  • Универсальный импорт подписок или полного JSON-экспорта Hiddify.
  • Протоколы и сочетания за пределами двух явно поддержанных семейств.
  • pip, venv и любые сторонние Python-библиотеки.
  • Сетевая изоляция голых claude и codex: как и раньше, гарантию намерения дают явные команды с префиксом p.

Рассмотренные варианты

Только Bash

Ближе всего к принесённому прототипу, но URL-кодирование, JSON, проверка схемы, контрольные суммы и безопасное управление процессом делают Bash-реализацию хрупкой и плохо тестируемой.

Bash-контроллер и отдельный Python-преобразователь

Оставляет жизненный цикл в Bash, а разбор VLESS переносит в Python. Граница между двумя реализациями усложняет ошибки, тесты и единый источник настроек.

Один Python CLI и тонкий Bash-модуль

Python отвечает за данные, установку Xray, процессы и запуск дочерних команд. Bash нужен только там, где необходимо изменить окружение текущей shell-сессии. Это выбранный вариант.

Не создавать менеджер

Можно хранить готовые JSON и вручную запускать Xray в tmux. Вариант почти не требует кода, но не решает основную боль: безопасный запуск pclaude и pcodex из точечной ссылки Hiddify.

Рекомендуемое решение

Границы компонентов

proxy-client — один исполняемый файл на Python 3.8+ без внешних библиотек. Он отвечает за установку Xray, запуск и остановку процесса, диагностику, преобразование VLESS и запуск произвольной дочерней команды через прокси. Нейтральное публичное имя описывает клиентскую прокси-подсистему целиком: внешний прокси и управляемый Xray. Название xray остаётся у конкретного движка и значения type = xray, где оно действительно важно.

Переносимый shell.bash — единственный владелец proxy_on, proxy_off, pclaude, pcodex, myip и внутренних proxy-помощников. При реализации они удаляются из bash/.bash_functions, чтобы результат не зависел от порядка source. update_hproxy остаётся там как отдельная WSL-утилита управления /etc/hosts, а не часть переносимого интерфейса прокси. Модуль не разбирает машинный конфиг самостоятельно:

  • pclaude и pcodex делегируют запуск форме proxy-client run -- COMMAND ARG..., где -- отделяет параметры клиента;
  • proxy_on получает от proxy-client env проверенный набор proxy-переменных и применяет его к текущей Bash-сессии;
  • proxy_off очищает верхний и нижний регистр proxy-переменных.

Общий bash/.bash_functions и модуль клиента не зависят друг от друга. В составе dotfiles .bash_custom подключает их двумя независимыми строками. Без остальных dotfiles пользователь добавляет только один source модуля клиента в .bashrc. Для неинтерактивных сценариев и других оболочек остаётся прямой proxy-client run.

proxy-client env сначала выполняет ту же проверку доступности, что и run, а затем печатает восемь строк KEY=value: HTTP, HTTPS, ALL и NO_PROXY в верхнем и нижнем регистре. shell.bash сначала целиком получает успешный ответ, затем разбирает строки по первому =, принимает только известные ключи и лишь после полной проверки экспортирует полученные значения через printf -v. eval не используется, частичного изменения окружения при ошибке нет.

У env stdout зарезервирован только для восьми машинно-читаемых строк. Предупреждения и ошибки идут в stderr; обычная безопасная сводка этой командой не печатается.

Совместимость существующих Bash-команд означает сохранение имён функций, набора переменных, fail-fast перед pclaude/pcodex и изоляции окружения дочернего процесса. Автоматический запрос внешнего IP из proxy_on и proxy_off удаляется: он замедляет переключение и смешивает изменение окружения с диагностикой. Для проверки остаются myip и proxy-client status.

Два независимых файла настройки

Машинный файл ~/.config/proxy-client/config хранит несекретное описание активного прокси: явный тип xray или external, отображаемое имя, адрес, порт и добавку к NO_PROXY. Формат — INI из стандартной библиотеки Python. Если файла нет, прокси-подсистема сохраняет прежний внешний адрес hproxy.local:12334 ради обратной совместимости.

Секретный ~/.config/proxy-client/default.url содержит одну VLESS-ссылку. Команда запуска принимает другой файл через -f. Профили можно хранить в нескольких файлах, но активным у пользователя бывает только один. CLI следует за симлинком, но проверяет права конечного файла: доступ группы или остальных пользователей считается ошибкой с подсказкой выполнить chmod 600. Файл должен содержать ровно одну непустую строку без комментариев и служебного текста.

Базовый NO_PROXY всегда включает loopback-адреса и узел самого прокси. Машинная добавка расширяет его локальными IP и доменами. Документация должна предупреждать, что поддержка CIDR в NO_PROXY различается между программами.

Явная семантика прокси

Тип xray означает, что pclaude и pcodex требуют запущенный процесс, которым управляет proxy-client. Если его нет, агент не запускается, а сообщение предлагает выполнить proxy-client start.

Тип external означает внешний процесс, например Hiddify. Проверяется только доступность явно заданного адреса и порта. Ни один тип не переходит на другой автоматически.

start разрешён только при type=xray; при type=external он завершается с подсказкой изменить машинный конфиг. Для Xray адрес машинного конфига обязан быть loopback-адресом, а порт обязан совпадать с создаваемым входом. Так нельзя случайно поднять локальный Xray, оставив pclaude направленным во внешний Hiddify.

status описывает именно активный тип из машинного конфига: состояние процесса и порта для Xray либо доступность адреса для external. stop от машинного типа не зависит и завершает записанный управляемый Xray, если он существует. Поэтому после явного переключения на external старый локальный процесс можно штатно остановить.

HTTP, HTTPS и SOCKS используют один локальный порт, по умолчанию 12334. Порт остаётся настраиваемым, чтобы разные Unix-пользователи одной машины могли запускать свои экземпляры без конфликта.

Локальный вход Xray слушает только loopback: 127.0.0.1 и, если поддержано выбранной конфигурацией, ::1. Он никогда не привязывается к 0.0.0.0, адресу сетевого интерфейса или имени узла. Это закрывает вход от удалённой сети, но не изолирует его от других пользователей того же Linux-узла. Первая версия не добавляет локальную аутентификацию и предполагает доверенных пользователей машины.

Поддерживаемые VLESS-ссылки

Первая версия поддерживает две семьи:

  • VLESS с TCP/RAW и REALITY;
  • VLESS с XHTTP и TLS, включая HTTP/1.1, h2 и h3 через ALPN.

Преобразователь сохраняет значимые параметры ссылки, проверяет обязательные поля и отклоняет неизвестное сочетание целиком. Он не должен молча пропускать неизвестные или несовместимые параметры. Поддержка REALITY опирается на официальную схему REALITY, а XHTTP с TLS — на схему TLS.

Для REALITY преобразователь явно сопоставляет UUID с VLESS id, узел и порт с адресом назначения, type=tcp с RAW, flow с режимом VLESS Vision, sni с serverName, fp с fingerprint, pbk с password, а sid с shortId. headerType=none принимается как нейтральное значение, другое значение отклоняется. hiddify, host и alpn для TCP/REALITY считаются метаданными и не меняют Xray JSON; безопасная сводка явно помечает host и alpn как неиспользованные. Это не скрытая потеря параметра: в целевой схеме REALITY Xray 26.3.27 нет полей Host или ALPN. Повтор одного query-параметра считается ошибкой. Остальные правила соответствуют стандарту VLESS-ссылок Xray.

Основной сценарий XHTTP/TLS — одиночная ссылка Hiddify с type=xhttp, security=tls, sni, alpn, path, host, encryption, fp и, возможно, extra. UUID, узел и порт преобразуются так же, как для REALITY. Остальные поля сопоставляются явно:

  • type=xhttp задаёт транспорт XHTTP;
  • security=tls включает TLS;
  • sni, alpn и fp задают serverName, список ALPN и fingerprint;
  • path, host и необязательный mode переходят в настройки XHTTP;
  • encryption задаёт шифрование VLESS и в первой версии должно быть none;
  • extra URL-декодируется, разбирается как JSON-объект без повторяющихся ключей и целиком передаётся в одноимённую секцию XHTTP;
  • pcs и vcn для Xray 26.3.27 переходят в pinnedPeerCertSha256 и verifyPeerCertByName;
  • hiddify=1 и core=xray принимаются как метаданные источника и не меняют JSON;
  • headerType=none принимается как устаревшее нейтральное поле Hiddify, другое значение отклоняется;
  • fragment после # используется только как отображаемое имя профиля.

Если mode отсутствует, преобразователь не придумывает его и оставляет выбор Xray. Параметры query не зависят от порядка, но не могут повторяться. После перечисленных полей неизвестный параметр считается ошибкой: он может менять смысл соединения и требует явного добавления в преобразователь. path, host, mode и extra входят в официальный стандарт ссылок Xray; параметры TLS pcs/vcn заменяют удалённый allowInsecure: стандарт VLESS-ссылок.

Перед запуском CLI печатает компактную безопасную сводку: сервер, порт, транспорт, защиту, SNI, ALPN, Host, наличие и длину пути, fingerprint и локальный порт. XHTTP path может содержать tenant ID или bearer-подобный токен, поэтому его содержимое никогда не печатается. Обычный режим не выводит подробный журнал Xray. UUID, REALITY password/public key, short ID и другие чувствительные значения обозначаются без фрагментов исходного значения. В создаваемом JSON журнал доступа отключён, а уровень ошибок по умолчанию — warning.

Hiddify Manager может добавлять allowInsecure=true и insecure=true даже к профилю с действительным публичным сертификатом — этот дефект описан в hiddify/Hiddify-Manager#5438. Современный Xray больше не поддерживает allowInsecure; удаление зафиксировано в релизе 26.2.6. Преобразователь принимает для обоих полей только точные строчные значения true и false. Если присутствуют оба поля, их значения должны совпадать; конфликт и любое другое написание отклоняются до создания JSON. Для Xray 26.3.27 поля не переносятся в JSON; истинное значение даёт предупреждение, что сертификат будет проверен обычным способом, а ложное не требует предупреждения. Соединение после этого может успешно заработать или завершиться ошибкой сертификата; отдельного раннего отказа нет.

Установка Xray

proxy-client install — отдельная явная операция. Она устанавливает Xray в ~/.local/bin, скачивает официальный архив и файл контрольной суммы, затем проверяет SHA-256. Поддерживается только зафиксированный релиз 26.3.27; параметра версии нет. Официальные релизы публикуют необходимые файлы .dgst: релиз 26.3.27.

Для Linux x86_64/amd64 используется Xray-linux-64.zip, для aarch64/arm64 — Xray-linux-arm64-v8a.zip; остальные архитектуры отклоняются. Официальный .dgst содержит записи MD5, SHA1, SHA2-256 и SHA2-512; принимается ровно один полный набор со строчными hex-значениями, для проверки архива используется SHA2-256. Дубликаты, uppercase, отсутствие записи и мусор отклоняются. Архив и извлечённый бинарник ограничены 64 MiB, .dgst — 4 KiB; фактический размер считается с limit+1 и должен совпадать с объявленным Content-Length. Архив распаковывается в закрытый staging-каталог внутри ~/.local/bin, проверенный бинарник запускается с version, после чего одним os.replace атомарно переносится в ~/.local/bin/xray.

Корректная существующая версия 26.3.27 даёт no-op без сети. Другой файл или симлинк не заменяется без --replace, а каталог не заменяется никогда. Start-lock берётся до проверки назначения и удерживается до завершения os.replace; живой, сиротский или неподтверждённый managed-state запрещает установку с подсказкой сначала выполнить stop. После установки CLI проверяет, что первый xray из PATH разрешается в установленный файл; иначе завершается с подсказкой поставить ~/.local/bin в начало PATH, не откатывая готовую установку. start всегда показывает фактический путь и версию выбранного бинарника.

Перед созданием JSON CLI разрешает первый xray из PATH до одного пути и запускает этим файлом xray version. Первая строка должна начинаться с точного токена Xray VERSION, после полного токена версии допускается только конец строки либо ASCII-пробел. Принимается только версия 26.3.27; ведущий мусор, похожий более длинный токен, пустой, неверный, завершившийся ошибкой или содержащий другую версию вывод запрещает запуск. Тот же разрешённый файл используется для run -test и основного процесса. Версия никогда не выводится из содержимого VLESS-ссылки.

start никогда не скачивает бинарник. Если xray отсутствует в PATH, команда завершается с подсказкой выполнить proxy-client install.

Жизненный цикл

CLI предоставляет install, start, stop, status, env и run. Запуск без подкоманды не устанавливает и не стартует ничего.

start остаётся на переднем плане как небольшой Python-супервизор и занимает текущую консоль. Он запускает один дочерний Xray без демонизации и без новой сессии процесса, ждёт его завершения и передаёт ему SIGINT, SIGTERM и SIGHUP. Ожидаемый способ работы — отдельная панель tmux или другого мультиплексора. Отсоединение от tmux не останавливает процесс, но закрытие панели или сессии останавливает Xray. Отдельный постоянный журнал и команда logs не нужны: достаточно истории tmux.

Супервизор на всё время работы удерживает неблокирующую эксклюзивную блокировку fcntl.flock в служебном каталоге ~/.local/state/proxy-client/. Второй start отказывает до запуска процессов и изменения state или сгенерированного конфига. state.json нужен для восстановления после сбоя, но не служит блокировкой.

Файл состояния содержит ровно supervisor_pid, xray_pid, xray_path, config_path, address, port, supervisor_path, supervisor_starttime, xray_starttime и boot_id. Время старта — поле 22 /proc/PID/stat; поле comm сначала отделяется по последней ). Для обоих процессов проверяются PID, точное время старта и boot_id. У ребёнка дополнительно сверяется канонический /proc/PID/exe с xray_path. У Python-супервизора операнд скрипта из /proc/PID/cmdline разрешается относительно /proc/PID/cwd и сравнивается с каноническим supervisor_path. Ошибка чтения или разбора означает несовпадение. Непосредственно перед каждым сигналом идентичность читается повторно.

Проверка состояния различает три исхода. Для здоровой пары stop посылает SIGTERM супервизору. Если супервизор исчез, но ребёнок подтверждён, status сообщает о сироте с ненулевым кодом, env и run отказывают, а stop посылает сигнал ребёнку напрямую без требования доступности порта и удаляет state и конфиг. При живом, но неподтверждённом PID сигналы не посылаются, файлы сохраняются, а диагностика требует ручной проверки и удаления. Если оба PID мертвы или boot_id не совпадает, устаревшие state и конфиг можно безопасно удалить без сигналов.

У пользователя может быть только один управляемый экземпляр. Повторный start не заменяет его другим профилем. Для смены профиля нужны явные stop и start.

Перед успешным запуском должны пройти разбор ссылки, проверка поддерживаемого сочетания и xray run -test. После запуска процесс должен оставаться живым, а локальный порт — принимать соединения. Проверка внешнего IP через прокси носит диагностический характер: её сбой даёт предупреждение, но не останавливает уже прошедший обязательные проверки Xray.

Сгенерированный JSON и временные файлы создаются внутри служебного каталога и удаляются супервизором после завершения Xray. Каталоги создаются с правами 0700, файлы с конфигурацией и состоянием — 0600. Исходная VLESS-ссылка не попадает в stdout или stderr при успехе, ошибках разбора и сбое run -test и никогда не передаётся аргументом командной строки. Те же поверхности не содержат UUID, ключи, short ID и другие уникальные секретные маркеры профиля.

run никогда не запускает Xray. Для типа xray он проверяет PID управляемого процесса и локальный порт; для типа external — только явно настроенный адрес и порт. Лишь после успешной проверки он выставляет proxy-переменные для дочерней команды. Поэтому pclaude и pcodex не имеют скрытого автозапуска.

Доставка

Компоненты образуют отдельный stow-совместимый каталог proxy-client/. Он доставляет CLI, Bash-модуль и три шаблона: машинного INI для внешнего прокси, машинного INI для Xray и файла VLESS-ссылки. Реальные пользовательские файлы не управляются stow и не входят в Git. CLI раскладывается как ~/.local/bin/proxy-client. Машинный конфиг, профиль, модуль shell.bash и каталог examples/ находятся вместе в ~/.config/proxy-client/. Шаблоны не подменяют настоящие пользовательские файлы.

В корне этого каталога находится самостоятельный README.md. Он является основной инструкцией клиента и исключается из раскладки stow. README остаётся рядом с кодом при выборочном клонировании или копировании каталога. Корневой README репозитория только кратко описывает подсистему и ссылается на него.

После клонирования репозитория пакет можно подключить отдельно от общего install.sh. README также должен описывать эквивалентные ручные симлинки и копирование файлов. Полный install.sh подключает этот же stow-пакет вместе с остальными dotfiles и не имеет отдельной реализации.

Решения и отклонённые альтернативы

  • Выбран Python 3.8+, потому что стандартной библиотеки достаточно для URL, JSON, INI, ZIP, SHA-256, HTTP, процессов и тестов. Более новый синтаксис и сторонние пакеты запрещены ради старых и непредсказуемых серверных систем.
  • Выбран INI, а не TOML: модуль tomllib добавлен только в Python 3.11, что исключило бы штатный Python 3.10 в Ubuntu 22.04.
  • Bash оставлен отдельным тонким модулем, потому что дочерний Python-процесс не может изменить окружение родительской shell-сессии.
  • Выбрано публичное имя proxy-client, потому что подсистема обслуживает и внешний прокси, и управляемый Xray. xray-proxy отклонено как имя, выпячивающее одну реализацию, а proxyctl — как менее понятное пользователю.
  • Все пользовательские файлы собраны в ~/.config/proxy-client/. Разделение между общим машинным конфигом и Xray-профилем остаётся логическим, но не требует помнить два каталога.
  • Машинный прокси и VLESS-ссылка разделены: первый файл описывает локальную политику shell, второй содержит секрет и меняется независимо.
  • Выбран один порт, потому что SOCKS-вход Xray совместим с HTTP и не требует второго локального слушателя.
  • Выбран явный тип прокси вместо автообнаружения. Предсказуемость канала важнее удобства автоматического перехода.
  • Выбрана одна активная конфигурация на пользователя. Именованные процессы и автоматическое распределение портов отложены до появления реальной нужды.
  • Официальный системный установщик отклонён: он требует root и создаёт systemd-службы. Пользовательская установка соответствует выбранной модели.
  • Готовые JSON и полный импорт Hiddify отклонены как основной интерфейс: точечная VLESS-ссылка проще для пользователя и ограничивает область преобразования.

Риски и меры

  • Формат ссылок Hiddify может расширяться. Строгая проверка и явный отказ безопаснее частично неверного JSON.
  • Проверка открытого порта не доказывает работоспособность маршрута. CLI разделяет обязательную проверку процесса и необязательную внешнюю диагностику.
  • VLESS-ссылка содержит чувствительные данные. CLI сокращает секреты в выводе, не журналирует их и использует закрытые пользовательские файлы.
  • Устаревшие Hiddify-поля allowInsecure и insecure неоднозначны. Они не переносятся в Xray 26.3.27, сертификат проверяется обычным способом, а истинное значение сопровождается предупреждением.
  • Старые дистрибутивы могут иметь Python ниже 3.8. CLI проверяет версию до основной работы и сообщает обнаруженную и требуемую версии.
  • NO_PROXY реализуется программами неодинаково. README рекомендует точные IP и домены, а CIDR описывает как совместимость best-effort.
  • Разные пользователи делят сетевое пространство имён. Настраиваемый порт и явная ошибка конфликта предотвращают случайный запуск на занятом порту, но loopback без аутентификации не запрещает намеренное подключение другого локального пользователя. Это принятое ограничение первой версии.

Проверка реализации

  • Модульные тесты разбирают обезличенные ссылки обеих поддерживаемых семей и все показанные варианты ALPN. Отдельный регрессионный пример повторяет форму типичной ссылки Hiddify XHTTP/TLS с hiddify, core, extra, headerType=none, allowInsecure и insecure.
  • Неподдерживаемые транспорт, защита, отсутствующие обязательные поля и любой неизвестный query-параметр дают понятный отказ до запуска Xray.
  • Сгенерированный JSON проходит xray run -test на Xray 26.3.27 для заявленных сочетаний. Интеграционная проверка подтверждает, что один локальный вход принимает HTTP и SOCKS.
  • Тесты отдельно проверяют удаление устаревших insecure-полей.
  • Тесты подтверждают сокращение секретов и отсутствие полной VLESS-ссылки в stdout, stderr, служебных файлах и аргументах дочернего процесса.
  • Установка проверяется на корректной и повреждённой SHA-256 без записи вне пользовательского каталога.
  • Управление процессом покрывает повторный запуск, устаревший PID, чужой PID, повторно использованный PID, передачу сигналов, аварийно исчезнувший супервизор, очистку файлов, смену профиля, остановку и конфликт порта.
  • Сбой внешней проверки IP не отменяет успешный запуск, но отображается отдельно от состояния процесса и порта.
  • run сохраняет аргументы и код возврата, не оставляет proxy-переменные в родительской Bash-сессии и не запускает команду при недоступном прокси.
  • env не печатает частичный результат при ошибке, а shell.bash отклоняет неизвестные строки без eval и без частичного экспорта.
  • Регрессионные Bash-тесты подтверждают прежнее поведение Hiddify при отсутствии машинного конфига, оба регистра proxy-переменных, настраиваемый NO_PROXY и отсутствие автоматического запроса внешнего IP в proxy_on/proxy_off.
  • Ручная проверка выполняется минимум на Ubuntu с Python 3.10 и на одной целевой удалённой системе. РЕД ОС, Astra Linux и Alt Linux проверяются по мере доступности: недоступная среда явно записывается как неподтверждённая, а поддержка заявляется только после проверки версии Python и полного прогона.

Влияние на документацию

Основная инструкция находится в proxy-client/README.md рядом с реализацией. Она должна описывать:

  • различие внешнего Hiddify и управляемого Xray;
  • выборочная установка через stow, ручные симлинки и копирование;
  • создание машинного INI из шаблона и отдельного файла VLESS-ссылки;
  • команды управления, proxy_on/off, pclaude/pcodex;
  • настройка NO_PROXY, ограничения CIDR и диагностика;
  • поддерживаемые семейства VLESS и современную проверку сертификата;
  • отсутствие systemd, автозапуска и автоматического перехода между прокси.

Корневой README получает только короткий обзор, пример подключения пакета и ссылку на полную инструкцию клиента.

Шаблоны должны содержать только вымышленные значения. Настоящие VLESS-ссылки, UUID и ключи никогда не входят в репозиторий.