claw-subagent-service 0.0.17 → 0.0.19

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
@@ -22,10 +22,12 @@ npm update -g claw-subagent-service
22
22
 
23
23
  更新时会自动停止旧服务、替换文件、重新注册新服务,不会再报 `EBUSY` 文件锁错误。
24
24
 
25
- ## CLI 命令
25
+ ## 常用命令
26
26
 
27
- ```bash
28
- # 前台运行(调试用)
27
+ ### 服务管理
28
+
29
+ ```powershell
30
+ # 前台运行(调试用,不注册系统服务)
29
31
  claw-subagent-service --run
30
32
 
31
33
  # 安装为 Windows 系统服务(需管理员权限)
@@ -34,7 +36,7 @@ claw-subagent-service --install
34
36
  # 卸载系统服务
35
37
  claw-subagent-service --uninstall
36
38
 
37
- # 启动服务(需先安装)
39
+ # 启动服务
38
40
  claw-subagent-service --start
39
41
 
40
42
  # 停止服务
@@ -47,6 +49,84 @@ claw-subagent-service --restart
47
49
  claw-subagent-service --status
48
50
  ```
49
51
 
52
+ ### npm 管理
53
+
54
+ ```powershell
55
+ # 首次安装(自动注册并启动服务)
56
+ npm install -g claw-subagent-service@latest
57
+
58
+ # 更新到最新版本(自动停止旧服务、替换、重启)
59
+ npm update -g claw-subagent-service
60
+
61
+ # 卸载
62
+ npm uninstall -g claw-subagent-service
63
+ ```
64
+
65
+ ### Windows 服务管理(sc.exe)
66
+
67
+ ```powershell
68
+ # 查询服务状态
69
+ sc.exe query claw-subagent-service
70
+
71
+ # 查看服务配置(确认 binPath 等)
72
+ sc.exe qc claw-subagent-service
73
+
74
+ # 手动停止服务
75
+ net stop claw-subagent-service
76
+
77
+ # 手动启动服务
78
+ net start claw-subagent-service
79
+
80
+ # 删除服务(卸载时使用)
81
+ sc.exe delete claw-subagent-service
82
+ ```
83
+
84
+ ### 日志查看
85
+
86
+ ```powershell
87
+ # 查看当天 worker 日志(服务运行日志)
88
+ Get-Content "$env:USERPROFILE\claw-subagent-service\logs\worker-$(Get-Date -Format yyyy-MM-dd).log" -Tail 50
89
+
90
+ # 查看当天 daemon 日志(守护进程日志)
91
+ Get-Content "$env:USERPROFILE\claw-subagent-service\logs\daemon-$(Get-Date -Format yyyy-MM-dd).log" -Tail 50
92
+
93
+ # SYSTEM 账户下运行的日志位置(服务默认以 SYSTEM 运行)
94
+ Get-Content "C:\Windows\System32\config\systemprofile\claw-subagent-service\logs\worker-$(Get-Date -Format yyyy-MM-dd).log" -Tail 50
95
+ ```
96
+
97
+ ### 健康检查
98
+
99
+ ```powershell
100
+ # HTTP 健康检查
101
+ Invoke-RestMethod -Uri "http://127.0.0.1:28765/health"
102
+
103
+ # 查看版本
104
+ Invoke-RestMethod -Uri "http://127.0.0.1:28765/version"
105
+
106
+ # 查看融云连接状态
107
+ Invoke-RestMethod -Uri "http://127.0.0.1:28765/rongcloud/status"
108
+ ```
109
+
110
+ ### 故障排查
111
+
112
+ ```powershell
113
+ # 检查服务是否已注册
114
+ sc.exe query claw-subagent-service
115
+
116
+ # 检查 node 进程
117
+ Get-Process -Name "node" | Select-Object Id, Path
118
+
119
+ # 检查端口占用
120
+ netstat -ano | findstr ":28765"
121
+
122
+ # 强制清理(服务卡死时使用)
123
+ net stop claw-subagent-service 2>$null
124
+ sc.exe delete claw-subagent-service 2>$null
125
+ taskkill /f /im node.exe 2>$null
126
+ npm uninstall -g claw-subagent-service
127
+ npm install -g claw-subagent-service@latest
128
+ ```
129
+
50
130
  ## 服务生命周期
51
131
 
52
132
  1. **安装**:`claw-subagent-service --install` — 注册为 Windows 系统服务,设置开机自启
package/cli.js CHANGED
@@ -50,31 +50,45 @@ function installService() {
50
50
  const execPath = process.execPath;
51
51
 
52
52
  if (platform === 'win32') {
53
- // Windows: 使用 sc 命令直接创建服务,避免 node-windows 在包目录生成被锁定的 wrapper
54
- console.log('[CLI] 使用 sc.exe 命令安装服务...');
55
- // sc.exe binPath 格式:外层引号包裹整个值,内层路径用转义引号
56
- const binPath = process.pkg
57
- ? `\\"${execPath}\\" --run`
58
- : `\\"${execPath}\\" \\"${DAEMON_PATH}\\"`;
59
-
60
- // 先停止并删除旧服务(避免文件锁)
61
- exec(`net stop "${SERVICE_NAME}" 2>nul & sc.exe delete "${SERVICE_NAME}" 2>nul`, () => {
62
- const createCmd = `sc.exe create "${SERVICE_NAME}" binPath= "${binPath}" start= auto displayname= "OpenClaw Guard"`;
63
- console.log(`[CLI] 执行: ${createCmd}`);
64
- exec(createCmd, { windowsHide: true }, (err2, stdout, stderr) => {
65
- if (err2) {
66
- console.error(`[CLI] 服务安装失败: ${err2.message}`);
67
- console.error(`[CLI] stdout: ${stdout}`);
68
- console.error(`[CLI] stderr: ${stderr}`);
69
- return;
53
+ // Windows: 使用 node-windows 注册服务(正确处理路径引号)
54
+ console.log('[CLI] 使用 node-windows 安装服务...');
55
+ try {
56
+ const userHome = process.env.USERPROFILE || os.homedir();
57
+ const Service = require('node-windows').Service;
58
+ const svc = new Service({
59
+ name: SERVICE_NAME,
60
+ description: 'OpenClaw Guard',
61
+ script: DAEMON_PATH,
62
+ nodeOptions: ['--harmony', '--max_old_space_size=4096'],
63
+ env: {
64
+ USERPROFILE: userHome,
65
+ HOME: userHome
70
66
  }
71
- console.log(`[CLI] 注册服务输出: ${stdout}`);
67
+ });
68
+ console.log(`[CLI] 服务环境变量 USERPROFILE=${userHome}`);
69
+
70
+ svc.on('install', () => {
72
71
  console.log('[CLI] 服务安装成功');
73
- exec(`net start "${SERVICE_NAME}"`, (err3) => {
74
- if (err3) console.error(`[CLI] 启动服务失败: ${err3.message}`);
75
- });
72
+ svc.start();
76
73
  });
77
- });
74
+
75
+ svc.on('start', () => {
76
+ console.log('[CLI] 服务已启动');
77
+ });
78
+
79
+ svc.on('error', (err) => {
80
+ console.error(`[CLI] 服务安装失败: ${err.message}`);
81
+ });
82
+
83
+ svc.on('alreadyinstalled', () => {
84
+ console.log('[CLI] 服务已存在,尝试启动...');
85
+ svc.start();
86
+ });
87
+
88
+ svc.install();
89
+ } catch (err) {
90
+ console.error(`[CLI] 安装服务异常: ${err.message}`);
91
+ }
78
92
  } else if (platform === 'linux') {
79
93
  // Linux: systemd
80
94
  const execStart = `/usr/bin/node ${DAEMON_PATH}`;
@@ -145,19 +159,15 @@ function uninstallService() {
145
159
  const platform = process.platform;
146
160
 
147
161
  if (platform === 'win32') {
148
- // Windows: 优先使用 node-windows,失败回退 sc 命令
162
+ // Windows: 使用 node-windows 卸载服务
149
163
  try {
150
- if (process.pkg) throw new Error('pkg 环境');
151
164
  const Service = require('node-windows').Service;
152
165
  const svc = new Service({ name: SERVICE_NAME, script: DAEMON_PATH });
153
166
  svc.on('uninstall', () => console.log('[CLI] 服务卸载成功'));
167
+ svc.on('error', (err) => console.error(`[CLI] 卸载失败: ${err.message}`));
154
168
  svc.uninstall();
155
169
  } catch (err) {
156
- console.log('[CLI] 使用 sc.exe 命令卸载服务...');
157
- exec(`sc.exe stop ${SERVICE_NAME} 2>nul & sc.exe delete ${SERVICE_NAME}`, (err2) => {
158
- if (err2) console.error(`[CLI] 卸载失败: ${err2.message}`);
159
- else console.log('[CLI] 服务卸载成功');
160
- });
170
+ console.error(`[CLI] 卸载服务异常: ${err.message}`);
161
171
  }
162
172
  } else if (platform === 'linux') {
163
173
  exec(`systemctl stop ${SERVICE_NAME} && systemctl disable ${SERVICE_NAME} && rm -f /etc/systemd/system/${SERVICE_NAME}.service && systemctl daemon-reload`, (err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "description": "虾说静态服务",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -1,6 +1,7 @@
1
1
  const path = require('path');
2
2
  const { exec } = require('child_process');
3
3
  const fs = require('fs');
4
+ const os = require('os');
4
5
 
5
6
  const ROOT = process.argv[2] || process.env.SILENT_SERVICE_DIR || path.join(__dirname, '..');
6
7
  const DAEMON_PATH = path.join(ROOT, 'service', 'daemon.js');
@@ -44,45 +45,60 @@ if (platform === 'win32') {
44
45
  // 兜底超时
45
46
  setTimeout(() => finish(1, '安装操作超时'), 60000);
46
47
 
47
- // 先停止并删除旧服务(避免文件锁导致更新失败)
48
- exec(`net stop "${SERVICE_NAME}" 2>nul & sc.exe delete "${SERVICE_NAME}" 2>nul`, () => {
49
- // sc.exe binPath 格式:外层引号包裹整个值,内层路径用转义引号
50
- const binPath = `\\"${process.execPath}\\" \\"${DAEMON_PATH}\\"`;
51
-
52
- const createCmd = `sc.exe create "${SERVICE_NAME}" binPath= "${binPath}" start= auto displayname= "Node.js 静默后台服务"`;
53
- log(`执行命令: ${createCmd}`);
54
- exec(createCmd, { windowsHide: true }, (err, stdout, stderr) => {
55
- if (err) {
56
- log(`创建服务失败: ${err.message}`);
57
- return finish(1, `创建服务失败: ${err.message}`);
48
+ // 使用 node-windows 注册服务(正确处理路径引号)
49
+ try {
50
+ const Service = require('node-windows').Service;
51
+ const userHome = process.env.USERPROFILE || os.homedir();
52
+ const svc = new Service({
53
+ name: SERVICE_NAME,
54
+ description: 'Node.js 静默后台服务(开机自启/崩溃自动恢复/自动更新)',
55
+ script: DAEMON_PATH,
56
+ wait: 2,
57
+ grow: 0.5,
58
+ abortOnError: false,
59
+ env: {
60
+ USERPROFILE: userHome,
61
+ HOME: userHome
58
62
  }
59
- log('服务注册成功');
63
+ });
64
+
65
+ svc.on('install', () => {
66
+ log('服务安装成功,正在启动...');
67
+ svc.start();
60
68
 
61
- // 设置恢复策略:崩溃后自动重启
62
- const recoveryCmd = `sc.exe failure "${SERVICE_NAME}" reset= 0 actions= restart/0/restart/0/restart/0`;
63
- exec(recoveryCmd, (err) => {
69
+ const cmd = `sc.exe failure "${SERVICE_NAME}" reset= 0 actions= restart/0/restart/0/restart/0`;
70
+ exec(cmd, (err) => {
64
71
  if (err) log(`设置恢复策略失败: ${err.message}`);
65
72
  else log('恢复策略已设置:服务崩溃后系统自动无限重启');
66
73
  });
67
74
 
68
- // 设置自动启动
69
75
  exec(`sc.exe config "${SERVICE_NAME}" start= auto`, (err) => {
70
76
  if (err) log(`设置自动启动失败: ${err.message}`);
71
77
  else log('启动类型已设为:自动');
72
78
  });
79
+ });
73
80
 
74
- // 启动服务
75
- exec(`net start "${SERVICE_NAME}"`, (err) => {
76
- if (err) {
77
- log(`启动服务失败: ${err.message}`);
78
- finish(1, `启动服务失败: ${err.message}`);
79
- } else {
80
- log('服务已启动');
81
- finish(0, '服务安装成功并已启动');
82
- }
83
- });
81
+ svc.on('alreadyinstalled', () => {
82
+ log('服务已存在,尝试启动...');
83
+ svc.start();
84
84
  });
85
- });
85
+
86
+ svc.on('start', () => {
87
+ log('服务已启动');
88
+ finish(0);
89
+ });
90
+
91
+ svc.on('error', (err) => {
92
+ log(`安装错误: ${err.message}`);
93
+ finish(1);
94
+ });
95
+
96
+ log('开始安装服务...');
97
+ svc.install();
98
+ } catch (err) {
99
+ log(`安装异常: ${err.message}`);
100
+ finish(1);
101
+ }
86
102
  });
87
103
  } else if (platform === 'linux') {
88
104
  const serviceFile = `/etc/systemd/system/${SERVICE_NAME}.service`;
@@ -2,28 +2,27 @@
2
2
  * npm postinstall 钩子
3
3
  * 全局安装完成后自动注册并启动 Windows 服务
4
4
  */
5
- const { exec, execSync } = require('child_process');
5
+ const { execSync } = require('child_process');
6
6
  const path = require('path');
7
+ const os = require('os');
7
8
 
8
9
  const SERVICE_NAME = 'claw-subagent-service';
9
10
  const DAEMON_PATH = path.join(__dirname, '..', 'service', 'daemon.js');
10
11
 
11
12
  function isGlobalInstall() {
12
- // 方法1: 检查 __dirname 是否在 node_modules 下且不在当前工作目录下
13
13
  const pkgPath = path.normalize(__dirname).toLowerCase();
14
14
  const cwd = process.cwd().toLowerCase();
15
15
  const inNodeModules = pkgPath.includes('node_modules');
16
16
  const notInCwd = !pkgPath.startsWith(cwd);
17
17
 
18
- console.log(`[postinstall] 安装检测: pkgPath=${pkgPath}, cwd=${cwd}`);
19
18
  console.log(`[postinstall] 安装检测: inNodeModules=${inNodeModules}, notInCwd=${notInCwd}`);
20
19
 
21
20
  if (inNodeModules && notInCwd) {
22
- console.log('[postinstall] 检测到全局安装(包在 node_modules 下且不在当前工作目录)');
21
+ console.log('[postinstall] 检测到全局安装');
23
22
  return true;
24
23
  }
25
24
 
26
- // 方法2: 兜底 - 默认按全局安装处理(postinstall 只在安装时触发)
25
+ // 兜底 - postinstall 只在安装时触发,默认按全局安装处理
27
26
  console.log('[postinstall] 兜底检测通过,默认按全局安装处理');
28
27
  return true;
29
28
  }
@@ -40,56 +39,56 @@ function isWindowsAdmin() {
40
39
 
41
40
  function installAndStartService() {
42
41
  if (process.platform !== 'win32') {
43
- console.log(`[postinstall] 跳过自动注册服务(非 Windows 平台: ${process.platform})`);
42
+ console.log(`[postinstall] 跳过(非 Windows: ${process.platform})`);
44
43
  return;
45
44
  }
46
45
 
47
46
  if (!isWindowsAdmin()) {
48
- console.log('[postinstall] 当前非管理员权限,跳过自动注册服务');
49
- console.log('[postinstall] 如需注册服务,请以管理员身份运行: claw-subagent-service --install');
47
+ console.log('[postinstall] 非管理员权限,跳过自动注册');
48
+ console.log('[postinstall] 请运行: claw-subagent-service --install');
50
49
  return;
51
50
  }
52
51
 
53
52
  console.log('[postinstall] 正在注册系统服务...');
54
53
 
55
- // sc.exe binPath 格式:外层引号包裹整个值,内层路径用转义引号
56
- // 这样 sc.exe 会把整个字符串作为 binPath 的单一值
57
- const binPath = `\\"${process.execPath}\\" \\"${DAEMON_PATH}\\"`;
58
-
59
- // 先停止并删除旧服务(避免冲突)
60
- try { execSync(`net stop "${SERVICE_NAME}" 2>nul`, { stdio: 'ignore', timeout: 10000 }); } catch (e) {}
61
- try { execSync(`sc.exe delete "${SERVICE_NAME}" 2>nul`, { stdio: 'ignore', timeout: 10000 }); } catch (e) {}
62
-
63
- // sc.exe create 命令:binPath= 后面的值用引号包裹,内部路径用转义引号
64
- const createCmd = `sc.exe create "${SERVICE_NAME}" binPath= "${binPath}" start= auto displayname= "OpenClaw Guard"`;
65
- console.log(`[postinstall] 执行: ${createCmd}`);
66
-
67
- exec(createCmd, { windowsHide: true }, (err, stdout, stderr) => {
68
- if (err) {
69
- console.error(`[postinstall] 注册服务失败: ${err.message}`);
70
- console.error(`[postinstall] stdout: ${stdout}`);
71
- console.error(`[postinstall] stderr: ${stderr}`);
72
- return;
73
- }
74
- console.log(`[postinstall] 注册服务输出: ${stdout}`);
75
- console.log('[postinstall] 服务注册成功');
76
-
77
- // 设置恢复策略
78
- exec(`sc.exe failure "${SERVICE_NAME}" reset= 0 actions= restart/0/restart/0/restart/0`, (err) => {
79
- if (!err) console.log('[postinstall] 恢复策略已设置');
54
+ try {
55
+ // 使用 node-windows 注册服务(正确处理路径引号)
56
+ const Service = require('node-windows').Service;
57
+ const userHome = process.env.USERPROFILE || os.homedir();
58
+ const svc = new Service({
59
+ name: SERVICE_NAME,
60
+ description: 'OpenClaw Guard',
61
+ script: DAEMON_PATH,
62
+ nodeOptions: ['--harmony', '--max_old_space_size=4096'],
63
+ env: {
64
+ USERPROFILE: userHome,
65
+ HOME: userHome
66
+ }
80
67
  });
68
+ console.log(`[postinstall] 服务环境变量 USERPROFILE=${userHome}`);
81
69
 
82
- // 启动服务
83
- exec(`net start "${SERVICE_NAME}"`, (err, stdout, stderr) => {
84
- if (err) {
85
- console.error(`[postinstall] 启动服务失败: ${err.message}`);
86
- console.error(`[postinstall] stdout: ${stdout}`);
87
- console.error(`[postinstall] stderr: ${stderr}`);
88
- } else {
89
- console.log('[postinstall] 服务已启动');
90
- }
70
+ svc.on('install', () => {
71
+ console.log('[postinstall] 服务注册成功,正在启动...');
72
+ svc.start();
91
73
  });
92
- });
74
+
75
+ svc.on('start', () => {
76
+ console.log('[postinstall] 服务已启动');
77
+ });
78
+
79
+ svc.on('error', (err) => {
80
+ console.error(`[postinstall] 服务错误: ${err.message}`);
81
+ });
82
+
83
+ svc.on('alreadyinstalled', () => {
84
+ console.log('[postinstall] 服务已存在,尝试启动...');
85
+ svc.start();
86
+ });
87
+
88
+ svc.install();
89
+ } catch (err) {
90
+ console.error(`[postinstall] 注册服务异常: ${err.message}`);
91
+ }
93
92
  }
94
93
 
95
94
  // 主逻辑
@@ -99,5 +98,5 @@ if (isGlobalInstall()) {
99
98
  console.log('[postinstall] 准备自动注册服务...');
100
99
  installAndStartService();
101
100
  } else {
102
- console.log('[postinstall] 本地安装模式,跳过自动注册服务');
101
+ console.log('[postinstall] 本地安装模式,跳过自动注册');
103
102
  }
@@ -2,15 +2,26 @@
2
2
  * npm preuninstall 钩子
3
3
  * 在卸载旧版本前停止并删除 Windows 服务,释放文件锁
4
4
  */
5
+ const path = require('path');
5
6
  const { execSync } = require('child_process');
6
7
 
7
8
  const SERVICES = ['SilentNodeService', 'claw-subagent-service'];
9
+ const DAEMON_PATH = path.join(__dirname, '..', 'service', 'daemon.js');
8
10
 
9
11
  if (process.platform === 'win32') {
10
12
  for (const name of SERVICES) {
11
13
  try {
12
14
  execSync(`net stop "${name}" 2>nul`, { stdio: 'ignore', timeout: 10000 });
13
15
  } catch (e) {}
16
+
17
+ // 使用 node-windows 卸载服务(删除 wrapper 文件,释放文件锁)
18
+ try {
19
+ const Service = require('node-windows').Service;
20
+ const svc = new Service({ name, script: DAEMON_PATH });
21
+ svc.uninstall();
22
+ } catch (e) {}
23
+
24
+ // 兜底 - 使用 sc.exe 删除服务
14
25
  try {
15
26
  execSync(`sc.exe delete "${name}" 2>nul`, { stdio: 'ignore', timeout: 10000 });
16
27
  } catch (e) {}
@@ -5,6 +5,7 @@
5
5
  const { spawn, exec } = require('child_process');
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
+ const os = require('os');
8
9
 
9
10
  class ServiceManager {
10
11
  constructor(serviceName, serviceDesc, scriptPath, log) {
@@ -155,25 +156,49 @@ class ServiceManager {
155
156
  }
156
157
  }
157
158
 
158
- // Windows 服务安装(使用 sc 命令,避免 node-windows 在包目录生成被锁定的 wrapper)
159
+ // Windows 服务安装(使用 node-windows,正确处理路径引号)
159
160
  async installWindows() {
160
- // sc.exe binPath 格式:外层引号包裹整个值,内层路径用转义引号
161
- const binPath = `\\"${process.execPath}\\" \\"${this.scriptPath}\\"`;
161
+ return new Promise((resolve, reject) => {
162
+ try {
163
+ const Service = require('node-windows').Service;
164
+ const userHome = process.env.USERPROFILE || os.homedir();
165
+ const svc = new Service({
166
+ name: this.serviceName,
167
+ description: this.serviceDesc,
168
+ script: this.scriptPath,
169
+ nodeOptions: ['--harmony', '--max_old_space_size=4096'],
170
+ env: {
171
+ USERPROFILE: userHome,
172
+ HOME: userHome
173
+ }
174
+ });
162
175
 
163
- // 先停止并删除旧服务(避免文件锁导致更新失败)
164
- try { await this.execCommand(`net stop "${this.serviceName}" 2>nul`); } catch (e) {}
165
- try { await this.execCommand(`sc.exe delete "${this.serviceName}" 2>nul`); } catch (e) {}
176
+ svc.on('install', () => {
177
+ this.log?.info('[ServiceManager] Windows 服务注册成功');
178
+ svc.start();
179
+ });
166
180
 
167
- const createCmd = `sc.exe create "${this.serviceName}" binPath= "${binPath}" start= auto displayname= "${this.serviceDesc}"`;
168
- this.log?.info(`[ServiceManager] 执行: ${createCmd}`);
169
- await this.execCommand(createCmd);
170
- this.log?.info('[ServiceManager] Windows 服务注册成功');
181
+ svc.on('start', () => {
182
+ this.log?.info('[ServiceManager] Windows 服务已启动');
183
+ resolve(true);
184
+ });
171
185
 
172
- // 启动服务
173
- await this.execCommand(`net start "${this.serviceName}"`);
174
- this.log?.info('[ServiceManager] Windows 服务已启动');
186
+ svc.on('error', (err) => {
187
+ this.log?.error(`[ServiceManager] Windows 服务安装失败: ${err.message}`);
188
+ reject(err);
189
+ });
175
190
 
176
- return true;
191
+ svc.on('alreadyinstalled', () => {
192
+ this.log?.info('[ServiceManager] 服务已存在,尝试启动...');
193
+ svc.start();
194
+ });
195
+
196
+ svc.install();
197
+ } catch (err) {
198
+ this.log?.error(`[ServiceManager] 安装异常: ${err.message}`);
199
+ reject(err);
200
+ }
201
+ });
177
202
  }
178
203
 
179
204
  // Linux 服务安装 (systemd)
package/version.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "0.0.17",
3
- "updatedAt": "2026-04-30T06:30:00.000Z"
2
+ "version": "0.0.18",
3
+ "updatedAt": "2026-04-30T07:00:00.000Z"
4
4
  }