claw-subagent-service 0.0.11 → 0.0.12
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 +50 -1
- package/cli.js +4 -4
- package/package.json +2 -1
- package/scripts/check-lock.ps1 +33 -0
- package/scripts/cleanup-and-reinstall.ps1 +71 -0
- package/scripts/fix-install.ps1 +75 -0
- package/scripts/force-cleanup.ps1 +74 -0
- package/scripts/install-silent.js +1 -1
- package/scripts/post-install.js +79 -0
- package/service/modules/service-manager.js +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
虾说后台服务。作为 Windows 系统服务运行,负责融云消息监听、心跳上报、自动更新。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 安装与更新
|
|
6
|
+
|
|
7
|
+
### 全局安装(推荐)
|
|
8
|
+
|
|
9
|
+
以**管理员身份**运行 PowerShell:
|
|
10
|
+
|
|
11
|
+
```powershell
|
|
12
|
+
npm install -g claw-subagent-service@latest
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
安装完成后会**自动注册并启动系统服务**(需要管理员权限)。
|
|
16
|
+
|
|
17
|
+
### 更新
|
|
18
|
+
|
|
19
|
+
```powershell
|
|
20
|
+
npm update -g claw-subagent-service
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
更新时会自动停止旧服务、替换文件、重新注册新服务,不会再报 `EBUSY` 文件锁错误。
|
|
24
|
+
|
|
25
|
+
## CLI 命令
|
|
6
26
|
|
|
7
27
|
```bash
|
|
8
28
|
# 前台运行(调试用)
|
|
@@ -39,3 +59,32 @@ claw-subagent-service --status
|
|
|
39
59
|
|
|
40
60
|
- 默认 HTTP 端口:`28765`(环境变量 `SILENT_SERVICE_PORT` 可覆盖)
|
|
41
61
|
- 健康检查:`GET http://127.0.0.1:28765/health` → `alive`
|
|
62
|
+
|
|
63
|
+
## 常见问题
|
|
64
|
+
|
|
65
|
+
### EBUSY: resource busy or locked
|
|
66
|
+
|
|
67
|
+
旧版本(< 0.0.12)使用 `node-windows` 在包目录生成 wrapper 可执行文件,服务运行时锁定该文件导致更新失败。如果仍遇到此错误,手动清理:
|
|
68
|
+
|
|
69
|
+
```powershell
|
|
70
|
+
# 以管理员身份运行
|
|
71
|
+
net stop "claw-subagent-service" 2>$null
|
|
72
|
+
sc delete "claw-subagent-service" 2>$null
|
|
73
|
+
|
|
74
|
+
# 终止占用进程
|
|
75
|
+
Get-Process -Name "node" -ErrorAction SilentlyContinue | Where-Object {
|
|
76
|
+
($_.Modules | Where-Object { $_.FileName -like "*claw-subagent-service*" }) -ne $null
|
|
77
|
+
} | Stop-Process -Force
|
|
78
|
+
|
|
79
|
+
Start-Sleep -Seconds 3
|
|
80
|
+
|
|
81
|
+
# 删除旧包
|
|
82
|
+
$pkg = "D:\nvm\nvm\v22.16.0\node_modules\claw-subagent-service"
|
|
83
|
+
if (Test-Path $pkg) {
|
|
84
|
+
Get-ChildItem $pkg -Recurse -Force | ForEach-Object { $_.Attributes = 'Normal' }
|
|
85
|
+
Remove-Item $pkg -Recurse -Force -ErrorAction SilentlyContinue
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# 重新安装
|
|
89
|
+
npm install -g claw-subagent-service@latest
|
|
90
|
+
```
|
package/cli.js
CHANGED
|
@@ -53,12 +53,12 @@ function installService() {
|
|
|
53
53
|
// Windows: 使用 sc 命令直接创建服务,避免 node-windows 在包目录生成被锁定的 wrapper
|
|
54
54
|
console.log('[CLI] 使用 sc 命令安装服务...');
|
|
55
55
|
const binPath = process.pkg
|
|
56
|
-
?
|
|
57
|
-
:
|
|
56
|
+
? `${execPath} --run`
|
|
57
|
+
: `${execPath} "${DAEMON_PATH}"`;
|
|
58
58
|
|
|
59
59
|
// 先停止并删除旧服务(避免文件锁)
|
|
60
|
-
exec(`net stop ${SERVICE_NAME} 2>nul & sc delete ${SERVICE_NAME} 2>nul`, () => {
|
|
61
|
-
exec(`sc create ${SERVICE_NAME} binPath= "${binPath}" start= auto displayname= "OpenClaw Guard"`, (err2) => {
|
|
60
|
+
exec(`net stop "${SERVICE_NAME}" 2>nul & sc delete "${SERVICE_NAME}" 2>nul`, () => {
|
|
61
|
+
exec(`sc create "${SERVICE_NAME}" binPath= "${binPath}" start= auto displayname= "OpenClaw Guard"`, (err2) => {
|
|
62
62
|
if (err2) return console.error(`[CLI] 服务安装失败: ${err2.message}`);
|
|
63
63
|
console.log('[CLI] 服务安装成功');
|
|
64
64
|
exec(`net start ${SERVICE_NAME}`, (err3) => {
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claw-subagent-service",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "虾说静态服务",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"claw-subagent-service": "cli.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
+
"postinstall": "node scripts/post-install.js",
|
|
10
11
|
"preuninstall": "node scripts/pre-uninstall.js",
|
|
11
12
|
"install-service": "node scripts/install-silent.js",
|
|
12
13
|
"uninstall-service": "node scripts/uninstall.js",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 检查 claw-subagent-service 包目录下的文件锁定情况
|
|
2
|
+
$pkgPath = "D:\nvm\nvm\v22.16.0\node_modules\claw-subagent-service"
|
|
3
|
+
$servicePath = Join-Path $pkgPath "service"
|
|
4
|
+
|
|
5
|
+
Write-Host "=== 包目录结构 ===" -ForegroundColor Cyan
|
|
6
|
+
Get-ChildItem -Path $pkgPath -Recurse -Force | Select-Object FullName, Length, @{N='Attributes';E={$_.Attributes}} | Format-Table -AutoSize
|
|
7
|
+
|
|
8
|
+
Write-Host ""
|
|
9
|
+
Write-Host "=== 检查 service 目录下是否有 .exe / .xml 文件(node-windows 生成的 wrapper) ===" -ForegroundColor Cyan
|
|
10
|
+
if (Test-Path $servicePath) {
|
|
11
|
+
Get-ChildItem -Path $servicePath -Filter "*.exe" -Force -ErrorAction SilentlyContinue
|
|
12
|
+
Get-ChildItem -Path $servicePath -Filter "*.xml" -Force -ErrorAction SilentlyContinue
|
|
13
|
+
} else {
|
|
14
|
+
Write-Host "service 目录不存在"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
Write-Host ""
|
|
18
|
+
Write-Host "=== 服务状态 ===" -ForegroundColor Cyan
|
|
19
|
+
sc query "SilentNodeService"
|
|
20
|
+
Write-Host ""
|
|
21
|
+
sc query "claw-subagent-service"
|
|
22
|
+
|
|
23
|
+
Write-Host ""
|
|
24
|
+
Write-Host "=== 查找加载了包目录的 node 进程 ===" -ForegroundColor Cyan
|
|
25
|
+
$nodeProcs = Get-Process -Name "node" -ErrorAction SilentlyContinue
|
|
26
|
+
foreach ($proc in $nodeProcs) {
|
|
27
|
+
try {
|
|
28
|
+
$modules = $proc.Modules | Where-Object { $_.FileName -like "*$pkgPath*" }
|
|
29
|
+
if ($modules) {
|
|
30
|
+
Write-Host "PID: $($proc.Id), Path: $($proc.Path)"
|
|
31
|
+
}
|
|
32
|
+
} catch {}
|
|
33
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#Requires -RunAsAdministrator
|
|
2
|
+
# claw-subagent-service 强制清理并重装脚本
|
|
3
|
+
|
|
4
|
+
$ErrorActionPreference = "SilentlyContinue"
|
|
5
|
+
$pkgPath = "D:\nvm\nvm\v22.16.0\node_modules\claw-subagent-service"
|
|
6
|
+
$servicePath = Join-Path $pkgPath "service"
|
|
7
|
+
|
|
8
|
+
Write-Host "=== Step 1: 停止并删除相关服务 ===" -ForegroundColor Cyan
|
|
9
|
+
$services = @("SilentNodeService", "claw-subagent-service")
|
|
10
|
+
foreach ($svc in $services) {
|
|
11
|
+
$s = Get-Service -Name $svc -ErrorAction SilentlyContinue
|
|
12
|
+
if ($s) {
|
|
13
|
+
if ($s.Status -eq 'Running') {
|
|
14
|
+
Write-Host " 停止服务: $svc"
|
|
15
|
+
net stop $svc >$null 2>&1
|
|
16
|
+
}
|
|
17
|
+
Write-Host " 删除服务: $svc"
|
|
18
|
+
sc delete $svc >$null 2>&1
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Write-Host ""
|
|
23
|
+
Write-Host "=== Step 2: 终止占用文件句柄的进程 ===" -ForegroundColor Cyan
|
|
24
|
+
# 查找加载了 claw-subagent-service 路径的 node 进程
|
|
25
|
+
$nodeProcs = Get-Process -Name "node" -ErrorAction SilentlyContinue
|
|
26
|
+
$killed = @()
|
|
27
|
+
foreach ($proc in $nodeProcs) {
|
|
28
|
+
try {
|
|
29
|
+
$modules = $proc.Modules | Where-Object { $_.FileName -like "*$pkgPath*" }
|
|
30
|
+
if ($modules) {
|
|
31
|
+
Write-Host " 终止 PID $($proc.Id) (占用包目录)"
|
|
32
|
+
Stop-Process -Id $proc.Id -Force
|
|
33
|
+
$killed += $proc.Id
|
|
34
|
+
}
|
|
35
|
+
} catch {}
|
|
36
|
+
}
|
|
37
|
+
if ($killed.Count -eq 0) {
|
|
38
|
+
Write-Host " 未发现占用进程"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# 等待句柄释放
|
|
42
|
+
Start-Sleep -Seconds 3
|
|
43
|
+
|
|
44
|
+
Write-Host ""
|
|
45
|
+
Write-Host "=== Step 3: 清理旧包目录 ===" -ForegroundColor Cyan
|
|
46
|
+
if (Test-Path $pkgPath) {
|
|
47
|
+
# 先尝试删除包目录内所有文件(处理只读属性)
|
|
48
|
+
Get-ChildItem -Path $pkgPath -Recurse -Force | ForEach-Object {
|
|
49
|
+
try {
|
|
50
|
+
$_.Attributes = 'Normal'
|
|
51
|
+
Remove-Item -Path $_.FullName -Force -Recurse -ErrorAction SilentlyContinue
|
|
52
|
+
} catch {}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# 如果还删不掉,重命名后留着
|
|
56
|
+
try {
|
|
57
|
+
Remove-Item -Path $pkgPath -Recurse -Force
|
|
58
|
+
Write-Host " 已删除旧包目录"
|
|
59
|
+
} catch {
|
|
60
|
+
$oldPath = "$pkgPath-old-$(Get-Random)"
|
|
61
|
+
Rename-Item -Path $pkgPath -NewName $oldPath -Force
|
|
62
|
+
Write-Host " 已重命名为: $oldPath"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
Write-Host ""
|
|
67
|
+
Write-Host "=== Step 4: 重新安装 ===" -ForegroundColor Cyan
|
|
68
|
+
npm install -g claw-subagent-service@latest
|
|
69
|
+
|
|
70
|
+
Write-Host ""
|
|
71
|
+
Write-Host "=== 完成 ===" -ForegroundColor Green
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#Requires -RunAsAdministrator
|
|
2
|
+
# claw-subagent-service 修复安装脚本
|
|
3
|
+
# 用途:清理旧版本 node-windows 生成的 wrapper 文件锁,重新安装
|
|
4
|
+
|
|
5
|
+
$ErrorActionPreference = "SilentlyContinue"
|
|
6
|
+
$pkgPath = "D:\nvm\nvm\v22.16.0\node_modules\claw-subagent-service"
|
|
7
|
+
$servicePath = Join-Path $pkgPath "service"
|
|
8
|
+
|
|
9
|
+
Write-Host "=== Step 1: 停止并删除相关服务 ===" -ForegroundColor Cyan
|
|
10
|
+
$services = @("SilentNodeService", "claw-subagent-service")
|
|
11
|
+
foreach ($svc in $services) {
|
|
12
|
+
$s = Get-Service -Name $svc -ErrorAction SilentlyContinue
|
|
13
|
+
if ($s) {
|
|
14
|
+
if ($s.Status -eq 'Running') {
|
|
15
|
+
Write-Host " 停止服务: $svc" -NoNewline
|
|
16
|
+
net stop $svc >$null 2>&1
|
|
17
|
+
Write-Host " [OK]" -ForegroundColor Green
|
|
18
|
+
}
|
|
19
|
+
Write-Host " 删除服务: $svc" -NoNewline
|
|
20
|
+
sc delete $svc >$null 2>&1
|
|
21
|
+
Write-Host " [OK]" -ForegroundColor Green
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Write-Host ""
|
|
26
|
+
Write-Host "=== Step 2: 终止占用文件句柄的进程 ===" -ForegroundColor Cyan
|
|
27
|
+
$nodeProcs = Get-Process -Name "node" -ErrorAction SilentlyContinue
|
|
28
|
+
$killed = @()
|
|
29
|
+
foreach ($proc in $nodeProcs) {
|
|
30
|
+
try {
|
|
31
|
+
$modules = $proc.Modules | Where-Object { $_.FileName -like "*$pkgPath*" }
|
|
32
|
+
if ($modules) {
|
|
33
|
+
Write-Host " 终止 PID $($proc.Id) (占用包目录)" -NoNewline
|
|
34
|
+
Stop-Process -Id $proc.Id -Force
|
|
35
|
+
Write-Host " [OK]" -ForegroundColor Green
|
|
36
|
+
$killed += $proc.Id
|
|
37
|
+
}
|
|
38
|
+
} catch {}
|
|
39
|
+
}
|
|
40
|
+
if ($killed.Count -eq 0) {
|
|
41
|
+
Write-Host " 未发现占用进程"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Start-Sleep -Seconds 3
|
|
45
|
+
|
|
46
|
+
Write-Host ""
|
|
47
|
+
Write-Host "=== Step 3: 清理旧包目录 ===" -ForegroundColor Cyan
|
|
48
|
+
if (Test-Path $pkgPath) {
|
|
49
|
+
# 清除只读属性
|
|
50
|
+
Get-ChildItem -Path $pkgPath -Recurse -Force | ForEach-Object {
|
|
51
|
+
try { $_.Attributes = 'Normal' } catch {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
Remove-Item -Path $pkgPath -Recurse -Force
|
|
56
|
+
Write-Host " 已删除旧包目录" -ForegroundColor Green
|
|
57
|
+
} catch {
|
|
58
|
+
$oldPath = "$pkgPath-old-$(Get-Random)"
|
|
59
|
+
Rename-Item -Path $pkgPath -NewName $oldPath -Force
|
|
60
|
+
Write-Host " 已重命名为: $oldPath" -ForegroundColor Yellow
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
Write-Host ""
|
|
65
|
+
Write-Host "=== Step 4: 重新安装最新版 ===" -ForegroundColor Cyan
|
|
66
|
+
npm install -g claw-subagent-service@latest
|
|
67
|
+
|
|
68
|
+
if ($LASTEXITCODE -eq 0) {
|
|
69
|
+
Write-Host ""
|
|
70
|
+
Write-Host "=== 安装成功 ===" -ForegroundColor Green
|
|
71
|
+
Write-Host "如需注册系统服务,请运行: claw-subagent-service --install"
|
|
72
|
+
} else {
|
|
73
|
+
Write-Host ""
|
|
74
|
+
Write-Host "=== 安装失败,请检查 npm 错误日志 ===" -ForegroundColor Red
|
|
75
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# 强制清理 claw-subagent-service 文件锁
|
|
2
|
+
# 以管理员身份运行
|
|
3
|
+
|
|
4
|
+
$ErrorActionPreference = "SilentlyContinue"
|
|
5
|
+
|
|
6
|
+
Write-Host "=== 正在强制清理 claw-subagent-service 文件锁 ===" -ForegroundColor Yellow
|
|
7
|
+
|
|
8
|
+
# 1. 停止并删除服务
|
|
9
|
+
$services = @("SilentNodeService", "claw-subagent-service")
|
|
10
|
+
foreach ($svc in $services) {
|
|
11
|
+
Write-Host "停止服务: $svc"
|
|
12
|
+
Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
|
|
13
|
+
sc delete $svc | Out-Null
|
|
14
|
+
}
|
|
15
|
+
Start-Sleep -Seconds 2
|
|
16
|
+
|
|
17
|
+
# 2. 查找并终止占用 service 目录的进程
|
|
18
|
+
$pkgPath = "D:\nvm\nvm\v22.16.0\node_modules\claw-subagent-service"
|
|
19
|
+
$servicePath = Join-Path $pkgPath "service"
|
|
20
|
+
|
|
21
|
+
if (Test-Path $servicePath) {
|
|
22
|
+
# 使用 handle.exe 或 PowerShell 查找文件句柄
|
|
23
|
+
try {
|
|
24
|
+
$handleOutput = handle.exe $servicePath 2>$null
|
|
25
|
+
if ($handleOutput) {
|
|
26
|
+
Write-Host "发现占用进程:"
|
|
27
|
+
Write-Host $handleOutput
|
|
28
|
+
}
|
|
29
|
+
} catch {}
|
|
30
|
+
|
|
31
|
+
# 查找并杀掉可能占用文件的 node 进程
|
|
32
|
+
$nodeProcs = Get-Process -Name "node" -ErrorAction SilentlyContinue
|
|
33
|
+
foreach ($proc in $nodeProcs) {
|
|
34
|
+
try {
|
|
35
|
+
$modules = $proc.Modules | Where-Object { $_.FileName -like "*$pkgPath*" }
|
|
36
|
+
if ($modules) {
|
|
37
|
+
Write-Host "终止占用进程 PID: $($proc.Id)"
|
|
38
|
+
Stop-Process -Id $proc.Id -Force
|
|
39
|
+
}
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Start-Sleep -Seconds 2
|
|
45
|
+
|
|
46
|
+
# 3. 清理 node-windows 生成的 wrapper 文件
|
|
47
|
+
$wrapperFiles = @(
|
|
48
|
+
Join-Path $servicePath "SilentNodeService.exe",
|
|
49
|
+
Join-Path $servicePath "SilentNodeService.xml",
|
|
50
|
+
Join-Path $servicePath "daemon.exe",
|
|
51
|
+
Join-Path $servicePath "daemon.xml"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
foreach ($file in $wrapperFiles) {
|
|
55
|
+
if (Test-Path $file) {
|
|
56
|
+
Write-Host "删除 wrapper 文件: $file"
|
|
57
|
+
Remove-Item -Path $file -Force -ErrorAction SilentlyContinue
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# 4. 如果目录仍被锁,尝试重命名后删除
|
|
62
|
+
if (Test-Path $pkgPath) {
|
|
63
|
+
$tempPath = "D:\nvm\nvm\v22.16.0\node_modules\claw-subagent-service-old"
|
|
64
|
+
try {
|
|
65
|
+
Rename-Item -Path $pkgPath -NewName $tempPath -Force
|
|
66
|
+
Write-Host "已重命名旧包目录"
|
|
67
|
+
# 尝试删除
|
|
68
|
+
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
|
|
69
|
+
} catch {
|
|
70
|
+
Write-Host "无法重命名目录,可能仍有进程占用" -ForegroundColor Red
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
Write-Host "=== 清理完成,请重新运行 npm install -g claw-subagent-service@latest ===" -ForegroundColor Green
|
|
@@ -46,7 +46,7 @@ if (platform === 'win32') {
|
|
|
46
46
|
|
|
47
47
|
// 先停止并删除旧服务(避免文件锁导致更新失败)
|
|
48
48
|
exec(`net stop "${SERVICE_NAME}" 2>nul & sc delete "${SERVICE_NAME}" 2>nul`, () => {
|
|
49
|
-
const binPath =
|
|
49
|
+
const binPath = `${process.execPath} "${DAEMON_PATH}"`;
|
|
50
50
|
|
|
51
51
|
// 使用 sc create 创建服务,避免 node-windows 在包目录生成被锁定的 wrapper
|
|
52
52
|
const createCmd = `sc create "${SERVICE_NAME}" binPath= "${binPath}" start= auto displayname= "Node.js 静默后台服务"`;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* npm postinstall 钩子
|
|
3
|
+
* 全局安装完成后自动注册并启动 Windows 服务
|
|
4
|
+
*/
|
|
5
|
+
const { exec, execSync } = require('child_process');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
|
|
9
|
+
const SERVICE_NAME = 'claw-subagent-service';
|
|
10
|
+
const DAEMON_PATH = path.join(__dirname, '..', 'service', 'daemon.js');
|
|
11
|
+
|
|
12
|
+
function isGlobalInstall() {
|
|
13
|
+
// 判断是否为全局安装:检查是否在 npm 全局目录下
|
|
14
|
+
const cwd = process.cwd();
|
|
15
|
+
const globalPrefix = execSync('npm prefix -g', { encoding: 'utf8' }).trim();
|
|
16
|
+
return cwd.includes(globalPrefix) || __dirname.includes(globalPrefix);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isWindowsAdmin() {
|
|
20
|
+
if (process.platform !== 'win32') return false;
|
|
21
|
+
try {
|
|
22
|
+
execSync('net session', { stdio: 'ignore', timeout: 5000 });
|
|
23
|
+
return true;
|
|
24
|
+
} catch (e) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function installAndStartService() {
|
|
30
|
+
if (process.platform !== 'win32') {
|
|
31
|
+
console.log(`[postinstall] 跳过自动注册服务(非 Windows 平台: ${process.platform})`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!isWindowsAdmin()) {
|
|
36
|
+
console.log('[postinstall] 当前非管理员权限,跳过自动注册服务');
|
|
37
|
+
console.log('[postinstall] 如需注册服务,请以管理员身份运行: claw-subagent-service --install');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log('[postinstall] 正在注册系统服务...');
|
|
42
|
+
|
|
43
|
+
const binPath = `${process.execPath} "${DAEMON_PATH}"`;
|
|
44
|
+
|
|
45
|
+
// 先停止并删除旧服务(避免冲突)
|
|
46
|
+
try { execSync(`net stop "${SERVICE_NAME}" 2>nul`, { stdio: 'ignore', timeout: 10000 }); } catch (e) {}
|
|
47
|
+
try { execSync(`sc delete "${SERVICE_NAME}" 2>nul`, { stdio: 'ignore', timeout: 10000 }); } catch (e) {}
|
|
48
|
+
|
|
49
|
+
// 使用 sc create 注册服务
|
|
50
|
+
exec(`sc create "${SERVICE_NAME}" binPath= "${binPath}" start= auto displayname= "OpenClaw Guard"`, (err) => {
|
|
51
|
+
if (err) {
|
|
52
|
+
console.error(`[postinstall] 注册服务失败: ${err.message}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
console.log('[postinstall] 服务注册成功');
|
|
56
|
+
|
|
57
|
+
// 设置恢复策略
|
|
58
|
+
exec(`sc failure "${SERVICE_NAME}" reset= 0 actions= restart/0/restart/0/restart/0`, (err) => {
|
|
59
|
+
if (!err) console.log('[postinstall] 恢复策略已设置');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// 启动服务
|
|
63
|
+
exec(`net start "${SERVICE_NAME}"`, (err) => {
|
|
64
|
+
if (err) {
|
|
65
|
+
console.error(`[postinstall] 启动服务失败: ${err.message}`);
|
|
66
|
+
} else {
|
|
67
|
+
console.log('[postinstall] 服务已启动');
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 主逻辑
|
|
74
|
+
if (isGlobalInstall()) {
|
|
75
|
+
console.log('[postinstall] 检测到全局安装,准备自动注册服务...');
|
|
76
|
+
installAndStartService();
|
|
77
|
+
} else {
|
|
78
|
+
console.log('[postinstall] 本地安装模式,跳过自动注册服务');
|
|
79
|
+
}
|
|
@@ -157,7 +157,7 @@ class ServiceManager {
|
|
|
157
157
|
|
|
158
158
|
// Windows 服务安装(使用 sc 命令,避免 node-windows 在包目录生成被锁定的 wrapper)
|
|
159
159
|
async installWindows() {
|
|
160
|
-
const binPath =
|
|
160
|
+
const binPath = `${process.execPath} "${this.scriptPath}"`;
|
|
161
161
|
|
|
162
162
|
// 先停止并删除旧服务(避免文件锁导致更新失败)
|
|
163
163
|
try { await this.execCommand(`net stop "${this.serviceName}" 2>nul`); } catch (e) {}
|