clawmux 0.3.2 → 0.3.4
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 +11 -4
- package/dist/cli.cjs +37 -31
- package/dist/index.cjs +14 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,15 +14,22 @@ Smart model routing + context compression proxy for OpenClaw.
|
|
|
14
14
|
|
|
15
15
|
## Installation
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Copy and paste this into your OpenClaw agent:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
+
Install and configure ClawMux by following the instructions here:
|
|
20
21
|
curl -s https://raw.githubusercontent.com/HyeokjaeLee/ClawMux/refs/heads/main/docs/guide/installation.md
|
|
21
22
|
```
|
|
22
23
|
|
|
23
24
|
## Configuration
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
ClawMux stores its config at `~/.openclaw/clawmux.json` (next to `openclaw.json`). `clawmux init` creates it automatically. You can also copy `clawmux.example.json` as a starting point:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cp clawmux.example.json ~/.openclaw/clawmux.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Adjust as needed:
|
|
26
33
|
|
|
27
34
|
```jsonc
|
|
28
35
|
{
|
|
@@ -46,7 +53,7 @@ Copy `clawmux.example.json` to `clawmux.json` and adjust as needed:
|
|
|
46
53
|
}
|
|
47
54
|
```
|
|
48
55
|
|
|
49
|
-
Config is watched for changes. Edit
|
|
56
|
+
Config is watched for changes. Edit `~/.openclaw/clawmux.json` while the proxy is running and it reloads automatically. Override the path with `CLAWMUX_CONFIG=/path/to/clawmux.json`.
|
|
50
57
|
|
|
51
58
|
### Cross-Provider Routing
|
|
52
59
|
|
|
@@ -99,7 +106,7 @@ OpenClaw → ClawMux Proxy (localhost:3456) → Upstream Provider(s)
|
|
|
99
106
|
|
|
100
107
|
ClawMux resolves each model's context window using this priority chain:
|
|
101
108
|
|
|
102
|
-
1.
|
|
109
|
+
1. **~/.openclaw/clawmux.json** `routing.contextWindows` — explicit per-model override
|
|
103
110
|
2. **openclaw.json** `models.providers[provider].models[].contextWindow` — user config
|
|
104
111
|
3. **OpenClaw built-in catalog** — pi-ai model database (812+ models)
|
|
105
112
|
4. **Default: 200,000 tokens**
|
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_promises6 = require("node:fs/promises");
|
|
83
|
-
var
|
|
83
|
+
var import_node_path5 = 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
|
|
|
@@ -424,12 +424,17 @@ function validateConfig(raw) {
|
|
|
424
424
|
}
|
|
425
425
|
|
|
426
426
|
// src/config/loader.ts
|
|
427
|
-
function
|
|
427
|
+
function getHomeDir() {
|
|
428
|
+
return process.env.HOME ?? "/root";
|
|
429
|
+
}
|
|
430
|
+
function getClawmuxConfigPath() {
|
|
428
431
|
const envPath = process.env.CLAWMUX_CONFIG;
|
|
429
|
-
if (envPath)
|
|
432
|
+
if (envPath)
|
|
430
433
|
return import_node_path.resolve(envPath);
|
|
431
|
-
|
|
432
|
-
|
|
434
|
+
return import_node_path.join(getHomeDir(), ".openclaw", "clawmux.json");
|
|
435
|
+
}
|
|
436
|
+
function findConfigPath() {
|
|
437
|
+
return getClawmuxConfigPath();
|
|
433
438
|
}
|
|
434
439
|
async function loadConfig(configPath) {
|
|
435
440
|
const filePath = configPath ?? findConfigPath();
|
|
@@ -553,7 +558,7 @@ function resolveEnvVar(value) {
|
|
|
553
558
|
}
|
|
554
559
|
return value;
|
|
555
560
|
}
|
|
556
|
-
function
|
|
561
|
+
function getHomeDir2() {
|
|
557
562
|
return process.env.HOME ?? "/root";
|
|
558
563
|
}
|
|
559
564
|
function getConfigPath(override) {
|
|
@@ -561,7 +566,7 @@ function getConfigPath(override) {
|
|
|
561
566
|
return override;
|
|
562
567
|
if (process.env.OPENCLAW_CONFIG_PATH)
|
|
563
568
|
return process.env.OPENCLAW_CONFIG_PATH;
|
|
564
|
-
return import_node_path2.join(
|
|
569
|
+
return import_node_path2.join(getHomeDir2(), ".openclaw", "openclaw.json");
|
|
565
570
|
}
|
|
566
571
|
async function readOpenClawConfig(configPath) {
|
|
567
572
|
const path = getConfigPath(configPath);
|
|
@@ -584,7 +589,7 @@ async function readOpenClawConfig(configPath) {
|
|
|
584
589
|
}
|
|
585
590
|
function getAuthProfilesPath(agentId) {
|
|
586
591
|
const id = agentId ?? "main";
|
|
587
|
-
return import_node_path2.join(
|
|
592
|
+
return import_node_path2.join(getHomeDir2(), ".openclaw", "agents", id, "agent", "auth-profiles.json");
|
|
588
593
|
}
|
|
589
594
|
function parseAuthProfilesFile(text) {
|
|
590
595
|
try {
|
|
@@ -618,7 +623,7 @@ function parseAuthProfilesFile(text) {
|
|
|
618
623
|
}
|
|
619
624
|
}
|
|
620
625
|
async function readAuthProfiles(_agentId, _profilesPath, agentsDirOverride) {
|
|
621
|
-
const agentsDir = agentsDirOverride ?? import_node_path2.join(
|
|
626
|
+
const agentsDir = agentsDirOverride ?? import_node_path2.join(getHomeDir2(), ".openclaw", "agents");
|
|
622
627
|
let agentDirs;
|
|
623
628
|
try {
|
|
624
629
|
agentDirs = (await import_promises4.readdir(agentsDir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name).sort();
|
|
@@ -3833,9 +3838,8 @@ function setupPipelineRoutes(config, openclawConfig, authProfiles, compressionMi
|
|
|
3833
3838
|
}
|
|
3834
3839
|
|
|
3835
3840
|
// src/index.ts
|
|
3836
|
-
var import_node_path4 = require("node:path");
|
|
3837
3841
|
async function bootstrap(portOverride) {
|
|
3838
|
-
const configPath =
|
|
3842
|
+
const configPath = getClawmuxConfigPath();
|
|
3839
3843
|
const result = await loadConfig(configPath);
|
|
3840
3844
|
if (!result.valid) {
|
|
3841
3845
|
console.error("[clawmux] Config errors:");
|
|
@@ -3870,8 +3874,8 @@ if (typeof Bun !== "undefined" && Bun.main === "/home/runner/work/ClawMux/ClawMu
|
|
|
3870
3874
|
|
|
3871
3875
|
// src/utils/logger.ts
|
|
3872
3876
|
var import_node_fs2 = require("node:fs");
|
|
3873
|
-
var
|
|
3874
|
-
var LOG_DIR =
|
|
3877
|
+
var import_node_path4 = require("node:path");
|
|
3878
|
+
var LOG_DIR = import_node_path4.join(process.env.HOME ?? "/root", ".openclaw", "clawmux");
|
|
3875
3879
|
var MAX_DAYS = 7;
|
|
3876
3880
|
var fileStream = null;
|
|
3877
3881
|
var currentDate = "";
|
|
@@ -3880,7 +3884,7 @@ function todayString() {
|
|
|
3880
3884
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
3881
3885
|
}
|
|
3882
3886
|
function logPath(date) {
|
|
3883
|
-
return
|
|
3887
|
+
return import_node_path4.join(LOG_DIR, `${date}.log`);
|
|
3884
3888
|
}
|
|
3885
3889
|
function rotateIfNeeded() {
|
|
3886
3890
|
const today = todayString();
|
|
@@ -3898,7 +3902,7 @@ function purgeOldLogs() {
|
|
|
3898
3902
|
const files = import_node_fs2.readdirSync(LOG_DIR).filter((f) => f.endsWith(".log")).sort();
|
|
3899
3903
|
while (files.length > MAX_DAYS) {
|
|
3900
3904
|
const oldest = files.shift();
|
|
3901
|
-
import_node_fs2.unlinkSync(
|
|
3905
|
+
import_node_fs2.unlinkSync(import_node_path4.join(LOG_DIR, oldest));
|
|
3902
3906
|
}
|
|
3903
3907
|
} catch (_) {}
|
|
3904
3908
|
}
|
|
@@ -3938,7 +3942,7 @@ function getLogDir() {
|
|
|
3938
3942
|
}
|
|
3939
3943
|
|
|
3940
3944
|
// src/cli.ts
|
|
3941
|
-
var VERSION2 = process.env.npm_package_version ?? "0.3.
|
|
3945
|
+
var VERSION2 = process.env.npm_package_version ?? "0.3.4";
|
|
3942
3946
|
var SERVICE_NAME = "clawmux";
|
|
3943
3947
|
var HELP = `Usage: clawmux <command>
|
|
3944
3948
|
|
|
@@ -3998,13 +4002,13 @@ function resolveClawmuxBin() {
|
|
|
3998
4002
|
return detectPackageManager() === "bunx" ? "bunx clawmux" : "npx clawmux";
|
|
3999
4003
|
}
|
|
4000
4004
|
}
|
|
4001
|
-
function
|
|
4005
|
+
function getHomeDir3() {
|
|
4002
4006
|
return process.env.HOME ?? "/root";
|
|
4003
4007
|
}
|
|
4004
|
-
var SYSTEMD_DIR =
|
|
4005
|
-
var SYSTEMD_PATH =
|
|
4006
|
-
var LAUNCHD_DIR =
|
|
4007
|
-
var LAUNCHD_PATH =
|
|
4008
|
+
var SYSTEMD_DIR = import_node_path5.join(getHomeDir3(), ".config", "systemd", "user");
|
|
4009
|
+
var SYSTEMD_PATH = import_node_path5.join(SYSTEMD_DIR, `${SERVICE_NAME}.service`);
|
|
4010
|
+
var LAUNCHD_DIR = import_node_path5.join(getHomeDir3(), "Library", "LaunchAgents");
|
|
4011
|
+
var LAUNCHD_PATH = import_node_path5.join(LAUNCHD_DIR, `com.${SERVICE_NAME}.plist`);
|
|
4008
4012
|
function buildSystemdUnit(bin, port, workDir) {
|
|
4009
4013
|
return `[Unit]
|
|
4010
4014
|
Description=ClawMux - Smart model routing proxy
|
|
@@ -4023,7 +4027,7 @@ WantedBy=default.target
|
|
|
4023
4027
|
`;
|
|
4024
4028
|
}
|
|
4025
4029
|
function buildLaunchdPlist(bin, port, workDir) {
|
|
4026
|
-
const logDir =
|
|
4030
|
+
const logDir = import_node_path5.join(getHomeDir3(), ".openclaw", "clawmux");
|
|
4027
4031
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
4028
4032
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
4029
4033
|
<plist version="1.0">
|
|
@@ -4078,7 +4082,7 @@ async function installService(port, workDir) {
|
|
|
4078
4082
|
}
|
|
4079
4083
|
} else if (os === "darwin") {
|
|
4080
4084
|
await import_promises6.mkdir(LAUNCHD_DIR, { recursive: true });
|
|
4081
|
-
const logDir =
|
|
4085
|
+
const logDir = import_node_path5.join(getHomeDir3(), ".openclaw", "clawmux");
|
|
4082
4086
|
await import_promises6.mkdir(logDir, { recursive: true });
|
|
4083
4087
|
await import_promises6.writeFile(LAUNCHD_PATH, buildLaunchdPlist(bin, port, workDir));
|
|
4084
4088
|
try {
|
|
@@ -4227,8 +4231,8 @@ async function update() {
|
|
|
4227
4231
|
async function init() {
|
|
4228
4232
|
const args = process.argv.slice(2);
|
|
4229
4233
|
const noService = args.includes("--no-service");
|
|
4230
|
-
const homeDir =
|
|
4231
|
-
const openclawConfigPath = process.env.OPENCLAW_CONFIG_PATH ??
|
|
4234
|
+
const homeDir = getHomeDir3();
|
|
4235
|
+
const openclawConfigPath = process.env.OPENCLAW_CONFIG_PATH ?? import_node_path5.join(homeDir, ".openclaw", "openclaw.json");
|
|
4232
4236
|
if (!await fileExistsLocal(openclawConfigPath)) {
|
|
4233
4237
|
console.error(`[error] OpenClaw config not found at ${openclawConfigPath}`);
|
|
4234
4238
|
console.error("Set OPENCLAW_CONFIG_PATH or ensure ~/.openclaw/openclaw.json exists");
|
|
@@ -4238,8 +4242,9 @@ async function init() {
|
|
|
4238
4242
|
const backupPath = `${openclawConfigPath}.bak.${Date.now()}`;
|
|
4239
4243
|
await import_promises6.copyFile(openclawConfigPath, backupPath);
|
|
4240
4244
|
console.log(`[info] Backup created: ${backupPath}`);
|
|
4241
|
-
const clawmuxJsonPath =
|
|
4242
|
-
const examplePath =
|
|
4245
|
+
const clawmuxJsonPath = getClawmuxConfigPath();
|
|
4246
|
+
const examplePath = import_node_path5.join(process.cwd(), "clawmux.example.json");
|
|
4247
|
+
console.log(`[info] Using ClawMux config: ${clawmuxJsonPath}`);
|
|
4243
4248
|
if (!await fileExistsLocal(clawmuxJsonPath)) {
|
|
4244
4249
|
if (await fileExistsLocal(examplePath)) {
|
|
4245
4250
|
await import_promises6.copyFile(examplePath, clawmuxJsonPath);
|
|
@@ -4307,14 +4312,15 @@ async function init() {
|
|
|
4307
4312
|
[info] ClawMux setup complete!`);
|
|
4308
4313
|
console.log(`
|
|
4309
4314
|
Next steps:`);
|
|
4310
|
-
console.log(
|
|
4315
|
+
console.log(` 1. Edit ${clawmuxJsonPath} to configure your models`);
|
|
4311
4316
|
if (noService) {
|
|
4312
4317
|
console.log(" 2. Run: clawmux start");
|
|
4313
4318
|
} else {
|
|
4314
4319
|
console.log(" 2. ClawMux is running and will auto-start on boot");
|
|
4315
4320
|
console.log(" Check status: clawmux status");
|
|
4316
4321
|
}
|
|
4317
|
-
console.log(" 3.
|
|
4322
|
+
console.log(" 3. Ask the user whether to switch agent and session models to clawmux/auto,");
|
|
4323
|
+
console.log(" then use the openclaw CLI to apply their choice per agent.");
|
|
4318
4324
|
console.log(" 4. Start chatting: openclaw chat");
|
|
4319
4325
|
}
|
|
4320
4326
|
async function start() {
|
|
@@ -4331,8 +4337,8 @@ async function start() {
|
|
|
4331
4337
|
}
|
|
4332
4338
|
async function uninstall() {
|
|
4333
4339
|
await removeService();
|
|
4334
|
-
const homeDir =
|
|
4335
|
-
const openclawConfigPath = process.env.OPENCLAW_CONFIG_PATH ??
|
|
4340
|
+
const homeDir = getHomeDir3();
|
|
4341
|
+
const openclawConfigPath = process.env.OPENCLAW_CONFIG_PATH ?? import_node_path5.join(homeDir, ".openclaw", "openclaw.json");
|
|
4336
4342
|
if (await fileExistsLocal(openclawConfigPath)) {
|
|
4337
4343
|
const backupPath = `${openclawConfigPath}.bak.${Date.now()}`;
|
|
4338
4344
|
await import_promises6.copyFile(openclawConfigPath, backupPath);
|
package/dist/index.cjs
CHANGED
|
@@ -447,12 +447,17 @@ function validateConfig(raw) {
|
|
|
447
447
|
}
|
|
448
448
|
|
|
449
449
|
// src/config/loader.ts
|
|
450
|
-
function
|
|
450
|
+
function getHomeDir() {
|
|
451
|
+
return process.env.HOME ?? "/root";
|
|
452
|
+
}
|
|
453
|
+
function getClawmuxConfigPath() {
|
|
451
454
|
const envPath = process.env.CLAWMUX_CONFIG;
|
|
452
|
-
if (envPath)
|
|
455
|
+
if (envPath)
|
|
453
456
|
return import_node_path.resolve(envPath);
|
|
454
|
-
|
|
455
|
-
|
|
457
|
+
return import_node_path.join(getHomeDir(), ".openclaw", "clawmux.json");
|
|
458
|
+
}
|
|
459
|
+
function findConfigPath() {
|
|
460
|
+
return getClawmuxConfigPath();
|
|
456
461
|
}
|
|
457
462
|
async function loadConfig(configPath) {
|
|
458
463
|
const filePath = configPath ?? findConfigPath();
|
|
@@ -576,7 +581,7 @@ function resolveEnvVar(value) {
|
|
|
576
581
|
}
|
|
577
582
|
return value;
|
|
578
583
|
}
|
|
579
|
-
function
|
|
584
|
+
function getHomeDir2() {
|
|
580
585
|
return process.env.HOME ?? "/root";
|
|
581
586
|
}
|
|
582
587
|
function getConfigPath(override) {
|
|
@@ -584,7 +589,7 @@ function getConfigPath(override) {
|
|
|
584
589
|
return override;
|
|
585
590
|
if (process.env.OPENCLAW_CONFIG_PATH)
|
|
586
591
|
return process.env.OPENCLAW_CONFIG_PATH;
|
|
587
|
-
return import_node_path2.join(
|
|
592
|
+
return import_node_path2.join(getHomeDir2(), ".openclaw", "openclaw.json");
|
|
588
593
|
}
|
|
589
594
|
async function readOpenClawConfig(configPath) {
|
|
590
595
|
const path = getConfigPath(configPath);
|
|
@@ -607,7 +612,7 @@ async function readOpenClawConfig(configPath) {
|
|
|
607
612
|
}
|
|
608
613
|
function getAuthProfilesPath(agentId) {
|
|
609
614
|
const id = agentId ?? "main";
|
|
610
|
-
return import_node_path2.join(
|
|
615
|
+
return import_node_path2.join(getHomeDir2(), ".openclaw", "agents", id, "agent", "auth-profiles.json");
|
|
611
616
|
}
|
|
612
617
|
function parseAuthProfilesFile(text) {
|
|
613
618
|
try {
|
|
@@ -641,7 +646,7 @@ function parseAuthProfilesFile(text) {
|
|
|
641
646
|
}
|
|
642
647
|
}
|
|
643
648
|
async function readAuthProfiles(_agentId, _profilesPath, agentsDirOverride) {
|
|
644
|
-
const agentsDir = agentsDirOverride ?? import_node_path2.join(
|
|
649
|
+
const agentsDir = agentsDirOverride ?? import_node_path2.join(getHomeDir2(), ".openclaw", "agents");
|
|
645
650
|
let agentDirs;
|
|
646
651
|
try {
|
|
647
652
|
agentDirs = (await import_promises4.readdir(agentsDir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name).sort();
|
|
@@ -3856,9 +3861,8 @@ function setupPipelineRoutes(config, openclawConfig, authProfiles, compressionMi
|
|
|
3856
3861
|
}
|
|
3857
3862
|
|
|
3858
3863
|
// src/index.ts
|
|
3859
|
-
var import_node_path4 = require("node:path");
|
|
3860
3864
|
async function bootstrap(portOverride) {
|
|
3861
|
-
const configPath =
|
|
3865
|
+
const configPath = getClawmuxConfigPath();
|
|
3862
3866
|
const result = await loadConfig(configPath);
|
|
3863
3867
|
if (!result.valid) {
|
|
3864
3868
|
console.error("[clawmux] Config errors:");
|