@lark-apaas/openclaw-scripts-diagnose-cli 0.1.1-alpha.6 → 0.1.1-alpha.8

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 CHANGED
@@ -1078,7 +1078,6 @@ function startAsyncReset(ctxBase64) {
1078
1078
  //#region src/reset.ts
1079
1079
  const STEPS = [
1080
1080
  "备份当前配置",
1081
- "下载技术栈模板",
1082
1081
  "生成默认配置",
1083
1082
  "杀掉 openclaw 进程",
1084
1083
  "重装 openclaw",
@@ -1089,10 +1088,14 @@ const STEPS = [
1089
1088
  ];
1090
1089
  const TOTAL_STEPS = STEPS.length;
1091
1090
  const CORE_BACKUP_PATH = "/home/gem/workspace/.force/openclaw/core-backup.json";
1092
- const TMP_RESET_DIR = "/tmp/openclaw-reset";
1093
1091
  /**
1094
- * Atomically write the result file (write .tmp + rename).
1092
+ * Directory holding the bundled openclaw template (openclaw.json + scripts/).
1093
+ * Synced from git@code.byted.org:apaas/miaoda-openclaw-template.git via
1094
+ * scripts/sync-template.sh and published alongside dist/.
1095
+ *
1096
+ * At runtime, __dirname points to dist/, so the template lives one level up.
1095
1097
  */
1098
+ const TEMPLATE_DIR = node_path.default.resolve(__dirname, "..", "template");
1096
1099
  function writeResultFile(resultFile, result) {
1097
1100
  const dir = node_path.default.dirname(resultFile);
1098
1101
  if (!node_fs.default.existsSync(dir)) node_fs.default.mkdirSync(dir, { recursive: true });
@@ -1100,21 +1103,15 @@ function writeResultFile(resultFile, result) {
1100
1103
  node_fs.default.writeFileSync(tmpPath, JSON.stringify(result), "utf-8");
1101
1104
  node_fs.default.renameSync(tmpPath, resultFile);
1102
1105
  }
1103
- /**
1104
- * Update progress in the result file.
1105
- */
1106
- function updateProgress(resultFile, step, progress, startedAt) {
1106
+ function updateProgress(resultFile, step, startedAt) {
1107
1107
  writeResultFile(resultFile, {
1108
1108
  status: "running",
1109
1109
  step,
1110
1110
  totalSteps: TOTAL_STEPS,
1111
- progress,
1111
+ progress: STEPS[step - 1],
1112
1112
  startedAt
1113
1113
  });
1114
1114
  }
1115
- /**
1116
- * Mark the task as done.
1117
- */
1118
1115
  function markDone(resultFile, startedAt) {
1119
1116
  writeResultFile(resultFile, {
1120
1117
  status: "done",
@@ -1125,151 +1122,169 @@ function markDone(resultFile, startedAt) {
1125
1122
  completedAt: (/* @__PURE__ */ new Date()).toISOString()
1126
1123
  });
1127
1124
  }
1128
- /**
1129
- * Mark the task as failed.
1130
- */
1131
- function markFailed(resultFile, step, progress, error, startedAt) {
1125
+ function markFailed(resultFile, step, error, startedAt) {
1132
1126
  writeResultFile(resultFile, {
1133
1127
  status: "failed",
1134
1128
  step,
1135
1129
  totalSteps: TOTAL_STEPS,
1136
- progress,
1130
+ progress: step > 0 ? STEPS[step - 1] : "初始化",
1137
1131
  error,
1138
1132
  startedAt,
1139
1133
  completedAt: (/* @__PURE__ */ new Date()).toISOString()
1140
1134
  });
1141
1135
  }
1136
+ /** Step 1: Backup current config as openclaw.json.bak.N */
1137
+ function backupCurrentConfig(configPath) {
1138
+ if (!fileExists(configPath)) return;
1139
+ const dir = node_path.default.dirname(configPath);
1140
+ let maxN = 0;
1141
+ try {
1142
+ for (const f of node_fs.default.readdirSync(dir)) {
1143
+ const match = f.match(/^openclaw\.json\.bak\.(\d+)$/);
1144
+ if (match) {
1145
+ const n = parseInt(match[1], 10);
1146
+ if (n > maxN) maxN = n;
1147
+ }
1148
+ }
1149
+ } catch {}
1150
+ node_fs.default.copyFileSync(configPath, configPath + ".bak." + (maxN + 1));
1151
+ }
1152
+ /** Step 2: Replace $$__XXX__ placeholders and write default config. */
1153
+ function generateDefaultConfig(srcDir, configPath, templateVars) {
1154
+ const srcConfigPath = node_path.default.join(srcDir, "openclaw.json");
1155
+ if (!fileExists(srcConfigPath)) throw new Error("template openclaw.json not found at " + srcConfigPath);
1156
+ let content = node_fs.default.readFileSync(srcConfigPath, "utf-8");
1157
+ for (const [placeholder, value] of Object.entries(templateVars)) content = content.split(placeholder).join(value);
1158
+ node_fs.default.writeFileSync(configPath, content, "utf-8");
1159
+ }
1160
+ /** Step 3: Kill all openclaw processes. */
1161
+ function killOpenclawProcesses() {
1162
+ try {
1163
+ shell("pkill -f openclaw-gateway || true", 5e3);
1164
+ } catch {}
1165
+ shell("sleep 2", 5e3);
1166
+ }
1167
+ /** Step 4: Reinstall openclaw to the version specified in template. */
1168
+ function reinstallOpenclaw(srcDir) {
1169
+ const version = loadJSON5().parse(node_fs.default.readFileSync(node_path.default.join(srcDir, "openclaw.json"), "utf-8")).meta?.lastTouchedVersion;
1170
+ try {
1171
+ shell("npm uninstall -g openclaw 2>/dev/null || true", 3e4);
1172
+ } catch {}
1173
+ shell(`npm i -g openclaw@${version || "latest"}`, 6e5);
1174
+ shell("openclaw doctor --fix", 12e4);
1175
+ }
1176
+ /** Step 5: Merge core-backup.json into config + ensure allowedOrigins. */
1177
+ function mergeCoreBackupAndOrigins(configPath, vars) {
1178
+ const JSON5 = loadJSON5();
1179
+ if (fileExists(CORE_BACKUP_PATH)) {
1180
+ const backup = JSON.parse(node_fs.default.readFileSync(CORE_BACKUP_PATH, "utf-8"));
1181
+ const config = JSON5.parse(node_fs.default.readFileSync(configPath, "utf-8"));
1182
+ if (backup.agents) config.agents = backup.agents;
1183
+ if (backup.bindings) config.bindings = backup.bindings;
1184
+ const backupAccounts = backup.channels?.feishu;
1185
+ if (backupAccounts?.accounts) {
1186
+ if (!config.channels) config.channels = {};
1187
+ const ch = config.channels;
1188
+ if (!ch.feishu) ch.feishu = {};
1189
+ ch.feishu.accounts = backupAccounts.accounts;
1190
+ }
1191
+ node_fs.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
1192
+ }
1193
+ const expectedOrigins = Array.isArray(vars.expectedOrigins) ? vars.expectedOrigins : [];
1194
+ if (expectedOrigins.length > 0) {
1195
+ const config = JSON5.parse(node_fs.default.readFileSync(configPath, "utf-8"));
1196
+ if (!config.gateway) config.gateway = {};
1197
+ const gw = config.gateway;
1198
+ if (!gw.controlUi) gw.controlUi = {};
1199
+ const cui = gw.controlUi;
1200
+ const current = Array.isArray(cui.allowedOrigins) ? cui.allowedOrigins.filter((o) => typeof o === "string") : [];
1201
+ const seen = new Set(current);
1202
+ const merged = [...current];
1203
+ for (const o of expectedOrigins) if (!seen.has(o)) {
1204
+ merged.push(o);
1205
+ seen.add(o);
1206
+ }
1207
+ cui.allowedOrigins = merged;
1208
+ node_fs.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
1209
+ }
1210
+ }
1211
+ /** Step 6: Copy startup scripts from template to agent dir. */
1212
+ function copyStartupScripts(srcDir, configDir) {
1213
+ const srcScriptsDir = node_path.default.join(srcDir, "scripts");
1214
+ const targetScriptsDir = node_path.default.join(configDir, "scripts");
1215
+ if (!node_fs.default.existsSync(srcScriptsDir)) return;
1216
+ if (!node_fs.default.existsSync(targetScriptsDir)) node_fs.default.mkdirSync(targetScriptsDir, { recursive: true });
1217
+ shell(`cp -r '${srcScriptsDir}'/* '${targetScriptsDir}/'`, 1e4);
1218
+ }
1219
+ /** Step 7: Reinstall all plugins via openclaw CLI. */
1220
+ function reinstallPlugins() {
1221
+ try {
1222
+ shell("openclaw plugins update --all", 3e5);
1223
+ } catch {}
1224
+ }
1225
+ /** Step 8: Write secrets/provider key files and restart openclaw. */
1226
+ function writeSecretsAndRestart(vars, resetData, configDir) {
1227
+ if (resetData.secretsContent && vars.secretsFilePath) writeFile(vars.secretsFilePath, resetData.secretsContent);
1228
+ if (resetData.providerKeyContent && vars.providerFilePath) writeFile(vars.providerFilePath, resetData.providerKeyContent);
1229
+ const restartScript = node_path.default.join(configDir, "scripts", "restart.sh");
1230
+ if (fileExists(restartScript)) shell(`bash '${restartScript}'`, 3e4);
1231
+ }
1142
1232
  /**
1143
- * Run the 9-step reset process. Called from the worker entry point.
1233
+ * Run the 8-step reset process. Called from the worker entry point.
1234
+ *
1235
+ * Each step is an independent function. The orchestrator handles progress
1236
+ * reporting, error handling, and process-level exception guards.
1237
+ *
1238
+ * The openclaw.json / scripts/*.sh template files are bundled with this CLI
1239
+ * (see TEMPLATE_DIR) and synced from the miaoda-openclaw-template repo via
1240
+ * scripts/sync-template.sh, so no runtime download is required.
1144
1241
  */
1145
1242
  function runReset(input, taskId, resultFile) {
1146
1243
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
1147
- const { configPath, resetData } = input;
1244
+ const { configPath, vars, resetData } = input;
1148
1245
  const configDir = node_path.default.dirname(configPath);
1246
+ const srcDir = TEMPLATE_DIR;
1149
1247
  let currentStep = 0;
1248
+ if (!node_fs.default.existsSync(node_path.default.join(srcDir, "openclaw.json"))) {
1249
+ markFailed(resultFile, 0, `bundled template not found at ${srcDir}`, startedAt);
1250
+ process.exit(1);
1251
+ }
1150
1252
  process.on("uncaughtException", (err) => {
1151
- const stepName = currentStep > 0 ? STEPS[currentStep - 1] : "初始化";
1152
- markFailed(resultFile, currentStep, stepName, `uncaught exception: ${err.message}`, startedAt);
1253
+ markFailed(resultFile, currentStep, `uncaught exception: ${err.message}`, startedAt);
1153
1254
  process.exit(1);
1154
1255
  });
1155
1256
  process.on("unhandledRejection", (reason) => {
1156
- const stepName = currentStep > 0 ? STEPS[currentStep - 1] : "初始化";
1157
- markFailed(resultFile, currentStep, stepName, `unhandled rejection: ${reason}`, startedAt);
1257
+ markFailed(resultFile, currentStep, `unhandled rejection: ${reason}`, startedAt);
1158
1258
  process.exit(1);
1159
1259
  });
1260
+ /** Advance to the next step, updating the progress file. */
1261
+ const step = (n) => {
1262
+ currentStep = n;
1263
+ updateProgress(resultFile, n, startedAt);
1264
+ };
1160
1265
  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
- try {
1206
- shell("npm uninstall -g openclaw 2>/dev/null || true", 3e4);
1207
- } catch {}
1208
- if (version) shell(`npm i -g openclaw@${version}`, 6e5);
1209
- else shell("npm i -g openclaw@latest", 6e5);
1210
- shell("openclaw doctor --fix", 12e4);
1211
- currentStep = 6;
1212
- updateProgress(resultFile, currentStep, STEPS[5], startedAt);
1213
- if (fileExists(CORE_BACKUP_PATH)) {
1214
- const backup = JSON.parse(node_fs.default.readFileSync(CORE_BACKUP_PATH, "utf-8"));
1215
- const mergeConfig = JSON5.parse(node_fs.default.readFileSync(configPath, "utf-8"));
1216
- if (backup.agents) mergeConfig.agents = backup.agents;
1217
- if (backup.bindings) mergeConfig.bindings = backup.bindings;
1218
- const backupFeishu = backup.channels?.feishu;
1219
- if (backupFeishu?.accounts) {
1220
- if (!mergeConfig.channels) mergeConfig.channels = {};
1221
- const ch = mergeConfig.channels;
1222
- if (!ch.feishu) ch.feishu = {};
1223
- const feishu = ch.feishu;
1224
- feishu.accounts = backupFeishu.accounts;
1225
- }
1226
- node_fs.default.writeFileSync(configPath, JSON.stringify(mergeConfig, null, 2), "utf-8");
1227
- }
1228
- currentStep = 7;
1229
- updateProgress(resultFile, currentStep, STEPS[6], startedAt);
1230
- const srcScriptsDir = node_path.default.join(srcDir, "scripts");
1231
- const targetScriptsDir = node_path.default.join(configDir, "scripts");
1232
- if (node_fs.default.existsSync(srcScriptsDir)) {
1233
- if (!node_fs.default.existsSync(targetScriptsDir)) node_fs.default.mkdirSync(targetScriptsDir, { recursive: true });
1234
- shell(`cp -r '${srcScriptsDir}'/* '${targetScriptsDir}/'`, 1e4);
1235
- }
1236
- currentStep = 8;
1237
- updateProgress(resultFile, currentStep, STEPS[7], startedAt);
1238
- try {
1239
- shell("openclaw plugins update --all", 3e5);
1240
- } catch (e) {}
1241
- currentStep = 9;
1242
- updateProgress(resultFile, currentStep, STEPS[8], startedAt);
1243
- if (resetData.secretsContent && input.vars.secretsFilePath) writeFile(input.vars.secretsFilePath, resetData.secretsContent);
1244
- if (resetData.providerKeyContent && input.vars.providerFilePath) writeFile(input.vars.providerFilePath, resetData.providerKeyContent);
1245
- const restartScript = node_path.default.join(configDir, "scripts", "restart.sh");
1246
- if (fileExists(restartScript)) shell(`bash '${restartScript}'`, 3e4);
1247
- try {
1248
- node_fs.default.rmSync(TMP_RESET_DIR, {
1249
- recursive: true,
1250
- force: true
1251
- });
1252
- } catch {}
1266
+ step(1);
1267
+ backupCurrentConfig(configPath);
1268
+ step(2);
1269
+ generateDefaultConfig(srcDir, configPath, resetData.templateVars);
1270
+ step(3);
1271
+ killOpenclawProcesses();
1272
+ step(4);
1273
+ reinstallOpenclaw(srcDir);
1274
+ step(5);
1275
+ mergeCoreBackupAndOrigins(configPath, vars);
1276
+ step(6);
1277
+ copyStartupScripts(srcDir, configDir);
1278
+ step(7);
1279
+ reinstallPlugins();
1280
+ step(8);
1281
+ writeSecretsAndRestart(vars, resetData, configDir);
1253
1282
  markDone(resultFile, startedAt);
1254
1283
  } catch (e) {
1255
- const stepName = currentStep > 0 ? STEPS[currentStep - 1] : "初始化";
1256
- markFailed(resultFile, currentStep, stepName, e.message, startedAt);
1284
+ markFailed(resultFile, currentStep, e.message, startedAt);
1257
1285
  process.exit(1);
1258
1286
  }
1259
1287
  }
1260
- /**
1261
- * Find the source directory within the extracted zip.
1262
- * Looks for openclaw.json in TMP_RESET_DIR or one level deep.
1263
- */
1264
- function findSrcDir(baseDir) {
1265
- if (node_fs.default.existsSync(node_path.default.join(baseDir, "openclaw.json"))) return baseDir;
1266
- const entries = node_fs.default.readdirSync(baseDir, { withFileTypes: true });
1267
- for (const entry of entries) if (entry.isDirectory()) {
1268
- const candidate = node_path.default.join(baseDir, entry.name);
1269
- if (node_fs.default.existsSync(node_path.default.join(candidate, "openclaw.json"))) return candidate;
1270
- }
1271
- return baseDir;
1272
- }
1273
1288
  //#endregion
1274
1289
  //#region src/get-reset-task.ts
1275
1290
  /**
package/package.json CHANGED
@@ -1,19 +1,21 @@
1
1
  {
2
2
  "name": "@lark-apaas/openclaw-scripts-diagnose-cli",
3
- "version": "0.1.1-alpha.6",
3
+ "version": "0.1.1-alpha.8",
4
4
  "description": "CLI for OpenClaw config diagnose and repair with JSON5 support",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {
7
7
  "mclaw-diagnose": "./dist/index.cjs"
8
8
  },
9
9
  "files": [
10
- "dist"
10
+ "dist",
11
+ "template"
11
12
  ],
12
13
  "scripts": {
13
14
  "build": "tsdown",
14
15
  "test": "vitest run",
15
16
  "test:watch": "vitest",
16
17
  "test:integration": "vitest run --config vitest.integration.config.ts",
18
+ "sync:template": "bash scripts/sync-template.sh",
17
19
  "prepublishOnly": "npm run build"
18
20
  },
19
21
  "keywords": [
@@ -0,0 +1,522 @@
1
+ {
2
+ "meta": {
3
+ "lastTouchedVersion": "2026.4.9",
4
+ "lastTouchedAt": "2026-04-11T09:30:21.703Z"
5
+ },
6
+ "wizard": {
7
+ "lastRunAt": "2026-03-30T14:54:56.160Z",
8
+ "lastRunVersion": "2026.3.24",
9
+ "lastRunCommand": "doctor",
10
+ "lastRunMode": "local"
11
+ },
12
+ "update": {
13
+ "checkOnStart": false
14
+ },
15
+ "browser": {
16
+ "enabled": true,
17
+ "color": "#00AA00",
18
+ "executablePath": "/usr/bin/chromium-browser",
19
+ "headless": true,
20
+ "noSandbox": true,
21
+ "defaultProfile": "openclaw",
22
+ "extraArgs": [
23
+ "--window-size=1920,1080",
24
+ "--test-type",
25
+ "--disable-gpu",
26
+ "--no-sandbox"
27
+ ]
28
+ },
29
+ "secrets": {
30
+ "providers": {
31
+ "miaoda-provider": {
32
+ "source": "file",
33
+ "path": "$$__MIAODA_PROVIDER_FILEPATH__",
34
+ "mode": "singleValue"
35
+ },
36
+ "miaoda-secret-provider": {
37
+ "source": "file",
38
+ "path": "$$__MIAODA_OPENCLAW_SECRETS_FILEPATH__",
39
+ "mode": "json"
40
+ }
41
+ }
42
+ },
43
+ "models": {
44
+ "providers": {
45
+ "miaoda": {
46
+ "baseUrl": "$$__MIAODA_PROVIDER_BASE_URL__",
47
+ "apiKey": {
48
+ "source": "file",
49
+ "provider": "miaoda-provider",
50
+ "id": "value"
51
+ },
52
+ "api": "openai-completions",
53
+ "headers": {
54
+ "x-api-key": {
55
+ "source": "file",
56
+ "provider": "miaoda-secret-provider",
57
+ "id": "/models_providers_miaoda_headers_x_api_key"
58
+ }
59
+ },
60
+ "models": [
61
+ {
62
+ "id": "miaoda-model-auto",
63
+ "name": "妙搭",
64
+ "reasoning": false,
65
+ "input": [
66
+ "text"
67
+ ],
68
+ "cost": {
69
+ "input": 0,
70
+ "output": 0,
71
+ "cacheRead": 0,
72
+ "cacheWrite": 0
73
+ },
74
+ "contextWindow": 200000,
75
+ "maxTokens": 8192
76
+ },
77
+ {
78
+ "id": "miaoda-auto-multimodal",
79
+ "name": "妙搭多模态",
80
+ "reasoning": false,
81
+ "input": [
82
+ "text",
83
+ "image"
84
+ ],
85
+ "cost": {
86
+ "input": 0,
87
+ "output": 0,
88
+ "cacheRead": 0,
89
+ "cacheWrite": 0
90
+ },
91
+ "contextWindow": 200000,
92
+ "maxTokens": 8192
93
+ },
94
+ {
95
+ "id": "miaoda-model-flash",
96
+ "name": "妙搭 Flash",
97
+ "reasoning": false,
98
+ "input": [
99
+ "text"
100
+ ],
101
+ "cost": {
102
+ "input": 0,
103
+ "output": 0,
104
+ "cacheRead": 0,
105
+ "cacheWrite": 0
106
+ },
107
+ "contextWindow": 200000,
108
+ "maxTokens": 8192
109
+ }
110
+ ]
111
+ }
112
+ }
113
+ },
114
+ "agents": {
115
+ "defaults": {
116
+ "model": {
117
+ "primary": "miaoda/miaoda-model-auto"
118
+ },
119
+ "imageModel": "miaoda/miaoda-auto-multimodal",
120
+ "imageGenerationModel": {
121
+ "primary": "miaoda/miaoda-image-gen"
122
+ },
123
+ "models": {
124
+ "miaoda/miaoda-model-auto": {
125
+ "alias": "Miaoda Auto"
126
+ },
127
+ "miaoda/miaoda-auto-multimodal": {
128
+ "alias": "Miaoda Multimodal"
129
+ },
130
+ "miaoda/miaoda-model-flash": {
131
+ "alias": "Miaoda Flash"
132
+ }
133
+ },
134
+ "workspace": "$$__MIAODA_WORKSPACE_DIR__/workspace",
135
+ "compaction": {
136
+ "mode": "safeguard",
137
+ "reserveTokensFloor": 50000
138
+ },
139
+ "verboseDefault": "off",
140
+ "blockStreamingCoalesce": {
141
+ "minChars": 20,
142
+ "maxChars": 800,
143
+ "idleMs": 300
144
+ },
145
+ "humanDelay": {
146
+ "mode": "off"
147
+ },
148
+ "heartbeat": {
149
+ "every": "4h",
150
+ "activeHours": {
151
+ "start": "08:00",
152
+ "end": "22:00"
153
+ },
154
+ "model": "miaoda/miaoda-model-flash"
155
+ },
156
+ "maxConcurrent": 4,
157
+ "subagents": {
158
+ "maxConcurrent": 8
159
+ }
160
+ }
161
+ },
162
+ "tools": {
163
+ "profile": "full",
164
+ "alsoAllow": [
165
+ "feishu_bitable_app",
166
+ "feishu_bitable_app_table",
167
+ "feishu_bitable_app_table_field",
168
+ "feishu_bitable_app_table_record",
169
+ "feishu_bitable_app_table_view",
170
+ "feishu_calendar_calendar",
171
+ "feishu_calendar_event",
172
+ "feishu_calendar_event_attendee",
173
+ "feishu_calendar_freebusy",
174
+ "feishu_chat",
175
+ "feishu_chat_members",
176
+ "feishu_create_doc",
177
+ "feishu_doc_comments",
178
+ "feishu_doc_media",
179
+ "feishu_drive_file",
180
+ "feishu_fetch_doc",
181
+ "feishu_get_user",
182
+ "feishu_im_bot_image",
183
+ "feishu_im_user_fetch_resource",
184
+ "feishu_im_user_get_messages",
185
+ "feishu_im_user_get_thread_messages",
186
+ "feishu_im_user_message",
187
+ "feishu_im_user_search_messages",
188
+ "feishu_oauth",
189
+ "feishu_oauth_batch_auth",
190
+ "feishu_search_doc_wiki",
191
+ "feishu_search_user",
192
+ "feishu_sheet",
193
+ "feishu_task_comment",
194
+ "feishu_task_subtask",
195
+ "feishu_task_task",
196
+ "feishu_task_tasklist",
197
+ "feishu_update_doc",
198
+ "feishu_wiki_space",
199
+ "feishu_wiki_space_node"
200
+ ],
201
+ "deny": [
202
+ "web_fetch",
203
+ "tts",
204
+ "agents_list",
205
+ "feishu_task_task",
206
+ "feishu_task_tasklist",
207
+ "feishu_task_comment",
208
+ "feishu_task_subtask",
209
+ "feishu_bitable_app_table_view",
210
+ "feishu_doc_comments",
211
+ "feishu_doc_media",
212
+ "feishu_drive_file",
213
+ "feishu_wiki_space",
214
+ "feishu_wiki_space_node",
215
+ "feishu_sheet"
216
+ ],
217
+ "web": {
218
+ "search": {
219
+ "provider": "miaoda"
220
+ }
221
+ },
222
+ "media": {
223
+ "image": {
224
+ "models": [
225
+ {
226
+ "provider": "miaoda"
227
+ }
228
+ ]
229
+ },
230
+ "audio": {
231
+ "models": [
232
+ {
233
+ "provider": "miaoda"
234
+ }
235
+ ]
236
+ }
237
+ },
238
+ "sessions": {
239
+ "visibility": "all"
240
+ }
241
+ },
242
+ "messages": {
243
+ "ackReactionScope": "group-mentions"
244
+ },
245
+ "commands": {
246
+ "native": "auto",
247
+ "nativeSkills": "auto",
248
+ "restart": true,
249
+ "ownerDisplay": "raw"
250
+ },
251
+ "session": {
252
+ "dmScope": "per-channel-peer"
253
+ },
254
+ "channels": {
255
+ "feishu": {
256
+ "enabled": true,
257
+ "appId": "$$__FEISHU_APP_ID__",
258
+ "appSecret": {
259
+ "source": "file",
260
+ "provider": "miaoda-secret-provider",
261
+ "id": "/channels_feishu_app_secret"
262
+ },
263
+ "domain": "feishu",
264
+ "requireMention": true,
265
+ "dmPolicy": "allowlist",
266
+ "allowFrom": [
267
+ "$$__FEISHU_OPEN_ID__"
268
+ ],
269
+ "groupPolicy": "allowlist",
270
+ "groupAllowFrom": [
271
+ "$$__FEISHU_OPEN_ID__"
272
+ ],
273
+ "groups": {
274
+ "*": {
275
+ "enabled": true
276
+ }
277
+ },
278
+ "streaming": true,
279
+ "threadSession": true,
280
+ "footer": {
281
+ "elapsed": false,
282
+ "status": false
283
+ }
284
+ }
285
+ },
286
+ "discovery": {
287
+ "mdns": {
288
+ "mode": "off"
289
+ }
290
+ },
291
+ "gateway": {
292
+ "port": 18789,
293
+ "mode": "local",
294
+ "bind": "loopback",
295
+ "controlUi": {
296
+ "allowedOrigins": [
297
+ "$$__MIAODA_DOMAIN__",
298
+ "$$__MIAODA_ORIGIN__"
299
+ ],
300
+ "dangerouslyDisableDeviceAuth": true
301
+ },
302
+ "auth": {
303
+ "mode": "token",
304
+ "token": "$$__CLAW_TOKEN__"
305
+ },
306
+ "trustedProxies": [
307
+ "::1",
308
+ "127.0.0.1"
309
+ ],
310
+ "tailscale": {
311
+ "mode": "off",
312
+ "resetOnExit": false
313
+ }
314
+ },
315
+ "skills": {
316
+ "install": {
317
+ "nodeManager": "npm"
318
+ },
319
+ "entries": {
320
+ "1password": {
321
+ "enabled": false
322
+ },
323
+ "apple-notes": {
324
+ "enabled": false
325
+ },
326
+ "apple-reminders": {
327
+ "enabled": false
328
+ },
329
+ "bear-notes": {
330
+ "enabled": false
331
+ },
332
+ "bluebubbles": {
333
+ "enabled": false
334
+ },
335
+ "blucli": {
336
+ "enabled": false
337
+ },
338
+ "camsnap": {
339
+ "enabled": false
340
+ },
341
+ "coding-agent": {
342
+ "enabled": false
343
+ },
344
+ "discord": {
345
+ "enabled": false
346
+ },
347
+ "eightctl": {
348
+ "enabled": false
349
+ },
350
+ "gemini": {
351
+ "enabled": false
352
+ },
353
+ "gifgrep": {
354
+ "enabled": false
355
+ },
356
+ "gog": {
357
+ "enabled": false
358
+ },
359
+ "goplaces": {
360
+ "enabled": false
361
+ },
362
+ "imsg": {
363
+ "enabled": false
364
+ },
365
+ "model-usage": {
366
+ "enabled": false
367
+ },
368
+ "notion": {
369
+ "enabled": false
370
+ },
371
+ "openai-image-gen": {
372
+ "enabled": false
373
+ },
374
+ "openai-whisper": {
375
+ "enabled": false
376
+ },
377
+ "openai-whisper-api": {
378
+ "enabled": false
379
+ },
380
+ "openhue": {
381
+ "enabled": false
382
+ },
383
+ "oracle": {
384
+ "enabled": false
385
+ },
386
+ "ordercli": {
387
+ "enabled": false
388
+ },
389
+ "peekaboo": {
390
+ "enabled": false
391
+ },
392
+ "sag": {
393
+ "enabled": false
394
+ },
395
+ "slack": {
396
+ "enabled": false
397
+ },
398
+ "sonoscli": {
399
+ "enabled": false
400
+ },
401
+ "spotify-player": {
402
+ "enabled": false
403
+ },
404
+ "summarize": {
405
+ "enabled": false
406
+ },
407
+ "things-mac": {
408
+ "enabled": false
409
+ },
410
+ "trello": {
411
+ "enabled": false
412
+ },
413
+ "voice-call": {
414
+ "enabled": false
415
+ },
416
+ "wacli": {
417
+ "enabled": false
418
+ },
419
+ "xurl": {
420
+ "enabled": false
421
+ },
422
+ "feishu-task": {
423
+ "enabled": false
424
+ },
425
+ "gh-issues": {
426
+ "enabled": false
427
+ },
428
+ "github": {
429
+ "enabled": false
430
+ },
431
+ "tmux": {
432
+ "enabled": false
433
+ },
434
+ "blogwatcher": {
435
+ "enabled": false
436
+ },
437
+ "himalaya": {
438
+ "enabled": false
439
+ },
440
+ "video-frames": {
441
+ "enabled": false
442
+ },
443
+ "obsidian": {
444
+ "enabled": false
445
+ }
446
+ }
447
+ },
448
+ "plugins": {
449
+ "allow": [
450
+ "openclaw-lark",
451
+ "openclaw-extension-miaoda",
452
+ "openclaw-extension-miaoda-coding",
453
+ "browser"
454
+ ],
455
+ "entries": {
456
+ "feishu": {
457
+ "enabled": false
458
+ },
459
+ "openclaw-extension-miaoda": {
460
+ "enabled": true,
461
+ "config": {
462
+ "greeting": {
463
+ "message": "👋 Hi,我是**$$__MIAODA_CLAW_NAME__**,一只生活在飞书里的 🦞 小龙虾,打个招呼,我们开始认识一下?",
464
+ "targets": [
465
+ "$$__FEISHU_OPEN_ID__"
466
+ ]
467
+ }
468
+ }
469
+ },
470
+ "openclaw-lark": {
471
+ "enabled": true
472
+ },
473
+ "openclaw-extension-miaoda-coding": {
474
+ "enabled": true
475
+ },
476
+ "browser": {
477
+ "enabled": true
478
+ }
479
+ },
480
+ "installs": {
481
+ "openclaw-lark": {
482
+ "source": "npm",
483
+ "spec": "@lark-apaas/openclaw-lark",
484
+ "installPath": "./extensions/openclaw-lark",
485
+ "version": "2026.4.3",
486
+ "resolvedName": "@lark-apaas/openclaw-lark",
487
+ "resolvedVersion": "2026.4.3",
488
+ "resolvedSpec": "@lark-apaas/openclaw-lark@2026.4.3",
489
+ "integrity": "sha512-1eJ2WCvAYsnM9TPwPbEoD3nJtqNSOP2zOBV/3Vb9YQRg1kJJspEly5yCjiZt1wew4UhyN8Tcrp/XV78Qn747GA==",
490
+ "shasum": "e8d8cf05f8cb96cf5de4bca097c527eb9116e655",
491
+ "resolvedAt": "2026-04-03T06:27:44.706Z",
492
+ "installedAt": "2026-04-03T06:28:10.547Z"
493
+ },
494
+ "openclaw-extension-miaoda": {
495
+ "source": "npm",
496
+ "installPath": "./extensions/openclaw-extension-miaoda",
497
+ "version": "1.0.9",
498
+ "installedAt": "2026-04-11T09:27:06.639Z",
499
+ "spec": "@lark-apaas/openclaw-extension-miaoda@1.0.9",
500
+ "resolvedVersion": "1.0.9",
501
+ "resolvedName": "@lark-apaas/openclaw-extension-miaoda",
502
+ "resolvedSpec": "@lark-apaas/openclaw-extension-miaoda@1.0.9",
503
+ "resolvedAt": "2026-04-11T09:27:06.639Z",
504
+ "integrity": "sha512-McNeuPAUDLrMhT3yZuwk9A7pI262r2CK1N1KNQP6VuzymkDUjx2sTcJPCEBB3bFkdXd0yUU983/OhJiaJo+JWg==",
505
+ "shasum": "a3c75886e40b63f39a33a2660932f8afdae6a514"
506
+ },
507
+ "openclaw-extension-miaoda-coding": {
508
+ "source": "npm",
509
+ "spec": "@lark-apaas/openclaw-extension-miaoda-coding",
510
+ "installPath": "./extensions/openclaw-extension-miaoda-coding",
511
+ "version": "1.0.8",
512
+ "resolvedName": "@lark-apaas/openclaw-extension-miaoda-coding",
513
+ "resolvedVersion": "1.0.8",
514
+ "resolvedSpec": "@lark-apaas/openclaw-extension-miaoda-coding@1.0.8",
515
+ "integrity": "sha512-uxlLtgH2CTwz56UTaZD+n/x1p2a3Q01o3Og7oLUJCm6izWHXFEI1SQhNnCPggrfSam49KFir8xB64tY4T9dt2Q==",
516
+ "shasum": "058eadf5bc71ae87f79b5096b9d96f4afb89a9db",
517
+ "resolvedAt": "2026-04-09T11:33:36.208Z",
518
+ "installedAt": "2026-04-09T11:33:37.171Z"
519
+ }
520
+ }
521
+ }
522
+ }
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env bash
2
+
3
+ log() { echo "[restart.sh] $(date '+%Y-%m-%d %H:%M:%S') $*"; }
4
+
5
+ gw_alive() {
6
+ pgrep -f "openclaw-gateway|openclaw gateway" | grep -vw "$$" >/dev/null 2>&1
7
+ }
8
+
9
+ if [ -d "/run/systemd/system/" ]; then
10
+ log "systemd detected, restarting via systemctl..."
11
+ sudo systemctl restart openclaw
12
+ log "systemctl restart exit code: $?"
13
+ else
14
+ log "killing openclaw-gateway processes..."
15
+ PIDS_GW=$(pgrep -f "openclaw-gateway|openclaw gateway" | grep -vw "$$" || true)
16
+ if [ -n "$PIDS_GW" ]; then
17
+ log "killing gateway pids: $(echo $PIDS_GW | tr '\n' ' ')"
18
+ kill -9 $PIDS_GW 2>&1
19
+ else
20
+ log "no openclaw-gateway processes found"
21
+ fi
22
+
23
+ for i in $(seq 1 50); do
24
+ gw_alive || break
25
+ sleep 0.1
26
+ done
27
+
28
+ if gw_alive; then
29
+ log "ERROR: openclaw-gateway still alive after 5s, abort"
30
+ exit 1
31
+ fi
32
+ log "openclaw-gateway stopped"
33
+
34
+ log "starting openclaw gateway..."
35
+ nohup openclaw gateway run --port 18789 > /tmp/openclaw-gateway.log 2>&1 &
36
+ log "gateway started (pid=$!)"
37
+ fi
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ if [ -d "/run/systemd/system/" ]; then
3
+ sudo systemctl start openclaw
4
+ else
5
+ nohup openclaw gateway run --port 18789 > /tmp/openclaw-gateway.log 2>&1 &
6
+ fi
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bash
2
+ lsof -nP -iTCP:18789 -sTCP:LISTEN -t | xargs -r kill -9