rol-websocket-channel 1.4.2 → 1.4.9

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.
@@ -1,10 +1,14 @@
1
- import { exec } from 'node:child_process';
1
+ import { exec, execFile } from 'node:child_process';
2
2
  import fs from 'node:fs/promises';
3
3
  import path from 'node:path';
4
4
  import { promisify } from 'node:util';
5
+ import { JsonRpcException, JSON_RPC_ERRORS } from '../jsonrpc.js';
5
6
  import type { JsonValue, MethodHandler, MethodContext } from '../types.js';
6
7
 
7
8
  const execAsync = promisify(exec);
9
+ const execFileAsync = promisify(execFile);
10
+ const UPDATE_COMMAND_TIMEOUT_MS = 10 * 60 * 1000;
11
+ const UPDATE_COMMAND_MAX_BUFFER = 10 * 1024 * 1024;
8
12
 
9
13
  export const ping: MethodHandler = async (): Promise<JsonValue> => {
10
14
  return {
@@ -74,6 +78,33 @@ export const doctorFix: MethodHandler = async (_params, context: MethodContext):
74
78
  }
75
79
  };
76
80
 
81
+ export const openclawUpdate: MethodHandler = async (_params, context: MethodContext): Promise<JsonValue> => {
82
+ const result = await runOpenClawCommand(['update'], context, 'openclawUpdate');
83
+
84
+ return {
85
+ ok: true,
86
+ action: 'openclawUpdate',
87
+ restartRecommended: true,
88
+ ...result
89
+ };
90
+ };
91
+
92
+ export const pluginSelfUpdate: MethodHandler = async (_params, context: MethodContext): Promise<JsonValue> => {
93
+ const result = await runOpenClawCommand(
94
+ ['plugins', 'install', 'clawhub:rol-websocket-channel'],
95
+ context,
96
+ 'pluginSelfUpdate'
97
+ );
98
+
99
+ return {
100
+ ok: true,
101
+ action: 'pluginSelfUpdate',
102
+ plugin: 'clawhub:rol-websocket-channel',
103
+ restartRecommended: true,
104
+ ...result
105
+ };
106
+ };
107
+
77
108
  export const logs: MethodHandler = async (params: any, context: MethodContext): Promise<JsonValue> => {
78
109
  try {
79
110
  // 根据实际情况可能需要调整,这里默认尝试 project root 或 user home 下的 .openclaw/logs
@@ -203,3 +234,100 @@ export const logs: MethodHandler = async (params: any, context: MethodContext):
203
234
  };
204
235
  }
205
236
  };
237
+
238
+ async function runOpenClawCommand(
239
+ args: string[],
240
+ context: MethodContext,
241
+ action: string
242
+ ): Promise<{ command: string; args: string[]; cwd: string; stdout: string; stderr: string }> {
243
+ const command = process.env.OPENCLAW_BIN || 'openclaw';
244
+ const options = buildOpenClawExecOptions(context.openclawRoot, context.openclawRoot);
245
+ const openclawBin = process.env.OPENCLAW_BIN || '';
246
+ const openclawHome = options.env?.OPENCLAW_HOME || '';
247
+ const home = options.env?.HOME || '';
248
+
249
+ console.log(
250
+ `[system] exec start: action=${action}, command=${command}, args=${JSON.stringify(args)}, cwd=${options.cwd}, OPENCLAW_BIN=${openclawBin}, OPENCLAW_HOME=${openclawHome}, HOME=${home}`
251
+ );
252
+
253
+ try {
254
+ const { stdout, stderr } = await execFileAsync(command, args, {
255
+ ...options,
256
+ timeout: UPDATE_COMMAND_TIMEOUT_MS,
257
+ maxBuffer: UPDATE_COMMAND_MAX_BUFFER
258
+ });
259
+
260
+ console.log(
261
+ `[system] exec success: action=${action}, command=${command}, args=${JSON.stringify(args)}, stdoutLength=${stdout.length}, stderrLength=${stderr.length}`
262
+ );
263
+
264
+ return {
265
+ command,
266
+ args,
267
+ cwd: options.cwd,
268
+ stdout,
269
+ stderr
270
+ };
271
+ } catch (err: any) {
272
+ const stdout = typeof err?.stdout === 'string' ? err.stdout : '';
273
+ const stderr = typeof err?.stderr === 'string' ? err.stderr : '';
274
+ console.error(
275
+ `[system] exec failed: action=${action}, command=${command}, args=${JSON.stringify(args)}, cwd=${options.cwd}, OPENCLAW_BIN=${openclawBin}, OPENCLAW_HOME=${openclawHome}, HOME=${home}, stdout=${JSON.stringify(stdout)}, stderr=${JSON.stringify(stderr)}`
276
+ );
277
+
278
+ throw new JsonRpcException(
279
+ JSON_RPC_ERRORS.internalError,
280
+ `OpenClaw system command failed: ${err instanceof Error ? err.message : String(err)}`,
281
+ {
282
+ action,
283
+ command,
284
+ args,
285
+ cwd: options.cwd,
286
+ stdout,
287
+ stderr
288
+ }
289
+ );
290
+ }
291
+ }
292
+
293
+ function buildOpenClawExecOptions(
294
+ cwd: string,
295
+ openclawRoot?: string
296
+ ): { cwd: string; shell?: boolean; env: NodeJS.ProcessEnv } {
297
+ const env: NodeJS.ProcessEnv = { ...process.env };
298
+ const openclawHome = resolveOpenClawHomeForCli(openclawRoot);
299
+ if (openclawHome) {
300
+ env.OPENCLAW_HOME = openclawHome;
301
+ }
302
+
303
+ if (openclawRoot && path.basename(path.resolve(openclawRoot)) === '.openclaw') {
304
+ const home = path.dirname(path.resolve(openclawRoot));
305
+ env.HOME = home;
306
+ if (process.platform === 'win32') {
307
+ env.USERPROFILE = home;
308
+ }
309
+ }
310
+
311
+ if (process.platform === 'win32') {
312
+ return {
313
+ cwd,
314
+ shell: true,
315
+ env
316
+ };
317
+ }
318
+
319
+ return { cwd, env };
320
+ }
321
+
322
+ function resolveOpenClawHomeForCli(openclawRoot?: string): string | undefined {
323
+ if (!openclawRoot) {
324
+ return process.env.OPENCLAW_HOME;
325
+ }
326
+
327
+ const resolvedRoot = path.resolve(openclawRoot);
328
+ if (path.basename(resolvedRoot) === '.openclaw') {
329
+ return path.dirname(resolvedRoot);
330
+ }
331
+
332
+ return process.env.OPENCLAW_HOME;
333
+ }