@lancewu602/mihomo-dash 0.6.1 → 0.6.3
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/package.json
CHANGED
package/server/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.6.3] - 2026-10-31
|
|
9
|
+
|
|
10
|
+
### 工程
|
|
11
|
+
|
|
12
|
+
- 服务定义带版本与文档地址:`Description` 里写 `mihomo-dash <版本>`,
|
|
13
|
+
并加 `Documentation=https://github.com/lancewu602/mihomo-dash`——
|
|
14
|
+
`systemctl status` 的标题行与 `Docs:` 行直接显示;面板启动日志与内核日志也带上版本号
|
|
15
|
+
|
|
16
|
+
## [0.6.2] - 2026-10-31
|
|
17
|
+
|
|
18
|
+
### 修复
|
|
19
|
+
|
|
20
|
+
- `service uninstall` / `service start` 回显的动作命令按作用域生成:system 作用域下不再印
|
|
21
|
+
`systemctl --user …`(真实执行的 argv 本来就不带 `--user`,只有文案错)
|
|
22
|
+
|
|
8
23
|
## [0.6.1] - 2026-10-31
|
|
9
24
|
|
|
10
25
|
### 修复
|
package/server/package.json
CHANGED
package/server/src/http/index.js
CHANGED
|
@@ -255,6 +255,6 @@ export async function startServer(opts) {
|
|
|
255
255
|
server.on('error', reject);
|
|
256
256
|
});
|
|
257
257
|
|
|
258
|
-
console.log(`mihomo-dash 面板已启动: http://${opts.host}:${opts.port}`);
|
|
258
|
+
console.log(`mihomo-dash ${PKG_VERSION} 面板已启动: http://${opts.host}:${opts.port}`);
|
|
259
259
|
console.log(`内核接口: ${getController().url} 配置目录: ${detectMihomoDir()}`);
|
|
260
260
|
}
|
|
@@ -19,8 +19,12 @@ import {
|
|
|
19
19
|
detectMihomoDir,
|
|
20
20
|
ensureCliDir,
|
|
21
21
|
} from '../shared/paths.js';
|
|
22
|
+
import { createRequire } from 'node:module';
|
|
22
23
|
import { readTailLines, rotateLogFile } from '../shared/log-file.js';
|
|
23
24
|
|
|
25
|
+
const require = createRequire(import.meta.url);
|
|
26
|
+
const { version: PKG_VERSION } = require('../../../package.json');
|
|
27
|
+
|
|
24
28
|
/** pid 活着没(不发信号判断,避免误杀) */
|
|
25
29
|
export function isAlive(pid) {
|
|
26
30
|
const n = Number(pid);
|
|
@@ -223,7 +227,14 @@ export async function kernelStart(opts = {}) {
|
|
|
223
227
|
if (!isAlive(child.pid)) break;
|
|
224
228
|
const ready = await probeKernel(600);
|
|
225
229
|
if (ready) {
|
|
226
|
-
|
|
230
|
+
// 前台 = 系统服务管理器拉起的路径,输出进 kernel.log:面板的「内核日志」与
|
|
231
|
+
// `systemctl status` 的日志尾都能看到「面板版本 + 内核版本」
|
|
232
|
+
if (opts.foreground) {
|
|
233
|
+
console.log(
|
|
234
|
+
`mihomo-dash ${PKG_VERSION} 内核已启动: ${ready.url}(pid ${child.pid},v${ready.version})`,
|
|
235
|
+
);
|
|
236
|
+
return waitChildExit(child);
|
|
237
|
+
}
|
|
227
238
|
console.log(`内核已启动: ${ready.url}(pid ${child.pid},v${ready.version})`);
|
|
228
239
|
return { ok: true, pid: child.pid };
|
|
229
240
|
}
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
import fs from 'node:fs';
|
|
29
29
|
import os from 'node:os';
|
|
30
30
|
import path from 'node:path';
|
|
31
|
+
import { createRequire } from 'node:module';
|
|
31
32
|
import { fileURLToPath } from 'node:url';
|
|
32
33
|
import { defaultRun } from './exec.js';
|
|
33
34
|
import { CLI_DIR, DEFAULT_HOST, DEFAULT_PORT } from './paths.js';
|
|
@@ -41,19 +42,27 @@ export const SERVICE_ENTRIES = {
|
|
|
41
42
|
/** 面板 / 内核两个 agent 共用的 bundle 标识:只是给「登录项」UI 认领用的,不是真的 app bundle */
|
|
42
43
|
export const BUNDLE_ID = 'com.mihomo-dash';
|
|
43
44
|
|
|
45
|
+
/** 单元 / plist 里指回仓库的地址:`systemctl status` 的 `Docs:` 行就是它 */
|
|
46
|
+
export const DOCS_URL = 'https://github.com/lancewu602/mihomo-dash';
|
|
47
|
+
|
|
48
|
+
const require = createRequire(import.meta.url);
|
|
49
|
+
const { version: PKG_VERSION } = require('../../../package.json');
|
|
50
|
+
|
|
44
51
|
/** 两个受监管的 job:面板与面板自有内核 */
|
|
45
52
|
const JOBS = {
|
|
46
53
|
panel: {
|
|
47
54
|
label: 'com.mihomo-dash.panel',
|
|
48
55
|
unit: 'mihomo-dash-panel.service',
|
|
49
|
-
|
|
56
|
+
// 版本进 Description:`systemctl status` / `launchctl print` 的第一行就是它,
|
|
57
|
+
// 升级后跑一次 `service install` 即可刷新(定义本来就随安装重写)
|
|
58
|
+
description: `mihomo-dash ${PKG_VERSION} 面板(Web UI + REST 转发)`,
|
|
50
59
|
args: (opts) => ['--port', String(opts.port), '--host', opts.host],
|
|
51
60
|
log: (cliDir) => path.join(cliDir, 'daemon.log'),
|
|
52
61
|
},
|
|
53
62
|
kernel: {
|
|
54
63
|
label: 'com.mihomo-dash.kernel',
|
|
55
64
|
unit: 'mihomo-dash-kernel.service',
|
|
56
|
-
description:
|
|
65
|
+
description: `mihomo-dash ${PKG_VERSION} 自有内核(用配置目录里的 config.yaml)`,
|
|
57
66
|
args: () => [],
|
|
58
67
|
log: (cliDir) => path.join(cliDir, 'kernel.log'),
|
|
59
68
|
},
|
|
@@ -147,6 +156,8 @@ export function renderUnit(job, opts) {
|
|
|
147
156
|
# 作用域:${scope === 'system' ? 'system(/etc/systemd/system,以 root 运行,开机即起)' : 'user(~/.config/systemd/user,登录后启动 or linger)'}
|
|
148
157
|
[Unit]
|
|
149
158
|
Description=${def.description}
|
|
159
|
+
# systemctl status 的 Docs: 行就是它;没有这条时那行是空的
|
|
160
|
+
Documentation=${DOCS_URL}
|
|
150
161
|
After=network-online.target
|
|
151
162
|
|
|
152
163
|
[Service]
|
|
@@ -227,6 +238,8 @@ export function createServiceManager(options = {}) {
|
|
|
227
238
|
const scope = platform === 'linux' ? (options.scope ?? (isRoot ? 'system' : 'user')) : 'user';
|
|
228
239
|
/** systemd 的公共参数:system 作用域不带 `--user` */
|
|
229
240
|
const systemdArgs = scope === 'system' ? [] : ['--user'];
|
|
241
|
+
/** 回显给人看的 systemctl 前缀,必须与 systemdArgs 一致 */
|
|
242
|
+
const systemctlCmd = ['systemctl', ...systemdArgs].join(' ');
|
|
230
243
|
/** launchd 的域:GUI 会话固定在 gui/<uid>,只有 SSH 时会话里退到 user/<uid> */
|
|
231
244
|
const domains = [`gui/${uid}`, `user/${uid}`];
|
|
232
245
|
const dir = serviceDir({ platform, home, scope, systemDir: options.systemDir });
|
|
@@ -433,7 +446,7 @@ export function createServiceManager(options = {}) {
|
|
|
433
446
|
const stillLoaded = platform === 'darwin' && !!(await loadedDomain(job));
|
|
434
447
|
if (platform === 'linux') {
|
|
435
448
|
const r = await run('systemctl', [...systemdArgs, 'disable', jobOf(job).unit]);
|
|
436
|
-
if (r.ok) actions.push(
|
|
449
|
+
if (r.ok) actions.push(`${systemctlCmd} disable ${jobOf(job).unit}`);
|
|
437
450
|
else if (r.stderr && !/not loaded|does not exist|No such file/i.test(r.stderr)) {
|
|
438
451
|
errors.push(`${job}: ${r.stderr.trim()}`);
|
|
439
452
|
}
|
|
@@ -541,7 +554,7 @@ export function createServiceManager(options = {}) {
|
|
|
541
554
|
else errors.push(`${j}: ${r.stderr.trim() || 'launchctl kickstart 失败'}`);
|
|
542
555
|
} else {
|
|
543
556
|
const r = await run('systemctl', [...systemdArgs, 'start', jobOf(j).unit]);
|
|
544
|
-
if (r.ok) started.push(
|
|
557
|
+
if (r.ok) started.push(`${systemctlCmd} start ${jobOf(j).unit}`);
|
|
545
558
|
else errors.push(`${j}: ${r.stderr.trim() || 'systemctl start 失败'}`);
|
|
546
559
|
}
|
|
547
560
|
}
|
|
@@ -107,7 +107,10 @@ test('plist:路径里的 XML 特殊字符会被转义', () => {
|
|
|
107
107
|
test('systemd 单元:ExecStart 固定 argv、Restart=no、日志 append', () => {
|
|
108
108
|
const unit = renderUnit('panel', OPTS());
|
|
109
109
|
assert.match(unit, /^# 由 `mihomo-dash service install` 生成/m);
|
|
110
|
-
|
|
110
|
+
// 版本进 Description:`systemctl status` 第一行就能看到装的是哪一版
|
|
111
|
+
assert.match(unit, /Description=mihomo-dash \d+\.\d+\.\d+ 面板/);
|
|
112
|
+
// `systemctl status` 的 `Docs:` 行来自 Documentation=
|
|
113
|
+
assert.match(unit, /^Documentation=https:\/\/github\.com\/lancewu602\/mihomo-dash$/m);
|
|
111
114
|
assert.match(
|
|
112
115
|
unit,
|
|
113
116
|
/ExecStart=\/usr\/local\/bin\/node \/opt\/mihomo-dash\/server\/src\/index\.js --port 8981 --host 127\.0\.0\.1/,
|
|
@@ -252,6 +255,36 @@ test('Linux 安装/卸载:daemon-reload + enable --now / disable(不 --now
|
|
|
252
255
|
assert.ok(!calls.some((c) => c.includes('--now') && c.includes('disable')));
|
|
253
256
|
});
|
|
254
257
|
|
|
258
|
+
test('Linux system 作用域:回显的动作命令不带 --user', async () => {
|
|
259
|
+
const { run, calls } = stubRun();
|
|
260
|
+
// system 作用域默认写 /etc(测试里换成临时目录,别碰本机)
|
|
261
|
+
const systemDir = path.join(tmpDir, 'etc-systemd');
|
|
262
|
+
const svc = createServiceManager({
|
|
263
|
+
run,
|
|
264
|
+
platform: 'linux',
|
|
265
|
+
scope: 'system',
|
|
266
|
+
systemDir,
|
|
267
|
+
home,
|
|
268
|
+
cliDir,
|
|
269
|
+
});
|
|
270
|
+
await svc.install({ port: 8982, host: '0.0.0.0' });
|
|
271
|
+
// 真正执行的命令本来就不带 --user;回显文案以前写死了 --user,照着抄会失败
|
|
272
|
+
assert.ok(calls.some((c) => c.join(' ') === 'systemctl enable --now mihomo-dash-panel.service'));
|
|
273
|
+
|
|
274
|
+
const started = await svc.start();
|
|
275
|
+
assert.deepEqual(started.started, [
|
|
276
|
+
'systemctl start mihomo-dash-panel.service',
|
|
277
|
+
'systemctl start mihomo-dash-kernel.service',
|
|
278
|
+
]);
|
|
279
|
+
|
|
280
|
+
const res = await svc.uninstall();
|
|
281
|
+
assert.deepEqual(res.actions, [
|
|
282
|
+
'systemctl disable mihomo-dash-panel.service',
|
|
283
|
+
'systemctl disable mihomo-dash-kernel.service',
|
|
284
|
+
]);
|
|
285
|
+
assert.deepEqual(res.errors, []);
|
|
286
|
+
});
|
|
287
|
+
|
|
255
288
|
test('Linux 安装:manualRunning 的 job 只 enable(不 --now),不拉第二个实例', async () => {
|
|
256
289
|
const { run, calls } = stubRun();
|
|
257
290
|
const svc = createServiceManager({ run, platform: 'linux', home, cliDir });
|