Merge pull request #195 from wnlen/dev

Dev
This commit is contained in:
Arvin
2026-04-14 11:47:11 +08:00
committed by GitHub
4 changed files with 135 additions and 5 deletions
+15
View File
@@ -64,6 +64,7 @@ bash install.sh
clashctl ls 📡 查看订阅列表
📌 高级
clashctl tun 🧪 Tun 模式管理
clashctl boot 🚦 开机代理接管管理
clashctl mixin 🧩 Mixin 配置管理
clashctl relay 🔗 多跳节点管理
clashctl sub 🧩 订阅高级管理(启用 / 禁用 / 重命名 / 删除)
@@ -156,6 +157,20 @@ clashctl sub remove <名称>
WSL / 普通用户如果无权写入 `/etc/environment`,`clashon` 会自动降级:运行时照常启动,当前 Shell 代理变量生效;系统代理持久接管和开机代理保持不可用。
### 开机接管(内核 + 代理)
```bash
clashctl boot status
clashctl boot on
clashctl boot off
clashctl boot runtime on|off|status
clashctl boot proxy on|off|status
```
- `boot runtime`:只管理内核开机自启(systemd / systemd-user 可用,script 后端为 `unsupported`)。
- `boot proxy`:只管理 `/etc/environment` 中的代理持久块(决定开机后是否自动保持代理变量)。
- `boot`:整体接管开关,等价于同时编排 runtime + proxy 两层状态。
### 本地订阅
可以先手动下载 Clash 格式的订阅 YAML 文件到本地,再通过 `file://` 添加:
+97 -2
View File
@@ -2618,7 +2618,7 @@ remove_alias_command_wrappers() {
}
install_status_text() {
local has_subscription install_ready runtime_ready controller_ready build_status
local has_subscription install_ready runtime_ready controller_ready build_status bind_failure_kind
local live_runtime="false"
local live_controller="false"
@@ -2632,6 +2632,7 @@ install_status_text() {
runtime_ready="$(install_verify_runtime_ready 2>/dev/null || true)"
controller_ready="$(install_verify_controller_ready 2>/dev/null || true)"
build_status="$(read_build_value "BUILD_LAST_STATUS" 2>/dev/null || true)"
bind_failure_kind="$(install_mixed_port_bind_failure_kind 2>/dev/null || true)"
if status_is_running 2>/dev/null; then
live_runtime="true"
@@ -2651,6 +2652,11 @@ install_status_text() {
return 0
fi
if [ -n "${bind_failure_kind:-}" ]; then
echo "broken"
return 0
fi
if [ "${live_runtime:-false}" = "true" ] && [ "${live_controller:-false}" = "true" ]; then
echo "ready"
return 0
@@ -2672,6 +2678,72 @@ install_status_text() {
echo "verifying"
}
install_mixed_port_bind_failure_line() {
local log_file="$LOG_DIR/mihomo.out.log"
local mixed_port line
[ -f "$log_file" ] || return 1
runtime_config_exists 2>/dev/null || return 1
mixed_port="$(runtime_config_mixed_port 2>/dev/null || true)"
if [ -n "${mixed_port:-}" ] && [ "$mixed_port" != "null" ]; then
line="$(grep -Ei "Start Mixed.*server error: listen tcp .*:${mixed_port}:.*(operation not permitted|permission denied|address already in use)" "$log_file" 2>/dev/null | tail -n 1 || true)"
fi
if [ -z "${line:-}" ]; then
line="$(grep -Ei 'Start Mixed.*server error: listen tcp .*:.*(operation not permitted|permission denied|address already in use)' "$log_file" 2>/dev/null | tail -n 1 || true)"
fi
[ -n "${line:-}" ] || return 1
printf '%s\n' "$line"
}
install_mixed_port_bind_failure_kind() {
local line lower
line="$(install_mixed_port_bind_failure_line 2>/dev/null || true)"
[ -n "${line:-}" ] || return 1
lower="$(printf '%s' "$line" | tr '[:upper:]' '[:lower:]')"
case "$lower" in
*"address already in use"*)
echo "address_in_use"
;;
*"operation not permitted"*|*"permission denied"*)
echo "bind_denied"
;;
*)
echo "bind_failed"
;;
esac
}
install_mixed_port_bind_failure_port() {
local port line
port="$(runtime_config_mixed_port 2>/dev/null || true)"
if runtime_port_value_is_valid "$port"; then
echo "$port"
return 0
fi
line="$(install_mixed_port_bind_failure_line 2>/dev/null || true)"
[ -n "${line:-}" ] || return 1
printf '%s\n' "$line" | grep -Eo ':[0-9]+:' | tail -n 1 | tr -d ':'
}
install_mixed_port_bind_observation_line() {
local mixed_port controller_port
mixed_port="$(install_mixed_port_bind_failure_port 2>/dev/null || true)"
controller_port="$(runtime_config_controller_port 2>/dev/null || true)"
if proxy_controller_reachable 2>/dev/null \
|| { runtime_port_value_is_valid "$controller_port" && is_port_in_use "$controller_port"; }; then
echo "配置已加载,控制器已启动,仅代理端口 ${mixed_port:-unknown} 绑定失败;这不是订阅或配置主链失败"
fi
}
install_status_label() {
case "$(install_status_text)" in
ready) echo "ready" ;;
@@ -2715,9 +2787,10 @@ install_default_next_action() {
}
install_runtime_brief_line() {
local status_text mixed_port controller controller_display
local status_text mixed_port controller controller_display bind_failure_kind
status_text="$(install_status_text)"
bind_failure_kind="$(install_mixed_port_bind_failure_kind 2>/dev/null || true)"
mixed_port="$(install_plan_mixed_port 2>/dev/null || true)"
[ -n "${mixed_port:-}" ] || mixed_port="$(read_env_value "MIXED_PORT" 2>/dev/null || echo "7890")"
@@ -2750,6 +2823,15 @@ install_runtime_brief_line() {
;;
broken)
echo "❗ 当前状态:broken"
case "${bind_failure_kind:-}" in
bind_denied)
echo "🚫 代理端口绑定被系统拒绝(非端口冲突)"
echo "📌 修改端口通常无法解决,请先排查当前环境限制"
;;
address_in_use)
echo "⚠️ 代理端口存在冲突(address already in use)"
;;
esac
;;
*)
echo "⚪ 当前状态:unknown"
@@ -2827,6 +2909,19 @@ print_install_summary() {
echo "📦 订阅:$subscription_text"
[ -n "${node_count:-}" ] && echo "🔢 节点数量:$node_count"
case "$(install_mixed_port_bind_failure_kind 2>/dev/null || true)" in
bind_denied)
echo "🚫 安装后验证:代理端口绑定被系统拒绝(非端口冲突)"
echo "📌 这通常是环境限制,修改端口通常无法解决"
install_mixed_port_bind_observation_line 2>/dev/null || true
echo "👉 下一步:clashctl doctor"
echo "👉 日志:clashctl logs mihomo"
;;
address_in_use)
:
;;
esac
if [ -f "$clashctl_file" ]; then
CLASH_UI_BOX_ONLY=1 bash "$clashctl_file" ui || true
fi
+8 -2
View File
@@ -113,8 +113,14 @@ system_proxy_write_block() {
mv -f "${tmp}.clean" "$tmp"
if [ "$mode" = "on" ]; then
http_url="$(proxy_http_url)"
socks_url="$(proxy_socks_url)"
if ! http_url="$(proxy_http_url 2>/dev/null)"; then
rm -f "$tmp" 2>/dev/null || true
return 1
fi
if ! socks_url="$(proxy_socks_url 2>/dev/null)"; then
rm -f "$tmp" 2>/dev/null || true
return 1
fi
no_proxy="$(proxy_no_proxy_value)"
{
+15 -1
View File
@@ -312,6 +312,7 @@ post_install_verify() {
local has_subscription="false"
local runtime_ready="false"
local controller_ready="false"
local bind_failure_kind="" bind_failure_port=""
if clashctl_command_available; then
write_runtime_value "INSTALL_VERIFY_COMMAND_READY" "true"
@@ -348,10 +349,23 @@ post_install_verify() {
runtime_ready="$(install_verify_runtime_ready 2>/dev/null || true)"
controller_ready="$(install_verify_controller_ready 2>/dev/null || true)"
bind_failure_kind="$(install_mixed_port_bind_failure_kind 2>/dev/null || true)"
bind_failure_port="$(install_mixed_port_bind_failure_port 2>/dev/null || true)"
if [ "${has_subscription:-false}" = "true" ] && [ "${bind_failure_kind:-}" = "bind_denied" ]; then
echo
echo "🚫 安装后验证发现:代理端口 ${bind_failure_port:-unknown} 绑定被系统拒绝(非端口冲突)"
echo "📌 修改端口通常无法解决;install 阶段不会通过自动换端口处理该问题"
install_mixed_port_bind_observation_line 2>/dev/null || true
echo "👉 下一步:clashctl doctor"
echo "👉 日志:clashctl logs mihomo"
echo
fi
if [ "$has_subscription" = "true" ] \
&& [ "${runtime_ready:-false}" = "true" ] \
&& [ "${controller_ready:-false}" = "true" ]; then
&& [ "${controller_ready:-false}" = "true" ] \
&& [ "${bind_failure_kind:-}" != "bind_denied" ]; then
write_runtime_event_value "RUNTIME_LAST_INSTALL_READY" "true"
else
write_runtime_event_value "RUNTIME_LAST_INSTALL_READY" "false"