@lark-apaas/openclaw-scripts-diagnose-cli 0.1.1-alpha.8 → 0.1.1-alpha.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.
- package/dist/index.cjs +108 -10
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -198,6 +198,74 @@ function shell(cmd, timeoutMs = 1e4) {
|
|
|
198
198
|
timeout: timeoutMs
|
|
199
199
|
}).trim();
|
|
200
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* Run a long-lived command and kill it only when it goes idle (no stdout/stderr
|
|
203
|
+
* for `idleMs`) or hits the total deadline `maxTotalMs`. Suited to commands like
|
|
204
|
+
* `npm install` that may be slow but keep streaming progress — we don't want to
|
|
205
|
+
* kill them just because they exceeded some fixed wall-clock budget, only when
|
|
206
|
+
* they actually stall (e.g. blocked on a cache / lockfile held by another npm).
|
|
207
|
+
*/
|
|
208
|
+
function shellUntilIdle(cmd, opts = {}) {
|
|
209
|
+
const idleMs = opts.idleMs ?? 9e4;
|
|
210
|
+
const maxTotalMs = opts.maxTotalMs ?? 9e5;
|
|
211
|
+
return new Promise((resolve, reject) => {
|
|
212
|
+
const proc = (0, node_child_process.spawn)("bash", ["-c", cmd], { stdio: [
|
|
213
|
+
"ignore",
|
|
214
|
+
"pipe",
|
|
215
|
+
"pipe"
|
|
216
|
+
] });
|
|
217
|
+
const startedAt = Date.now();
|
|
218
|
+
let lastOutputAt = Date.now();
|
|
219
|
+
let killed = null;
|
|
220
|
+
const bump = () => {
|
|
221
|
+
lastOutputAt = Date.now();
|
|
222
|
+
};
|
|
223
|
+
proc.stdout.on("data", bump);
|
|
224
|
+
proc.stderr.on("data", bump);
|
|
225
|
+
const timer = setInterval(() => {
|
|
226
|
+
const now = Date.now();
|
|
227
|
+
if (now - lastOutputAt > idleMs) {
|
|
228
|
+
killed = `idle > ${idleMs}ms`;
|
|
229
|
+
proc.kill("SIGKILL");
|
|
230
|
+
} else if (now - startedAt > maxTotalMs) {
|
|
231
|
+
killed = `total > ${maxTotalMs}ms`;
|
|
232
|
+
proc.kill("SIGKILL");
|
|
233
|
+
}
|
|
234
|
+
}, 5e3);
|
|
235
|
+
proc.on("exit", (code, signal) => {
|
|
236
|
+
clearInterval(timer);
|
|
237
|
+
if (killed) return reject(/* @__PURE__ */ new Error(`shellUntilIdle killed (${killed}): ${cmd}`));
|
|
238
|
+
if (code === 0) return resolve();
|
|
239
|
+
reject(/* @__PURE__ */ new Error(`shellUntilIdle exit code=${code} signal=${signal}: ${cmd}`));
|
|
240
|
+
});
|
|
241
|
+
proc.on("error", (err) => {
|
|
242
|
+
clearInterval(timer);
|
|
243
|
+
reject(err);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Retry a Promise-returning runner until it succeeds or the overall deadline
|
|
249
|
+
* passes. Designed to pair with `shellUntilIdle` for npm-style operations that
|
|
250
|
+
* may need several attempts if a concurrent npm is holding a lock.
|
|
251
|
+
*/
|
|
252
|
+
async function retryUntilDeadline(run, opts) {
|
|
253
|
+
const betweenAttemptsMs = opts.betweenAttemptsMs ?? 1e4;
|
|
254
|
+
const deadline = Date.now() + opts.maxTotalMs;
|
|
255
|
+
let lastErr;
|
|
256
|
+
let attempt = 0;
|
|
257
|
+
while (Date.now() < deadline) {
|
|
258
|
+
attempt++;
|
|
259
|
+
try {
|
|
260
|
+
return await run();
|
|
261
|
+
} catch (e) {
|
|
262
|
+
lastErr = e;
|
|
263
|
+
if (Date.now() + betweenAttemptsMs >= deadline) break;
|
|
264
|
+
await new Promise((r) => setTimeout(r, betweenAttemptsMs));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
throw new Error(`retryUntilDeadline gave up after ${attempt} attempt(s): ${lastErr?.message ?? lastErr}`);
|
|
268
|
+
}
|
|
201
269
|
//#endregion
|
|
202
270
|
//#region \0@oxc-project+runtime@0.121.0/helpers/decorate.js
|
|
203
271
|
function __decorate(decorators, target, key, desc) {
|
|
@@ -1164,13 +1232,29 @@ function killOpenclawProcesses() {
|
|
|
1164
1232
|
} catch {}
|
|
1165
1233
|
shell("sleep 2", 5e3);
|
|
1166
1234
|
}
|
|
1167
|
-
/**
|
|
1168
|
-
|
|
1235
|
+
/**
|
|
1236
|
+
* Step 4: Reinstall openclaw to the version specified in template.
|
|
1237
|
+
*
|
|
1238
|
+
* `npm i -g` contends on ~/.npm cache/lock with any concurrent npm (e.g. the
|
|
1239
|
+
* sandbox's own init_sandbox.sh busy installing plugin deps). Using
|
|
1240
|
+
* `shellUntilIdle` lets slow-but-progressing installs run freely (we only kill
|
|
1241
|
+
* on genuine idleness), and `retryUntilDeadline` recovers when we *are* killed
|
|
1242
|
+
* because another npm was holding the lock — the next attempt is likely to
|
|
1243
|
+
* succeed once that npm completes.
|
|
1244
|
+
*/
|
|
1245
|
+
async function reinstallOpenclaw(srcDir) {
|
|
1169
1246
|
const version = loadJSON5().parse(node_fs.default.readFileSync(node_path.default.join(srcDir, "openclaw.json"), "utf-8")).meta?.lastTouchedVersion;
|
|
1170
1247
|
try {
|
|
1171
1248
|
shell("npm uninstall -g openclaw 2>/dev/null || true", 3e4);
|
|
1172
1249
|
} catch {}
|
|
1173
|
-
|
|
1250
|
+
const installCmd = `npm i -g openclaw@${version || "latest"} --loglevel=http --prefer-offline`;
|
|
1251
|
+
await retryUntilDeadline(() => shellUntilIdle(installCmd, {
|
|
1252
|
+
idleMs: 9e4,
|
|
1253
|
+
maxTotalMs: 6e5
|
|
1254
|
+
}), {
|
|
1255
|
+
maxTotalMs: 12e5,
|
|
1256
|
+
betweenAttemptsMs: 1e4
|
|
1257
|
+
});
|
|
1174
1258
|
shell("openclaw doctor --fix", 12e4);
|
|
1175
1259
|
}
|
|
1176
1260
|
/** Step 5: Merge core-backup.json into config + ensure allowedOrigins. */
|
|
@@ -1216,10 +1300,21 @@ function copyStartupScripts(srcDir, configDir) {
|
|
|
1216
1300
|
if (!node_fs.default.existsSync(targetScriptsDir)) node_fs.default.mkdirSync(targetScriptsDir, { recursive: true });
|
|
1217
1301
|
shell(`cp -r '${srcScriptsDir}'/* '${targetScriptsDir}/'`, 1e4);
|
|
1218
1302
|
}
|
|
1219
|
-
/**
|
|
1220
|
-
|
|
1303
|
+
/**
|
|
1304
|
+
* Step 7: Reinstall all plugins via openclaw CLI.
|
|
1305
|
+
*
|
|
1306
|
+
* Same contention story as Step 4 — under the hood this shells out to npm, so
|
|
1307
|
+
* we apply the same idle-timeout + retry strategy.
|
|
1308
|
+
*/
|
|
1309
|
+
async function reinstallPlugins() {
|
|
1221
1310
|
try {
|
|
1222
|
-
|
|
1311
|
+
await retryUntilDeadline(() => shellUntilIdle("openclaw plugins update --all", {
|
|
1312
|
+
idleMs: 12e4,
|
|
1313
|
+
maxTotalMs: 6e5
|
|
1314
|
+
}), {
|
|
1315
|
+
maxTotalMs: 9e5,
|
|
1316
|
+
betweenAttemptsMs: 1e4
|
|
1317
|
+
});
|
|
1223
1318
|
} catch {}
|
|
1224
1319
|
}
|
|
1225
1320
|
/** Step 8: Write secrets/provider key files and restart openclaw. */
|
|
@@ -1239,7 +1334,7 @@ function writeSecretsAndRestart(vars, resetData, configDir) {
|
|
|
1239
1334
|
* (see TEMPLATE_DIR) and synced from the miaoda-openclaw-template repo via
|
|
1240
1335
|
* scripts/sync-template.sh, so no runtime download is required.
|
|
1241
1336
|
*/
|
|
1242
|
-
function runReset(input, taskId, resultFile) {
|
|
1337
|
+
async function runReset(input, taskId, resultFile) {
|
|
1243
1338
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1244
1339
|
const { configPath, vars, resetData } = input;
|
|
1245
1340
|
const configDir = node_path.default.dirname(configPath);
|
|
@@ -1270,13 +1365,13 @@ function runReset(input, taskId, resultFile) {
|
|
|
1270
1365
|
step(3);
|
|
1271
1366
|
killOpenclawProcesses();
|
|
1272
1367
|
step(4);
|
|
1273
|
-
reinstallOpenclaw(srcDir);
|
|
1368
|
+
await reinstallOpenclaw(srcDir);
|
|
1274
1369
|
step(5);
|
|
1275
1370
|
mergeCoreBackupAndOrigins(configPath, vars);
|
|
1276
1371
|
step(6);
|
|
1277
1372
|
copyStartupScripts(srcDir, configDir);
|
|
1278
1373
|
step(7);
|
|
1279
|
-
reinstallPlugins();
|
|
1374
|
+
await reinstallPlugins();
|
|
1280
1375
|
step(8);
|
|
1281
1376
|
writeSecretsAndRestart(vars, resetData, configDir);
|
|
1282
1377
|
markDone(resultFile, startedAt);
|
|
@@ -1366,7 +1461,10 @@ switch (mode) {
|
|
|
1366
1461
|
node_process.default.exit(1);
|
|
1367
1462
|
}
|
|
1368
1463
|
const resultFile = `/tmp/openclaw-reset-${taskId}.json`;
|
|
1369
|
-
runReset(JSON.parse(Buffer.from(ctx, "base64").toString("utf-8")), taskId, resultFile)
|
|
1464
|
+
runReset(JSON.parse(Buffer.from(ctx, "base64").toString("utf-8")), taskId, resultFile).catch((e) => {
|
|
1465
|
+
console.error("runReset failed:", e);
|
|
1466
|
+
node_process.default.exit(1);
|
|
1467
|
+
});
|
|
1370
1468
|
} else {
|
|
1371
1469
|
console.error("Usage: reset --async --ctx=<base64> | reset --worker --task-id=<id> --ctx=<base64>");
|
|
1372
1470
|
node_process.default.exit(1);
|