dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH 出口线路池(测试阶段): 集中管理 GitHub/npm/PyPI/HF 出站线路,自动探测健康度、按速选线、失败切换;子进程走正规通道且零污染全局配置
⚠️ 测试阶段(v0.6.3) — 核心能力已实现并通过 562 项测试(离线 472 项,不含核对脚本),但在真实使用中的长期表现尚未积累数据。接口与线路表可能调整。欢迎试用与反馈,不建议在生产环境依赖。
给 DeepSeek Harness 一个集中管理的出站线路池:把 GitHub / npm / PyPI / HuggingFace 等各类出口的候选线路收在一处,自动探测健康度、按速度选线、失败自动切换,让模型不再把时间浪费在慢线路和超时上。
cd <你的路径>\line-pool
node install-line-pool.mjs install # 装进 profile 并跑 pnpm install
然后完全退出并重启 DSH(不是刷新页面)。重启后自动生效,无需任何配置:
pip install requests → 实际执行 pip install -i https://mirrors.aliyun.com/pypi/simple/ requestsgit clone https://github.com/o/r → 自动走最快的 GitHub 镜像dsh-better-sidebar 则在「设置 → 侧边卡片」)装完没反应?看 %USERPROFILE%\.dsh\line-pool\line-pool.log,或查故障排查。
原始痛点不是"不通",而是**"用错了那条"**:
npm 装包 官方源超时 10.3s → 腾讯镜像 224ms 差 46 倍
GitHub raw 直连 653ms 可用 → 而 DSH 里硬编码的第一条兜底 gh-proxy.com 是死的
pip 装包 官方源 817ms → 阿里云镜像 983ms ← 反直觉:官方更快
最后一条尤其关键:"国内镜像一定快"是错的。速度随时间和网络环境波动,必须实测,不能按刻板印象写死。本插件就是干这个的。
| 能力 | 说明 |
|---|---|
| 线路池管理 | 内置 15 条实测过的线路(GitHub raw/codeload/main、npm、PyPI、HF、通用直连),外加 10 条已知失效线路备查 |
| 两阶段探测 | 先并发 TCP/TLS 握手(便宜)→ 按延迟+丢包排序 → 只对前 N 条做真实 HTTP 拉取(贵)。15 条线路约 7 秒探完 |
| 健康状态机 | HEALTHY → COOLING → PROBING,失败只认 DNS/TLS/超时/断连四类;冷却阶梯 2→5→15 分钟,成功即恢复 |
| 按类选线 | 专线优先、通用兜底。github-raw 请求只走 GitHub 类线路,全挂才用直连垫底 |
| URL 改写 | 4 种规则:前缀拼接(gh-proxy 类)、registry 替换、index 替换、域名替换(HF);另有 rewrite: null 表示直连不改写 |
| 子进程传递 | git / pip / npm / pnpm / gh / curl 各走各自的正规通道,零污染用户全局配置 |
| 上游 IP 表自验 | 拉取公开的 GitHub 域名→IP 表(多源自动切换),逐个 IP 做 TLS 握手 + 证书链校验(自签名/过期/域名不符一律拒),只保留真正可用的 IP;导出 hosts 片段供用户自行应用 |
| 线路表自动更新 | 内置 20 条候选镜像,全部经真实握手 + HTTP 验证后才纳入(实测:纳入 16 / 拒绝 4)。每次启动后若无记录则自动发现一次,之后每 24 小时一遍;另支持人工补充(lines-custom.json)。优先级 custom > auto > seed |
| 侧边栏面板 | 可视化查看每条线路的健康/延迟/失败原因、按类别的选线顺序、上游自验结果;支持单条手测、启停线路、手动重测、复制 hosts 片段。挂在 dsh-better-sidebar 的侧边卡片上(可启停开关),没装时自动回退到 DSH 原生右侧栏 |
| 接线:给模型的工具 | 注册 line_pool_status(查现在哪条快、各类目标会选哪条)与 line_pool_run(跑一条下载命令并自动注入最快线路的镜像参数) |
| 接线:拦截子进程 | 包住 DSH 的 shell seam,自动改写模型的下载命令:git clone → URL 加前缀、pip install → 插 -i、npm/pnpm → --registry=、HF → HF_ENDPOINT、curl/wget → URL 加前缀。改写失败或无可用线路 → 原样放行;用户已指定镜像 → 不覆盖;命令结构复杂 → 整体放弃 |
| 网络环境检测 | 面板常驻显示 TUN 开关状态与本地代理端口:网卡名 + TUN 常用网段(198.18/15)实时判定,纯本地零成本;代理端口扫描 13 个常见端口(回环,7ms)。两枚芯片均可点击立即重测 |
| 状态可观测 | 探测结果落 status.json + 日志;每次探测后刷新 |
| 范围 | 是否覆盖 | 原因 |
|---|---|---|
| 模型用 bash 工具跑的下载命令 | ✅ 覆盖 | 插件包住 ctx.shell.execute,命令到达 shell 前被改写 |
模型主动调 line_pool_run | ✅ 覆盖 | 插件注册的工具,显式走线路池 |
其他插件显式调 ctx.linePool.fetchLine() | ✅ 可覆盖 | 但需要调用方自己这么做,插件不会替它接管 |
DSH 宿主自身的 fetch | ❌ 不覆盖 | 技术可行(P0 实测 setGlobalDispatcher 能接管原生 fetch),但本插件从未接线。当前接管方式只有上表前两条 |
Electron 渲染进程的 fetch | ❌ 不覆盖 | 走 Chromium 网络栈,与 Node/undici 是两套独立栈(实测确认,见下文) |
⚠️ 上表第 4 行是最容易误解的一条:"装了本插件"不等于"DSH 里所有网络请求都会走最优线路"。 它只接管模型跑的命令与显式调用。宿主内部、页面里、其他插件自己的
fetch都不受影响。 B 方案(接管宿主 fetch)在 P0 验证过可行性,但未实现 —— 见P0/verdict.md。
| 不会做的事 | 原因 |
|---|---|
| 不设系统代理、不改注册表 | 一旦进程崩溃不恢复,会导致整机断网(dev-sidecar 记录过这类副作用) |
| 不装 CA 证书、不做 MITM | 装 CA 需要管理员权限,且部分应用仍不信任;出问题排查成本极高 |
不自动写 hosts | 写 hosts 要管理员权限,写错会让整机某些域名全挂。只产出已验证片段,应用与否由你决定 |
| 不修改你的全局配置 | 不写 ~/.npmrc、不写 git config --global、不写 pip.conf。所有改写都用命令行参数或单次 env 传递 |
| 不联网上报任何数据 | 只有出站请求(拉上游 IP 表、探测线路),没有遥测、没有回调 |
设计原则:能力靠 URL 改写实现,出问题最多影响一次请求,不会让整机断网。
0.2.0-rc.2,Node 24.18.1)createRequire().resolve(),从 profile / DSH 安装目录动态定位,不写死路径# 1. 进入本目录
cd <你的路径>\line-pool
# 2. 安装(自动改 profile 的 dependencies + bundles,并跑 pnpm install)
node install-line-pool.mjs install
# 3. 完全退出并重启 DSH
# 重启后插件会自动做首次探测
# 4. 查看结果
# 日志 : %USERPROFILE%\.dsh\line-pool\line-pool.log
# 快照 : %USERPROFILE%\.dsh\line-pool\status.json
可选参数:
node install-line-pool.mjs install --profile=<profile名> # 默认 desktop
node install-line-pool.mjs install --profile-dir=<绝对路径> # 直接指定目录
node install-line-pool.mjs status # 只看状态,不改动
node install-line-pool.mjs uninstall
# 然后重启 DSH。数据目录会保留(供诊断),需要的话手动删 %USERPROFILE%\.dsh\line-pool
重启后自动探测,结果在 %USERPROFILE%\.dsh\line-pool\status.json:
{
"lastProbeAt": "2026-10-16T10:02:45.194Z",
"envInfo": { "viaProxy": false, "note": "未检测到代理环境变量…" },
"lines": [
{ "id": "pypi-aliyun", "healthy": true, "latencyMs": 75, "state": "HEALTHY" }
],
"availableByKind": {
"github-raw": ["gh-raw-ghfast", "gh-raw-direct", "http-direct"]
}
}
availableByKind 就是每类请求会按什么顺序尝试——排在最前的是最快的。
// 在你的插件里:从 ctx 拿到本插件实例
const pool = ctx.linePool;
// 按类别发请求,自动选最快线路 + 失败自动换下一条
const res = await pool.fetchLine('github-raw', 'https://raw.githubusercontent.com/a/b/c');
import { spawnWithLine } from 'dsh-line-pool/lib/spawn.js';
// 各工具自动选正经通道,不改任何全局配置
await spawnWithLine('git', ['clone', 'https://github.com/a/b'], line);
await spawnWithLine('pip', ['install', 'requests'], line);
await spawnWithLine('npm', ['install', 'lodash'], line);
先用 planSpawn 预览会执行什么(不实际运行):
import { planSpawn, planToCommandLine } from 'dsh-line-pool/lib/spawn.js';
const plan = planSpawn('git', ['clone', 'https://github.com/a/b'], line);
console.log(planToCommandLine(plan));
// git -c http.proxy=http://127.0.0.1:7890 clone https://github.com/a/b
console.log(plan.warnings); // 例如 --trusted-host 的安全提示
插件每 30 分钟自动拉取一次公开的 GitHub 域名→IP 表,逐个 IP 做 TLS + 证书链校验,结果落
%USERPROFILE%\.dsh\line-pool\upstream-ips.json,并生成可直接使用的 hosts 片段
%USERPROFILE%\.dsh\line-pool\hosts-fragment.txt。
import { fetchAndVerify, saveUpstreamSnapshot } from 'dsh-line-pool/lib/upstream.js';
const up = await fetchAndVerify({ onLog: console.log });
console.log(up.verified);
// { 'github.com': [{ ip: '20.205.243.166', ms: 8 }], ... }
console.log(up.domainsWithoutUsableIp); // 上游给了 IP 但实际全部连不上的域名
为什么不自动写 hosts:需要管理员权限(本机实测 Access denied),而且写错会导致整机某些域名全挂。插件只产出经过验证的片段,是否应用由用户决定(可粘贴到 hosts,或用 SwitchHosts 等工具)。
为什么必须自验:实测证据 —— 上游表给的 IP 里有相当比例从本机根本连不通。
2026-10-16 一次实测:7 个 IP 中 2 个不可用(gist.github.com、github.global.ssl.fastly.net 全部失败)。
上游 IP 表不是全可用,且可用性会波动,所以自验必须每次都做,不能缓存一次结果永久使用。
为什么判据是 TLS 而不是 TCP:TCP 握手可以被「本地应答」欺骗 —— 本机有 TUN/代理时,
连 RFC 5737 保留地址都能秒回成功(实测 3ms 连上 Azure 是不可能的)。
所以判据是 TLS 握手 + 证书链过系统 CA + CN/SAN 覆盖目标域名,三者缺一不可。
伪造一张 CN=github.com 的自签名证书会被拒(报 CHAIN_INVALID)。
装好后会出现在两个地方(取决于你是否装了 dsh-better-sidebar):
dsh-better-sidebar → 设置 → 侧边卡片 里出现「线路池」卡片(带启停开关),同时作为原生 chip 出现在右侧栏面板内容:
┌─ 线路池 ───────────────[重测]─┐
│ 3 分钟前探测 │
├──────────────────────────────┤
│ 按类别(选线顺序,可折叠) │
│ ▾ github-raw 3 条 │
│ ● GitHub raw 直连 97ms │ ← 实心=当前首选
│ ○ ghfast.top 前缀 218ms │
│ ○ 直连(不使用代理) — │
├──────────────────────────────┤
│ 全部线路(15/15 启用) │
│ ● 阿里云 PyPI pypi-index 75ms │
│ ◐ hf-mirror hf — 1:42 ← 冷却倒计时
│ ○ npmjs 官方源 npm-registry — TIMEOUT
│ [测] [停] │ ← 单条手测 / 启停
├──────────────────────────────┤
│ 上游 IP 自验 │
│ 源 github520-json · 可用5/不可用2 │
│ ⚠ 无可用 IP: gist.github.com… │
│ [复制 hosts 片段] │
└──────────────────────────────┘
两个功能开关(在卡片的「功能设置」里):
| 开关 | 默认 | 作用 |
|---|---|---|
| 自动探测 | 开 | 关闭后host 侧每 10 分钟的周期探测停止,面板也不自动刷新(只能手动「重测」)。选择持久化,重启后延续 |
| 显示上游 IP 自验 | 开 | 关闭后隐藏面板底部的上游区块 |
注意:better-sidebar 的卡片开关在关闭状态下不绘制开关图形(它用"开关消失 + 卡片失去高亮"表达已关闭)。点击卡片主体仍可重新启用。这是上游设计,对所有卡片一致。
为什么需要:镜像死亡率极高(gh-proxy 类实测 9 个里 7 个死),而且会复活——实测发现我 5 小时前手工判定"死了"的线路里,gh-proxy.com、ghproxy.net、清华 PyPI、npmjs 官方源都已经恢复可用。写死的清单永远不会知道这些变化。
机制:
候选池(内置 20 条) → 逐条真实握手+HTTP 验证 → 通过的纳入 / 不通过的拒绝并记原因
↓
<数据目录>/lines-auto.json(含纳入与拒绝的完整记录)
↓
与种子表、自定义表合并(custom > auto > seed,同 id 高优先级覆盖)
source: 'auto-discovered' 与 discoveredAt,便于排查与撤销enabled 状态,不会因为重新发现而把你的禁用改回启用实测效果(2026-10-16):
纳入 16 / 拒绝 4(共 20)
✓ gh-proxy.org 717ms ← 新发现,最快的 GitHub 镜像
✓ gh-proxy.com 2029ms ← 此前被我判为"死"(TIMEOUT),已复活
✓ npmjs 官方源 747ms ← 此前超时 10.3s,现已恢复
✗ github.moeyy.xyz DNS 失败 ✗ npm.taobao.org TLS 错误(旧域名证书失效)
✗ huggingface.co 超时 ✗ gh.ddlc.top 16 秒超时
这组数字的价值不在具体毫秒数(会变),而在结论:同一条线路几小时内可能 死而复生,写死的清单永远跟不上,所以必须每次实测。
人工补充:写 <数据目录>/lines-custom.json(可用面板的 customLinesTemplate RPC 取模板):
{
"lines": [
{
"id": "my-mirror",
"kind": "github-raw",
"name": "我的 GitHub 镜像",
"enabled": true,
"rewrite": { "type": "prefix", "prefix": "https://example.com/" },
"probeUrl": "https://example.com/https://raw.githubusercontent.com/torvalds/linux/master/README",
"probeKind": "http"
}
]
}
必填 id / kind / name / probeUrl;rewrite 见 lib/rewrite.js 的 4 种类型(prefix / registry / index / host-replace;null 表示直连不改写)。缺字段的条目会被忽略并记日志。custom 优先级最高,可以覆盖种子表或自动发现的同 id 条目。
入口 A —— 注册给模型的工具(模型主动调用)
| 工具 | 用途 |
|---|---|
line_pool_status | 查当前哪条线路健康、各类目标会选哪条 |
line_pool_run | 跑一条下载命令,自动注入最快健康线路的镜像参数 |
入口 B —— 拦截子进程(模型不用做任何事)
接入点是 DSH 的 shell seam:ctx.shell.execute(spec)。插件包住这个方法,
只在命令里确实有可改写的下载命令时才动。四道安全阀:
| 情况 | 行为 |
|---|---|
| 改写失败 / 没有可用线路 | 原样透传(绝不会因为插件出错而让命令跑不了) |
用户已显式指定镜像(-i / --registry / --endpoint) | 尊重用户,不覆盖 |
命令结构复杂($(...)、heredoc、引号未闭合) | 整体放弃改写,不半改 |
URL 含 user:token@ 形式 | 跳过改写,避免凭据被送到第三方镜像 |
改写明细见日志:[shell-hook] 改写: 「pip install x」→ …(线路 pypi-aliyun)
注意:入口 B 只覆盖模型跑的 bash 命令。被
pwsh工具包装过的命令 (第一 token 不是 pip/git/npm)不会被识别 —— 这是设计如此,详见「覆盖范围」。
| 工具 | 用什么 | 为什么不这么用别的 |
|---|---|---|
git | git -c http.proxy=<url> | -c 单次生效、无持久状态、天然可逆。不写 git config --global(污染用户配置) |
pip | -i <index> --trusted-host <host> | 这是换源不是代理。--extra-index-url 绝不可当 failover——pip 官方文档原文:"There is no priority in the locations that are searched",所有源都会被查,一个慢/挂的会拖死安装 |
npm / pnpm | --registry <url> | 不改 ~/.npmrc |
gh | HTTPS_PROXY / https_proxy env | gh 没有镜像概念,只能直连或走代理 |
curl | -x <url> 或 URL 前缀改写 | — |
| 其他 | env 代理(若线路提供 proxyUrl) | 能做的有限,如实标注 |
大小写都设(HTTPS_PROXY + https_proxy):不同工具认的大小写不同,两个都设最稳。
node test/run-all.mjs # 一键跑全部 21 套件(含联网),570 项
node test/run-all.mjs --offline # 只跑不联网的(16 套件,480 项)
node test/run-all.mjs --json # 额外输出机器可读摘要
# 或单独跑
node test/unit.test.mjs # 68 项
node test/apply.test.mjs # 20 项(插件生命周期 + 工具执行 + P0 回归)
node test/client.test.mjs # 7 项(客户端模块:加载 + apply)
node test/client-render.test.mjs # 12 项(客户端渲染:预置 state 真渲染)
node test/apply-online.test.mjs # 9 项(联网:有可用线路时的成功路径 —— picked 映射 / 真实改写 / 4 个 RPC 端点 / 开关落盘)
node test/fetchline.test.mjs # 12 项:fetchLine 换线逻辑(403/429/5xx)+ diagnoseFetch 入参校验
node test/client-interact.test.mjs # 10 项:面板交互(4 个按钮 / 复制 hosts / 错误态)
node test/tunnel.test.mjs # 12 项:TUN 网卡识别(跨平台 + 误报检验)/ tunnelProbe 三态
node test/upstream-failures.test.mjs # 25 项:tcpCheck 防崩溃 / 证书匹配边界 / verifyIps 不跳过 / 解析边界
node test/degradation.test.mjs # 8 项:A/C/RPC 服务缺失时的降级(失败必须可见,不静默)
node test/spawn.test.mjs # 40 项:子进程参数规划(含"不污染全局配置"强断言)
node test/check-plugin.test.mjs # 124 项(含 P1 回归):文件结构 / import / patch / 注册形态契约 / A+C 接线
node test/upstream.test.mjs # 22 项:上游表解析 / 分组 / hosts 片段(离线)
node test/rpc.test.mjs # 28 项:RPC endpoint 分派 / 错误处理 / 开关同步
node test/lines-auto.test.mjs # 25 项:线路合并优先级 / 自定义线路解析(离线)
node test/cmd-rewrite.test.mjs # 59 项(含多行/凭据断言):命令改写 + shell 拦截(离线)
node test/readme-facts.mjs # 8 项:README 声明与仓库实况核对(离线)
node test/integration.test.mjs # 12 项:真实线路探测 + 选线(联网,约 10 秒)
node test/spawn-verify.mjs # 10 项:真机跑子进程 + 全局配置前后快照对比(联网)
node test/upstream.test.mjs --online # 30 项:上游真实拉取 + IP 自验(联网)
node test/lines-auto.test.mjs --online # 29 项:候选池真实验证与纳入(联网)
合计 570 项(离线 480 项)。其中 562/472 是插件自身的被测项数,另外 8 项是 README 事实核对脚本(它检查文档与仓库是否一致,不计入插件质量指标)。集成、真机与在线上游测试需要联网。
| 结论 | 证据 |
|---|---|
setGlobalDispatcher 能接管宿主原生 fetch | 录制型 dispatcher 录到 origin/path/method(11/11 PASS) |
渲染进程 fetch 不被接管 | 渲染进程实发 3 条请求(UA 含 Chrome/152),但录制器对该路径录到 0 次;对照组 host 自查路径录到 1 次 |
| 死线路快速失败 | ECONNREFUSED 2ms 内抛出 |
| 子进程零污染 | git config --global 前后 13 行完全一致;npm registry / pip config 均未变 |
| 国内镜像不一定快 | pip 阿里云 983ms vs 官方 817ms(同一包、同一时刻) |
| 上游 IP 表不可盲信 | 上游 7 个 IP 实测 2 个不可用(gist.github.com、github.global.ssl.fastly.net 全部握手失败)。判据是 TLS + 证书链而非裸 TCP —— 裸 TCP 在 TUN 下会被本地应答欺骗(连 RFC 5737 保留地址都秒回成功),而 TLS 判据在 TUN 下依然有效(实测 github.com 848ms、证书链通过) |
ctx.get 看不到兄弟插件的服务 | better-sidebar 装着(0.26.0)但 ctx.get('betterSidebar') 返回 undefined;同次探测 ctx.get('slots') 正常 → 是作用域可见性问题(cordis 的 get 只查自己这层 store,不沿 fiber 父链上溯) |
可选依赖的正确写法是 ctx.inject | ctx.inject(['betterSidebar'], cb) 真机验证:回调会执行、scoped.betterSidebar 属性直取可用、有 registerTab;依赖缺失时静默不执行且不报错 |
| 只有 better-sidebar 路径才有设置页卡片 | 其卡片列表来自自己的 getTabs(),不收录外部注册到原生 sidebarRightTabs 的类型 |
卡片开关只认 === true | 上流源码 checked: read(key) === true;未写入时为 undefined → 显示为关,需要注册时补默认值 |
三条路实测对比(详见 P0/verdict.md):
| 路线 | 结论 | 证据 |
|---|---|---|
| 改 hosts | ❌ | 无管理员权限写不了 C:\Windows\System32\drivers\etc\hosts(实测 Access denied);写错=整机某些域名全挂 |
| 本地代理 / MITM | ❌ | 必须装 CA + 改系统代理。同类项目 dev-sidecar 的 README 记录了实证副作用:装了 CA 浏览器(Firefox)仍可能不信任;应用崩溃不恢复系统代理会导致整机断网;与其它代理软件冲突 |
| 镜像 URL 改写 | ✅ | 零权限、零副作用、失败只影响一次请求 |
旁证:VS Code 官方文档也是这个哲学——自己不改 hosts、不装 CA,而是"声明需要放行的域名清单 + 完全交给系统代理栈",甚至承认 "Extensions don't benefit yet by the same proxy support that VS Code supports"。
调研了同类项目(nrm / chsrc / GitHub520 / fetch-github-hosts / Watt Toolkit / dev-sidecar / CloudflareSpeedTest / dsh-geek2api 等),没有一个实现指数退避或半开熔断。主流是两档:固定短冷却 + 定期全量重算。线路数是个位数时全量探测只要几秒,不需要"半开"来省成本。所以本插件自写状态机(state.js 约 160 行),少一个依赖。
两条继承来的硬警告:
HTTPS_PROXY / https_proxy / NODE_USE_ENV_PROXY;② 查本机网卡(utun/tun/wintun/FlClash 等名称 + 198.18.0.0/15 网段)——这是 TUN 的关键信号,环境变量里看不到;③ 连通性探测(探 google:443)交叉验证。三者任一判定有隧道就改用 HTTP 层判定健康度(TUN 下 TCP 握手对所有目标都成功,判据失效)http-direct(通用直连)的探针目标是别的站点,延迟天生更低。如果让它和 GitHub 专线同台比延迟,它总能"胜出"——但那是拿不同目标的延迟在比,不公平。所以选线规则是:专线优先,通用线路只在专线全挂时兜底。
fetch 不覆盖——这是 Electron 架构决定的(Chromium 网络栈 vs Node/undici 是两套)。若需要覆盖页面发出的请求,必须让它们经宿主中转。fetch 也不覆盖——B 方案(setGlobalDispatcher)在 P0 验证过可行但未实现。当前只接管模型跑的 bash 命令与 line_pool_run。详见「覆盖范围」表。gh 无镜像通道——只能直连或走代理。utun/tun/wintun/FlClash 等)+ 198.18.0.0/15 网段判定。若某代理软件的 TUN 适配器既不含关键词、也不用该网段(如 Windows 上叫"以太网 2"且用 10.0.0.1),会漏检;此时靠连通性探测兜底,面板显示 TUN 开? 如实标注不确定。line-pool/
├── dsh-line-pool/ ← 插件本体(这就是被安装的包)
│ ├── package.json
│ ├── cordis.patch.yml ← bundle 注册
│ ├── icon.svg ← DSH 插件列表的图标
│ ├── locale/{zh,en}.json
│ ├── client.js ← 面板(Client half):双路径注册 + UI
│ └── lib/
│ ├── index.js ← 主入口:探测调度 / fetchLine / RPC 注册 / 状态输出
│ ├── lines-default.js ← 种子线路表
│ ├── probe.js ← 两阶段探测 / 失败分类 / 代理环境检测
│ ├── rewrite.js ← 4 种 URL 改写规则(prefix / registry / index / host-replace)
│ ├── state.js ← 健康状态机 + 带 TTL 持久化
│ ├── spawn.js ← 子进程线路传递(planSpawn 纯函数 + spawnWithLine)
│ ├── upstream.js ← 上游 IP 表拉取 + 自验 + hosts 片段
│ ├── rpc.js ← 面板数据通道(endpoint 分派)
│ ├── lines-auto.js ← 线路表自动更新(候选池验证 / 三来源合并)
│ ├── cmd-rewrite.js ← 下载命令改写(7 类工具 × 4 种规则,纯函数)
│ ├── shell-hook.js ← shell seam 拦截(包住 ctx.shell.execute,最小侵入可卸载)
│ └── tools.js ← 注册给模型的工具(line_pool_status / line_pool_run)
├── test/ ← 570 项测试(21 套件;562 项为插件自身)
├── P0/verdict.md ← 架构验证结论(host 可接管 / 渲染进程不可)
├── P3/probe-findings.md ← 可选依赖探测结论(ctx.get vs ctx.inject)
├── P3/panel-dual-scheme.md ← 面板双方案设计
├── .github/README-CI.md ← CI 激活说明(推 workflow 需 gh token 的 workflow scope)
├── install-line-pool.mjs ← 安装器
└── README.md
说明:
P0/probe-plugin/与P3/probe2/是一次性验证用的探针目录,已从仓库移除 (它们的package.json也声明dsh.bundle,会干扰上游收录 CI 的 manifest 扫描—— 详见 CHANGELOG v0.4.0)。探针源码保留在开发者的本地归档中,不在发布仓库里。
| 现象 | 原因 | 处理 |
|---|---|---|
装完没反应,%USERPROFILE%\.dsh\line-pool\ 不存在 | 没重启 DSH | 完全退出并重启(不是刷新页面) |
安装时报 'pnpm' is not recognized | 本机 PATH 里没有 pnpm,且没能自动定位到 DSH 自带的那个 | 安装器会打印它试过的位置。显式指定:node install-line-pool.mjs install --pnpm="<DSH安装目录>/resources/runtime/primary-runtime/dependencies/pnpm/bin/pnpm.cjs",或设 DSH_PNPM 环境变量。注意 DSH 的 pnpm 路径随版本变化过(runtime/pnpm/bin/ → runtime/primary-runtime/dependencies/pnpm/bin/) |
装了但 pnpm 报 Already up to date 且 node_modules/ 下没有链接 | 用了 file: 绝对路径依赖 | 改用 link:(本安装器已用) |
卸载后 node_modules/dsh-line-pool 还在 | pnpm 不移除 link: 软链 | 本安装器会手动清;手动清用 cmd /c rmdir |
| 安装成功但重启后插件没加载 | 安装目录被移走/删除(link: 指向的路径失效) | node install-line-pool.mjs status 看 linkTarget 是否可达;不可达就重装 |
| 探测结果显示"经过代理" | 环境变量里配了代理 | 正常提示;若想测直连速度,先清代理环境变量 |
面板显示 TUN 开 但实际没开 | 残留的 TUN 网卡(软件异常退出) | 点面板上的 TUN 芯片强制重测;仍有问题就查 ipconfig /all 里是否有 TUN 类适配器 |
| 某条线路一直 COOLING | 该线路确实挂了 | 查 status.json 的 failure 字段(DNS/TLS/TIMEOUT/CONNECTION) |
日志里 webServer 不可用(非致命) | 宿主 webServer 有鉴权(实测根路径 401),且 Electron 页面走 IPC 桥 | 正常降级,改用 status.json 观测 |
node test/run-all.mjs(21 套件 570 项),再看日志里 A/C 方案是否都生效本插件为原创实现,但在设计与算法上借鉴了以下公开项目(详见 NOTICE.md 与 P0/verdict.md):
| 项目 | 借鉴内容 |
|---|---|
| XIU2/CloudflareSpeedTest | 两阶段测速剪枝算法、"可用数 vs 过筛数"双指标、两条探测警告 |
| CoderKuo/dsh-geek2api | DSH 插件内多入口线路池的产品形态(10 分钟测速、失败冷却、状态展示) |
| 521xueweihan/GitHub520 | 上游 IP/域名数据源与多源切换的必要性 |
| docmirror/dev-sidecar | "代理路线不可行"的实证材料(CA/系统代理的副作用记录) |
| microsoft/vscode | "声明域名清单 + 依赖系统栈,绝不自己造代理"的架构哲学 |
| nodejs/undici | setGlobalDispatcher / ProxyAgent / EnvHttpProxyAgent 的官方语义 |
MIT License。第三方项目版权归原作者所有,本项目不包含其代码。