@lark-apaas/openclaw-scripts-diagnose-cli 0.1.1-alpha.5 → 0.1.1-alpha.7

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.cjs +150 -116
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1090,9 +1090,6 @@ const STEPS = [
1090
1090
  const TOTAL_STEPS = STEPS.length;
1091
1091
  const CORE_BACKUP_PATH = "/home/gem/workspace/.force/openclaw/core-backup.json";
1092
1092
  const TMP_RESET_DIR = "/tmp/openclaw-reset";
1093
- /**
1094
- * Atomically write the result file (write .tmp + rename).
1095
- */
1096
1093
  function writeResultFile(resultFile, result) {
1097
1094
  const dir = node_path.default.dirname(resultFile);
1098
1095
  if (!node_fs.default.existsSync(dir)) node_fs.default.mkdirSync(dir, { recursive: true });
@@ -1100,21 +1097,15 @@ function writeResultFile(resultFile, result) {
1100
1097
  node_fs.default.writeFileSync(tmpPath, JSON.stringify(result), "utf-8");
1101
1098
  node_fs.default.renameSync(tmpPath, resultFile);
1102
1099
  }
1103
- /**
1104
- * Update progress in the result file.
1105
- */
1106
- function updateProgress(resultFile, step, progress, startedAt) {
1100
+ function updateProgress(resultFile, step, startedAt) {
1107
1101
  writeResultFile(resultFile, {
1108
1102
  status: "running",
1109
1103
  step,
1110
1104
  totalSteps: TOTAL_STEPS,
1111
- progress,
1105
+ progress: STEPS[step - 1],
1112
1106
  startedAt
1113
1107
  });
1114
1108
  }
1115
- /**
1116
- * Mark the task as done.
1117
- */
1118
1109
  function markDone(resultFile, startedAt) {
1119
1110
  writeResultFile(resultFile, {
1120
1111
  status: "done",
@@ -1125,139 +1116,182 @@ function markDone(resultFile, startedAt) {
1125
1116
  completedAt: (/* @__PURE__ */ new Date()).toISOString()
1126
1117
  });
1127
1118
  }
1128
- /**
1129
- * Mark the task as failed.
1130
- */
1131
- function markFailed(resultFile, step, progress, error, startedAt) {
1119
+ function markFailed(resultFile, step, error, startedAt) {
1132
1120
  writeResultFile(resultFile, {
1133
1121
  status: "failed",
1134
1122
  step,
1135
1123
  totalSteps: TOTAL_STEPS,
1136
- progress,
1124
+ progress: step > 0 ? STEPS[step - 1] : "初始化",
1137
1125
  error,
1138
1126
  startedAt,
1139
1127
  completedAt: (/* @__PURE__ */ new Date()).toISOString()
1140
1128
  });
1141
1129
  }
1130
+ /** Step 1: Backup current config as openclaw.json.bak.N */
1131
+ function backupCurrentConfig(configPath) {
1132
+ if (!fileExists(configPath)) return;
1133
+ const dir = node_path.default.dirname(configPath);
1134
+ let maxN = 0;
1135
+ try {
1136
+ for (const f of node_fs.default.readdirSync(dir)) {
1137
+ const match = f.match(/^openclaw\.json\.bak\.(\d+)$/);
1138
+ if (match) {
1139
+ const n = parseInt(match[1], 10);
1140
+ if (n > maxN) maxN = n;
1141
+ }
1142
+ }
1143
+ } catch {}
1144
+ node_fs.default.copyFileSync(configPath, configPath + ".bak." + (maxN + 1));
1145
+ }
1146
+ /** Step 2: Download/copy template zip and extract to TMP_RESET_DIR. Returns srcDir. */
1147
+ function downloadAndExtractTemplate(zipDownloadURL) {
1148
+ if (!node_fs.default.existsSync(TMP_RESET_DIR)) node_fs.default.mkdirSync(TMP_RESET_DIR, { recursive: true });
1149
+ const zipPath = node_path.default.join(TMP_RESET_DIR, "template.zip");
1150
+ if (zipDownloadURL.startsWith("http://") || zipDownloadURL.startsWith("https://")) shell(`curl -sSL -o '${zipPath}' '${zipDownloadURL}'`, 12e4);
1151
+ else shell(`cp "${zipDownloadURL}" '${zipPath}'`, 1e4);
1152
+ shell(`unzip -o '${zipPath}' -d '${TMP_RESET_DIR}'`, 6e4);
1153
+ return findSrcDir(TMP_RESET_DIR);
1154
+ }
1155
+ /** Step 3: Replace $$__XXX__ placeholders and write default config. */
1156
+ function generateDefaultConfig(srcDir, configPath, templateVars) {
1157
+ const srcConfigPath = node_path.default.join(srcDir, "openclaw.json");
1158
+ if (!fileExists(srcConfigPath)) throw new Error("template openclaw.json not found at " + srcConfigPath);
1159
+ let content = node_fs.default.readFileSync(srcConfigPath, "utf-8");
1160
+ for (const [placeholder, value] of Object.entries(templateVars)) content = content.split(placeholder).join(value);
1161
+ node_fs.default.writeFileSync(configPath, content, "utf-8");
1162
+ }
1163
+ /** Step 4: Kill all openclaw processes. */
1164
+ function killOpenclawProcesses() {
1165
+ try {
1166
+ shell("pkill -f openclaw-gateway || true", 5e3);
1167
+ } catch {}
1168
+ shell("sleep 2", 5e3);
1169
+ }
1170
+ /** Step 5: Reinstall openclaw to the version specified in template. */
1171
+ function reinstallOpenclaw(srcDir) {
1172
+ const version = loadJSON5().parse(node_fs.default.readFileSync(node_path.default.join(srcDir, "openclaw.json"), "utf-8")).meta?.lastTouchedVersion;
1173
+ try {
1174
+ shell("npm uninstall -g openclaw 2>/dev/null || true", 3e4);
1175
+ } catch {}
1176
+ shell(`npm i -g openclaw@${version || "latest"}`, 6e5);
1177
+ shell("openclaw doctor --fix", 12e4);
1178
+ }
1179
+ /** Step 6: Merge core-backup.json into config + ensure allowedOrigins. */
1180
+ function mergeCoreBackupAndOrigins(configPath, vars) {
1181
+ const JSON5 = loadJSON5();
1182
+ if (fileExists(CORE_BACKUP_PATH)) {
1183
+ const backup = JSON.parse(node_fs.default.readFileSync(CORE_BACKUP_PATH, "utf-8"));
1184
+ const config = JSON5.parse(node_fs.default.readFileSync(configPath, "utf-8"));
1185
+ if (backup.agents) config.agents = backup.agents;
1186
+ if (backup.bindings) config.bindings = backup.bindings;
1187
+ const backupAccounts = backup.channels?.feishu;
1188
+ if (backupAccounts?.accounts) {
1189
+ if (!config.channels) config.channels = {};
1190
+ const ch = config.channels;
1191
+ if (!ch.feishu) ch.feishu = {};
1192
+ ch.feishu.accounts = backupAccounts.accounts;
1193
+ }
1194
+ node_fs.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
1195
+ }
1196
+ const expectedOrigins = Array.isArray(vars.expectedOrigins) ? vars.expectedOrigins : [];
1197
+ if (expectedOrigins.length > 0) {
1198
+ const config = JSON5.parse(node_fs.default.readFileSync(configPath, "utf-8"));
1199
+ if (!config.gateway) config.gateway = {};
1200
+ const gw = config.gateway;
1201
+ if (!gw.controlUi) gw.controlUi = {};
1202
+ const cui = gw.controlUi;
1203
+ const current = Array.isArray(cui.allowedOrigins) ? cui.allowedOrigins.filter((o) => typeof o === "string") : [];
1204
+ const seen = new Set(current);
1205
+ const merged = [...current];
1206
+ for (const o of expectedOrigins) if (!seen.has(o)) {
1207
+ merged.push(o);
1208
+ seen.add(o);
1209
+ }
1210
+ cui.allowedOrigins = merged;
1211
+ node_fs.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
1212
+ }
1213
+ }
1214
+ /** Step 7: Copy startup scripts from template to agent dir. */
1215
+ function copyStartupScripts(srcDir, configDir) {
1216
+ const srcScriptsDir = node_path.default.join(srcDir, "scripts");
1217
+ const targetScriptsDir = node_path.default.join(configDir, "scripts");
1218
+ if (!node_fs.default.existsSync(srcScriptsDir)) return;
1219
+ if (!node_fs.default.existsSync(targetScriptsDir)) node_fs.default.mkdirSync(targetScriptsDir, { recursive: true });
1220
+ shell(`cp -r '${srcScriptsDir}'/* '${targetScriptsDir}/'`, 1e4);
1221
+ }
1222
+ /** Step 8: Reinstall all plugins via openclaw CLI. */
1223
+ function reinstallPlugins() {
1224
+ try {
1225
+ shell("openclaw plugins update --all", 3e5);
1226
+ } catch {}
1227
+ }
1228
+ /** Step 9: Write secrets/provider key files and restart openclaw. */
1229
+ function writeSecretsAndRestart(vars, resetData, configDir) {
1230
+ if (resetData.secretsContent && vars.secretsFilePath) writeFile(vars.secretsFilePath, resetData.secretsContent);
1231
+ if (resetData.providerKeyContent && vars.providerFilePath) writeFile(vars.providerFilePath, resetData.providerKeyContent);
1232
+ const restartScript = node_path.default.join(configDir, "scripts", "restart.sh");
1233
+ if (fileExists(restartScript)) shell(`bash '${restartScript}'`, 3e4);
1234
+ }
1235
+ /** Clean up temporary reset directory. */
1236
+ function cleanup() {
1237
+ try {
1238
+ node_fs.default.rmSync(TMP_RESET_DIR, {
1239
+ recursive: true,
1240
+ force: true
1241
+ });
1242
+ } catch {}
1243
+ }
1142
1244
  /**
1143
1245
  * Run the 9-step reset process. Called from the worker entry point.
1246
+ *
1247
+ * Each step is an independent function. The orchestrator handles progress
1248
+ * reporting, error handling, and process-level exception guards.
1144
1249
  */
1145
1250
  function runReset(input, taskId, resultFile) {
1146
1251
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
1147
- const { configPath, resetData } = input;
1252
+ const { configPath, vars, resetData } = input;
1148
1253
  const configDir = node_path.default.dirname(configPath);
1149
1254
  let currentStep = 0;
1150
1255
  process.on("uncaughtException", (err) => {
1151
- const stepName = currentStep > 0 ? STEPS[currentStep - 1] : "初始化";
1152
- markFailed(resultFile, currentStep, stepName, `uncaught exception: ${err.message}`, startedAt);
1256
+ markFailed(resultFile, currentStep, `uncaught exception: ${err.message}`, startedAt);
1153
1257
  process.exit(1);
1154
1258
  });
1155
1259
  process.on("unhandledRejection", (reason) => {
1156
- const stepName = currentStep > 0 ? STEPS[currentStep - 1] : "初始化";
1157
- markFailed(resultFile, currentStep, stepName, `unhandled rejection: ${reason}`, startedAt);
1260
+ markFailed(resultFile, currentStep, `unhandled rejection: ${reason}`, startedAt);
1158
1261
  process.exit(1);
1159
1262
  });
1263
+ /** Advance to the next step, updating the progress file. */
1264
+ const step = (n) => {
1265
+ currentStep = n;
1266
+ updateProgress(resultFile, n, startedAt);
1267
+ };
1160
1268
  try {
1161
- currentStep = 1;
1162
- updateProgress(resultFile, currentStep, STEPS[0], startedAt);
1163
- if (fileExists(configPath)) {
1164
- let maxN = 0;
1165
- try {
1166
- const files = node_fs.default.readdirSync(configDir);
1167
- const bakPattern = /^openclaw\.json\.bak\.(\d+)$/;
1168
- for (const f of files) {
1169
- const match = f.match(bakPattern);
1170
- if (match) {
1171
- const n = parseInt(match[1], 10);
1172
- if (n > maxN) maxN = n;
1173
- }
1174
- }
1175
- } catch {}
1176
- const bakPath = configPath + ".bak." + (maxN + 1);
1177
- node_fs.default.copyFileSync(configPath, bakPath);
1178
- }
1179
- currentStep = 2;
1180
- updateProgress(resultFile, currentStep, STEPS[1], startedAt);
1181
- if (!node_fs.default.existsSync(TMP_RESET_DIR)) node_fs.default.mkdirSync(TMP_RESET_DIR, { recursive: true });
1182
- const zipPath = node_path.default.join(TMP_RESET_DIR, "template.zip");
1183
- const zipSource = resetData.zipDownloadURL;
1184
- if (zipSource.startsWith("http://") || zipSource.startsWith("https://")) shell(`curl -sSL -o '${zipPath}' '${zipSource}'`, 12e4);
1185
- else shell(`cp "${zipSource}" '${zipPath}'`, 1e4);
1186
- shell(`unzip -o '${zipPath}' -d '${TMP_RESET_DIR}'`, 6e4);
1187
- const srcDir = findSrcDir(TMP_RESET_DIR);
1188
- currentStep = 3;
1189
- updateProgress(resultFile, currentStep, STEPS[2], startedAt);
1190
- const srcConfigPath = node_path.default.join(srcDir, "openclaw.json");
1191
- if (!fileExists(srcConfigPath)) throw new Error("template openclaw.json not found in downloaded zip at " + srcConfigPath);
1192
- let configContent = node_fs.default.readFileSync(srcConfigPath, "utf-8");
1193
- for (const [placeholder, value] of Object.entries(resetData.templateVars)) configContent = configContent.split(placeholder).join(value);
1194
- node_fs.default.writeFileSync(configPath, configContent, "utf-8");
1195
- currentStep = 4;
1196
- updateProgress(resultFile, currentStep, STEPS[3], startedAt);
1197
- try {
1198
- shell("pkill -f openclaw-gateway || true", 5e3);
1199
- } catch {}
1200
- shell("sleep 2", 5e3);
1201
- currentStep = 5;
1202
- updateProgress(resultFile, currentStep, STEPS[4], startedAt);
1203
- const JSON5 = loadJSON5();
1204
- const version = JSON5.parse(node_fs.default.readFileSync(srcConfigPath, "utf-8")).meta?.lastTouchedVersion;
1205
- if (version) shell(`npm i -g openclaw@${version}`, 3e5);
1206
- else shell("npm i -g openclaw@latest", 3e5);
1207
- shell("openclaw doctor --fix", 6e4);
1208
- currentStep = 6;
1209
- updateProgress(resultFile, currentStep, STEPS[5], startedAt);
1210
- if (fileExists(CORE_BACKUP_PATH)) {
1211
- const backup = JSON.parse(node_fs.default.readFileSync(CORE_BACKUP_PATH, "utf-8"));
1212
- const mergeConfig = JSON5.parse(node_fs.default.readFileSync(configPath, "utf-8"));
1213
- if (backup.agents) mergeConfig.agents = backup.agents;
1214
- if (backup.bindings) mergeConfig.bindings = backup.bindings;
1215
- const backupFeishu = backup.channels?.feishu;
1216
- if (backupFeishu?.accounts) {
1217
- if (!mergeConfig.channels) mergeConfig.channels = {};
1218
- const ch = mergeConfig.channels;
1219
- if (!ch.feishu) ch.feishu = {};
1220
- const feishu = ch.feishu;
1221
- feishu.accounts = backupFeishu.accounts;
1222
- }
1223
- node_fs.default.writeFileSync(configPath, JSON.stringify(mergeConfig, null, 2), "utf-8");
1224
- }
1225
- currentStep = 7;
1226
- updateProgress(resultFile, currentStep, STEPS[6], startedAt);
1227
- const srcScriptsDir = node_path.default.join(srcDir, "scripts");
1228
- const targetScriptsDir = node_path.default.join(configDir, "scripts");
1229
- if (node_fs.default.existsSync(srcScriptsDir)) {
1230
- if (!node_fs.default.existsSync(targetScriptsDir)) node_fs.default.mkdirSync(targetScriptsDir, { recursive: true });
1231
- shell(`cp -r '${srcScriptsDir}'/* '${targetScriptsDir}/'`, 1e4);
1232
- }
1233
- currentStep = 8;
1234
- updateProgress(resultFile, currentStep, STEPS[7], startedAt);
1235
- try {
1236
- shell("openclaw plugins update --all", 3e5);
1237
- } catch (e) {}
1238
- currentStep = 9;
1239
- updateProgress(resultFile, currentStep, STEPS[8], startedAt);
1240
- if (resetData.secretsContent && input.vars.secretsFilePath) writeFile(input.vars.secretsFilePath, resetData.secretsContent);
1241
- if (resetData.providerKeyContent && input.vars.providerFilePath) writeFile(input.vars.providerFilePath, resetData.providerKeyContent);
1242
- const restartScript = node_path.default.join(configDir, "scripts", "restart.sh");
1243
- if (fileExists(restartScript)) shell(`bash '${restartScript}'`, 3e4);
1244
- try {
1245
- node_fs.default.rmSync(TMP_RESET_DIR, {
1246
- recursive: true,
1247
- force: true
1248
- });
1249
- } catch {}
1269
+ step(1);
1270
+ backupCurrentConfig(configPath);
1271
+ step(2);
1272
+ const srcDir = downloadAndExtractTemplate(resetData.zipDownloadURL);
1273
+ step(3);
1274
+ generateDefaultConfig(srcDir, configPath, resetData.templateVars);
1275
+ step(4);
1276
+ killOpenclawProcesses();
1277
+ step(5);
1278
+ reinstallOpenclaw(srcDir);
1279
+ step(6);
1280
+ mergeCoreBackupAndOrigins(configPath, vars);
1281
+ step(7);
1282
+ copyStartupScripts(srcDir, configDir);
1283
+ step(8);
1284
+ reinstallPlugins();
1285
+ step(9);
1286
+ writeSecretsAndRestart(vars, resetData, configDir);
1287
+ cleanup();
1250
1288
  markDone(resultFile, startedAt);
1251
1289
  } catch (e) {
1252
- const stepName = currentStep > 0 ? STEPS[currentStep - 1] : "初始化";
1253
- markFailed(resultFile, currentStep, stepName, e.message, startedAt);
1290
+ markFailed(resultFile, currentStep, e.message, startedAt);
1254
1291
  process.exit(1);
1255
1292
  }
1256
1293
  }
1257
- /**
1258
- * Find the source directory within the extracted zip.
1259
- * Looks for openclaw.json in TMP_RESET_DIR or one level deep.
1260
- */
1294
+ /** Find the source directory within the extracted zip (openclaw.json location). */
1261
1295
  function findSrcDir(baseDir) {
1262
1296
  if (node_fs.default.existsSync(node_path.default.join(baseDir, "openclaw.json"))) return baseDir;
1263
1297
  const entries = node_fs.default.readdirSync(baseDir, { withFileTypes: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/openclaw-scripts-diagnose-cli",
3
- "version": "0.1.1-alpha.5",
3
+ "version": "0.1.1-alpha.7",
4
4
  "description": "CLI for OpenClaw config diagnose and repair with JSON5 support",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {