Releases: xhqing/XPilot
Releases · xhqing/XPilot
Release list
Add real-traffic node testing, speed tests, VLESS+Reality support, and subscription by-name refresh
Add real-traffic node testing, speed tests, VLESS+Reality support, and subscription by-name refresh
Latest
Added
- Real-traffic node testing by default. The
testcommand now starts a temporary xray instance per node (dedicated SOCKS port, bound to 127.0.0.1 only) and requestsgenerate_204through it, separating "TCP reachable" from "proxy actually usable." This fixes the long-standing issue where a TCP-only check marked a node as healthy even though proxy traffic never flowed (expired credentials, protocol handshake failure, no outbound connectivity on the peer). Output now shows separate TCP and proxy columns; pass--tcpto keep the fast TCP-only check. Addedcheck_real_traffic,batch_check_real,_curl_through_socks(usessocks5hso DNS resolves through the proxy, avoiding local DNS-pollution false negatives),_find_free_port, and_kill_procinxpilot/health_checker.py. auto_switchredesigned as active best-node selection. Everyintervalseconds it runs a real-traffic check across all nodes, picks the lowest-latency usable node as the best, and switches whenever the best is not the current node — no longer just a fallback that switches only when the current node fails.hysteresis(default 0) prevents flapping between nodes with similar latency; when the current node is unusable it ignores hysteresis and switches to the best; when every node is unreachable it refreshes the subscription by name (with backoff), re-checks, and switches. Thethresholdoption is replaced byhysteresis. Rewrote_check_and_switchinxpilot/auto_switch.pyand added_try_refresh_subscription,_switch_to(reused bymanual_switch), and_log_usable_status.- Subscription import with by-name refresh.
NodeManager.import_from_subscriptiongains anupdate_existingparameter; when true, it matches existing nodes by name and overwrites their connection fields (address, port, UUID, password, cipher, transport, TLS, SNI) while preserving id, group, and custom name — so when the provider rotates credentials or IPs, the same node is actually refreshed instead of a suffixed duplicate being created (jms-c56s1→jms-c56s1_1). Added theSUBSCRIPTION_REFRESH_FIELDSconstant and_refresh_node_fields. statuswarns whenauto_switchis off, reminding you that the proxy will not auto-switch if the current node fails.- VLESS+Reality support.
_parse_vless_linkparses Reality parameters (pbkpublic key,sidshort ID,fpfingerprint,flow) and URL-decodes the fragment node name (fixing%40/%3Agarble after import).ProxyManager._generate_outboundemitsrealitySettingsfor Reality nodes and writesflow(e.g.xtls-rprx-vision) into the VLESS user object. The storage field whitelist (add_node/update_node/ subscription refresh) now includes the Reality fields. - Automatic subscription cleanup with source tagging.
import_from_subscriptiongains asourceparameter that tags imported/refreshed nodes (e.g.source: 'JMS') and prunes nodes the subscription no longer returns. When a subscription renames a node (e.g.JMS-c56s1→JMS-1336028@c56s1) or drops one, the stale entry is removed so the local set always matches what the subscription returns. Includes cliff protection (skips pruning when the returned count drops below 50% of existing, to avoid mass deletion on a transient outage). Manually added nodes have nosourceand are never pruned. Bothsubscription updateand the auto_switch auto-refresh use this mode. - Usable-node anomaly logging. After each real-traffic check, if fewer nodes are usable than the total,
auto_switchlogs a warning listing the unreachable nodes and likely causes (written tolog_file, default/tmp/xpilot.log); after subscription import, if a source's node count does not match what the subscription returned, it logs the reason (with added/refreshed/failed/pruned counts) so you can tell why usable nodes dropped. xpilot test speed. Measures download speed via Cloudflare's__downendpoint (default 10 MB per node).--all-nodestests every node's proxy speed concurrently;--directtests direct (no-proxy) speed;--currenttests the current node;--sizesets the download size. Extracted_start_probe(shared temp-xray-probe logic reused by connectivity and speed) and addedcheck_speed,check_direct_speed,batch_check_speed, and_curl_downloadinxpilot/health_checker.py.testis now a command group (invoke_without_commandkeepsxpilot test --all-nodes/--tcp/--current/--groupworking) to host thespeedsubcommand. Breaking change: single-node testing moved from a positional argument (xpilot test my_node) to the--nodeoption (xpilot test --node my_node), because a group's positional would collide with the subcommand name.statusshows three live metrics by default: the current node's real-traffic latency, through-node download speed, and direct download speed (downloading 5 MB through the running proxy and directly).--no-speedskips the speed test and shows latency only.- Latency comparison everywhere. Wherever "through-node latency" is shown, "direct latency" now appears alongside —
statusshows them side by side;testshows the direct-latency baseline in its connectivity summary for comparison. AddedHealthChecker.check_direct_latency(a directgenerate_204request that auto-falls back to the Cloudflare endpoint behind the GFW). - New unit tests: subscription by-name refresh vs. default append, source auto-cleanup with cliff protection (
tests/test_node_manager.py); real-traffic check failure paths and port probing (tests/test_health_checker.py); auto_switch real-traffic switch decisions and subscription-refresh backoff (tests/test_auto_switch.py); VLESS+Reality parsing and outbound-config generation (tests/test_subscription.py,tests/test_proxy_manager.py).
Changed
subscription updatenow refreshes by name and imports new nodes instead of only appending new ones (matching the "update" semantics). Usenode importto append without refreshing existing nodes.- Default
auto_switchsettings inxpilot/config.pyaddauto_update_subscription(defaultTrue) andsubscription_refresh_cooldown(default3600). auto_switch.enableddefaults toTrue(wasFalse). A fresh install orxpilot initnow enables real-traffic auto-switching out of the box — no manualconfig setneeded.
Fixed
subscription.fetchnow uses atrust_env=Falsesession to force a direct connection, bypassing environment variables and the macOS system proxy. Previously,xpilot startpointed the system proxy at the local xray, so when the proxy itself was broken the subscription request was intercepted too — a "proxy down → can't fetch subscription → can't recover proxy" deadlock._parse_ss_linkrewritten to fix SIP002 (ss://base64(method:password)@host:port#name) parsing. Base64 characters (+/=) in the userinfo madeurlparsemistake the userinfo for hostname/port, so SS nodes failed to parse and were silently skipped during subscription updates, leaving stale nodes unrefreshed. Added_b64decode_loosefor websafe-base64 compatibility.
Full Changelog: v0.3.0...v0.4.0
Add rollback command for reverting to a previous release
Added
xpilot rollbackcommand: install an earlier GitHub Release — without--versionit rolls back to the most recent release strictly older than the running version, and with--version X.Y.Zit installs the specified version. Installation reuses the--updateasset-selection logic (wheel first, then sdist tarball, falling back to building from the tagged source when neither is present). To support this,xpilot/updater.pygainsfetch_releases,pick_previous_release,find_release_by_version, andperform_rollback; the "pick asset + invoke pip install" step shared by--updateand rollback is extracted into the internal helper_install_release. Adds corresponding unit tests intests/test_updater.py.
Full Changelog: v0.2.0...v0.3.0
Add --update self-update command
Added
xpilot --updateself-update command: checks the project's GitHub Release for a newer version and installs it automatically — preferring the wheel attached to the release, then the sdist tarball, falling back to building from the tagged source when neither is present; reports and exits when already on the latest version. xpilot is distributed only via GitHub Release (not published on PyPI), so the update source points to GitHub Release rather thanpip install --upgrade xpilot. Adds thexpilot/updater.pymodule (latest-release lookup, version comparison, asset selection, pip install) withtests/test_updater.pyunit tests.
Changed
- Fixed a version baseline mismatch:
xpilot/__init__.py__version__and thecli.py--versionoutput were synced from0.1.0to0.1.1to align withVERSION, so--updatecompares against an accurate current version.
Full Changelog: v0.1.1...v0.2.0
Show live node latency in the status command
Added
- The
statuscommand now shows the live latency of the current node. It performs a TCP probe against the current node to measure real-time latency, replacing the previous approach of reading a cached latency field, so the status output reflects the node's current reachability.
Install
Download the wheel or sdist attached to this release and install with pip:
pip install dist/xpilot-0.1.1-py3-none-any.whlThen run xpilot --help.
Initial release — pure-Python proxy toolkit built on Xray-core
First public release. xpilot is a pure-Python command-line proxy toolkit that uses Xray-core (v26.3.27) as its backend, providing node management, proxy service control, health checks, and automatic node switching.
Added
- Supported protocols: VMess, VLESS, Trojan, Shadowsocks.
- Node management: add, remove, edit, query, and import nodes.
- Smart health detection: latency- and connectivity-based health checks.
- Automatic node switching based on latency thresholds.
- Subscription auto-import: supports Base64, JSON, and Clash subscription formats.
- macOS system proxy integration: one-click enable/disable of the system proxy.
- Flexible routing rule management: proxy, direct, and block rule types.
- Command-line entry point
xpilot(built on Click). - Unit tests, Docker deployment files, development toolchain, and release workflow.
- MIT license.
Install
Download the wheel or sdist attached to this release and install with pip:
pip install dist/xpilot-0.1.0-py3-none-any.whlThen run xpilot --help.