mihomo-cli 1.0.3 → 1.1.0
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/CHANGELOG.md +35 -0
- package/README.md +11 -11
- package/index.js +400 -212
- package/package.json +1 -1
- package/src/config.js +36 -26
- package/src/overwrite.js +258 -0
- package/src/process.js +10 -10
- package/src/subscription.js +19 -29
package/index.js
CHANGED
|
@@ -6,6 +6,7 @@ const config = require('./src/config');
|
|
|
6
6
|
const kernel = require('./src/kernel');
|
|
7
7
|
const subscription = require('./src/subscription');
|
|
8
8
|
const processMgr = require('./src/process');
|
|
9
|
+
const overwrite = require('./src/overwrite');
|
|
9
10
|
|
|
10
11
|
const VERSION = require('./package.json').version;
|
|
11
12
|
|
|
@@ -19,11 +20,11 @@ let exiting = false;
|
|
|
19
20
|
|
|
20
21
|
process.on('SIGINT', () => {
|
|
21
22
|
if (exiting) {
|
|
22
|
-
console.log('\n
|
|
23
|
+
console.log('\n强制退出');
|
|
23
24
|
process.exit(1);
|
|
24
25
|
}
|
|
25
26
|
exiting = true;
|
|
26
|
-
console.log('\n
|
|
27
|
+
console.log('\n正在退出...');
|
|
27
28
|
process.exit(0);
|
|
28
29
|
});
|
|
29
30
|
|
|
@@ -32,16 +33,16 @@ process.on('SIGTERM', () => {
|
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
process.on('uncaughtException', (e) => {
|
|
35
|
-
console.error('\n
|
|
36
|
+
console.error('\n未捕获的异常: ' + e.message);
|
|
36
37
|
if (e.stack) {
|
|
37
|
-
console.error(
|
|
38
|
+
console.error(e.stack.split('\n').slice(1).join('\n'));
|
|
38
39
|
}
|
|
39
40
|
process.exit(1);
|
|
40
41
|
});
|
|
41
42
|
|
|
42
43
|
process.on('unhandledRejection', (reason) => {
|
|
43
44
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
44
|
-
console.error('\n
|
|
45
|
+
console.error('\n未处理的 Promise 拒绝: ' + msg);
|
|
45
46
|
process.exit(1);
|
|
46
47
|
});
|
|
47
48
|
|
|
@@ -49,21 +50,20 @@ function printShortHelp() {
|
|
|
49
50
|
console.log('\nmihomo-cli v' + VERSION);
|
|
50
51
|
console.log('别名: mihomo, mmc, mh\n');
|
|
51
52
|
console.log('命令:\n' +
|
|
52
|
-
' start [tun|mixed]
|
|
53
|
-
' stop
|
|
54
|
-
' status
|
|
55
|
-
'
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'
|
|
62
|
-
'
|
|
63
|
-
'
|
|
64
|
-
' reset
|
|
65
|
-
'
|
|
66
|
-
' version 版本信息\n');
|
|
53
|
+
' start [tun|mixed] 启动/切换代理\n' +
|
|
54
|
+
' stop 停止代理\n' +
|
|
55
|
+
' status 查看状态\n' +
|
|
56
|
+
' ui [zash|dash|yacd] Web 界面\n' +
|
|
57
|
+
' log 实时日志\n' +
|
|
58
|
+
' logs 日志列表\n' +
|
|
59
|
+
' subscription add <url> 添加订阅(别名 sub)\n' +
|
|
60
|
+
' subscription update 更新订阅\n' +
|
|
61
|
+
' subscription use <name> 切换默认订阅\n' +
|
|
62
|
+
' overwrite [on|off] 覆写配置(别名 ow)\n' +
|
|
63
|
+
' directories 数据目录(别名 dir)\n' +
|
|
64
|
+
' kernel 更新内核\n' +
|
|
65
|
+
' reset 重置配置\n' +
|
|
66
|
+
' version 版本信息\n');
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function printHelp() {
|
|
@@ -74,30 +74,37 @@ function printHelp() {
|
|
|
74
74
|
'用法:\n' +
|
|
75
75
|
' mihomo-cli <命令> [选项]\n' +
|
|
76
76
|
'\n' +
|
|
77
|
-
'
|
|
78
|
-
' start [tun|mixed]
|
|
79
|
-
' stop
|
|
80
|
-
' status
|
|
81
|
-
'
|
|
82
|
-
'
|
|
83
|
-
' ui [zash|dash|yacd]
|
|
84
|
-
'
|
|
85
|
-
'
|
|
86
|
-
'
|
|
87
|
-
'
|
|
88
|
-
'
|
|
89
|
-
'
|
|
90
|
-
'
|
|
91
|
-
'
|
|
92
|
-
'
|
|
93
|
-
'
|
|
77
|
+
'控制:\n' +
|
|
78
|
+
' start [tun|mixed] 启动/切换代理 (默认 mixed)\n' +
|
|
79
|
+
' stop 停止代理\n' +
|
|
80
|
+
' status 查看状态\n' +
|
|
81
|
+
'\n' +
|
|
82
|
+
'界面:\n' +
|
|
83
|
+
' ui [zash|dash|yacd] 打开 Web UI (默认 zash)\n' +
|
|
84
|
+
' log [-o] 实时日志(-o 打开文件)\n' +
|
|
85
|
+
' logs [编号] [-n N] [-o] 日志列表(0=当前,1+=归档)\n' +
|
|
86
|
+
'\n' +
|
|
87
|
+
'订阅:\n' +
|
|
88
|
+
' subscription add <url> [name] 添加订阅(别名 sub)\n' +
|
|
89
|
+
' subscription update [name] 更新订阅(无参更新所有)\n' +
|
|
90
|
+
' subscription use <name> 设置默认订阅\n' +
|
|
91
|
+
' subscription web [name] 打开订阅页面\n' +
|
|
92
|
+
'\n' +
|
|
93
|
+
'配置:\n' +
|
|
94
|
+
' overwrite [on|off] 覆写配置(别名 ow)\n' +
|
|
95
|
+
' directories [open] 数据目录(别名 dir)\n' +
|
|
96
|
+
'\n' +
|
|
97
|
+
'系统:\n' +
|
|
98
|
+
' kernel [镜像|--no-mirror] 更新内核\n' +
|
|
99
|
+
' reset [--full] 重置用户数据 (--full 同时删除内核)\n' +
|
|
100
|
+
' help, -h 显示帮助\n' +
|
|
101
|
+
' version, -v 显示版本\n' +
|
|
94
102
|
'\n' +
|
|
95
103
|
'示例:\n' +
|
|
96
|
-
' mihomo-cli start
|
|
97
|
-
' mihomo-cli start tun
|
|
98
|
-
' mihomo-cli
|
|
99
|
-
' mihomo-cli ui
|
|
100
|
-
' mihomo-cli ui yacd # 打开 YACD\n' +
|
|
104
|
+
' mihomo-cli start # 启动/重启 Mixed 模式\n' +
|
|
105
|
+
' mihomo-cli start tun # 切换到 TUN 透明代理模式\n' +
|
|
106
|
+
' mihomo-cli sub add <url> # 添加订阅 (sub 是 subscription 别名)\n' +
|
|
107
|
+
' mihomo-cli ui # 打开 Web UI\n' +
|
|
101
108
|
'\n' +
|
|
102
109
|
'模式说明:\n' +
|
|
103
110
|
' mixed HTTP + SOCKS5 混合端口 (默认)\n' +
|
|
@@ -118,24 +125,59 @@ function printVersion() {
|
|
|
118
125
|
function printStatus() {
|
|
119
126
|
const status = processMgr.getStatus();
|
|
120
127
|
const info = subscription.getConfigInfo();
|
|
128
|
+
const owEnabled = overwrite.isOverwriteEnabled();
|
|
129
|
+
const owFiles = overwrite.listOverwriteFiles().files;
|
|
130
|
+
const activeSub = getActiveSubscription();
|
|
121
131
|
|
|
122
132
|
console.log('');
|
|
123
|
-
|
|
133
|
+
let modeLabel = '';
|
|
134
|
+
if (info && status.running) {
|
|
135
|
+
modeLabel = info.tun ? ' (TUN)' : ' (Mixed)';
|
|
136
|
+
}
|
|
137
|
+
console.log('状态: ' + (status.running ? '运行中' : '已停止') + modeLabel);
|
|
138
|
+
console.log('内核: ' + (status.kernelVersion || '未安装'));
|
|
139
|
+
|
|
124
140
|
if (status.pid) {
|
|
125
|
-
console.log('
|
|
141
|
+
console.log('PID: ' + status.pid);
|
|
126
142
|
if (status.processInfo) {
|
|
127
|
-
console.log('
|
|
128
|
-
if (status.processInfo.cpu) {
|
|
129
|
-
console.log(' CPU: ' + status.processInfo.cpu);
|
|
130
|
-
}
|
|
143
|
+
console.log('内存: ' + status.processInfo.memory);
|
|
131
144
|
}
|
|
132
145
|
}
|
|
146
|
+
|
|
133
147
|
if (info) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
148
|
+
if (info.mixedPort) {
|
|
149
|
+
console.log('端口: ' + info.mixedPort);
|
|
150
|
+
} else {
|
|
151
|
+
let ports = [];
|
|
152
|
+
if (info.httpPort) ports.push('HTTP:' + info.httpPort);
|
|
153
|
+
if (info.socksPort) ports.push('SOCKS:' + info.socksPort);
|
|
154
|
+
console.log('端口: ' + (ports.length > 0 ? ports.join(', ') : '未知'));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (activeSub) {
|
|
159
|
+
let subLine = '订阅: ' + activeSub.name;
|
|
160
|
+
if (info) {
|
|
161
|
+
let parts = [];
|
|
162
|
+
if (info.proxyGroups && info.proxyGroups > 0) {
|
|
163
|
+
parts.push(info.proxyGroups + ' 组');
|
|
164
|
+
}
|
|
165
|
+
parts.push(info.proxies + ' 节点');
|
|
166
|
+
subLine += ' (' + parts.join(', ') + ')';
|
|
167
|
+
}
|
|
168
|
+
console.log(subLine);
|
|
169
|
+
} else {
|
|
170
|
+
console.log('订阅: 未配置');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (owEnabled && owFiles.length > 0) {
|
|
174
|
+
const names = owFiles.map(f => f.name).join(', ');
|
|
175
|
+
console.log('覆写: 已启用 (' + names + ')');
|
|
176
|
+
} else if (owEnabled) {
|
|
177
|
+
console.log('覆写: 已启用 (无文件)');
|
|
178
|
+
} else {
|
|
179
|
+
console.log('覆写: 已禁用');
|
|
137
180
|
}
|
|
138
|
-
console.log(' 内核: ' + (status.kernelVersion || '未安装'));
|
|
139
181
|
console.log('');
|
|
140
182
|
}
|
|
141
183
|
|
|
@@ -171,15 +213,15 @@ function findSubsFuzzy(subs, pattern) {
|
|
|
171
213
|
|
|
172
214
|
function pickSingleSub(subs, pattern, actionName) {
|
|
173
215
|
if (subs.length === 0) {
|
|
174
|
-
console.error('
|
|
216
|
+
console.error('错误: 未找到匹配 "' + pattern + '" 的订阅');
|
|
175
217
|
process.exit(1);
|
|
176
218
|
}
|
|
177
219
|
if (subs.length === 1) {
|
|
178
220
|
return subs[0];
|
|
179
221
|
}
|
|
180
|
-
console.error('
|
|
181
|
-
console.log('\n
|
|
182
|
-
subs.forEach(s => console.log('
|
|
222
|
+
console.error('错误: 匹配到多个订阅,请更精确指定');
|
|
223
|
+
console.log('\n匹配的订阅:');
|
|
224
|
+
subs.forEach(s => console.log(' ' + s.name));
|
|
183
225
|
process.exit(1);
|
|
184
226
|
}
|
|
185
227
|
|
|
@@ -212,10 +254,19 @@ function getNonFlagArg(args, startIdx) {
|
|
|
212
254
|
|
|
213
255
|
function openLogFile(logPath, label) {
|
|
214
256
|
const displayLabel = label || logPath;
|
|
215
|
-
console.log('
|
|
257
|
+
console.log('用系统默认程序打开: ' + displayLabel);
|
|
216
258
|
const success = processMgr.openUrl(logPath);
|
|
217
259
|
if (!success) {
|
|
218
|
-
console.log('
|
|
260
|
+
console.log('请手动打开: ' + logPath);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function openDir(dirPath, label) {
|
|
265
|
+
const displayLabel = label || dirPath;
|
|
266
|
+
console.log('正在打开: ' + displayLabel);
|
|
267
|
+
const success = processMgr.openUrl(dirPath);
|
|
268
|
+
if (!success) {
|
|
269
|
+
console.log('请手动打开: ' + dirPath);
|
|
219
270
|
}
|
|
220
271
|
}
|
|
221
272
|
|
|
@@ -223,11 +274,11 @@ function viewLogWithTail(logPath, options) {
|
|
|
223
274
|
const follow = options && options.follow;
|
|
224
275
|
const lines = (options && options.lines) || 100;
|
|
225
276
|
|
|
226
|
-
console.log('
|
|
277
|
+
console.log('日志: ' + logPath);
|
|
227
278
|
if (follow) {
|
|
228
|
-
console.log('
|
|
279
|
+
console.log('按 Ctrl+C 退出\n');
|
|
229
280
|
} else {
|
|
230
|
-
console.log('
|
|
281
|
+
console.log('显示最后 ' + lines + ' 行\n');
|
|
231
282
|
}
|
|
232
283
|
|
|
233
284
|
const tailArgs = [];
|
|
@@ -239,14 +290,14 @@ function viewLogWithTail(logPath, options) {
|
|
|
239
290
|
|
|
240
291
|
tail.on('close', () => process.exit(0));
|
|
241
292
|
tail.on('error', (e) => {
|
|
242
|
-
console.error('
|
|
293
|
+
console.error('无法读取日志: ' + e.message);
|
|
243
294
|
process.exit(1);
|
|
244
295
|
});
|
|
245
296
|
}
|
|
246
297
|
|
|
247
298
|
async function cmdStart(args) {
|
|
248
299
|
if (!config.hasKernel()) {
|
|
249
|
-
console.error('
|
|
300
|
+
console.error('错误: 未找到内核,请运行 \'mihomo-cli kernel\'');
|
|
250
301
|
process.exit(1);
|
|
251
302
|
}
|
|
252
303
|
|
|
@@ -254,7 +305,7 @@ async function cmdStart(args) {
|
|
|
254
305
|
|
|
255
306
|
const sub = getActiveSubscription();
|
|
256
307
|
if (!sub) {
|
|
257
|
-
console.error('
|
|
308
|
+
console.error('错误: 没有订阅,请先添加订阅');
|
|
258
309
|
process.exit(1);
|
|
259
310
|
}
|
|
260
311
|
|
|
@@ -266,40 +317,42 @@ async function cmdStart(args) {
|
|
|
266
317
|
|
|
267
318
|
if (hasProcess) {
|
|
268
319
|
const count = status.allProcesses.length > 0 ? status.allProcesses.length : 1;
|
|
269
|
-
console.log('
|
|
320
|
+
console.log('停止 ' + count + ' 个进程...');
|
|
270
321
|
}
|
|
271
322
|
|
|
272
323
|
// 总是调用 stop(即使没进程也会清理 PID 文件和运行时目录)
|
|
273
324
|
const stopResult = processMgr.stop(true);
|
|
274
325
|
|
|
275
326
|
if (stopResult.remaining && stopResult.remaining.length > 0) {
|
|
276
|
-
console.error('
|
|
277
|
-
console.error('
|
|
327
|
+
console.error('部分进程未终止: ' + stopResult.remaining.join(', '));
|
|
328
|
+
console.error('请手动运行: sudo pkill -9 mihomo');
|
|
278
329
|
process.exit(1);
|
|
279
330
|
}
|
|
280
331
|
|
|
281
332
|
if (hasProcess) {
|
|
282
|
-
console.log('
|
|
333
|
+
console.log('已停止\n');
|
|
283
334
|
}
|
|
284
335
|
|
|
285
336
|
let cfgInfo;
|
|
286
337
|
try {
|
|
287
338
|
cfgInfo = subscription.prepareConfigForStart(targetMode, sub.name);
|
|
288
339
|
} catch (e) {
|
|
289
|
-
console.error('
|
|
340
|
+
console.error('配置错误: ' + e.message);
|
|
290
341
|
process.exit(1);
|
|
291
342
|
}
|
|
292
343
|
|
|
293
344
|
const modeLabel = targetMode === 'tun' ? 'TUN' : 'Mixed';
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
345
|
+
const parts = [];
|
|
346
|
+
if (cfgInfo.proxyGroups && cfgInfo.proxyGroups > 0) parts.push(cfgInfo.proxyGroups + ' 组');
|
|
347
|
+
parts.push(cfgInfo.proxies + ' 节点');
|
|
348
|
+
console.log([modeLabel, sub.name, parts.join(', ')].join(' · '));
|
|
297
349
|
|
|
298
350
|
try {
|
|
299
351
|
const result = await processMgr.start(targetMode);
|
|
300
|
-
console.log('
|
|
352
|
+
console.log('已启动 (PID ' + result.pid + ')');
|
|
353
|
+
printStatus();
|
|
301
354
|
} catch (e) {
|
|
302
|
-
console.error('
|
|
355
|
+
console.error('启动失败: ' + e.message.split('\n')[0]);
|
|
303
356
|
process.exit(1);
|
|
304
357
|
}
|
|
305
358
|
}
|
|
@@ -307,19 +360,19 @@ async function cmdStart(args) {
|
|
|
307
360
|
async function cmdStop() {
|
|
308
361
|
const pids = processMgr.getAllMihomoPids();
|
|
309
362
|
if (pids.length === 0) {
|
|
310
|
-
console.log('
|
|
363
|
+
console.log('未在运行');
|
|
311
364
|
return;
|
|
312
365
|
}
|
|
313
366
|
|
|
314
|
-
console.log('
|
|
367
|
+
console.log('停止 ' + pids.length + ' 个进程...');
|
|
315
368
|
const result = processMgr.stop(true);
|
|
316
369
|
|
|
317
370
|
if (result.remaining && result.remaining.length > 0) {
|
|
318
|
-
console.error('
|
|
319
|
-
console.error('
|
|
371
|
+
console.error('部分进程未终止: ' + result.remaining.join(', '));
|
|
372
|
+
console.error('请手动运行: sudo pkill -9 mihomo');
|
|
320
373
|
process.exit(1);
|
|
321
374
|
}
|
|
322
|
-
console.log('
|
|
375
|
+
console.log('已停止');
|
|
323
376
|
}
|
|
324
377
|
|
|
325
378
|
function cmdUi(args) {
|
|
@@ -327,17 +380,17 @@ function cmdUi(args) {
|
|
|
327
380
|
const url = UI_URLS[uiName];
|
|
328
381
|
|
|
329
382
|
if (!url) {
|
|
330
|
-
console.error('
|
|
331
|
-
console.error('
|
|
383
|
+
console.error('错误: 未知的 UI "' + uiName + '"');
|
|
384
|
+
console.error('可用 UI: zash (默认), dash, yacd');
|
|
332
385
|
process.exit(1);
|
|
333
386
|
}
|
|
334
387
|
|
|
335
|
-
console.log('
|
|
336
|
-
console.log('
|
|
388
|
+
console.log('打开 Web UI: ' + uiName);
|
|
389
|
+
console.log('地址: ' + url);
|
|
337
390
|
|
|
338
391
|
const success = processMgr.openUrl(url);
|
|
339
392
|
if (!success) {
|
|
340
|
-
console.log('
|
|
393
|
+
console.log('请手动访问上面的地址');
|
|
341
394
|
}
|
|
342
395
|
}
|
|
343
396
|
|
|
@@ -368,8 +421,8 @@ function cmdLogs(args) {
|
|
|
368
421
|
}
|
|
369
422
|
|
|
370
423
|
if (!logPath) {
|
|
371
|
-
console.error('
|
|
372
|
-
console.log('
|
|
424
|
+
console.error('错误: 未找到日志 "' + targetName + '"');
|
|
425
|
+
console.log('使用 "mihomo-cli logs" 查看可用日志列表');
|
|
373
426
|
process.exit(1);
|
|
374
427
|
}
|
|
375
428
|
|
|
@@ -391,12 +444,12 @@ function cmdLogs(args) {
|
|
|
391
444
|
all.push(...logs.archives);
|
|
392
445
|
|
|
393
446
|
if (all.length === 0) {
|
|
394
|
-
console.log('
|
|
447
|
+
console.log('暂无日志');
|
|
395
448
|
return;
|
|
396
449
|
}
|
|
397
450
|
|
|
398
451
|
console.log('');
|
|
399
|
-
console.log('
|
|
452
|
+
console.log('日志列表:');
|
|
400
453
|
console.log('');
|
|
401
454
|
|
|
402
455
|
all.forEach((log, idx) => {
|
|
@@ -405,19 +458,19 @@ function cmdLogs(args) {
|
|
|
405
458
|
const size = subscription.formatBytes(log.size);
|
|
406
459
|
const name = log.isCurrent ? 'mihomo.log (当前运行中)' : log.name;
|
|
407
460
|
|
|
408
|
-
console.log('
|
|
409
|
-
console.log('
|
|
461
|
+
console.log(' ' + num + '. ' + name);
|
|
462
|
+
console.log(' 时间: ' + time + ' 大小: ' + size);
|
|
410
463
|
if (!log.isCurrent) {
|
|
411
|
-
console.log('
|
|
464
|
+
console.log(' 查看: mihomo-cli logs ' + idx + ' 或 mihomo-cli logs -o ' + idx);
|
|
412
465
|
}
|
|
413
466
|
console.log('');
|
|
414
467
|
});
|
|
415
468
|
|
|
416
|
-
console.log('
|
|
417
|
-
console.log('
|
|
418
|
-
console.log('
|
|
419
|
-
console.log('
|
|
420
|
-
console.log('
|
|
469
|
+
console.log('用法:');
|
|
470
|
+
console.log(' mihomo-cli logs 0 # 查看当前日志 (最后 100 行)');
|
|
471
|
+
console.log(' mihomo-cli logs 1 # 查看第 1 个归档日志');
|
|
472
|
+
console.log(' mihomo-cli logs 1 -n 200 # 查看 200 行');
|
|
473
|
+
console.log(' mihomo-cli logs 1 -o # 用系统默认程序打开');
|
|
421
474
|
console.log('');
|
|
422
475
|
}
|
|
423
476
|
|
|
@@ -473,107 +526,111 @@ async function cmdKernel(args) {
|
|
|
473
526
|
const effectiveMirror = mirrorInfo.isOverride ? mirrorInfo.mirror : config.getGitHubMirror();
|
|
474
527
|
const isDefault = !mirrorInfo.isOverride && effectiveMirror === config.DEFAULT_GITHUB_MIRROR;
|
|
475
528
|
|
|
476
|
-
console.log('
|
|
529
|
+
console.log('检查内核更新...');
|
|
477
530
|
|
|
478
531
|
if (mirrorInfo.isOverride) {
|
|
479
532
|
if (effectiveMirror === null) {
|
|
480
|
-
console.log('
|
|
533
|
+
console.log('镜像: 直连(命令行指定 --no-mirror)');
|
|
481
534
|
} else {
|
|
482
|
-
console.log('
|
|
535
|
+
console.log('镜像: ' + effectiveMirror + ' (命令行指定)');
|
|
483
536
|
}
|
|
484
537
|
} else {
|
|
485
|
-
console.log('
|
|
538
|
+
console.log('镜像: ' + (effectiveMirror || '直连(无镜像)') + (isDefault && effectiveMirror ? ' (默认)' : ''));
|
|
486
539
|
}
|
|
487
540
|
|
|
488
|
-
console.log('\n
|
|
541
|
+
console.log('\n可用镜像:');
|
|
489
542
|
config.AVAILABLE_MIRRORS.forEach(m => {
|
|
490
543
|
const isCurrent = effectiveMirror && (
|
|
491
544
|
effectiveMirror.includes('//' + m + '/') ||
|
|
492
545
|
effectiveMirror.includes('//' + m + ':') ||
|
|
493
546
|
effectiveMirror.endsWith('//' + m)
|
|
494
547
|
);
|
|
495
|
-
console.log('
|
|
548
|
+
console.log(' ' + m + (isCurrent ? ' (当前)' : ''));
|
|
496
549
|
});
|
|
497
550
|
|
|
498
|
-
console.log('\n
|
|
499
|
-
console.log('
|
|
500
|
-
console.log('
|
|
501
|
-
console.log('
|
|
502
|
-
console.log('
|
|
551
|
+
console.log('\n用法:');
|
|
552
|
+
console.log(' mihomo-cli kernel # 使用默认镜像');
|
|
553
|
+
console.log(' mihomo-cli kernel hk.gh-proxy.org # 使用指定镜像');
|
|
554
|
+
console.log(' mihomo-cli kernel --mirror hk.gh-proxy.org');
|
|
555
|
+
console.log(' mihomo-cli kernel --no-mirror # 直连,不使用镜像');
|
|
503
556
|
console.log('');
|
|
504
557
|
|
|
505
558
|
try {
|
|
506
559
|
const info = await kernel.checkUpdate();
|
|
507
|
-
console.log('
|
|
508
|
-
console.log('
|
|
560
|
+
console.log('当前: ' + info.current);
|
|
561
|
+
console.log('最新: ' + info.latest);
|
|
509
562
|
|
|
510
563
|
if (!info.needsUpdate) {
|
|
511
|
-
console.log('
|
|
564
|
+
console.log('已是最新版本');
|
|
512
565
|
return;
|
|
513
566
|
}
|
|
514
567
|
|
|
515
|
-
console.log('\n
|
|
568
|
+
console.log('\n正在下载...');
|
|
516
569
|
const result = await kernel.downloadKernel((msg) => {
|
|
517
|
-
console.log(
|
|
570
|
+
console.log(msg);
|
|
518
571
|
}, mirrorInfo.mirror); // 传递镜像参数(undefined = 用配置,null = 禁用)
|
|
519
|
-
console.log('
|
|
572
|
+
console.log('已更新到 ' + result.version);
|
|
520
573
|
} catch (e) {
|
|
521
|
-
console.error('
|
|
574
|
+
console.error('更新失败: ' + e.message);
|
|
522
575
|
process.exit(1);
|
|
523
576
|
}
|
|
524
577
|
}
|
|
525
578
|
|
|
526
|
-
async function
|
|
527
|
-
const
|
|
579
|
+
async function printSubList() {
|
|
580
|
+
const updateResult = await subscription.autoUpdateStaleSubscriptions();
|
|
581
|
+
if (updateResult.total > 0) {
|
|
582
|
+
console.log('');
|
|
583
|
+
}
|
|
528
584
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
585
|
+
const subs = config.getSubscriptionsWithCache();
|
|
586
|
+
if (subs.length === 0) {
|
|
587
|
+
console.log('没有订阅');
|
|
588
|
+
console.log('');
|
|
589
|
+
console.log('添加订阅: mihomo-cli sub add <url> [name]');
|
|
590
|
+
console.log('');
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
console.log('订阅列表:');
|
|
594
|
+
subs.forEach((s, i) => {
|
|
595
|
+
const time = subscription.formatDate(s.updated_at);
|
|
596
|
+
const defaultMark = i === 0 ? ' [默认]' : '';
|
|
597
|
+
const interval = s.update_interval || subscription.DEFAULT_UPDATE_INTERVAL_HOURS;
|
|
598
|
+
console.log(' ' + (i + 1) + '. ' + s.name + defaultMark);
|
|
599
|
+
console.log(' 更新: ' + time + ' (间隔: ' + interval + 'h)');
|
|
600
|
+
|
|
601
|
+
if (s.username) {
|
|
602
|
+
console.log(' 用户: ' + s.username);
|
|
533
603
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
604
|
+
if (s.download !== undefined || s.total !== undefined) {
|
|
605
|
+
const used = (s.upload || 0) + (s.download || 0);
|
|
606
|
+
const usedStr = subscription.formatBytes(used);
|
|
607
|
+
const totalStr = subscription.formatBytes(s.total);
|
|
608
|
+
let percentStr = '';
|
|
609
|
+
if (s.total && s.total > 0) {
|
|
610
|
+
const percent = Math.min((used / s.total) * 100, 100);
|
|
611
|
+
percentStr = ' (' + percent.toFixed(1) + '%)';
|
|
612
|
+
}
|
|
613
|
+
console.log(' 流量: ' + usedStr + ' / ' + totalStr + percentStr);
|
|
614
|
+
}
|
|
615
|
+
if (s.expire !== undefined) {
|
|
616
|
+
console.log(' 到期: ' + subscription.formatTimestamp(s.expire));
|
|
541
617
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
618
|
+
if (s.web_page_url) {
|
|
619
|
+
console.log(' 页面: ' + s.web_page_url);
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
console.log('');
|
|
623
|
+
console.log('切换默认: sub use <name>');
|
|
624
|
+
console.log('更新订阅: sub update [name]');
|
|
625
|
+
console.log('打开页面: sub web [name]');
|
|
626
|
+
console.log('');
|
|
627
|
+
}
|
|
549
628
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
const usedStr = subscription.formatBytes(used);
|
|
556
|
-
const totalStr = subscription.formatBytes(s.total);
|
|
557
|
-
let percentStr = '';
|
|
558
|
-
if (s.total && s.total > 0) {
|
|
559
|
-
const percent = Math.min((used / s.total) * 100, 100);
|
|
560
|
-
percentStr = ' (' + percent.toFixed(1) + '%)';
|
|
561
|
-
}
|
|
562
|
-
console.log(' 流量: ' + usedStr + ' / ' + totalStr + percentStr);
|
|
563
|
-
}
|
|
564
|
-
if (s.expire !== undefined) {
|
|
565
|
-
console.log(' 到期: ' + subscription.formatTimestamp(s.expire));
|
|
566
|
-
}
|
|
567
|
-
if (s.webPageUrl) {
|
|
568
|
-
console.log(' 页面: ' + s.webPageUrl);
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
console.log('\n 切换默认订阅:');
|
|
572
|
-
console.log(' mihomo-cli sub use <name>');
|
|
573
|
-
console.log(' 更新订阅:');
|
|
574
|
-
console.log(' mihomo-cli sub update [name]');
|
|
575
|
-
console.log(' 打开订阅页面:');
|
|
576
|
-
console.log(' mihomo-cli sub web [name]');
|
|
629
|
+
async function cmdSub(args) {
|
|
630
|
+
const action = args[1];
|
|
631
|
+
|
|
632
|
+
if (!action || action === 'list') {
|
|
633
|
+
await printSubList();
|
|
577
634
|
return;
|
|
578
635
|
}
|
|
579
636
|
|
|
@@ -582,19 +639,24 @@ async function cmdSub(args) {
|
|
|
582
639
|
const name = args[3] || 'default';
|
|
583
640
|
|
|
584
641
|
if (!url || !url.startsWith('http')) {
|
|
585
|
-
console.error('
|
|
642
|
+
console.error('错误: 请提供有效的订阅 URL');
|
|
586
643
|
process.exit(1);
|
|
587
644
|
}
|
|
588
645
|
|
|
589
|
-
console.log('
|
|
646
|
+
console.log('添加订阅: ' + name);
|
|
590
647
|
try {
|
|
591
648
|
config.addSubscription(url, name);
|
|
592
649
|
const info = await subscription.downloadSubscription(url, name);
|
|
593
|
-
|
|
650
|
+
const parts = [];
|
|
651
|
+
if (info.proxyGroups && info.proxyGroups > 0) parts.push(info.proxyGroups + ' 组');
|
|
652
|
+
parts.push(info.proxies + ' 节点');
|
|
653
|
+
console.log('已添加 (' + parts.join(', ') + ')');
|
|
594
654
|
} catch (e) {
|
|
595
|
-
console.error('
|
|
655
|
+
console.error('添加失败: ' + e.message);
|
|
596
656
|
process.exit(1);
|
|
597
657
|
}
|
|
658
|
+
console.log('');
|
|
659
|
+
await printSubList();
|
|
598
660
|
return;
|
|
599
661
|
}
|
|
600
662
|
|
|
@@ -603,37 +665,47 @@ async function cmdSub(args) {
|
|
|
603
665
|
const subs = config.getSubscriptions();
|
|
604
666
|
|
|
605
667
|
if (subs.length === 0) {
|
|
606
|
-
console.error('
|
|
668
|
+
console.error('错误: 没有订阅');
|
|
607
669
|
process.exit(1);
|
|
608
670
|
}
|
|
609
671
|
|
|
610
672
|
if (!name) {
|
|
611
|
-
console.log('
|
|
673
|
+
console.log('更新所有 ' + subs.length + ' 个订阅...');
|
|
612
674
|
const results = await Promise.all(subs.map(subscription.tryUpdateOne));
|
|
613
675
|
let ok = 0;
|
|
614
676
|
results.forEach(r => {
|
|
615
677
|
if (r.success) {
|
|
616
678
|
ok++;
|
|
617
|
-
|
|
679
|
+
const parts = [];
|
|
680
|
+
if (r.proxyGroups && r.proxyGroups > 0) parts.push(r.proxyGroups + ' 组');
|
|
681
|
+
parts.push(r.proxies + ' 节点');
|
|
682
|
+
console.log('✓ ' + r.name + ': 已更新 (' + parts.join(', ') + ')');
|
|
618
683
|
} else {
|
|
619
|
-
console.log('
|
|
684
|
+
console.log('✗ ' + r.name + ': 失败 (' + r.error.split('\n')[0] + ')');
|
|
620
685
|
}
|
|
621
686
|
});
|
|
622
687
|
if (ok === 0) process.exit(1);
|
|
688
|
+
console.log('');
|
|
689
|
+
await printSubList();
|
|
623
690
|
return;
|
|
624
691
|
}
|
|
625
692
|
|
|
626
693
|
const matches = findSubsFuzzy(subs, name);
|
|
627
694
|
const target = pickSingleSub(matches, name, '更新');
|
|
628
695
|
|
|
629
|
-
console.log('
|
|
696
|
+
console.log('更新订阅: ' + target.name);
|
|
630
697
|
try {
|
|
631
698
|
const info = await subscription.downloadSubscription(target.url, target.name);
|
|
632
|
-
|
|
699
|
+
const parts = [];
|
|
700
|
+
if (info.proxyGroups && info.proxyGroups > 0) parts.push(info.proxyGroups + ' 组');
|
|
701
|
+
parts.push(info.proxies + ' 节点');
|
|
702
|
+
console.log('已更新 (' + parts.join(', ') + ')');
|
|
633
703
|
} catch (e) {
|
|
634
|
-
console.error('
|
|
704
|
+
console.error('更新失败: ' + e.message);
|
|
635
705
|
process.exit(1);
|
|
636
706
|
}
|
|
707
|
+
console.log('');
|
|
708
|
+
await printSubList();
|
|
637
709
|
return;
|
|
638
710
|
}
|
|
639
711
|
|
|
@@ -642,10 +714,10 @@ async function cmdSub(args) {
|
|
|
642
714
|
const subs = config.getSubscriptions();
|
|
643
715
|
|
|
644
716
|
if (!name) {
|
|
645
|
-
console.error('
|
|
717
|
+
console.error('错误: 请指定订阅名称');
|
|
646
718
|
if (subs.length > 0) {
|
|
647
|
-
console.log('\n
|
|
648
|
-
subs.forEach(s => console.log('
|
|
719
|
+
console.log('\n可用订阅:');
|
|
720
|
+
subs.forEach(s => console.log(' ' + s.name));
|
|
649
721
|
}
|
|
650
722
|
process.exit(1);
|
|
651
723
|
}
|
|
@@ -655,11 +727,13 @@ async function cmdSub(args) {
|
|
|
655
727
|
|
|
656
728
|
const success = config.setDefaultSubscription(target.name);
|
|
657
729
|
if (success) {
|
|
658
|
-
console.log('
|
|
730
|
+
console.log('已设置 "' + target.name + '" 为默认订阅');
|
|
659
731
|
} else {
|
|
660
|
-
console.error('
|
|
732
|
+
console.error('错误: 未找到订阅 "' + name + '"');
|
|
661
733
|
process.exit(1);
|
|
662
734
|
}
|
|
735
|
+
console.log('');
|
|
736
|
+
await printSubList();
|
|
663
737
|
return;
|
|
664
738
|
}
|
|
665
739
|
|
|
@@ -668,7 +742,7 @@ async function cmdSub(args) {
|
|
|
668
742
|
const subs = config.getSubscriptionsWithCache();
|
|
669
743
|
|
|
670
744
|
if (subs.length === 0) {
|
|
671
|
-
console.error('
|
|
745
|
+
console.error('错误: 没有订阅');
|
|
672
746
|
process.exit(1);
|
|
673
747
|
}
|
|
674
748
|
|
|
@@ -680,33 +754,35 @@ async function cmdSub(args) {
|
|
|
680
754
|
target = subs[0];
|
|
681
755
|
}
|
|
682
756
|
|
|
683
|
-
let webPageUrl = target.
|
|
757
|
+
let webPageUrl = target.web_page_url;
|
|
684
758
|
if (!webPageUrl) {
|
|
685
|
-
console.log('
|
|
759
|
+
console.log('订阅信息中缺少页面地址,正在更新订阅...');
|
|
686
760
|
try {
|
|
687
761
|
const info = await subscription.downloadSubscription(target.url, target.name);
|
|
688
|
-
|
|
689
|
-
|
|
762
|
+
// 重新读取缓存获取 web_page_url
|
|
763
|
+
const cache = config.readSubscriptionsCache();
|
|
764
|
+
if (cache[target.name] && cache[target.name].web_page_url) {
|
|
765
|
+
webPageUrl = cache[target.name].web_page_url;
|
|
690
766
|
} else {
|
|
691
|
-
console.error('
|
|
767
|
+
console.error('错误: 该订阅没有提供页面地址');
|
|
692
768
|
process.exit(1);
|
|
693
769
|
}
|
|
694
770
|
} catch (e) {
|
|
695
|
-
console.error('
|
|
771
|
+
console.error('更新失败: ' + e.message);
|
|
696
772
|
process.exit(1);
|
|
697
773
|
}
|
|
698
774
|
}
|
|
699
775
|
|
|
700
|
-
console.log('
|
|
776
|
+
console.log('打开订阅页面: ' + webPageUrl);
|
|
701
777
|
const opened = processMgr.openUrl(webPageUrl);
|
|
702
778
|
if (!opened) {
|
|
703
|
-
console.log('
|
|
779
|
+
console.log('请手动访问上面的地址');
|
|
704
780
|
}
|
|
705
781
|
return;
|
|
706
782
|
}
|
|
707
783
|
|
|
708
|
-
console.error('
|
|
709
|
-
console.log('
|
|
784
|
+
console.error('错误: 未知的订阅命令');
|
|
785
|
+
console.log('用法: mihomo-cli sub [list|add|update|use|web]');
|
|
710
786
|
process.exit(1);
|
|
711
787
|
}
|
|
712
788
|
|
|
@@ -716,7 +792,7 @@ async function cmdReset(args) {
|
|
|
716
792
|
|
|
717
793
|
const pids = processMgr.getAllMihomoPids();
|
|
718
794
|
if (pids.length > 0) {
|
|
719
|
-
console.log('
|
|
795
|
+
console.log('停止 ' + pids.length + ' 个进程...');
|
|
720
796
|
processMgr.cleanupAll(true);
|
|
721
797
|
for (let i = 0; i < 50; i++) {
|
|
722
798
|
if (processMgr.getAllMihomoPids().length === 0) break;
|
|
@@ -725,7 +801,7 @@ async function cmdReset(args) {
|
|
|
725
801
|
}
|
|
726
802
|
|
|
727
803
|
const mode = fullReset ? '完整重置 (含内核)' : '重置配置';
|
|
728
|
-
console.log(
|
|
804
|
+
console.log(mode);
|
|
729
805
|
|
|
730
806
|
if (!skipConfirm) {
|
|
731
807
|
const readline = require('readline');
|
|
@@ -735,39 +811,143 @@ async function cmdReset(args) {
|
|
|
735
811
|
});
|
|
736
812
|
|
|
737
813
|
const answer = await new Promise(resolve => {
|
|
738
|
-
rl.question('
|
|
814
|
+
rl.question('确认? (y/N) ', (a) => {
|
|
739
815
|
rl.close();
|
|
740
816
|
resolve(a);
|
|
741
817
|
});
|
|
742
818
|
});
|
|
743
819
|
|
|
744
820
|
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
745
|
-
console.log('
|
|
821
|
+
console.log('已取消');
|
|
746
822
|
return;
|
|
747
823
|
}
|
|
748
824
|
}
|
|
749
825
|
|
|
750
826
|
const count = config.resetUserData({ keepKernel: !fullReset });
|
|
751
|
-
console.log('
|
|
827
|
+
console.log('已重置 ' + count + ' 项');
|
|
752
828
|
}
|
|
753
829
|
|
|
754
|
-
function
|
|
830
|
+
function printOverwriteList() {
|
|
831
|
+
const info = overwrite.listOverwriteFiles();
|
|
755
832
|
console.log('');
|
|
756
|
-
console.log('
|
|
757
|
-
console.log('
|
|
758
|
-
console.log(' 全局设置: ' + config.PATHS.settingsFile);
|
|
759
|
-
console.log(' 内核文件: ' + config.PATHS.mihomoBinary);
|
|
760
|
-
console.log(' 订阅目录: ' + config.DIRS.subs);
|
|
761
|
-
console.log(' - xxx.yaml (订阅原始配置,不修改)');
|
|
762
|
-
console.log(' 运行时目录: ' + config.DIRS.runtime);
|
|
763
|
-
console.log(' - config.yaml (启动时生成,stop 自动清除)');
|
|
764
|
-
console.log(' - pid (PID 文件,stop 自动清除)');
|
|
765
|
-
console.log(' 日志文件: ' + config.PATHS.logFile);
|
|
766
|
-
console.log(' mihomo 数据: ' + config.DIRS.data);
|
|
767
|
-
console.log(' - cache.db, Geo*.dat 等 (mihomo 自行管理)');
|
|
833
|
+
console.log('状态: ' + (info.enabled ? '已启用' : '已禁用'));
|
|
834
|
+
console.log('目录: ' + info.dir);
|
|
768
835
|
console.log('');
|
|
769
|
-
|
|
770
|
-
|
|
836
|
+
if (info.files.length === 0) {
|
|
837
|
+
console.log('暂无覆写文件');
|
|
838
|
+
console.log('');
|
|
839
|
+
console.log('用法示例: 创建文件 ' + path.join(info.dir, '01-custom.yaml'));
|
|
840
|
+
console.log('');
|
|
841
|
+
} else {
|
|
842
|
+
console.log('覆写文件 (' + info.files.length + ' 个,按顺序加载):');
|
|
843
|
+
console.log('');
|
|
844
|
+
info.files.forEach((f, i) => {
|
|
845
|
+
const num = i < 10 ? ' ' + i : '' + i;
|
|
846
|
+
console.log(' ' + num + '. ' + f.name);
|
|
847
|
+
if (f.keys.length > 0) {
|
|
848
|
+
console.log(' 字段: ' + f.keys.join(', '));
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
console.log('');
|
|
852
|
+
}
|
|
853
|
+
console.log('启用覆写: ow on');
|
|
854
|
+
console.log('禁用覆写: ow off');
|
|
855
|
+
console.log('');
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
function cmdOverwrite(args) {
|
|
859
|
+
const action = args && args[1];
|
|
860
|
+
|
|
861
|
+
if (action === 'on' || action === 'enable') {
|
|
862
|
+
overwrite.setOverwriteEnabled(true);
|
|
863
|
+
console.log('已启用覆写配置');
|
|
864
|
+
console.log('');
|
|
865
|
+
printOverwriteList();
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (action === 'off' || action === 'disable') {
|
|
870
|
+
overwrite.setOverwriteEnabled(false);
|
|
871
|
+
console.log('已禁用覆写配置');
|
|
872
|
+
console.log('');
|
|
873
|
+
printOverwriteList();
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// 无参数、list、ls 都显示文件列表
|
|
878
|
+
printOverwriteList();
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function cmdDirs(args) {
|
|
882
|
+
const action = args && args[1];
|
|
883
|
+
|
|
884
|
+
// dirs open [root|subs|logs|data|runtime|config|kernel]
|
|
885
|
+
if (action === 'open') {
|
|
886
|
+
const target = args[2];
|
|
887
|
+
|
|
888
|
+
if (!target || target === 'root') {
|
|
889
|
+
openDir(config.USER_DATA_DIR, '根目录');
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
const dirMap = {
|
|
894
|
+
'subs': { path: config.DIRS.subscriptions, label: '订阅目录' },
|
|
895
|
+
'subscriptions': { path: config.DIRS.subscriptions, label: '订阅目录' },
|
|
896
|
+
'logs': { path: config.DIRS.logs, label: '日志目录' },
|
|
897
|
+
'data': { path: config.DIRS.data, label: 'mihomo 数据目录' },
|
|
898
|
+
'runtime': { path: config.DIRS.runtime, label: '运行时目录' },
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
const fileMap = {
|
|
902
|
+
'config': { path: config.PATHS.settingsFile, label: '设置文件' },
|
|
903
|
+
'settings': { path: config.PATHS.settingsFile, label: '设置文件' },
|
|
904
|
+
'kernel': { path: config.DIRS.core, label: '内核目录' },
|
|
905
|
+
};
|
|
906
|
+
|
|
907
|
+
const targetInfo = dirMap[target] || fileMap[target];
|
|
908
|
+
if (targetInfo) {
|
|
909
|
+
openDir(targetInfo.path, targetInfo.label);
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
console.error('错误: 未知的目录目标 "' + target + '"');
|
|
914
|
+
console.log('');
|
|
915
|
+
console.log('可用目标:');
|
|
916
|
+
console.log(' root (默认) 根目录');
|
|
917
|
+
console.log(' subs 订阅目录');
|
|
918
|
+
console.log(' logs 日志目录');
|
|
919
|
+
console.log(' data mihomo 数据目录');
|
|
920
|
+
console.log(' runtime 运行时目录');
|
|
921
|
+
console.log(' config 设置文件 (settings.json)');
|
|
922
|
+
console.log(' kernel 内核目录');
|
|
923
|
+
console.log('');
|
|
924
|
+
process.exit(1);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// 无参数或未知参数:显示目录列表
|
|
928
|
+
console.log('');
|
|
929
|
+
console.log('数据目录位置:');
|
|
930
|
+
console.log(' 根目录: ' + config.USER_DATA_DIR);
|
|
931
|
+
console.log(' 全局设置: ' + config.PATHS.settingsFile);
|
|
932
|
+
console.log(' 内核文件: ' + config.PATHS.mihomoBinary);
|
|
933
|
+
console.log(' 订阅目录: ' + config.DIRS.subscriptions);
|
|
934
|
+
console.log(' - cache.json (订阅缓存:更新时间、流量等)');
|
|
935
|
+
console.log(' - xxx.yaml (订阅原始配置)');
|
|
936
|
+
console.log(' 运行时目录: ' + config.DIRS.runtime);
|
|
937
|
+
console.log(' - config.yaml (启动时生成,stop 自动清除)');
|
|
938
|
+
console.log(' - pid (PID 文件,stop 自动清除)');
|
|
939
|
+
console.log(' 日志文件: ' + config.PATHS.logFile);
|
|
940
|
+
console.log(' mihomo 数据: ' + config.DIRS.data);
|
|
941
|
+
console.log(' - cache.db, Geo*.dat 等 (mihomo 自行管理)');
|
|
942
|
+
console.log('');
|
|
943
|
+
console.log('打开目录:');
|
|
944
|
+
console.log(' mihomo-cli dirs open 打开根目录');
|
|
945
|
+
console.log(' mihomo-cli dirs open subscriptions 打开订阅目录');
|
|
946
|
+
console.log(' mihomo-cli dirs open logs 打开日志目录');
|
|
947
|
+
console.log(' mihomo-cli dirs open config 打开设置文件');
|
|
948
|
+
console.log('');
|
|
949
|
+
console.log('环境变量:');
|
|
950
|
+
console.log(' MIHOMO_CLI_DIR: 自定义根目录位置');
|
|
771
951
|
console.log('');
|
|
772
952
|
}
|
|
773
953
|
|
|
@@ -817,22 +997,30 @@ async function main() {
|
|
|
817
997
|
break;
|
|
818
998
|
case 'sub':
|
|
819
999
|
case 'subscription':
|
|
1000
|
+
case 'subscriptions':
|
|
820
1001
|
await cmdSub(args);
|
|
821
1002
|
break;
|
|
1003
|
+
case 'dir':
|
|
822
1004
|
case 'dirs':
|
|
823
|
-
|
|
1005
|
+
case 'directory':
|
|
1006
|
+
case 'directories':
|
|
1007
|
+
cmdDirs(args);
|
|
824
1008
|
break;
|
|
825
1009
|
case 'reset':
|
|
826
1010
|
await cmdReset(args);
|
|
827
1011
|
break;
|
|
1012
|
+
case 'overwrite':
|
|
1013
|
+
case 'ow':
|
|
1014
|
+
cmdOverwrite(args);
|
|
1015
|
+
break;
|
|
828
1016
|
default:
|
|
829
|
-
console.error('
|
|
830
|
-
console.error('
|
|
1017
|
+
console.error('未知命令: ' + cmd);
|
|
1018
|
+
console.error('使用 "mihomo-cli help" 查看帮助');
|
|
831
1019
|
process.exit(1);
|
|
832
1020
|
}
|
|
833
1021
|
}
|
|
834
1022
|
|
|
835
1023
|
main().catch(e => {
|
|
836
|
-
console.error('
|
|
1024
|
+
console.error('错误:', e.message);
|
|
837
1025
|
process.exit(1);
|
|
838
1026
|
});
|