@@ -634,47 +634,139 @@ export default function register(api: OpenClawPluginApi) {
634634
635635 cmd . command ( "setup" )
636636 . description ( "Configure OpenClaw to route all traffic through Carapace" )
637- . action ( async ( ) => {
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+
638643 console . log ( "\n🦞 Carapace Setup\n" ) ;
639644 backupConfig ( ) ;
640645 console . log ( " 📦 Backed up openclaw.json → openclaw.json.carapace-backup" ) ;
641646 let anyChanges = false ;
642647
643- // 1. Deny built-in bypass tools
644- const bypasses = checkForBypasses ( ) ;
645- if ( bypasses . length > 0 ) {
646- console . log ( " Denying built-in tools that bypass Cedar:" ) ;
647- const { patched, alreadyDenied } = patchConfigDenyTools ( ) ;
648- if ( alreadyDenied . length > 0 ) {
649- console . log ( ` Already denied: ${ alreadyDenied . join ( ", " ) } ` ) ;
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 { }
650667 }
651- if ( patched . length > 0 ) {
652- console . log ( ` ✅ Added to tools.deny: ${ patched . join ( ", " ) } ` ) ;
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" ) ;
653741 anyChanges = true ;
654742 }
655- } else {
656- console . log ( " ✅ Built-in bypass tools already denied." ) ;
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:" ) ;
662747 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 ( ", " ) } ` ) ;
666749 if ( patched . length > 0 ) {
667750 console . log ( ` ✅ Set models.providers baseUrl for: ${ patched . join ( ", " ) } ` ) ;
668751 anyChanges = true ;
669752 }
670- if ( patched . length === 0 && alreadySet . length === 0 ) {
671- console . log ( " ⚠️ No upstream providers configured in proxy config." ) ;
672- console . log ( ' Set proxy.upstream to a URL string (e.g., "https://api.anthropic.com") with proxy.apiKey,' ) ;
673- console . log ( " or use the object format: proxy.upstream = { anthropic: { apiKey: '...' } }" ) ;
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." ) ;
674769 }
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." ) ;
678770 }
679771
680772 if ( anyChanges ) {
0 commit comments