@clawdreyhepburn/carapace 0.4.4 ā 0.5.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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/index.ts +119 -27
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -634,47 +634,139 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
634
634
|
|
|
635
635
|
cmd.command("setup")
|
|
636
636
|
.description("Configure OpenClaw to route all traffic through Carapace")
|
|
637
|
-
.
|
|
637
|
+
.option("--no-proxy", "Skip LLM proxy setup (tool-deny mode only)")
|
|
638
|
+
.action(async (opts: any) => {
|
|
639
|
+
const { readFileSync, writeFileSync, existsSync, copyFileSync } = require("node:fs");
|
|
640
|
+
const { join } = require("node:path");
|
|
641
|
+
const { homedir } = require("node:os");
|
|
642
|
+
|
|
638
643
|
console.log("\nš¦ Carapace Setup\n");
|
|
639
644
|
backupConfig();
|
|
640
645
|
console.log(" š¦ Backed up openclaw.json ā openclaw.json.carapace-backup");
|
|
641
646
|
let anyChanges = false;
|
|
642
647
|
|
|
643
|
-
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
648
|
+
const configPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
649
|
+
const cfg = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
650
|
+
const skipProxy = opts.noProxy === true;
|
|
651
|
+
|
|
652
|
+
// Detect if proxy is already configured in the live config
|
|
653
|
+
const existingProxyEnabled = cfg.plugins?.entries?.carapace?.config?.proxy?.enabled;
|
|
654
|
+
|
|
655
|
+
if (!skipProxy && !existingProxyEnabled) {
|
|
656
|
+
// Enable the proxy by default ā find the API key automatically
|
|
657
|
+
console.log(" š Looking for Anthropic API key...");
|
|
658
|
+
let apiKey = "";
|
|
659
|
+
|
|
660
|
+
// Check auth.json
|
|
661
|
+
const authPath = join(homedir(), ".openclaw", "agents", "main", "agent", "auth.json");
|
|
662
|
+
if (existsSync(authPath)) {
|
|
663
|
+
try {
|
|
664
|
+
const auth = JSON.parse(readFileSync(authPath, "utf-8"));
|
|
665
|
+
apiKey = auth.anthropic?.key ?? "";
|
|
666
|
+
} catch {}
|
|
650
667
|
}
|
|
651
|
-
|
|
652
|
-
|
|
668
|
+
|
|
669
|
+
// Check environment
|
|
670
|
+
if (!apiKey) apiKey = process.env.ANTHROPIC_API_KEY ?? "";
|
|
671
|
+
|
|
672
|
+
if (!apiKey) {
|
|
673
|
+
console.log(" ā ļø Could not find Anthropic API key.");
|
|
674
|
+
console.log(" Checked: ~/.openclaw/agents/main/agent/auth.json, ANTHROPIC_API_KEY env");
|
|
675
|
+
console.log(" Falling back to tool-deny mode (no proxy).\n");
|
|
676
|
+
} else {
|
|
677
|
+
console.log(` Found key: ${apiKey.slice(0, 12)}...${apiKey.slice(-4)}`);
|
|
678
|
+
|
|
679
|
+
// Write proxy config into plugin entry
|
|
680
|
+
if (!cfg.plugins) cfg.plugins = {};
|
|
681
|
+
if (!cfg.plugins.entries) cfg.plugins.entries = {};
|
|
682
|
+
if (!cfg.plugins.entries.carapace) cfg.plugins.entries.carapace = {};
|
|
683
|
+
cfg.plugins.entries.carapace.enabled = true;
|
|
684
|
+
cfg.plugins.entries.carapace.config = {
|
|
685
|
+
defaultPolicy: "allow-all",
|
|
686
|
+
proxy: {
|
|
687
|
+
enabled: true,
|
|
688
|
+
port: 19821,
|
|
689
|
+
upstream: "https://api.anthropic.com",
|
|
690
|
+
apiKey,
|
|
691
|
+
},
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
// Set models.providers.anthropic.baseUrl
|
|
695
|
+
const proxyUrl = "http://127.0.0.1:19821";
|
|
696
|
+
if (!cfg.models) cfg.models = {};
|
|
697
|
+
if (!cfg.models.mode) cfg.models.mode = "merge";
|
|
698
|
+
if (!cfg.models.providers) cfg.models.providers = {};
|
|
699
|
+
if (!cfg.models.providers.anthropic) cfg.models.providers.anthropic = {};
|
|
700
|
+
if (!Array.isArray(cfg.models.providers.anthropic.models)) {
|
|
701
|
+
cfg.models.providers.anthropic.models = [];
|
|
702
|
+
}
|
|
703
|
+
if (cfg.models.providers.anthropic.baseUrl && cfg.models.providers.anthropic.baseUrl !== proxyUrl) {
|
|
704
|
+
cfg.models.providers.anthropic._originalBaseUrl = cfg.models.providers.anthropic.baseUrl;
|
|
705
|
+
}
|
|
706
|
+
cfg.models.providers.anthropic.baseUrl = proxyUrl;
|
|
707
|
+
|
|
708
|
+
// Do NOT deny built-in tools when proxy is enabled ā proxy handles filtering
|
|
709
|
+
// Remove any previous tool denials from earlier setup runs
|
|
710
|
+
if (cfg.tools?.deny) {
|
|
711
|
+
cfg.tools.deny = cfg.tools.deny.filter((t: string) => !BYPASS_TOOLS.includes(t));
|
|
712
|
+
if (cfg.tools.deny.length === 0) delete cfg.tools.deny;
|
|
713
|
+
if (cfg.tools && Object.keys(cfg.tools).length === 0) delete cfg.tools;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
writeFileSync(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
|
|
717
|
+
|
|
718
|
+
// Also patch models.json directly
|
|
719
|
+
const modelsPath = join(homedir(), ".openclaw", "agents", "main", "agent", "models.json");
|
|
720
|
+
if (existsSync(modelsPath)) {
|
|
721
|
+
try {
|
|
722
|
+
const modelsBackup = modelsPath + ".carapace-backup";
|
|
723
|
+
if (!existsSync(modelsBackup)) copyFileSync(modelsPath, modelsBackup);
|
|
724
|
+
const models = JSON.parse(readFileSync(modelsPath, "utf-8"));
|
|
725
|
+
if (!models.providers) models.providers = {};
|
|
726
|
+
if (!models.providers.anthropic) models.providers.anthropic = {};
|
|
727
|
+
if (models.providers.anthropic.baseUrl && models.providers.anthropic.baseUrl !== proxyUrl) {
|
|
728
|
+
models.providers.anthropic._originalBaseUrl = models.providers.anthropic.baseUrl;
|
|
729
|
+
}
|
|
730
|
+
models.providers.anthropic.baseUrl = proxyUrl;
|
|
731
|
+
writeFileSync(modelsPath, JSON.stringify(models, null, 2) + "\n", "utf-8");
|
|
732
|
+
console.log(" ā
Patched models.json with proxy baseUrl");
|
|
733
|
+
} catch (e: any) {
|
|
734
|
+
console.log(` ā ļø Could not patch models.json: ${e.message}`);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
console.log(" ā
LLM proxy enabled (allow-all policy, port 19821)");
|
|
739
|
+
console.log(" All API calls will route through Cedar.");
|
|
740
|
+
console.log(" Built-in tools (exec, web_fetch, web_search) are NOT denied ā proxy handles them.\n");
|
|
653
741
|
anyChanges = true;
|
|
654
742
|
}
|
|
655
|
-
} else {
|
|
656
|
-
console.log(" ā
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
// 2. Set up LLM proxy baseUrl if proxy is configured
|
|
660
|
-
if (config.proxy?.enabled) {
|
|
661
|
-
console.log("\n Configuring LLM proxy baseUrl:");
|
|
743
|
+
} else if (existingProxyEnabled) {
|
|
744
|
+
console.log(" ā
LLM proxy already configured.");
|
|
745
|
+
// Ensure baseUrl is set
|
|
746
|
+
console.log("\n Verifying baseUrl configuration:");
|
|
662
747
|
const { patched, alreadySet } = patchConfigProxyBaseUrl();
|
|
663
|
-
if (alreadySet.length > 0) {
|
|
664
|
-
console.log(` Already set: ${alreadySet.join(", ")}`);
|
|
665
|
-
}
|
|
748
|
+
if (alreadySet.length > 0) console.log(` Already set: ${alreadySet.join(", ")}`);
|
|
666
749
|
if (patched.length > 0) {
|
|
667
750
|
console.log(` ā
Set models.providers baseUrl for: ${patched.join(", ")}`);
|
|
668
751
|
anyChanges = true;
|
|
669
752
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// If proxy not enabled (skipped or no key), fall back to tool-deny mode
|
|
756
|
+
const finalCfg = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
757
|
+
if (!finalCfg.plugins?.entries?.carapace?.config?.proxy?.enabled) {
|
|
758
|
+
console.log(" Falling back to tool-deny mode:");
|
|
759
|
+
const bypasses = checkForBypasses();
|
|
760
|
+
if (bypasses.length > 0) {
|
|
761
|
+
const { patched, alreadyDenied } = patchConfigDenyTools();
|
|
762
|
+
if (alreadyDenied.length > 0) console.log(` Already denied: ${alreadyDenied.join(", ")}`);
|
|
763
|
+
if (patched.length > 0) {
|
|
764
|
+
console.log(` ā
Added to tools.deny: ${patched.join(", ")}`);
|
|
765
|
+
anyChanges = true;
|
|
766
|
+
}
|
|
767
|
+
} else {
|
|
768
|
+
console.log(" ā
Built-in bypass tools already denied.");
|
|
674
769
|
}
|
|
675
|
-
} else {
|
|
676
|
-
console.log("\n LLM proxy not enabled ā skipping baseUrl setup.");
|
|
677
|
-
console.log(" To enable, add proxy.enabled: true to your Carapace plugin config.");
|
|
678
770
|
}
|
|
679
771
|
|
|
680
772
|
if (anyChanges) {
|