@qpjoy/tunnel-cli 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,6 +27,18 @@ proxy and configures shell, SSH, Docker/containerd/buildkit proxy drop-ins witho
27
27
  enabling TUN route takeover. Reserve `tun-on` for machines that are not serving
28
28
  public inbound traffic.
29
29
 
30
+ Run any command through the active Mihomo local proxy:
31
+
32
+ ```bash
33
+ qp-tunnel-cli ./electron-server/scripts/manage.sh redeploy
34
+ qp-tunnel-cli -- docker compose build
35
+ ```
36
+
37
+ For host commands, `HTTP_PROXY` points at `127.0.0.1:<mixed-port>`. For
38
+ Docker/Compose build containers, the CLI also injects container-facing variables
39
+ such as `MARKET_CONTAINER_HTTP_PROXY` and `QP_TUNNEL_CONTAINER_HTTP_PROXY`
40
+ pointing at `host.docker.internal:<mixed-port>`.
41
+
30
42
  Install the bundled script as a normal Linux command:
31
43
 
32
44
  ```bash
@@ -0,0 +1,10 @@
1
+ ```bash
2
+ npm i -g @qpjoy/tunnel-cli@0.1.1
3
+
4
+ sudo qp-tunnel-cli install-script
5
+ sudo qp-tunnel-cli upgrade-systemd
6
+
7
+ sudo qp-tunnel-cli tun-off
8
+ sudo qp-tunnel-cli server-on
9
+ sudo qp-tunnel-cli status
10
+ ```
package/dist/index.js CHANGED
@@ -10,6 +10,28 @@ const packageRoot = (0, node_path_1.resolve)(__dirname, '..');
10
10
  const bundledClientScript = (0, node_path_1.resolve)(packageRoot, 'resources/mihomo-client.sh');
11
11
  const repoClientScript = (0, node_path_1.resolve)(packageRoot, '../../../scripts/mihomo-client.sh');
12
12
  const defaultInstallTarget = '/usr/local/bin/mihomo-client';
13
+ const defaultMihomoConfigFile = '/etc/mihomo-client/config.yaml';
14
+ const defaultNoProxyEntries = [
15
+ 'localhost',
16
+ '127.0.0.1',
17
+ '::1',
18
+ 'postgres',
19
+ 'market',
20
+ 'db',
21
+ 'redis',
22
+ 'host.docker.internal',
23
+ 'docker.for.mac.host.internal',
24
+ 'docker.for.win.localhost',
25
+ 'kubernetes.docker.internal',
26
+ '10.0.0.0/8',
27
+ '172.16.0.0/12',
28
+ '192.168.0.0/16',
29
+ '100.64.0.0/10',
30
+ '100.88.0.0/16',
31
+ '100.89.0.0/16',
32
+ '100.90.0.0/16',
33
+ '.local',
34
+ ];
13
35
  const clientCommands = new Set([
14
36
  'setup',
15
37
  'install',
@@ -50,6 +72,8 @@ Usage:
50
72
  qp-tunnel-cli script-path
51
73
  qp-tunnel-cli client-help
52
74
  qp-tunnel-cli <mihomo-client command> [options]
75
+ qp-tunnel-cli -- <command> [args...]
76
+ qp-tunnel-cli <command-path> [args...]
53
77
 
54
78
  Common commands:
55
79
  qp-tunnel-cli install --url http://IP:3434/peer_user01.mihomo.yaml --user download --password pass
@@ -60,10 +84,16 @@ Common commands:
60
84
  qp-tunnel-cli tun-off
61
85
  qp-tunnel-cli update-subscription
62
86
  qp-tunnel-cli uninstall --purge
87
+ qp-tunnel-cli ./electron-server/scripts/manage.sh redeploy
63
88
 
64
89
  The npm package is a thin distributor for the Linux mihomo-client script. Client
65
90
  commands re-run through sudo when needed, then execute the bundled shell script.
66
91
 
92
+ Unknown commands are executed with QPJoy proxy variables injected. Host commands
93
+ receive HTTP_PROXY=http://127.0.0.1:<mixed-port>; Docker/Compose build contexts
94
+ also receive container-facing variables such as MARKET_CONTAINER_HTTP_PROXY and
95
+ QP_TUNNEL_CONTAINER_HTTP_PROXY=http://host.docker.internal:<mixed-port>.
96
+
67
97
  Install the script as a normal server command:
68
98
  sudo qp-tunnel-cli install-script
69
99
  sudo mihomo-client status
@@ -129,6 +159,94 @@ function runClientCommand(scriptArgs) {
129
159
  }
130
160
  runScriptWithoutSudo(scriptArgs);
131
161
  }
162
+ function mixedPortFromConfig() {
163
+ const explicit = process.env.QP_TUNNEL_MIXED_PORT || process.env.MIHOMO_MIXED_PORT;
164
+ if (explicit && /^\d+$/.test(explicit)) {
165
+ return explicit;
166
+ }
167
+ const configFile = process.env.MIHOMO_CONFIG_FILE || defaultMihomoConfigFile;
168
+ if (!(0, node_fs_1.existsSync)(configFile)) {
169
+ process.stderr.write(`Mihomo config not found: ${configFile}\nRun: sudo qp-tunnel-cli install ... && sudo qp-tunnel-cli server-on\n`);
170
+ process.exit(1);
171
+ }
172
+ const content = (0, node_fs_1.readFileSync)(configFile, 'utf8');
173
+ const match = /^\s*mixed-port\s*:\s*(\d+)/m.exec(content);
174
+ if (!match) {
175
+ process.stderr.write(`Could not detect mixed-port from ${configFile}\n`);
176
+ process.exit(1);
177
+ }
178
+ return match[1];
179
+ }
180
+ function mergeCsvValues(...values) {
181
+ const seen = new Set();
182
+ const merged = [];
183
+ for (const value of values) {
184
+ for (const item of (value || '').split(',')) {
185
+ const trimmed = item.trim();
186
+ if (!trimmed || seen.has(trimmed))
187
+ continue;
188
+ seen.add(trimmed);
189
+ merged.push(trimmed);
190
+ }
191
+ }
192
+ return merged.join(',');
193
+ }
194
+ function proxyEnvironment() {
195
+ const port = mixedPortFromConfig();
196
+ const hostProxy = `http://127.0.0.1:${port}`;
197
+ const hostSocksProxy = `socks5://127.0.0.1:${port}`;
198
+ const containerHost = process.env.QP_TUNNEL_CONTAINER_HOST || 'host.docker.internal';
199
+ const containerProxy = `http://${containerHost}:${port}`;
200
+ const noProxy = mergeCsvValues(process.env.NO_PROXY, process.env.no_proxy, defaultNoProxyEntries.join(','));
201
+ const containerNoProxy = mergeCsvValues(process.env.MARKET_CONTAINER_NO_PROXY, process.env.QP_TUNNEL_CONTAINER_NO_PROXY, noProxy);
202
+ return {
203
+ ...process.env,
204
+ HTTP_PROXY: hostProxy,
205
+ HTTPS_PROXY: hostProxy,
206
+ ALL_PROXY: hostSocksProxy,
207
+ http_proxy: hostProxy,
208
+ https_proxy: hostProxy,
209
+ all_proxy: hostSocksProxy,
210
+ NO_PROXY: noProxy,
211
+ no_proxy: noProxy,
212
+ npm_config_proxy: hostProxy,
213
+ npm_config_https_proxy: hostProxy,
214
+ npm_config_noproxy: noProxy,
215
+ pnpm_config_proxy: hostProxy,
216
+ pnpm_config_https_proxy: hostProxy,
217
+ pnpm_config_noproxy: noProxy,
218
+ QP_TUNNEL_MIXED_PORT: port,
219
+ QP_TUNNEL_HOST_HTTP_PROXY: hostProxy,
220
+ QP_TUNNEL_HOST_HTTPS_PROXY: hostProxy,
221
+ QP_TUNNEL_HOST_ALL_PROXY: hostSocksProxy,
222
+ QP_TUNNEL_CONTAINER_HTTP_PROXY: containerProxy,
223
+ QP_TUNNEL_CONTAINER_HTTPS_PROXY: containerProxy,
224
+ QP_TUNNEL_CONTAINER_NO_PROXY: containerNoProxy,
225
+ CONTAINER_HTTP_PROXY: containerProxy,
226
+ CONTAINER_HTTPS_PROXY: containerProxy,
227
+ CONTAINER_NO_PROXY: containerNoProxy,
228
+ BUILD_CONTAINER_HTTP_PROXY: containerProxy,
229
+ BUILD_CONTAINER_HTTPS_PROXY: containerProxy,
230
+ BUILD_CONTAINER_NO_PROXY: containerNoProxy,
231
+ MARKET_CONTAINER_HTTP_PROXY: process.env.MARKET_CONTAINER_HTTP_PROXY || containerProxy,
232
+ MARKET_CONTAINER_HTTPS_PROXY: process.env.MARKET_CONTAINER_HTTPS_PROXY || containerProxy,
233
+ MARKET_CONTAINER_NO_PROXY: containerNoProxy,
234
+ };
235
+ }
236
+ function runExternalCommand(commandArgs) {
237
+ if (commandArgs.length === 0) {
238
+ process.stderr.write('Missing command after qp-tunnel-cli --\n');
239
+ process.exit(1);
240
+ }
241
+ const [rawCommand, ...rawArgs] = commandArgs;
242
+ const command = rawCommand === 'sudo' && !rawArgs.includes('-E') ? 'sudo' : rawCommand;
243
+ const commandArgsWithSudoEnv = rawCommand === 'sudo' && !rawArgs.includes('-E') ? ['-E', ...rawArgs] : rawArgs;
244
+ const result = (0, node_child_process_1.spawnSync)(command, commandArgsWithSudoEnv, {
245
+ stdio: 'inherit',
246
+ env: proxyEnvironment(),
247
+ });
248
+ exitFromSpawn(result);
249
+ }
132
250
  function parseInstallScriptArgs(scriptArgs) {
133
251
  let target = defaultInstallTarget;
134
252
  for (let index = 0; index < scriptArgs.length; index += 1) {
@@ -192,6 +310,9 @@ async function printScriptPath() {
192
310
  }
193
311
  async function main() {
194
312
  const command = args[0] ?? 'help';
313
+ if (command === '--') {
314
+ runExternalCommand(args.slice(1));
315
+ }
195
316
  if (command === 'help' || command === '--help' || command === '-h') {
196
317
  help();
197
318
  return;
@@ -215,9 +336,10 @@ async function main() {
215
336
  if (passthroughCommand && clientCommands.has(passthroughCommand)) {
216
337
  runClientCommand(args);
217
338
  }
218
- process.stderr.write(`Unknown command: ${command}\n`);
339
+ if (args.length > 0) {
340
+ runExternalCommand(args);
341
+ }
219
342
  help();
220
- process.exitCode = 1;
221
343
  }
222
344
  main().catch((error) => {
223
345
  const message = error instanceof Error ? error.message : String(error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qpjoy/tunnel-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Global QPJoy Tunnel CLI for installing and running the Linux mihomo-client script.",
5
5
  "private": false,
6
6
  "type": "commonjs",
@@ -97,6 +97,7 @@ Examples:
97
97
  sudo bash ./scripts/mihomo-client.sh ssh-proxy-on
98
98
  sudo bash ./scripts/mihomo-client.sh daemon-proxy-on
99
99
  sudo bash ./scripts/mihomo-client.sh run curl -I https://www.google.com/generate_204
100
+ sudo bash ./scripts/mihomo-client.sh run ./electron-server/scripts/manage.sh redeploy
100
101
  sudo bash ./scripts/mihomo-client.sh print-env
101
102
  EOF
102
103
  }
@@ -532,10 +533,10 @@ docker_proxy_env_lines() {
532
533
  cat <<EOF
533
534
  HTTP_PROXY=http://127.0.0.1:$port
534
535
  HTTPS_PROXY=http://127.0.0.1:$port
535
- NO_PROXY=localhost,127.0.0.1,::1
536
+ NO_PROXY=$MIHOMO_NO_PROXY
536
537
  http_proxy=http://127.0.0.1:$port
537
538
  https_proxy=http://127.0.0.1:$port
538
- no_proxy=localhost,127.0.0.1,::1
539
+ no_proxy=$MIHOMO_NO_PROXY
539
540
  EOF
540
541
  }
541
542
 
@@ -814,16 +815,38 @@ server_off_command() {
814
815
  }
815
816
 
816
817
  run_command() {
817
- local port
818
+ local port host_proxy host_socks_proxy container_host container_proxy
818
819
  [[ $# -gt 0 ]] || die "Usage: sudo bash ./scripts/mihomo-client.sh run <command> [args...]"
819
820
  port="$(mixed_port_from_config)"
820
821
  [[ -n "$port" ]] || die "Could not detect mixed-port from $MIHOMO_CONFIG_FILE"
821
- http_proxy="http://127.0.0.1:$port" \
822
- https_proxy="http://127.0.0.1:$port" \
823
- HTTP_PROXY="http://127.0.0.1:$port" \
824
- HTTPS_PROXY="http://127.0.0.1:$port" \
825
- all_proxy="socks5://127.0.0.1:$port" \
826
- ALL_PROXY="socks5://127.0.0.1:$port" \
822
+ host_proxy="http://127.0.0.1:$port"
823
+ host_socks_proxy="socks5://127.0.0.1:$port"
824
+ container_host="${QP_TUNNEL_CONTAINER_HOST:-host.docker.internal}"
825
+ container_proxy="http://${container_host}:$port"
826
+ http_proxy="$host_proxy" \
827
+ https_proxy="$host_proxy" \
828
+ HTTP_PROXY="$host_proxy" \
829
+ HTTPS_PROXY="$host_proxy" \
830
+ all_proxy="$host_socks_proxy" \
831
+ ALL_PROXY="$host_socks_proxy" \
832
+ no_proxy="$MIHOMO_NO_PROXY" \
833
+ NO_PROXY="$MIHOMO_NO_PROXY" \
834
+ QP_TUNNEL_MIXED_PORT="$port" \
835
+ QP_TUNNEL_HOST_HTTP_PROXY="$host_proxy" \
836
+ QP_TUNNEL_HOST_HTTPS_PROXY="$host_proxy" \
837
+ QP_TUNNEL_HOST_ALL_PROXY="$host_socks_proxy" \
838
+ QP_TUNNEL_CONTAINER_HTTP_PROXY="$container_proxy" \
839
+ QP_TUNNEL_CONTAINER_HTTPS_PROXY="$container_proxy" \
840
+ QP_TUNNEL_CONTAINER_NO_PROXY="$MIHOMO_NO_PROXY" \
841
+ CONTAINER_HTTP_PROXY="$container_proxy" \
842
+ CONTAINER_HTTPS_PROXY="$container_proxy" \
843
+ CONTAINER_NO_PROXY="$MIHOMO_NO_PROXY" \
844
+ BUILD_CONTAINER_HTTP_PROXY="$container_proxy" \
845
+ BUILD_CONTAINER_HTTPS_PROXY="$container_proxy" \
846
+ BUILD_CONTAINER_NO_PROXY="$MIHOMO_NO_PROXY" \
847
+ MARKET_CONTAINER_HTTP_PROXY="${MARKET_CONTAINER_HTTP_PROXY:-$container_proxy}" \
848
+ MARKET_CONTAINER_HTTPS_PROXY="${MARKET_CONTAINER_HTTPS_PROXY:-$container_proxy}" \
849
+ MARKET_CONTAINER_NO_PROXY="${MARKET_CONTAINER_NO_PROXY:-$MIHOMO_NO_PROXY}" \
827
850
  "$@"
828
851
  }
829
852