squad-openclaw 2026.2.2024 → 2026.2.2203

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.
Files changed (2) hide show
  1. package/dist/index.js +150 -31
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -215,6 +215,7 @@ var RelayClient = class {
215
215
  localConnectAttempts = /* @__PURE__ */ new Map();
216
216
  reconnectAttempts = 0;
217
217
  maxReconnectAttempts = 100;
218
+ autoConnectCounter = 0;
218
219
  reconnectTimer = null;
219
220
  shouldReconnect = true;
220
221
  destroyed = false;
@@ -482,6 +483,21 @@ var RelayClient = class {
482
483
  }
483
484
  if (!conn.connectHandshakeComplete) {
484
485
  conn.pendingMessages.push(msg);
486
+ if (!conn.pendingConnect) {
487
+ const autoConnect = this.buildAutoConnectRequest();
488
+ conn.pendingConnect = autoConnect;
489
+ console.log(`[relay-client] Auto-starting local connect handshake for ${userId} (${String(autoConnect.id)})`);
490
+ if (conn.challengeNonce) {
491
+ const pending = conn.pendingConnect;
492
+ conn.pendingConnect = null;
493
+ if (pending) {
494
+ this.injectDeviceIdentity(conn, pending);
495
+ if (conn.localWs.readyState === NodeWebSocket.OPEN) {
496
+ conn.localWs.send(JSON.stringify(pending));
497
+ }
498
+ }
499
+ }
500
+ }
485
501
  return;
486
502
  }
487
503
  if (conn.localWs.readyState === NodeWebSocket.CONNECTING) {
@@ -492,6 +508,26 @@ var RelayClient = class {
492
508
  }
493
509
  conn.localWs.send(JSON.stringify(msg));
494
510
  }
511
+ buildAutoConnectRequest() {
512
+ return {
513
+ type: "req",
514
+ id: `connect-auto-${++this.autoConnectCounter}`,
515
+ method: "connect",
516
+ params: {
517
+ minProtocol: 3,
518
+ maxProtocol: 3,
519
+ client: {
520
+ id: "cli",
521
+ version: "relay-client-auto",
522
+ platform: "gateway",
523
+ mode: "ui"
524
+ },
525
+ role: "operator",
526
+ scopes: ["operator.admin", "operator.read", "operator.write"],
527
+ auth: {}
528
+ }
529
+ };
530
+ }
495
531
  /**
496
532
  * Inject auth token and device identity into a connect request.
497
533
  *
@@ -2147,7 +2183,7 @@ function registerSqlTools(api) {
2147
2183
  }
2148
2184
 
2149
2185
  // src/version.ts
2150
- import { execSync as execSync2 } from "child_process";
2186
+ import { spawn } from "child_process";
2151
2187
  import fs9 from "fs";
2152
2188
  import path10 from "path";
2153
2189
  import { fileURLToPath } from "url";
@@ -2157,6 +2193,9 @@ var updateInProgress = false;
2157
2193
  var VERIFY_TIMEOUT_MS = 2e4;
2158
2194
  var VERIFY_INTERVAL_MS = 500;
2159
2195
  var RESTART_BUFFER_MS = 5e3;
2196
+ var REGISTRY_TIMEOUT_MS = 2500;
2197
+ var COMMAND_OUTPUT_LIMIT = 8e3;
2198
+ var COMMAND_KILL_GRACE_MS = 2e3;
2160
2199
  function readInstalledVersionFromConfig() {
2161
2200
  try {
2162
2201
  const raw = fs9.readFileSync(CONFIG_PATH, "utf-8");
@@ -2207,9 +2246,9 @@ function getCurrentVersion() {
2207
2246
  return "0.0.0";
2208
2247
  }
2209
2248
  }
2210
- async function fetchLatestVersion() {
2249
+ async function fetchLatestVersion(timeoutMs = REGISTRY_TIMEOUT_MS) {
2211
2250
  const controller = new AbortController();
2212
- const timeout = setTimeout(() => controller.abort(), 1e4);
2251
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
2213
2252
  try {
2214
2253
  const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}`, {
2215
2254
  signal: controller.signal
@@ -2221,14 +2260,64 @@ async function fetchLatestVersion() {
2221
2260
  clearTimeout(timeout);
2222
2261
  }
2223
2262
  }
2224
- function runDoctorFixSilently() {
2225
- try {
2226
- execSync2("openclaw doctor --fix 2>/dev/null || true", {
2227
- timeout: 3e4,
2228
- encoding: "utf-8"
2263
+ async function runCommand(args, timeoutMs) {
2264
+ return new Promise((resolve) => {
2265
+ const child = spawn("openclaw", args, {
2266
+ stdio: ["ignore", "pipe", "pipe"],
2267
+ detached: true
2229
2268
  });
2230
- } catch {
2231
- }
2269
+ let output = "";
2270
+ let timedOut = false;
2271
+ let resolved = false;
2272
+ let killGraceTimer = null;
2273
+ const append = (chunk) => {
2274
+ output += chunk.toString();
2275
+ if (output.length > COMMAND_OUTPUT_LIMIT) {
2276
+ output = output.slice(output.length - COMMAND_OUTPUT_LIMIT);
2277
+ }
2278
+ };
2279
+ const finalize = (result) => {
2280
+ if (resolved) return;
2281
+ resolved = true;
2282
+ if (killGraceTimer) clearTimeout(killGraceTimer);
2283
+ clearTimeout(timeout);
2284
+ resolve(result);
2285
+ };
2286
+ child.stdout?.on("data", append);
2287
+ child.stderr?.on("data", append);
2288
+ child.on("error", (err2) => {
2289
+ append(String(err2));
2290
+ finalize({
2291
+ ok: false,
2292
+ timedOut,
2293
+ exitCode: null,
2294
+ signal: null,
2295
+ output
2296
+ });
2297
+ });
2298
+ child.on("close", (code, signal) => {
2299
+ finalize({
2300
+ ok: !timedOut && code === 0,
2301
+ timedOut,
2302
+ exitCode: code,
2303
+ signal,
2304
+ output
2305
+ });
2306
+ });
2307
+ const timeout = setTimeout(() => {
2308
+ timedOut = true;
2309
+ try {
2310
+ process.kill(-child.pid, "SIGTERM");
2311
+ } catch {
2312
+ }
2313
+ killGraceTimer = setTimeout(() => {
2314
+ try {
2315
+ process.kill(-child.pid, "SIGKILL");
2316
+ } catch {
2317
+ }
2318
+ }, COMMAND_KILL_GRACE_MS);
2319
+ }, timeoutMs);
2320
+ });
2232
2321
  }
2233
2322
  function sleep(ms) {
2234
2323
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -2363,13 +2452,25 @@ async function waitForVerifiedInstall() {
2363
2452
  function registerVersionMethods(api) {
2364
2453
  api.registerGatewayMethod(
2365
2454
  "squad.version.check",
2366
- async ({ respond }) => {
2455
+ async ({ respond, params }) => {
2367
2456
  try {
2457
+ const checkParams = params ?? {};
2368
2458
  const current = getCurrentVersion();
2459
+ if (checkParams.skipRegistry) {
2460
+ console.log("[version_check_local] returning local version only");
2461
+ respond(true, {
2462
+ current,
2463
+ latest: null,
2464
+ updateAvailable: false,
2465
+ registrySkipped: true
2466
+ });
2467
+ return;
2468
+ }
2369
2469
  let latest;
2370
2470
  try {
2371
2471
  latest = await fetchLatestVersion();
2372
2472
  } catch {
2473
+ console.log("[version_check_registry_timeout] npm registry unavailable");
2373
2474
  respond(true, {
2374
2475
  current,
2375
2476
  latest: null,
@@ -2397,6 +2498,7 @@ function registerVersionMethods(api) {
2397
2498
  return;
2398
2499
  }
2399
2500
  updateInProgress = true;
2501
+ const updateAttemptId = `${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
2400
2502
  try {
2401
2503
  const before = getCurrentVersion();
2402
2504
  const beforeInstalledVersion = readInstalledVersionFromConfig();
@@ -2412,19 +2514,25 @@ function registerVersionMethods(api) {
2412
2514
  configBackup = fs9.readFileSync(CONFIG_PATH, "utf-8");
2413
2515
  } catch {
2414
2516
  }
2415
- runDoctorFixSilently();
2517
+ await runCommand(["doctor", "--fix"], 3e4);
2416
2518
  try {
2417
- updateOutput = execSync2(
2418
- `openclaw plugins update ${PACKAGE_NAME} 2>&1`,
2419
- { timeout: 12e4, encoding: "utf-8" }
2420
- );
2519
+ const first = await runCommand(["plugins", "update", PACKAGE_NAME], 12e4);
2520
+ updateOutput = first.output;
2521
+ if (!first.ok) {
2522
+ throw new Error(
2523
+ first.timedOut ? "UPDATE_TIMEOUT: plugins update timed out" : `UPDATE_FAILED: plugins update exited with code ${String(first.exitCode)}`
2524
+ );
2525
+ }
2421
2526
  } catch (firstErr) {
2422
- runDoctorFixSilently();
2527
+ await runCommand(["doctor", "--fix"], 3e4);
2423
2528
  try {
2424
- updateOutput = execSync2(
2425
- `openclaw plugins update ${PACKAGE_NAME} 2>&1`,
2426
- { timeout: 12e4, encoding: "utf-8" }
2427
- );
2529
+ const retry = await runCommand(["plugins", "update", PACKAGE_NAME], 12e4);
2530
+ updateOutput = retry.output;
2531
+ if (!retry.ok) {
2532
+ throw new Error(
2533
+ retry.timedOut ? "UPDATE_TIMEOUT: plugins update timed out after retry" : `UPDATE_FAILED: plugins update retry exited with code ${String(retry.exitCode)}`
2534
+ );
2535
+ }
2428
2536
  } catch (installErr) {
2429
2537
  if (configBackup) {
2430
2538
  try {
@@ -2435,9 +2543,11 @@ function registerVersionMethods(api) {
2435
2543
  const firstMsg = firstErr instanceof Error ? firstErr.message : String(firstErr);
2436
2544
  const retryMsg = installErr instanceof Error ? installErr.message : String(installErr);
2437
2545
  respond(false, {
2546
+ code: /UPDATE_TIMEOUT/.test(retryMsg) ? "UPDATE_TIMEOUT" : "UPDATE_FAILED",
2438
2547
  error: `Update failed after doctor fix retry: ${retryMsg}`,
2439
2548
  output: updateOutput,
2440
- firstError: firstMsg
2549
+ firstError: firstMsg,
2550
+ updateAttemptId
2441
2551
  });
2442
2552
  return;
2443
2553
  }
@@ -2451,9 +2561,11 @@ function registerVersionMethods(api) {
2451
2561
  }
2452
2562
  }
2453
2563
  respond(false, {
2564
+ code: "VERIFY_FAILED",
2454
2565
  error: `Update verification failed: ${verification.reason ?? "unknown error"}`,
2455
2566
  output: updateOutput.slice(0, 500),
2456
- verification
2567
+ verification,
2568
+ updateAttemptId
2457
2569
  });
2458
2570
  return;
2459
2571
  }
@@ -2462,10 +2574,12 @@ function registerVersionMethods(api) {
2462
2574
  if (beforeInstalledVersion && verificationAfterReconcile.packageVersion && beforeInstalledVersion === verificationAfterReconcile.packageVersion) {
2463
2575
  const alreadyLatest = !!latestVersion && compareVersions(verificationAfterReconcile.packageVersion, latestVersion) >= 0;
2464
2576
  respond(false, {
2577
+ code: "UPDATE_FAILED",
2465
2578
  error: alreadyLatest ? `Already at latest version (${verificationAfterReconcile.packageVersion}).` : `Update command completed but installed version did not change (${verificationAfterReconcile.packageVersion}).`,
2466
2579
  output: updateOutput.slice(0, 500),
2467
2580
  verification: verificationAfterReconcile,
2468
- latestVersion
2581
+ latestVersion,
2582
+ updateAttemptId
2469
2583
  });
2470
2584
  return;
2471
2585
  }
@@ -2478,22 +2592,27 @@ function registerVersionMethods(api) {
2478
2592
  restartInMs: RESTART_BUFFER_MS,
2479
2593
  verification: verificationAfterReconcile,
2480
2594
  latestVersion,
2481
- output: updateOutput.slice(0, 500)
2595
+ output: updateOutput.slice(0, 500),
2596
+ updateAttemptId
2482
2597
  });
2483
2598
  await sleep(RESTART_BUFFER_MS);
2484
2599
  console.log(
2485
2600
  `[version] Plugin update verified (was ${before}), restarting gateway...`
2486
2601
  );
2487
- try {
2488
- execSync2("openclaw gateway restart 2>&1", {
2489
- timeout: 3e4,
2490
- encoding: "utf-8"
2602
+ const restartResult = await runCommand(["gateway", "restart"], 3e4);
2603
+ if (!restartResult.ok && !restartResult.timedOut) {
2604
+ console.log("[update_cmd_timeout] restart command failed unexpectedly", {
2605
+ updateAttemptId,
2606
+ exitCode: restartResult.exitCode,
2607
+ signal: restartResult.signal
2491
2608
  });
2492
- } catch {
2493
2609
  }
2494
2610
  } catch (e) {
2495
2611
  const msg = e instanceof Error ? e.message : String(e);
2496
- respond(false, { error: msg });
2612
+ respond(false, {
2613
+ code: /VERIFY_FAILED/.test(msg) ? "VERIFY_FAILED" : /UPDATE_TIMEOUT/.test(msg) ? "UPDATE_TIMEOUT" : "UPDATE_FAILED",
2614
+ error: msg
2615
+ });
2497
2616
  } finally {
2498
2617
  updateInProgress = false;
2499
2618
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squad-openclaw",
3
- "version": "2026.2.2024",
3
+ "version": "2026.2.2203",
4
4
  "description": "Entity registry, filesystem tools, and version management plugin for OpenClaw gateway",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",