Install any skill in seconds. Free to start, no credit card required.
Get Started Free →查看指定进程的代理线路。通过 Mihomo API 查询当前活跃连接,显示进程匹配的规则和代理链路。用于确认某个进程(如 claude、chrome)走的是哪条订阅线路
.claude/skills/majiayu000-clash-routes/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 72% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 20% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 81% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 67% | 0% |
查看当前活跃连接的代理线路信息,确认指定进程走的是哪条订阅/代理链。
用户传入的参数:$ARGUMENTS 如果用户没有传入参数,显示所有活跃连接(按进程分组)。
读取 Clash Verge 配置获取 API secret:
bashSECRET=$(grep '^secret:' "$HOME/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/clash-verge.yaml" 2>/dev/null | awk '{print $2}') [ -z "$SECRET" ] && SECRET=$(grep '^secret:' "$HOME/.config/clash/config.yaml" 2>/dev/null | awk '{print $2}') echo "Secret: ${SECRET:-(未找到)}"
优先使用 Unix socket,fallback 到 HTTP:
bash# Unix socket 方式(Clash Verge Rev) SOCKET="/var/tmp/verge/verge-mihomo.sock" if [ -S "$SOCKET" ]; then CONNECTIONS=$(curl -s --unix-socket "$SOCKET" "http://localhost/connections" -H "Authorization: Bearer $SECRET" 2>/dev/null) else # HTTP fallback CONTROLLER=$(grep '^external-controller:' "$HOME/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/clash-verge.yaml" 2>/dev/null | awk '{print $2}' | tr -d "'\"") [ -z "$CONTROLLER" ] && CONTROLLER="127.0.0.1:9090" CONNECTIONS=$(curl -s "http://$CONTROLLER/connections" -H "Authorization: Bearer $SECRET" 2>/dev/null) fi
用 Python 解析 JSON,按进程分组显示:
pythonimport json, sys data = json.loads(sys.stdin.read()) connections = data.get("connections", []) # 过滤进程名(如果指定了参数) process_filter = "参数中的进程名" # 从 $ARGUMENTS 获取 results = [] for conn in connections: meta = conn.get("metadata", {}) process = meta.get("process", "unknown") host = meta.get("host", "") or meta.get("destinationIP", "") port = meta.get("destinationPort", "") rule = conn.get("rule", "") + ("/" + conn.get("rulePayload", "") if conn.get("rulePayload") else "") chains = conn.get("chains", []) network = meta.get("network", "") if process_filter and process_filter.lower() not in process.lower(): continue results.append({ "process": process, "host": f"{host}:{port}" if port else host, "rule": rule, "chains": " → ".join(reversed(chains)) if chains else "DIRECT", "network": network.upper(), }) # 按进程分组 from collections import defaultdict grouped = defaultdict(list) for r in results: grouped[r["process"]].append(r) for process, conns in sorted(grouped.items()): print(f"\n{'='*60}") print(f"进程: {process} ({len(conns)} 个连接)") print(f"{'='*60}") # 按链路去重统计 chain_stats = defaultdict(lambda: {"count": 0, "hosts": set()}) for c in conns: key = f"{c['rule']} → {c['chains']}" chain_stats[key]["count"] += 1 chain_stats[key]["hosts"].add(c["host"]) for route, info in sorted(chain_stats.items(), key=lambda x: -x[1]["count"]): print(f" 线路: {route}") print(f" 连接数: {info['count']}") hosts = sorted(info["hosts"]) if len(hosts) <= 5: print(f" 目标: {', '.join(hosts)}") else: print(f" 目标: {', '.join(hosts[:5])} ... (+{len(hosts)-5})") print()
将上面的步骤组合成一个完整的 bash 命令执行:
bashSECRET=$(grep '^secret:' "$HOME/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/clash-verge.yaml" 2>/dev/null | awk '{print $2}') SOCKET="/var/tmp/verge/verge-mihomo.sock" FILTER="$ARGUMENTS" if [ -S "$SOCKET" ]; then DATA=$(curl -s --unix-socket "$SOCKET" "http://localhost/connections" -H "Authorization: Bearer $SECRET" 2>/dev/null) else CONTROLLER=$(grep '^external-controller:' "$HOME/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/clash-verge.yaml" 2>/dev/null | awk '{print $2}' | tr -d "'\"") [ -z "$CONTROLLER" ] && CONTROLLER="127.0.0.1:9090" DATA=$(curl -s "http://$CONTROLLER/connections" -H "Authorization: Bearer $SECRET" 2>/dev/null) fi if [ -z "$DATA" ] || echo "$DATA" | python3 -c "import sys,json; json.load(sys.stdin)" 2>/dev/null; [ $? -ne 0 ]; then # 验证 JSON 有效性 : fi echo "$DATA" | python3 -c " import json, sys from collections import defaultdict data = json.loads(sys.stdin.read()) conns = data.get('connections', []) filt = '$FILTER'.strip().lower() results = [] for c in conns: m = c.get('metadata', {}) proc = m.get('process', 'unknown') if filt and filt not in proc.lower(): continue host = m.get('host', '') or m.get('destinationIP', '') port = m.get('destinationPort', '') rule = c.get('rule', '') rp = c.get('rulePayload', '') if rp: rule += '/' + rp chains = c.get('chains', []) chain_str = ' → '.join(reversed(chains)) if chains else 'DIRECT' results.append({'process': proc, 'host': f'{host}:{port}' if port else host, 'rule': rule, 'chains': chain_str}) grouped = defaultdict(list) for r in results: grouped[r['process']].append(r) if not grouped: target = filt if filt else '任何进程' print(f'未找到 {target} 的活跃连接') sys.exit(0) total = sum(len(v) for v in grouped.values()) print(f'共 {total} 个活跃连接,涉及 {len(grouped)} 个进程') for proc, pconns in sorted(grouped.items()): print(f'\n{\"=\"*60}') print(f'进程: {proc} ({len(pconns)} 个连接)') print(f'{\"=\"*60}') chain_stats = defaultdict(lambda: {'count': 0, 'hosts': set()}) for c in pconns: key = f'{c[\"rule\"]} → {c[\"chains\"]}' chain_stats[key]['count'] += 1 chain_stats[key]['hosts'].add(c['host']) for route, info in sorted(chain_stats.items(), key=lambda x: -x[1]['count']): print(f' 线路: {route}') print(f' 连接数: {info[\"count\"]}') hosts = sorted(info['hosts']) if len(hosts) <= 5: print(f' 目标: {\", \".join(hosts)}') else: print(f' 目标: {\", \".join(hosts[:5])} ... (+{len(hosts)-5})') print() "
按进程分组,每个进程显示:
ProcessName/claude → 🤖 AI → 🇯🇵 日本 东京)/clash-routes - 查看所有进程的线路/clash-routes claude - 只看 claude 进程/clash-routes chrome - 只看 chrome 进程/clash-routes telegram - 只看 telegram 进程| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 15,146 | 19,050 | +26% | 1 | 1 | 0% | 2,709 | 4,659 | +72% | 0 | 0 | — |
case-02 | fail→fail | 13,023 | 27,118 | +108% | 1 | 1 | 0% | 2,081 | 4,277 | +106% | 0 | 0 | — |
case-03 | fail→pass | 19,370 | 6,848 | -65% | 1 | 1 | 0% | 2,961 | 3,550 | +20% | 0 | 0 | — |
case-04 | fail→pass | 13,412 | 8,707 | -35% | 1 | 1 | 0% | 2,149 | 3,895 | +81% | 0 | 0 | — |
case-05 | fail→pass | 11,435 | 5,099 | -55% | 1 | 1 | 0% | 1,929 | 3,151 | +63% | 0 | 0 | — |
case-06 | fail→fail | 10,032 | 5,461 | -46% | 1 | 1 | 0% | 1,724 | 3,070 | +78% | 0 | 0 | — |
case-07 | pass→pass | 8,665 | 3,449 | -60% | 1 | 1 | 0% | 1,381 | 2,741 | +98% | 0 | 0 | — |
case-08 | pass→pass | 10,924 | 9,268 | -15% | 1 | 1 | 0% | 1,872 | 3,599 | +92% | 0 | 0 | — |
case-09 | fail→fail | 17,922 | 14,514 | -19% | 1 | 1 | 0% | 3,060 | 4,589 | +50% | 0 | 0 | — |
case-10 | pass→pass | 7,426 | 5,983 | -19% | 1 | 1 | 0% | 1,270 | 3,288 | +159% | 0 | 0 | — |
case-11 | pass→pass | 10,811 | 3,803 | -65% | 1 | 1 | 0% | 1,591 | 2,724 | +71% | 0 | 0 | — |
case-12 | pass→pass | 13,403 | 8,706 | -35% | 1 | 1 | 0% | 2,061 | 3,668 | +78% | 0 | 0 | — |
case-13 | pass→pass | 9,898 | 6,334 | -36% | 1 | 1 | 0% | 1,744 | 3,330 | +91% | 0 | 0 | — |
case-14 | pass→pass | 12,501 | 6,235 | -50% | 1 | 1 | 0% | 2,059 | 3,120 | +52% | 0 | 0 | — |
case-15 | pass→pass | 9,201 | 3,028 | -67% | 1 | 1 | 0% | 1,432 | 2,629 | +84% | 0 | 0 | — |
case-16 | pass→pass | 10,638 | 4,365 | -59% | 1 | 1 | 0% | 1,991 | 2,969 | +49% | 0 | 0 | — |
case-17 | fail→pass | 9,833 | 4,300 | -56% | 1 | 1 | 0% | 1,674 | 2,802 | +67% | 0 | 0 | — |
case-18 | pass→pass | 5,342 | 5,397 | +1% | 1 | 1 | 0% | 841 | 3,163 | +276% | 0 | 0 | — |
case-19 | pass→pass | 12,728 | 3,488 | -73% | 1 | 1 | 0% | 2,003 | 2,713 | +35% | 0 | 0 | — |
case-20 | fail→fail | 9,181 | 6,895 | -25% | 1 | 1 | 0% | 1,588 | 3,425 | +116% | 0 | 0 | — |
case-21 | pass→pass | 7,587 | 7,640 | +1% | 1 | 1 | 0% | 1,244 | 3,299 | +165% | 0 | 0 | — |
case-22 | pass→pass | 11,338 | 6,734 | -41% | 1 | 1 | 0% | 1,892 | 3,243 | +71% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +23 percentage points is the difference between those two pass rates over the 21 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.