claw-subagent-service 0.0.26 → 0.0.27
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/service/rongcloud/openclaw-client.js +100 -21
package/package.json
CHANGED
|
@@ -33,6 +33,66 @@ function getRealHomeDir() {
|
|
|
33
33
|
return homeDir;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* 构建 OpenClaw 需要的完整环境变量
|
|
38
|
+
* Windows SYSTEM 账户下必须设置 HOMEDRIVE/HOMEPATH/APPDATA 等
|
|
39
|
+
* 策略:从现有环境变量中推断正确路径,避免硬编码任何用户名或目录结构
|
|
40
|
+
*/
|
|
41
|
+
function getOpenClawEnv(baseEnv = process.env) {
|
|
42
|
+
const realHome = getRealHomeDir();
|
|
43
|
+
const env = { ...baseEnv };
|
|
44
|
+
const systemHome = os.homedir();
|
|
45
|
+
|
|
46
|
+
// 基础 home 目录变量
|
|
47
|
+
env.USERPROFILE = realHome;
|
|
48
|
+
env.HOME = realHome;
|
|
49
|
+
|
|
50
|
+
if (process.platform === 'win32') {
|
|
51
|
+
// 从 realHome 推断 HOMEDRIVE / HOMEPATH(匹配盘符 + 路径)
|
|
52
|
+
const match = realHome.match(/^([A-Za-z]:)(.*)$/);
|
|
53
|
+
if (match) {
|
|
54
|
+
env.HOMEDRIVE = match[1];
|
|
55
|
+
env.HOMEPATH = match[2];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 修复路径:把现有环境变量中的 systemprofile home 路径替换为真实用户 home 路径
|
|
60
|
+
* 这样能处理 Roaming Profiles、AppData 重定向、非标准安装等各种情况
|
|
61
|
+
*/
|
|
62
|
+
const fixPath = (originalPath) => {
|
|
63
|
+
if (!originalPath) return null;
|
|
64
|
+
const lowerOriginal = originalPath.toLowerCase();
|
|
65
|
+
const lowerSystemHome = systemHome.toLowerCase();
|
|
66
|
+
if (lowerOriginal.includes(lowerSystemHome)) {
|
|
67
|
+
const idx = lowerOriginal.indexOf(lowerSystemHome);
|
|
68
|
+
return originalPath.substring(0, idx) + realHome + originalPath.substring(idx + systemHome.length);
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// APPDATA:优先从现有变量推断,保留原始目录结构
|
|
74
|
+
if (baseEnv.APPDATA) {
|
|
75
|
+
const fixed = fixPath(baseEnv.APPDATA);
|
|
76
|
+
if (fixed) env.APPDATA = fixed;
|
|
77
|
+
}
|
|
78
|
+
// 兜底:按标准结构拼接(仅在无法推断时使用)
|
|
79
|
+
if (!env.APPDATA) {
|
|
80
|
+
env.APPDATA = path.join(realHome, 'AppData', 'Roaming');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// LOCALAPPDATA:同上
|
|
84
|
+
if (baseEnv.LOCALAPPDATA) {
|
|
85
|
+
const fixed = fixPath(baseEnv.LOCALAPPDATA);
|
|
86
|
+
if (fixed) env.LOCALAPPDATA = fixed;
|
|
87
|
+
}
|
|
88
|
+
if (!env.LOCALAPPDATA) {
|
|
89
|
+
env.LOCALAPPDATA = path.join(realHome, 'AppData', 'Local');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return env;
|
|
94
|
+
}
|
|
95
|
+
|
|
36
96
|
/**
|
|
37
97
|
* 检测端口是否监听
|
|
38
98
|
*/
|
|
@@ -68,24 +128,21 @@ function startOpenClawGateway(log) {
|
|
|
68
128
|
windowsHide: true,
|
|
69
129
|
detached: true,
|
|
70
130
|
stdio: 'ignore',
|
|
71
|
-
env:
|
|
72
|
-
...process.env,
|
|
73
|
-
USERPROFILE: getRealHomeDir(),
|
|
74
|
-
HOME: getRealHomeDir(),
|
|
75
|
-
},
|
|
131
|
+
env: getOpenClawEnv(),
|
|
76
132
|
});
|
|
77
133
|
|
|
78
134
|
child.unref();
|
|
79
135
|
|
|
80
|
-
// 等待 gateway 启动(最多
|
|
136
|
+
// 等待 gateway 启动(最多 20 秒)
|
|
81
137
|
let attempts = 0;
|
|
82
|
-
const maxAttempts =
|
|
138
|
+
const maxAttempts = 20;
|
|
83
139
|
const interval = setInterval(async () => {
|
|
84
140
|
attempts++;
|
|
85
|
-
const
|
|
86
|
-
|
|
141
|
+
const gatewayRunning = await checkPort(18789);
|
|
142
|
+
const apiRunning = await checkPort(5678);
|
|
143
|
+
if (gatewayRunning) {
|
|
87
144
|
clearInterval(interval);
|
|
88
|
-
log?.info(
|
|
145
|
+
log?.info(`[OpenClawClient] OpenClaw gateway 启动成功 (18789),API 状态: ${apiRunning ? '就绪' : '未就绪'}`);
|
|
89
146
|
resolve(true);
|
|
90
147
|
} else if (attempts >= maxAttempts) {
|
|
91
148
|
clearInterval(interval);
|
|
@@ -115,18 +172,36 @@ class OpenClawClient {
|
|
|
115
172
|
async ensureGatewayRunning() {
|
|
116
173
|
if (this.gatewayStarted) return true;
|
|
117
174
|
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
175
|
+
const gatewayRunning = await checkPort(18789);
|
|
176
|
+
const apiRunning = await checkPort(5678);
|
|
177
|
+
|
|
178
|
+
if (gatewayRunning && apiRunning) {
|
|
179
|
+
this.log?.info('[OpenClawClient] OpenClaw gateway 和 API 均已就绪');
|
|
121
180
|
this.gatewayStarted = true;
|
|
122
181
|
return true;
|
|
123
182
|
}
|
|
124
183
|
|
|
184
|
+
if (gatewayRunning && !apiRunning) {
|
|
185
|
+
this.log?.info('[OpenClawClient] gateway 已运行 (18789),但 API (5678) 未就绪,继续等待...');
|
|
186
|
+
// 等待最多 10 秒让 API 就绪
|
|
187
|
+
for (let i = 0; i < 10; i++) {
|
|
188
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
189
|
+
if (await checkPort(5678)) {
|
|
190
|
+
this.log?.info('[OpenClawClient] API (5678) 已就绪');
|
|
191
|
+
this.gatewayStarted = true;
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
this.log?.warn('[OpenClawClient] API (5678) 等待超时,gateway 可能未完全初始化');
|
|
196
|
+
// gateway 在运行但 API 没好,仍然允许继续,让 HTTP fallback 到 CLI
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
|
|
125
200
|
// 避免并发启动
|
|
126
201
|
if (this.gatewayStarting) {
|
|
127
202
|
this.log?.info('[OpenClawClient] gateway 正在启动中,等待...');
|
|
128
|
-
// 等待最多
|
|
129
|
-
for (let i = 0; i <
|
|
203
|
+
// 等待最多 25 秒
|
|
204
|
+
for (let i = 0; i < 25; i++) {
|
|
130
205
|
await new Promise(r => setTimeout(r, 1000));
|
|
131
206
|
if (await checkPort(18789)) {
|
|
132
207
|
this.gatewayStarted = true;
|
|
@@ -225,25 +300,29 @@ class OpenClawClient {
|
|
|
225
300
|
shell: true,
|
|
226
301
|
windowsHide: true,
|
|
227
302
|
env: {
|
|
228
|
-
...
|
|
303
|
+
...getOpenClawEnv(),
|
|
229
304
|
OPENCLAW_GATEWAY_URL: gatewayUrl,
|
|
230
|
-
USERPROFILE: realHome,
|
|
231
|
-
HOME: realHome,
|
|
232
305
|
},
|
|
233
306
|
});
|
|
234
307
|
|
|
308
|
+
this.log?.info(`[OpenClawClient] CLI 子进程 PID=${child.pid}`);
|
|
309
|
+
|
|
235
310
|
child.stdout.on('data', (chunk) => {
|
|
236
311
|
stdout += chunk.toString();
|
|
237
312
|
});
|
|
238
313
|
child.stderr.on('data', (chunk) => {
|
|
239
|
-
|
|
314
|
+
const text = chunk.toString();
|
|
315
|
+
stderr += text;
|
|
316
|
+
// 实时记录 stderr,方便调试卡死问题
|
|
317
|
+
this.log?.info(`[OpenClawClient] CLI stderr: ${text.trim().substring(0, 200)}`);
|
|
240
318
|
});
|
|
241
319
|
|
|
320
|
+
// 超时兜底(2 分钟)
|
|
242
321
|
const timeout = setTimeout(() => {
|
|
243
322
|
killed = true;
|
|
244
323
|
child.kill('SIGTERM');
|
|
245
|
-
this.log?.error('[OpenClawClient] CLI
|
|
246
|
-
},
|
|
324
|
+
this.log?.error('[OpenClawClient] CLI 执行超时(2分钟),强制终止');
|
|
325
|
+
}, 120000);
|
|
247
326
|
|
|
248
327
|
child.on('error', (err) => {
|
|
249
328
|
clearTimeout(timeout);
|