clawmux 0.1.7 → 0.2.0
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/README.md +17 -45
- package/dist/cli.cjs +181 -38
- package/dist/index.cjs +3223 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,42 +12,25 @@ Smart model routing + context compression proxy for OpenClaw.
|
|
|
12
12
|
- 📊 **Cost Tracking**: Real-time savings stats at /stats endpoint
|
|
13
13
|
- 🔄 **Hot Reload**: Config changes apply without restart
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Installation
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
### For Humans
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
npx clawmux init
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
This will:
|
|
24
|
-
1. Detect your OpenClaw config at `~/.openclaw/openclaw.json`
|
|
25
|
-
2. Create `clawmux.json` from the default template
|
|
26
|
-
3. Register 6 ClawMux providers in your OpenClaw config
|
|
27
|
-
4. Install a system service for auto-start on boot (systemd on Linux, launchd on macOS)
|
|
28
|
-
|
|
29
|
-
ClawMux is now running. Select a provider and start chatting:
|
|
19
|
+
Copy and paste this prompt to your LLM agent (OpenClaw, Claude Code, etc.):
|
|
30
20
|
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
```
|
|
22
|
+
Read the following guide and execute every step without asking for confirmation:
|
|
23
|
+
https://raw.githubusercontent.com/HyeokjaeLee/ClawMux/refs/heads/main/docs/guide/installation.md
|
|
34
24
|
```
|
|
35
25
|
|
|
36
|
-
|
|
26
|
+
Or install manually, but seriously, let an agent do it. Agents don't fat-finger configs.
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
clawmux status # check if running
|
|
40
|
-
clawmux stop # stop the service
|
|
41
|
-
clawmux start # manual foreground start
|
|
42
|
-
clawmux uninstall # remove service + OpenClaw providers
|
|
43
|
-
```
|
|
28
|
+
### For OpenClaw Agents
|
|
44
29
|
|
|
45
|
-
|
|
30
|
+
Fetch the installation guide and follow it:
|
|
46
31
|
|
|
47
32
|
```bash
|
|
48
|
-
|
|
49
|
-
cd ClawMux
|
|
50
|
-
bun install && bun run dev
|
|
33
|
+
curl -s https://raw.githubusercontent.com/HyeokjaeLee/ClawMux/refs/heads/main/docs/guide/installation.md
|
|
51
34
|
```
|
|
52
35
|
|
|
53
36
|
## Configuration
|
|
@@ -66,7 +49,7 @@ Copy `clawmux.example.json` to `clawmux.json` and adjust as needed:
|
|
|
66
49
|
"LIGHT": "anthropic/claude-3-5-haiku-20241022",
|
|
67
50
|
"MEDIUM": "anthropic/claude-sonnet-4-20250514",
|
|
68
51
|
"HEAVY": "anthropic/claude-opus-4-20250514"
|
|
69
|
-
// Model IDs use 'provider/model' format. Do NOT use
|
|
52
|
+
// Model IDs use 'provider/model' format. Do NOT use "clawmux" as provider — causes infinite loops
|
|
70
53
|
}
|
|
71
54
|
},
|
|
72
55
|
"server": {
|
|
@@ -98,20 +81,13 @@ All three providers must be configured in your `openclaw.json`. ClawMux handles
|
|
|
98
81
|
|
|
99
82
|
Supported translation pairs: Anthropic ↔ OpenAI ↔ Google ↔ Ollama ↔ Bedrock (all combinations).
|
|
100
83
|
|
|
101
|
-
##
|
|
102
|
-
|
|
103
|
-
ClawMux registers itself as six providers in OpenClaw, one per API format:
|
|
84
|
+
## Provider
|
|
104
85
|
|
|
105
|
-
|
|
106
|
-
|---|---|
|
|
107
|
-
| `anthropic-messages` | Anthropic, Synthetic, Kimi Coding |
|
|
108
|
-
| `openai-completions` | OpenAI, Moonshot, ZAI, Cerebras, vLLM, SGLang, LM Studio, OpenRouter, Together, NVIDIA, Venice, Groq, Mistral, xAI, HuggingFace, Cloudflare, Volcengine, BytePlus, Vercel, Kilocode, Qianfan, ModelStudio, MiniMax, Xiaomi |
|
|
109
|
-
| `openai-responses` | OpenAI (newer), OpenAI Codex |
|
|
110
|
-
| `google-generative-ai` | Google Gemini, Google Vertex |
|
|
111
|
-
| `ollama` | Ollama |
|
|
112
|
-
| `bedrock-converse-stream` | AWS Bedrock |
|
|
86
|
+
ClawMux registers as a single provider `clawmux` in OpenClaw with model `auto`. It accepts all API formats (Anthropic, OpenAI, Google, Ollama, Bedrock) and translates between them automatically.
|
|
113
87
|
|
|
114
|
-
|
|
88
|
+
```bash
|
|
89
|
+
openclaw provider clawmux
|
|
90
|
+
```
|
|
115
91
|
|
|
116
92
|
## How It Works
|
|
117
93
|
|
|
@@ -172,8 +148,4 @@ Tests are co-located with source files as `*.test.ts`.
|
|
|
172
148
|
clawmux uninstall
|
|
173
149
|
```
|
|
174
150
|
|
|
175
|
-
Stops the system service, removes the service file, and removes
|
|
176
|
-
|
|
177
|
-
## License
|
|
178
|
-
|
|
179
|
-
MIT
|
|
151
|
+
Stops the system service, removes the service file, and removes the `clawmux` provider from your OpenClaw config. A backup is created before any changes.
|
package/dist/cli.cjs
CHANGED
|
@@ -80,7 +80,7 @@ async function writeWebResponse(res, response) {
|
|
|
80
80
|
|
|
81
81
|
// src/cli.ts
|
|
82
82
|
var import_promises = require("node:fs/promises");
|
|
83
|
-
var
|
|
83
|
+
var import_node_path2 = require("node:path");
|
|
84
84
|
var import_node_child_process = require("node:child_process");
|
|
85
85
|
var import_node_os = require("node:os");
|
|
86
86
|
|
|
@@ -247,6 +247,75 @@ function createNodeServer(config) {
|
|
|
247
247
|
};
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
+
// src/utils/logger.ts
|
|
251
|
+
var import_node_fs = require("node:fs");
|
|
252
|
+
var import_node_path = require("node:path");
|
|
253
|
+
var LOG_DIR = import_node_path.join(process.env.HOME ?? "/root", ".openclaw", "clawmux");
|
|
254
|
+
var MAX_DAYS = 7;
|
|
255
|
+
var fileStream = null;
|
|
256
|
+
var currentDate = "";
|
|
257
|
+
function todayString() {
|
|
258
|
+
const d = new Date;
|
|
259
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
260
|
+
}
|
|
261
|
+
function logPath(date) {
|
|
262
|
+
return import_node_path.join(LOG_DIR, `${date}.log`);
|
|
263
|
+
}
|
|
264
|
+
function rotateIfNeeded() {
|
|
265
|
+
const today = todayString();
|
|
266
|
+
if (today === currentDate && fileStream)
|
|
267
|
+
return;
|
|
268
|
+
if (fileStream) {
|
|
269
|
+
fileStream.end();
|
|
270
|
+
}
|
|
271
|
+
currentDate = today;
|
|
272
|
+
fileStream = import_node_fs.createWriteStream(logPath(today), { flags: "a" });
|
|
273
|
+
purgeOldLogs();
|
|
274
|
+
}
|
|
275
|
+
function purgeOldLogs() {
|
|
276
|
+
try {
|
|
277
|
+
const files = import_node_fs.readdirSync(LOG_DIR).filter((f) => f.endsWith(".log")).sort();
|
|
278
|
+
while (files.length > MAX_DAYS) {
|
|
279
|
+
const oldest = files.shift();
|
|
280
|
+
import_node_fs.unlinkSync(import_node_path.join(LOG_DIR, oldest));
|
|
281
|
+
}
|
|
282
|
+
} catch (_) {}
|
|
283
|
+
}
|
|
284
|
+
function formatTimestamp() {
|
|
285
|
+
return new Date().toISOString();
|
|
286
|
+
}
|
|
287
|
+
function writeLine(level, args) {
|
|
288
|
+
rotateIfNeeded();
|
|
289
|
+
const message = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
290
|
+
const line = `${formatTimestamp()} [${level}] ${message}
|
|
291
|
+
`;
|
|
292
|
+
if (fileStream) {
|
|
293
|
+
fileStream.write(line);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function initLogger() {
|
|
297
|
+
import_node_fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
298
|
+
rotateIfNeeded();
|
|
299
|
+
const origLog = console.log.bind(console);
|
|
300
|
+
const origError = console.error.bind(console);
|
|
301
|
+
const origWarn = console.warn.bind(console);
|
|
302
|
+
console.log = (...args) => {
|
|
303
|
+
origLog(...args);
|
|
304
|
+
writeLine("INFO", args);
|
|
305
|
+
};
|
|
306
|
+
console.error = (...args) => {
|
|
307
|
+
origError(...args);
|
|
308
|
+
writeLine("ERROR", args);
|
|
309
|
+
};
|
|
310
|
+
console.warn = (...args) => {
|
|
311
|
+
origWarn(...args);
|
|
312
|
+
writeLine("WARN", args);
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function getLogDir() {
|
|
316
|
+
return LOG_DIR;
|
|
317
|
+
}
|
|
318
|
+
|
|
250
319
|
// src/cli.ts
|
|
251
320
|
var VERSION2 = process.env.npm_package_version ?? "0.1.0";
|
|
252
321
|
var SERVICE_NAME = "clawmux";
|
|
@@ -257,6 +326,7 @@ Commands:
|
|
|
257
326
|
start Start the proxy server (foreground)
|
|
258
327
|
stop Stop the system service
|
|
259
328
|
status Check if ClawMux service is running
|
|
329
|
+
update Update to the latest version and restart service
|
|
260
330
|
uninstall Remove system service and OpenClaw providers
|
|
261
331
|
version Print version
|
|
262
332
|
help Show this help message
|
|
@@ -268,14 +338,8 @@ Options:
|
|
|
268
338
|
Environment:
|
|
269
339
|
CLAWMUX_PORT Server port override
|
|
270
340
|
OPENCLAW_CONFIG_PATH Path to openclaw.json`;
|
|
271
|
-
var
|
|
272
|
-
|
|
273
|
-
{ key: "clawmux-openai", api: "openai-completions" },
|
|
274
|
-
{ key: "clawmux-openai-responses", api: "openai-responses" },
|
|
275
|
-
{ key: "clawmux-google", api: "google-generative-ai" },
|
|
276
|
-
{ key: "clawmux-ollama", api: "ollama" },
|
|
277
|
-
{ key: "clawmux-bedrock", api: "bedrock-converse-stream" }
|
|
278
|
-
];
|
|
341
|
+
var PROVIDER_KEY = "clawmux";
|
|
342
|
+
var PROVIDER_API = "anthropic-messages";
|
|
279
343
|
async function fileExistsLocal(path) {
|
|
280
344
|
try {
|
|
281
345
|
await import_promises.access(path);
|
|
@@ -294,10 +358,10 @@ function resolveClawmuxBin() {
|
|
|
294
358
|
function getHomeDir() {
|
|
295
359
|
return process.env.HOME ?? "/root";
|
|
296
360
|
}
|
|
297
|
-
var SYSTEMD_DIR =
|
|
298
|
-
var SYSTEMD_PATH =
|
|
299
|
-
var LAUNCHD_DIR =
|
|
300
|
-
var LAUNCHD_PATH =
|
|
361
|
+
var SYSTEMD_DIR = import_node_path2.join(getHomeDir(), ".config", "systemd", "user");
|
|
362
|
+
var SYSTEMD_PATH = import_node_path2.join(SYSTEMD_DIR, `${SERVICE_NAME}.service`);
|
|
363
|
+
var LAUNCHD_DIR = import_node_path2.join(getHomeDir(), "Library", "LaunchAgents");
|
|
364
|
+
var LAUNCHD_PATH = import_node_path2.join(LAUNCHD_DIR, `com.${SERVICE_NAME}.plist`);
|
|
301
365
|
function buildSystemdUnit(bin, port, workDir) {
|
|
302
366
|
return `[Unit]
|
|
303
367
|
Description=ClawMux - Smart model routing proxy
|
|
@@ -316,7 +380,7 @@ WantedBy=default.target
|
|
|
316
380
|
`;
|
|
317
381
|
}
|
|
318
382
|
function buildLaunchdPlist(bin, port, workDir) {
|
|
319
|
-
const logDir =
|
|
383
|
+
const logDir = import_node_path2.join(getHomeDir(), ".openclaw", "clawmux");
|
|
320
384
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
321
385
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
322
386
|
<plist version="1.0">
|
|
@@ -371,7 +435,7 @@ async function installService(port, workDir) {
|
|
|
371
435
|
}
|
|
372
436
|
} else if (os === "darwin") {
|
|
373
437
|
await import_promises.mkdir(LAUNCHD_DIR, { recursive: true });
|
|
374
|
-
const logDir =
|
|
438
|
+
const logDir = import_node_path2.join(getHomeDir(), ".openclaw", "clawmux");
|
|
375
439
|
await import_promises.mkdir(logDir, { recursive: true });
|
|
376
440
|
await import_promises.writeFile(LAUNCHD_PATH, buildLaunchdPlist(bin, port, workDir));
|
|
377
441
|
try {
|
|
@@ -450,11 +514,86 @@ async function removeService() {
|
|
|
450
514
|
}
|
|
451
515
|
}
|
|
452
516
|
}
|
|
517
|
+
async function checkForUpdate() {
|
|
518
|
+
try {
|
|
519
|
+
const res = await fetch("https://registry.npmjs.org/clawmux/latest", {
|
|
520
|
+
signal: AbortSignal.timeout(3000)
|
|
521
|
+
});
|
|
522
|
+
if (!res.ok)
|
|
523
|
+
return;
|
|
524
|
+
const data = await res.json();
|
|
525
|
+
const latest = data.version;
|
|
526
|
+
if (!latest || latest === VERSION2)
|
|
527
|
+
return;
|
|
528
|
+
const [curMajor, curMinor, curPatch] = VERSION2.split(".").map(Number);
|
|
529
|
+
const [latMajor, latMinor, latPatch] = latest.split(".").map(Number);
|
|
530
|
+
const isNewer = latMajor > curMajor || latMajor === curMajor && latMinor > curMinor || latMajor === curMajor && latMinor === curMinor && latPatch > curPatch;
|
|
531
|
+
if (isNewer) {
|
|
532
|
+
console.log(`[clawmux] Update available: ${VERSION2} → ${latest}`);
|
|
533
|
+
console.log(`[clawmux] Run 'clawmux update' to upgrade`);
|
|
534
|
+
}
|
|
535
|
+
} catch (_) {}
|
|
536
|
+
}
|
|
537
|
+
function detectPackageManager() {
|
|
538
|
+
try {
|
|
539
|
+
import_node_child_process.execSync("which bun", { stdio: "pipe" });
|
|
540
|
+
return "bunx";
|
|
541
|
+
} catch {
|
|
542
|
+
return "npx";
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
async function update() {
|
|
546
|
+
const pm = detectPackageManager();
|
|
547
|
+
console.log(`[clawmux] Checking for updates...`);
|
|
548
|
+
try {
|
|
549
|
+
const res = await fetch("https://registry.npmjs.org/clawmux/latest", {
|
|
550
|
+
signal: AbortSignal.timeout(5000)
|
|
551
|
+
});
|
|
552
|
+
if (!res.ok) {
|
|
553
|
+
console.error("[error] Failed to check npm registry");
|
|
554
|
+
process.exit(1);
|
|
555
|
+
}
|
|
556
|
+
const data = await res.json();
|
|
557
|
+
const latest = data.version;
|
|
558
|
+
if (!latest) {
|
|
559
|
+
console.error("[error] Could not determine latest version");
|
|
560
|
+
process.exit(1);
|
|
561
|
+
}
|
|
562
|
+
if (latest === VERSION2) {
|
|
563
|
+
console.log(`[clawmux] Already on latest version (${VERSION2})`);
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
console.log(`[clawmux] Updating ${VERSION2} → ${latest}...`);
|
|
567
|
+
if (pm === "bunx") {
|
|
568
|
+
import_node_child_process.execSync("bun pm cache rm clawmux 2>/dev/null; bunx clawmux@latest version", { stdio: "inherit" });
|
|
569
|
+
} else {
|
|
570
|
+
import_node_child_process.execSync("npx clawmux@latest version", { stdio: "inherit" });
|
|
571
|
+
}
|
|
572
|
+
const os = import_node_os.platform();
|
|
573
|
+
if (os === "linux") {
|
|
574
|
+
try {
|
|
575
|
+
import_node_child_process.execSync(`systemctl --user restart ${SERVICE_NAME}`, { stdio: "pipe" });
|
|
576
|
+
console.log("[clawmux] Service restarted");
|
|
577
|
+
} catch (_) {}
|
|
578
|
+
} else if (os === "darwin") {
|
|
579
|
+
try {
|
|
580
|
+
import_node_child_process.execSync(`launchctl unload ${LAUNCHD_PATH}`, { stdio: "pipe" });
|
|
581
|
+
import_node_child_process.execSync(`launchctl load -w ${LAUNCHD_PATH}`, { stdio: "pipe" });
|
|
582
|
+
console.log("[clawmux] Service restarted");
|
|
583
|
+
} catch (_) {}
|
|
584
|
+
}
|
|
585
|
+
console.log(`[clawmux] Updated to ${latest}`);
|
|
586
|
+
} catch (err) {
|
|
587
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
588
|
+
console.error(`[error] Update failed: ${msg}`);
|
|
589
|
+
process.exit(1);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
453
592
|
async function init() {
|
|
454
593
|
const args = process.argv.slice(2);
|
|
455
594
|
const noService = args.includes("--no-service");
|
|
456
595
|
const homeDir = getHomeDir();
|
|
457
|
-
const openclawConfigPath = process.env.OPENCLAW_CONFIG_PATH ??
|
|
596
|
+
const openclawConfigPath = process.env.OPENCLAW_CONFIG_PATH ?? import_node_path2.join(homeDir, ".openclaw", "openclaw.json");
|
|
458
597
|
if (!await fileExistsLocal(openclawConfigPath)) {
|
|
459
598
|
console.error(`[error] OpenClaw config not found at ${openclawConfigPath}`);
|
|
460
599
|
console.error("Set OPENCLAW_CONFIG_PATH or ensure ~/.openclaw/openclaw.json exists");
|
|
@@ -464,14 +603,20 @@ async function init() {
|
|
|
464
603
|
const backupPath = `${openclawConfigPath}.bak.${Date.now()}`;
|
|
465
604
|
await import_promises.copyFile(openclawConfigPath, backupPath);
|
|
466
605
|
console.log(`[info] Backup created: ${backupPath}`);
|
|
467
|
-
const clawmuxJsonPath =
|
|
468
|
-
const examplePath =
|
|
606
|
+
const clawmuxJsonPath = import_node_path2.join(process.cwd(), "clawmux.json");
|
|
607
|
+
const examplePath = import_node_path2.join(process.cwd(), "clawmux.example.json");
|
|
469
608
|
if (!await fileExistsLocal(clawmuxJsonPath)) {
|
|
470
609
|
if (await fileExistsLocal(examplePath)) {
|
|
471
610
|
await import_promises.copyFile(examplePath, clawmuxJsonPath);
|
|
472
611
|
console.log("[info] Created clawmux.json from clawmux.example.json");
|
|
473
612
|
} else {
|
|
474
|
-
|
|
613
|
+
const defaultConfig = {
|
|
614
|
+
compression: { threshold: 0.75, model: "" },
|
|
615
|
+
routing: { models: { LIGHT: "", MEDIUM: "", HEAVY: "" } }
|
|
616
|
+
};
|
|
617
|
+
await import_promises.writeFile(clawmuxJsonPath, JSON.stringify(defaultConfig, null, 2) + `
|
|
618
|
+
`);
|
|
619
|
+
console.log("[info] Created default clawmux.json (configure models before use)");
|
|
475
620
|
}
|
|
476
621
|
}
|
|
477
622
|
const raw = await import_promises.readFile(openclawConfigPath, "utf-8");
|
|
@@ -482,28 +627,17 @@ async function init() {
|
|
|
482
627
|
if (!models.providers)
|
|
483
628
|
models.providers = {};
|
|
484
629
|
const providers = models.providers;
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
providers[key] = {
|
|
630
|
+
if (providers[PROVIDER_KEY]) {
|
|
631
|
+
console.log(` skip ${PROVIDER_KEY} (already exists)`);
|
|
632
|
+
} else {
|
|
633
|
+
providers[PROVIDER_KEY] = {
|
|
492
634
|
baseUrl: "http://localhost:3456",
|
|
493
|
-
api,
|
|
635
|
+
api: PROVIDER_API,
|
|
494
636
|
models: [{ id: "auto", name: "ClawMux Auto Router" }]
|
|
495
637
|
};
|
|
496
|
-
added++;
|
|
497
|
-
console.log(` added ${key}`);
|
|
498
|
-
}
|
|
499
|
-
if (added > 0) {
|
|
500
638
|
await import_promises.writeFile(openclawConfigPath, JSON.stringify(config, null, 2) + `
|
|
501
639
|
`);
|
|
502
|
-
console.log(`
|
|
503
|
-
Added ${added} provider(s) to openclaw.json`);
|
|
504
|
-
} else {
|
|
505
|
-
console.log(`
|
|
506
|
-
All ClawMux providers already registered.`);
|
|
640
|
+
console.log(` added ${PROVIDER_KEY} provider to openclaw.json`);
|
|
507
641
|
}
|
|
508
642
|
const port = process.env.CLAWMUX_PORT ?? "3456";
|
|
509
643
|
if (!noService) {
|
|
@@ -531,14 +665,17 @@ function start() {
|
|
|
531
665
|
if (portIdx !== -1 && args[portIdx + 1]) {
|
|
532
666
|
port = parseInt(args[portIdx + 1], 10);
|
|
533
667
|
}
|
|
668
|
+
initLogger();
|
|
534
669
|
const server = createServer({ port, host: "127.0.0.1" });
|
|
535
670
|
server.start();
|
|
536
671
|
console.log(`[clawmux] Proxy server running on http://127.0.0.1:${port}`);
|
|
672
|
+
console.log(`[clawmux] Logs: ${getLogDir()}`);
|
|
673
|
+
checkForUpdate();
|
|
537
674
|
}
|
|
538
675
|
async function uninstall() {
|
|
539
676
|
await removeService();
|
|
540
677
|
const homeDir = getHomeDir();
|
|
541
|
-
const openclawConfigPath = process.env.OPENCLAW_CONFIG_PATH ??
|
|
678
|
+
const openclawConfigPath = process.env.OPENCLAW_CONFIG_PATH ?? import_node_path2.join(homeDir, ".openclaw", "openclaw.json");
|
|
542
679
|
if (await fileExistsLocal(openclawConfigPath)) {
|
|
543
680
|
const backupPath = `${openclawConfigPath}.bak.${Date.now()}`;
|
|
544
681
|
await import_promises.copyFile(openclawConfigPath, backupPath);
|
|
@@ -548,7 +685,7 @@ async function uninstall() {
|
|
|
548
685
|
const providers = models.providers ?? {};
|
|
549
686
|
let removed = 0;
|
|
550
687
|
for (const key of Object.keys(providers)) {
|
|
551
|
-
if (key.startsWith("clawmux-")) {
|
|
688
|
+
if (key === "clawmux" || key.startsWith("clawmux-")) {
|
|
552
689
|
delete providers[key];
|
|
553
690
|
removed++;
|
|
554
691
|
}
|
|
@@ -578,6 +715,12 @@ switch (command) {
|
|
|
578
715
|
case "status":
|
|
579
716
|
getStatus();
|
|
580
717
|
break;
|
|
718
|
+
case "update":
|
|
719
|
+
update().catch((err) => {
|
|
720
|
+
console.error(`[error] ${err.message}`);
|
|
721
|
+
process.exit(1);
|
|
722
|
+
});
|
|
723
|
+
break;
|
|
581
724
|
case "uninstall":
|
|
582
725
|
uninstall().catch((err) => {
|
|
583
726
|
console.error(`[error] ${err.message}`);
|