@simonyea/holysheep-cli 1.7.33 → 1.7.34
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 +1 -1
- package/src/commands/openclaw.js +172 -0
- package/src/index.js +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simonyea/holysheep-cli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.34",
|
|
4
4
|
"description": "Claude Code/Cursor/Cline API relay for China — ¥1=$1, WeChat/Alipay payment, no credit card, no VPN. One command setup for all AI coding tools.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"openai-china",
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { execSync, spawn, spawnSync } = require('child_process')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const chalk = require('chalk')
|
|
6
|
+
const openclawTool = require('../tools/openclaw')
|
|
7
|
+
const { readBridgeConfig } = require('../tools/openclaw-bridge')
|
|
8
|
+
|
|
9
|
+
const isWin = process.platform === 'win32'
|
|
10
|
+
|
|
11
|
+
function checkBridgeHealth(port) {
|
|
12
|
+
try {
|
|
13
|
+
execSync(
|
|
14
|
+
isWin
|
|
15
|
+
? `powershell -NonInteractive -Command "try{(Invoke-WebRequest -Uri http://127.0.0.1:${port}/health -TimeoutSec 1 -UseBasicParsing).StatusCode}catch{exit 1}"`
|
|
16
|
+
: `curl -sf http://127.0.0.1:${port}/health -o /dev/null --max-time 1`,
|
|
17
|
+
{ stdio: 'ignore', timeout: 3000 }
|
|
18
|
+
)
|
|
19
|
+
return true
|
|
20
|
+
} catch {
|
|
21
|
+
return false
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function checkGatewayHealth(port) {
|
|
26
|
+
try {
|
|
27
|
+
execSync(
|
|
28
|
+
isWin
|
|
29
|
+
? `powershell -NonInteractive -Command "try{(Invoke-WebRequest -Uri http://127.0.0.1:${port}/ -TimeoutSec 1 -UseBasicParsing).StatusCode}catch{exit 1}"`
|
|
30
|
+
: `curl -sf http://127.0.0.1:${port}/ -o /dev/null --max-time 1`,
|
|
31
|
+
{ stdio: 'ignore', timeout: 3000 }
|
|
32
|
+
)
|
|
33
|
+
return true
|
|
34
|
+
} catch {
|
|
35
|
+
return false
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function waitForPort(checkFn, maxTries, intervalMs) {
|
|
40
|
+
for (let i = 0; i < maxTries; i++) {
|
|
41
|
+
if (checkFn()) return true
|
|
42
|
+
const t0 = Date.now()
|
|
43
|
+
while (Date.now() - t0 < intervalMs) {}
|
|
44
|
+
}
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function openBrowser(url) {
|
|
49
|
+
const cmd = isWin ? 'start' : process.platform === 'darwin' ? 'open' : 'xdg-open'
|
|
50
|
+
try {
|
|
51
|
+
spawn(cmd, [url], { detached: true, stdio: 'ignore', shell: isWin }).unref()
|
|
52
|
+
} catch {}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function openclaw() {
|
|
56
|
+
console.log()
|
|
57
|
+
|
|
58
|
+
const runtime = openclawTool.detectRuntime()
|
|
59
|
+
if (!runtime.available) {
|
|
60
|
+
console.log(chalk.red('✗ 未检测到 OpenClaw'))
|
|
61
|
+
console.log(chalk.gray(` 安装命令: ${openclawTool.installCmd}`))
|
|
62
|
+
console.log(chalk.gray(' 安装后运行 hs setup 完成配置'))
|
|
63
|
+
process.exit(1)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!openclawTool.isConfigured()) {
|
|
67
|
+
console.log(chalk.yellow('⚠ OpenClaw 尚未配置 HolySheep,请先运行 hs setup'))
|
|
68
|
+
process.exit(1)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let bridgeConfig
|
|
72
|
+
try {
|
|
73
|
+
bridgeConfig = readBridgeConfig()
|
|
74
|
+
} catch {
|
|
75
|
+
console.log(chalk.yellow('⚠ 未找到 Bridge 配置,请先运行 hs setup'))
|
|
76
|
+
process.exit(1)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const bridgePort = openclawTool.getBridgePort()
|
|
80
|
+
const gatewayPort = openclawTool.getGatewayPort()
|
|
81
|
+
|
|
82
|
+
// 确保 Bridge 运行
|
|
83
|
+
if (checkBridgeHealth(bridgePort)) {
|
|
84
|
+
console.log(chalk.green(`✓ Bridge 已运行 (端口 ${bridgePort})`))
|
|
85
|
+
} else {
|
|
86
|
+
process.stdout.write(chalk.gray(` 正在启动 Bridge (端口 ${bridgePort})... `))
|
|
87
|
+
const scriptPath = path.join(__dirname, '..', 'index.js')
|
|
88
|
+
const spawnCmd = isWin ? 'node' : process.execPath
|
|
89
|
+
const child = spawn(spawnCmd, [scriptPath, 'openclaw-bridge', '--port', String(bridgePort)], {
|
|
90
|
+
detached: true,
|
|
91
|
+
stdio: 'ignore',
|
|
92
|
+
windowsHide: true,
|
|
93
|
+
})
|
|
94
|
+
child.unref()
|
|
95
|
+
|
|
96
|
+
const bridgeReady = waitForPort(() => checkBridgeHealth(bridgePort), 10, 1000)
|
|
97
|
+
if (bridgeReady) {
|
|
98
|
+
console.log(chalk.green('✓'))
|
|
99
|
+
} else {
|
|
100
|
+
console.log(chalk.red('✗'))
|
|
101
|
+
console.log(chalk.red(` Bridge 启动失败,请手动运行: hs openclaw-bridge --port ${bridgePort}`))
|
|
102
|
+
process.exit(1)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 确保 Gateway 运行
|
|
107
|
+
if (checkGatewayHealth(gatewayPort)) {
|
|
108
|
+
console.log(chalk.green(`✓ Gateway 已运行 (端口 ${gatewayPort})`))
|
|
109
|
+
} else {
|
|
110
|
+
process.stdout.write(chalk.gray(` 正在启动 Gateway (端口 ${gatewayPort})... `))
|
|
111
|
+
|
|
112
|
+
const preferNpx = runtime.via === 'npx'
|
|
113
|
+
const gatewayStartArgs = preferNpx ? ['openclaw', 'gateway', 'start'] : ['gateway', 'start']
|
|
114
|
+
const gatewayStartCmd = preferNpx ? 'npx' : 'openclaw'
|
|
115
|
+
const serviceResult = spawnSync(gatewayStartCmd, gatewayStartArgs, {
|
|
116
|
+
stdio: 'ignore',
|
|
117
|
+
timeout: 10000,
|
|
118
|
+
shell: isWin,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
if (serviceResult.status !== 0) {
|
|
122
|
+
const directArgs = preferNpx
|
|
123
|
+
? ['openclaw', 'gateway', '--port', String(gatewayPort)]
|
|
124
|
+
: ['gateway', '--port', String(gatewayPort)]
|
|
125
|
+
const directCmd = preferNpx ? 'npx' : 'openclaw'
|
|
126
|
+
const gatewayChild = spawn(directCmd, directArgs, {
|
|
127
|
+
detached: true,
|
|
128
|
+
stdio: 'ignore',
|
|
129
|
+
shell: isWin,
|
|
130
|
+
windowsHide: true,
|
|
131
|
+
})
|
|
132
|
+
gatewayChild.unref()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const gatewayReady = waitForPort(() => checkGatewayHealth(gatewayPort), 12, 1500)
|
|
136
|
+
if (gatewayReady) {
|
|
137
|
+
console.log(chalk.green('✓'))
|
|
138
|
+
} else {
|
|
139
|
+
console.log(chalk.yellow('⚠'))
|
|
140
|
+
console.log(chalk.yellow(' Gateway 未就绪,仍将尝试打开 Dashboard'))
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 获取 Dashboard URL
|
|
145
|
+
const fallbackUrl = `http://127.0.0.1:${gatewayPort}/`
|
|
146
|
+
let dashUrl = fallbackUrl
|
|
147
|
+
try {
|
|
148
|
+
const preferNpx = runtime.via === 'npx'
|
|
149
|
+
const dashArgs = preferNpx ? ['openclaw', 'dashboard', '--no-open'] : ['dashboard', '--no-open']
|
|
150
|
+
const dashCmd = preferNpx ? 'npx' : 'openclaw'
|
|
151
|
+
const result = spawnSync(dashCmd, dashArgs, {
|
|
152
|
+
timeout: preferNpx ? 60000 : 20000,
|
|
153
|
+
shell: isWin,
|
|
154
|
+
encoding: 'utf8',
|
|
155
|
+
stdio: 'pipe',
|
|
156
|
+
})
|
|
157
|
+
if (result.status === 0) {
|
|
158
|
+
const output = String(result.stdout || '')
|
|
159
|
+
const match = output.match(/Dashboard URL:\s*(\S+)/) || output.match(/(https?:\/\/\S+)/)
|
|
160
|
+
if (match) dashUrl = match[1]
|
|
161
|
+
}
|
|
162
|
+
} catch {}
|
|
163
|
+
|
|
164
|
+
console.log()
|
|
165
|
+
console.log(chalk.cyan.bold(`🌐 正在打开 OpenClaw Dashboard: ${dashUrl}`))
|
|
166
|
+
openBrowser(dashUrl)
|
|
167
|
+
console.log(chalk.gray(` Bridge: http://127.0.0.1:${bridgePort}/v1`))
|
|
168
|
+
console.log(chalk.gray(` Gateway: http://127.0.0.1:${gatewayPort}/`))
|
|
169
|
+
console.log()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = openclaw
|
package/src/index.js
CHANGED
|
@@ -149,6 +149,14 @@ program
|
|
|
149
149
|
})
|
|
150
150
|
})
|
|
151
151
|
|
|
152
|
+
// ── openclaw ─────────────────────────────────────────────────────────────────
|
|
153
|
+
program
|
|
154
|
+
.command('openclaw')
|
|
155
|
+
.description('启动 HolySheep 桥接版 OpenClaw(自动启动 Bridge + Gateway 并打开 Dashboard)')
|
|
156
|
+
.action(async () => {
|
|
157
|
+
await require('./commands/openclaw')()
|
|
158
|
+
})
|
|
159
|
+
|
|
152
160
|
// ── openclaw-bridge ──────────────────────────────────────────────────────────
|
|
153
161
|
program
|
|
154
162
|
.command('openclaw-bridge')
|