badgerclaw 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.
Files changed (2) hide show
  1. package/dist/index.js +98 -66
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -1,23 +1,24 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var ys=Object.create;var yt=Object.defineProperty;var ws=Object.getOwnPropertyDescriptor;var bs=Object.getOwnPropertyNames;var _s=Object.getPrototypeOf,Ss=Object.prototype.hasOwnProperty;var H=(e,t)=>()=>(e&&(t=e(e=0)),t);var ks=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),to=(e,t)=>{for(var o in t)yt(e,o,{get:t[o],enumerable:!0})},an=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of bs(t))!Ss.call(e,r)&&r!==o&&yt(e,r,{get:()=>t[r],enumerable:!(n=ws(t,r))||n.enumerable});return e};var u=(e,t,o)=>(o=e!=null?ys(_s(e)):{},an(t||!e||!e.__esModule?yt(o,"default",{value:e,enumerable:!0}):o,e)),ln=e=>an(yt({},"__esModule",{value:!0}),e);function b(){try{let e=Ye.default.readFileSync(ro,"utf-8");return JSON.parse(e)}catch{return null}}function wt(e){Ye.default.mkdirSync(mn,{recursive:!0}),Ye.default.writeFileSync(ro,JSON.stringify(e,null,2),{mode:384})}function Je(){try{Ye.default.unlinkSync(ro)}catch{}}function bt(){let e=b();return e?new Date(e.expires_at)>new Date:!1}function _t(e){let t=e.match(/^@?([^:]+)/);return t?t[1]:e}var Ye,no,un,mn,ro,M=H(()=>{"use strict";Ye=u(require("fs")),no=u(require("path")),un=u(require("os")),mn=no.default.join(un.default.homedir(),".badgerclaw"),ro=no.default.join(mn,"auth.json")});function so(){return pn.default.createHash("sha256").update(`${Q.default.hostname()}-${Q.default.platform()}-${Q.default.arch()}`).digest("hex").slice(0,16)}function Z(){let e=b();if(e?.instance_id)return e.instance_id;let t=so();return`openclaw-${Q.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${t}`}function St(){return{hostname:Q.default.hostname(),os:Q.default.platform(),arch:Q.default.arch(),uptimeSeconds:Math.floor(Q.default.uptime()),memFreeMb:Math.floor(Q.default.freemem()/1024/1024)}}var Q,pn,xe=H(()=>{"use strict";Q=u(require("os")),pn=u(require("crypto"));M()});var gn,N,fn,oe=H(()=>{"use strict";gn=process.env.BADGERCLAW_ENV==="local",N=process.env.BADGERCLAW_API_URL??(gn?"http://localhost:8000":"https://api.badger.signout.io"),fn=process.env.BADGERCLAW_AUTH_URL??(gn?"http://localhost:5500":"https://badgerclaw.ai")});function yn(){return ze}function vs(e){if(!e)return null;let t=e.split(".");if(t.length!==3)return null;try{let o=t[1].replace(/-/g,"+").replace(/_/g,"/"),n=o.length%4===0?o:o+"=".repeat(4-o.length%4),r=JSON.parse(Buffer.from(n,"base64").toString("utf8"));return(typeof r?.sub=="string"?r.sub:null)||null}catch{return null}}async function ao(){let e=b();if(!e?.refresh_token||!e?.email)return ze=e?e.refresh_token?"no email in auth.json \u2014 re-run `badgerclaw login`":"no refresh_token in auth.json \u2014 re-run `badgerclaw login`":"not logged in (auth.json missing)",null;let t=vs(e.access_token);try{let o=await Xe.default.post(`${vt}/api/v1/user/token/refresh`,{refresh_token:e.refresh_token,email:e.email,...t?{cognito_username:t}:{}}),n=o.data?.result??o.data,r=n?.access_token;if(!r)return ze="server returned no access_token",null;let s=n.expires_in||3600,a=new Date(Date.now()+s*1e3).toISOString();return wt({...e,access_token:r,expires_at:a}),ze=null,r}catch(o){let n=o?.response?.status,r=o?.response?.data?.errors?.[0]||o?.response?.data?.detail||o?.message||"unknown error";ze=n?`HTTP ${n}: ${r}`:`network error: ${r}`;let s=o?.response?.data?.errors?.[0]||o?.response?.data?.detail||o?.message||"";if(n===403&&hn.test(s))throw Je(),new Ae(s);return null}}function io(e){return e.interceptors.response.use(t=>(t.data&&typeof t.data=="object"&&"result"in t.data&&"errors"in t.data&&(t.data=t.data.result),t),t=>{let o=t.response?.data?.errors;return o?.length&&(t.message=o[0]),Promise.reject(t)}),e}function wn(e){return e.interceptors.response.use(void 0,t=>{if(t.response?.status===403){let n=t.message||t.response?.data?.errors?.[0]||t.response?.data?.detail||"";if(hn.test(n))return Je(),Promise.reject(new Ae(n))}return Promise.reject(t)}),e}function bn(e){return e.interceptors.response.use(void 0,async t=>{let o=t.config;if(t.response?.status!==401||o._retried)return Promise.reject(t);o._retried=!0,kt||(kt=ao().finally(()=>{kt=null}));let n=await kt;return n?(o.headers.Authorization=`Bearer ${n}`,e.request(o)):Promise.reject(t)}),e}function L(){let e=b(),t={"Content-Type":"application/json"};e&&(t.Authorization=`Bearer ${e.access_token}`);let o=Xe.default.create({baseURL:vt,headers:t});return io(o),bn(o),wn(o),o}function _n(){return io(Xe.default.create({baseURL:vt,headers:{"Content-Type":"application/json"}}))}function Qe(e){let t=Xe.default.create({baseURL:vt,headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});return io(t),bn(t),wn(t),t}var Xe,vt,Ae,hn,kt,ze,he=H(()=>{"use strict";Xe=u(require("axios"));M();oe();vt=N,Ae=class extends Error{constructor(o){super(o);this.code="DEACTIVATED";this.name="DeactivatedError"}},hn=/account\s+has\s+been\s+(deleted|deactivated)/i,kt=null,ze=null});function $n(){try{let e=ie.default.statSync(ye);return Date.now()-e.mtimeMs>kn}catch{return!0}}function lo(){try{return ie.default.mkdirSync(co.default.dirname(ye),{recursive:!0}),ie.default.writeFileSync(ye,String(process.pid),{flag:"wx"}),!0}catch{if($n())try{return ie.default.unlinkSync(ye),ie.default.writeFileSync(ye,String(process.pid),{flag:"wx"}),!0}catch{return!1}return!1}}function Cn(){try{ie.default.unlinkSync(ye)}catch{}}async function In(e){let t=!1;for(let o=0;o<$s;o++){if(lo()){t=!0;break}await new Promise(n=>setTimeout(n,vn))}t||console.warn("[config-lock] Could not acquire lock after timeout \u2014 proceeding without lock");try{return await e()}finally{t&&Cn()}}function we(e){let t=lo();if(!t&&$n()){try{ie.default.unlinkSync(ye)}catch{}t=lo()}try{return e()}finally{t&&Cn()}}var ie,Sn,co,ye,kn,vn,$s,Ze=H(()=>{"use strict";ie=u(require("fs")),Sn=u(require("os")),co=u(require("path")),ye=co.default.join(Sn.default.homedir(),".openclaw","openclaw.json.lock"),kn=1e4,vn=50,$s=Math.ceil(kn/vn)});var be=ks((ul,Cs)=>{Cs.exports={name:"badgerclaw",version:"0.3.2",engines:{node:">=18"},description:"BadgerClaw CLI \u2014 one-click bot provisioning",main:"dist/index.js",bin:{badgerclaw:"./dist/index.js"},files:["dist/","scripts/","assets/","README.md"],scripts:{build:"node build.mjs","verify-dist-version":`node -e "const v=require('./package.json').version; const d=require('fs').readFileSync('./dist/index.js','utf8'); if(!d.includes('version:\\"'+v+'\\"')){console.error('dist/index.js is stale \u2014 rebuild before publish (package.json='+v+')'); process.exit(1);} console.log('dist/index.js OK \u2014 version '+v);"`,prepublishOnly:"rm -rf dist && npm run build && npm run verify-dist-version",preuninstall:"node scripts/preuninstall.cjs",test:"tsx --test 'tests/**/*.test.ts'"},keywords:[],author:"",license:"ISC",dependencies:{"@modelcontextprotocol/sdk":"^1.29.0",axios:"^1.6.0",chalk:"^4.1.2",commander:"^12.0.0",eventsource:"^1.1.2",open:"^8.4.2",ora:"^5.4.1"},devDependencies:{"@types/eventsource":"^1.1.15","@types/node":"^20.0.0",esbuild:"^0.28.0",tsx:"^4.22.0",typescript:"^5.3.0"}}});function Ct(e=Es){try{return po.default.readdirSync(e,{withFileTypes:!0}).filter(t=>t.isDirectory()&&t.name.startsWith("badgerclaw-connect-")).map(t=>ne.default.join(e,t.name))}catch{return[]}}function Ps(){return[...Ct().map(t=>ne.default.join(t,"node_modules/@badgerclaw/connect/package.json")),ne.default.join(As,"package.json"),ne.default.join(Rn,"node_modules/@badgerclaw/connect/package.json"),ne.default.join(Rn,"package.json")]}function go(){return"0.3.2"}function It(){for(let e of Ps())try{let t=po.default.readFileSync(e,"utf-8"),o=JSON.parse(t);if(o.version&&(!o.name||o.name==="@badgerclaw/connect"||o.name==="badgerclaw")||o.version)return o.version}catch{}return null}function mo(e){let t=e.trim(),o=t.match(/\d+(?:\.\d+){1,3}/);return o?o[0]:t}function G(){if((0,uo.spawnSync)("which",["openclaw"],{encoding:"utf-8"}).status!==0)return null;let t=(0,uo.spawnSync)("openclaw",["--version"],{encoding:"utf-8",timeout:3e3});return t.status!==0||!t.stdout?null:mo(t.stdout)||null}function Ds(e,t){let o=e.split(".").map(s=>parseInt(s,10)||0),n=t.split(".").map(s=>parseInt(s,10)||0),r=Math.max(o.length,n.length);for(let s=0;s<r;s++){let a=(o[s]??0)-(n[s]??0);if(a!==0)return a<0?-1:1}return 0}function xn(e,t=G()){return t?Ds(mo(t),mo(e))>=0:!1}async function Os(){let e=new AbortController,t=setTimeout(()=>e.abort(),Rs);try{let o=await fetch(Is,{signal:e.signal});if(!o.ok)return null;let n=await o.json(),r=n.result&&typeof n.result=="object"?n.result:n;return{cli:r.cli??"unknown",plugin:r.plugin??"unknown",supported_openclaw:r.supported_openclaw??"unknown"}}catch{return null}finally{clearTimeout(t)}}function Ls(e){let t=[];if(e.cli&&e.cli!=="unknown"){let n=go();n!==e.cli&&t.push({component:"cli",current:n,approved:e.cli})}if(!(G()!==null))return t;if(e.plugin&&e.plugin!=="unknown"){let n=It();(n===null||n!==e.plugin)&&t.push({component:"plugin",current:n??"not installed",approved:e.plugin})}if(e.supported_openclaw&&e.supported_openclaw!=="unknown"){let n=G();(n===null||n!==e.supported_openclaw)&&t.push({component:"openclaw",current:n??"not installed",approved:e.supported_openclaw})}return t}function Ns(e){return e[2]}function Ts(e){return!e||e.startsWith("-")?!0:xs.has(e)}function Ms(e){let t=[];t.push(""),t.push(le.default.red.bold("\u2717 Unsupported versions detected")),t.push("");for(let o of e){let n=o.component.padEnd(8);t.push(` ${n} ${le.default.yellow(o.current)} \u2192 ${le.default.green(o.approved)} ${le.default.dim("(supported)")}`)}return t.push(""),t.push("This command is blocked until your installation matches the supported versions."),t.push(""),t.push(le.default.green(" To fix, run:")),t.push(le.default.green.bold(" badgerclaw setup")),t.push(""),t.push(le.default.dim(" (bypass temporarily: BADGERCLAW_NO_VERSION_CHECK=1 badgerclaw <cmd>)")),t.push(""),t.join(`
3
- `)}async function An(e){if(process.env.BADGERCLAW_NO_VERSION_CHECK)return;let t=Ns(e);if(Ts(t))return;let o=await Os();if(!o)return;let n=Ls(o);n.length!==0&&(process.stderr.write(Ms(n)),process.exit(1))}var po,$t,ne,uo,le,Is,Rs,xs,Rn,As,Es,Ee=H(()=>{"use strict";po=u(require("fs")),$t=u(require("os")),ne=u(require("path")),uo=require("child_process"),le=u(require("chalk"));oe();Is=`${N}/api/v1/dashboard/versions/latest`,Rs=2500,xs=new Set(["setup","logout","help","--version","-V","--help","-h","heartbeat","watch","autopair"]),Rn=ne.default.join($t.default.homedir(),".openclaw/extensions/badgerclaw"),As=ne.default.join($t.default.homedir(),".openclaw/npm/node_modules/@badgerclaw/connect"),Es=ne.default.join($t.default.homedir(),".openclaw/npm/projects")});var Ln={};to(Ln,{HERMES_IMAGE_DEFAULT:()=>Pe,detectCapabilities:()=>ce,detectDiskFreeGb:()=>On,detectDocker:()=>Rt,detectHermes:()=>xt,detectOpenClaw:()=>Dn});function Rt(){if((0,et.spawnSync)("which",["docker"],{encoding:"utf-8"}).status!==0)return{installed:!1};let t=(0,et.spawnSync)("docker",["version","--format","{{.Server.Version}}"],{encoding:"utf-8",timeout:3e3});return t.status!==0||!t.stdout.trim()?{installed:!1}:{installed:!0,version:t.stdout.trim()}}function Dn(){let e=G();return e?{installed:!0,version:e}:{installed:!1}}function xt(e){if(!e.installed)return{installed:!1};let t=process.env.HERMES_IMAGE||Pe;return(0,et.spawnSync)("docker",["image","inspect","--format","{{.RepoDigests}}",t],{encoding:"utf-8",timeout:3e3}).status!==0?{installed:!1}:{installed:!0,image:t}}function On(){let e=Pn.default.join(fo.default.homedir(),".badgerclaw"),t=En.default.existsSync(e)?e:fo.default.homedir();if(process.platform==="win32")return null;let o=(0,et.spawnSync)("df",["-Pk",t],{encoding:"utf-8",timeout:3e3});if(o.status!==0||!o.stdout)return null;let n=o.stdout.trim().split(`
4
- `);if(n.length<2)return null;let r=n[1].split(/\s+/),s=parseInt(r[3]||"",10);return Number.isFinite(s)?Math.floor(s/1024/1024):null}function ce(){let e=Rt();return{openclaw:Dn(),hermes:xt(e),docker:e,disk_free_gb:On(),ports_in_use:[]}}var et,En,fo,Pn,Pe,_e=H(()=>{"use strict";et=require("child_process"),En=u(require("fs")),fo=u(require("os")),Pn=u(require("path"));Ee();Pe="hermes-agent-bc:bundled"});function Et(e){return V.default.join(Bs,`bot-${e}`)}function jn(e){x.default.existsSync(Se)||x.default.mkdirSync(Se,{recursive:!0,mode:448}),x.default.writeFileSync(yo,JSON.stringify(e,null,2)+`
5
- `,{mode:384})}function Hs(){if(!x.default.existsSync(yo))return null;try{let e=JSON.parse(x.default.readFileSync(yo,"utf-8"));return e&&e.provider==="ollama"?e:null}catch{return null}}function wo(e){return`badgerclaw-hermes-bot-${e}`}function bo(){if(!x.default.existsSync(ho))return{hermes_bots:{}};try{let e=x.default.readFileSync(ho,"utf-8"),t=JSON.parse(e);return{hermes_bots:t.hermes_bots&&typeof t.hermes_bots=="object"?t.hermes_bots:{}}}catch{return{hermes_bots:{}}}}function Us(e){x.default.existsSync(Se)||x.default.mkdirSync(Se,{recursive:!0,mode:448}),x.default.writeFileSync(ho,JSON.stringify(e,null,2)+`
6
- `,{mode:384})}function Fs(e,t=js){let o=new Set(Object.values(e.hermes_bots).map(r=>r.port)),n=t;for(;o.has(n)||!Gs(n);)if(n+=1,n-t>1e3)throw new Error(`Could not find a free port near ${t} after 1000 tries \u2014 host is unusually busy`);return n}function Gs(e){let t=Mn.default.createServer(),o=!1;try{t.listen(e,"127.0.0.1"),o=!0}catch{o=!1}finally{try{t.close()}catch{}}return o}function Hn(e=process.env){let t=e.BADGERCLAW_LLM_PROVIDER?.toLowerCase(),o=e.BADGERCLAW_LLM_API_KEY;if(t==="ollama")return{provider:"ollama",apiKey:"",baseUrl:e.BADGERCLAW_LLM_BASE_URL||At,model:e.BADGERCLAW_LLM_MODEL||void 0};if(t&&o){if(t!=="gemini"&&t!=="anthropic"&&t!=="openrouter")throw new Error(`BADGERCLAW_LLM_PROVIDER must be one of: gemini, anthropic, openrouter, ollama. Got '${t}'.`);return{provider:t,apiKey:o}}let n=Hs();if(n)return{provider:"ollama",apiKey:"",baseUrl:n.base_url||At,model:n.model||void 0};let r=e.GOOGLE_API_KEY||e.GEMINI_API_KEY;if(r)return{provider:"gemini",apiKey:r};if(e.ANTHROPIC_API_KEY)return{provider:"anthropic",apiKey:e.ANTHROPIC_API_KEY};if(e.OPENROUTER_API_KEY)return{provider:"openrouter",apiKey:e.OPENROUTER_API_KEY}}function _o(e){switch(e){case"gemini":return"gemini-2.5-flash";case"anthropic":return"claude-sonnet-4-6";case"openrouter":return"anthropic/claude-sonnet-4-6";case"ollama":return"qwen2.5:3b"}}function Ws(e){switch(e){case"gemini":return"GOOGLE_API_KEY";case"anthropic":return"ANTHROPIC_API_KEY";case"openrouter":return"OPENROUTER_API_KEY";case"ollama":return"OPENAI_API_KEY"}}function qs(e,t){let o=[`# Generated by badgerclaw CLI for bot ${e.botId}.`,"# Edit at your own risk; subsequent pair operations may overwrite.","",`MATRIX_HOMESERVER=${e.matrixHomeserver}`,`MATRIX_ACCESS_TOKEN=${e.matrixAccessToken}`,`MATRIX_USER_ID=${e.matrixUserId}`,`MATRIX_DEVICE_ID=${e.matrixDeviceId}`,"MATRIX_ENCRYPTION=true",`MATRIX_ALLOWED_USERS=${e.ownerMatrixUserId}`];return e.homeRoomId&&o.push(`MATRIX_HOME_ROOM=${e.homeRoomId}`),e.llm&&(o.push(""),e.llm.provider==="ollama"?(o.push("# Local Ollama (OpenAI-compatible) \u2014 no real API key needed."),o.push(`OPENAI_BASE_URL=${e.llm.baseUrl||At}`),o.push("OPENAI_API_KEY=ollama")):(o.push("# LLM provider \u2014 set by the operator's environment at pair time."),o.push("# Hermes reads this directly; model selection lives in config.yaml."),o.push(`${Ws(e.llm.provider)}=${e.llm.apiKey}`))),o.push("","# OpenAI-compatible API surface \u2014 localhost only by default so the","# CLI's daemon can health-check the container without exposing it","# beyond the host loopback.","API_SERVER_ENABLED=true","API_SERVER_HOST=127.0.0.1",`API_SERVER_PORT=${t}`,`API_SERVER_KEY=${(0,Tn.randomBytes)(24).toString("hex")}`),o.join(`
2
+ "use strict";var za=Object.create;var Bt=Object.defineProperty;var Qa=Object.getOwnPropertyDescriptor;var Xa=Object.getOwnPropertyNames;var Za=Object.getPrototypeOf,ei=Object.prototype.hasOwnProperty;var q=(e,t)=>()=>(e&&(t=e(e=0)),t);var ti=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Dn=(e,t)=>{for(var n in t)Bt(e,n,{get:t[n],enumerable:!0})},Xo=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Xa(t))!ei.call(e,r)&&r!==n&&Bt(e,r,{get:()=>t[r],enumerable:!(o=Qa(t,r))||o.enumerable});return e};var m=(e,t,n)=>(n=e!=null?za(Za(e)):{},Xo(t||!e||!e.__esModule?Bt(n,"default",{value:e,enumerable:!0}):n,e)),Zo=e=>Xo(Bt({},"__esModule",{value:!0}),e);function R(){try{let e=ut.default.readFileSync(Bn,"utf-8");return JSON.parse(e)}catch{return null}}function Ut(e){ut.default.mkdirSync(or,{recursive:!0}),ut.default.writeFileSync(Bn,JSON.stringify(e,null,2),{mode:384})}function dt(){try{ut.default.unlinkSync(Bn)}catch{}}function Ft(){let e=R();return e?new Date(e.expires_at)>new Date:!1}function Ht(e){let t=e.match(/^@?([^:]+)/);return t?t[1]:e}var ut,jn,nr,or,Bn,F=q(()=>{"use strict";ut=m(require("fs")),jn=m(require("path")),nr=m(require("os")),or=jn.default.join(nr.default.homedir(),".badgerclaw"),Bn=jn.default.join(or,"auth.json")});function mt(){return rr.default.createHash("sha256").update(`${se.default.hostname()}-${se.default.platform()}-${se.default.arch()}`).digest("hex").slice(0,16)}function ae(){let e=R();if(e?.instance_id)return e.instance_id;let t=mt();return`openclaw-${se.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${t}`}function Gt(){return{hostname:se.default.hostname(),os:se.default.platform(),arch:se.default.arch(),uptimeSeconds:Math.floor(se.default.uptime()),memFreeMb:Math.floor(se.default.freemem()/1024/1024)}}var se,rr,Ie=q(()=>{"use strict";se=m(require("os")),rr=m(require("crypto"));F()});var sr,N,ar,ie=q(()=>{"use strict";sr=process.env.BADGERCLAW_ENV==="local",N=process.env.BADGERCLAW_API_URL??(sr?"http://localhost:8000":"https://api.badger.signout.io"),ar=process.env.BADGERCLAW_AUTH_URL??(sr?"http://localhost:5500":"https://badgerclaw.ai")});function lr(){return pt}function ni(e){if(!e)return null;let t=e.split(".");if(t.length!==3)return null;try{let n=t[1].replace(/-/g,"+").replace(/_/g,"/"),o=n.length%4===0?n:n+"=".repeat(4-n.length%4),r=JSON.parse(Buffer.from(o,"base64").toString("utf8"));return(typeof r?.sub=="string"?r.sub:null)||null}catch{return null}}async function Un(){let e=R();if(!e?.refresh_token||!e?.email)return pt=e?e.refresh_token?"no email in auth.json \u2014 re-run `badgerclaw login`":"no refresh_token in auth.json \u2014 re-run `badgerclaw login`":"not logged in (auth.json missing)",null;let t=ni(e.access_token);try{let n=await gt.default.post(`${Vt}/api/v1/user/token/refresh`,{refresh_token:e.refresh_token,email:e.email,...t?{cognito_username:t}:{}}),o=n.data?.result??n.data,r=o?.access_token;if(!r)return pt="server returned no access_token",null;let s=o.expires_in||3600,a=new Date(Date.now()+s*1e3).toISOString();return Ut({...e,access_token:r,expires_at:a}),pt=null,r}catch(n){let o=n?.response?.status,r=n?.response?.data?.errors?.[0]||n?.response?.data?.detail||n?.message||"unknown error";pt=o?`HTTP ${o}: ${r}`:`network error: ${r}`;let s=n?.response?.data?.errors?.[0]||n?.response?.data?.detail||n?.message||"";if(o===403&&ir.test(s))throw dt(),new He(s);return null}}function Fn(e){return e.interceptors.response.use(t=>(t.data&&typeof t.data=="object"&&"result"in t.data&&"errors"in t.data&&(t.data=t.data.result),t),t=>{let n=t.response?.data?.errors;return n?.length&&(t.message=n[0]),Promise.reject(t)}),e}function cr(e){return e.interceptors.response.use(void 0,t=>{if(t.response?.status===403){let o=t.message||t.response?.data?.errors?.[0]||t.response?.data?.detail||"";if(ir.test(o))return dt(),Promise.reject(new He(o))}return Promise.reject(t)}),e}function ur(e){return e.interceptors.response.use(void 0,async t=>{let n=t.config;if(t.response?.status!==401||n._retried)return Promise.reject(t);n._retried=!0,qt||(qt=Un().finally(()=>{qt=null}));let o=await qt;return o?(n.headers.Authorization=`Bearer ${o}`,e.request(n)):Promise.reject(t)}),e}function B(){let e=R(),t={"Content-Type":"application/json"};e&&(t.Authorization=`Bearer ${e.access_token}`);let n=gt.default.create({baseURL:Vt,headers:t});return Fn(n),ur(n),cr(n),n}function dr(){return Fn(gt.default.create({baseURL:Vt,headers:{"Content-Type":"application/json"}}))}function ft(e){let t=gt.default.create({baseURL:Vt,headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});return Fn(t),ur(t),cr(t),t}var gt,Vt,He,ir,qt,pt,Ae=q(()=>{"use strict";gt=m(require("axios"));F();ie();Vt=N,He=class extends Error{constructor(n){super(n);this.code="DEACTIVATED";this.name="DeactivatedError"}},ir=/account\s+has\s+been\s+(deleted|deactivated)/i,qt=null,pt=null});function fr(){try{let e=be.default.statSync(Pe);return Date.now()-e.mtimeMs>pr}catch{return!0}}function Hn(){try{return be.default.mkdirSync(Gn.default.dirname(Pe),{recursive:!0}),be.default.writeFileSync(Pe,String(process.pid),{flag:"wx"}),!0}catch{if(fr())try{return be.default.unlinkSync(Pe),be.default.writeFileSync(Pe,String(process.pid),{flag:"wx"}),!0}catch{return!1}return!1}}function hr(){try{be.default.unlinkSync(Pe)}catch{}}async function yr(e){let t=!1;for(let n=0;n<oi;n++){if(Hn()){t=!0;break}await new Promise(o=>setTimeout(o,gr))}t||console.warn("[config-lock] Could not acquire lock after timeout \u2014 proceeding without lock");try{return await e()}finally{t&&hr()}}function Ee(e){let t=Hn();if(!t&&fr()){try{be.default.unlinkSync(Pe)}catch{}t=Hn()}try{return e()}finally{t&&hr()}}var be,mr,Gn,Pe,pr,gr,oi,ht=q(()=>{"use strict";be=m(require("fs")),mr=m(require("os")),Gn=m(require("path")),Pe=Gn.default.join(mr.default.homedir(),".openclaw","openclaw.json.lock"),pr=1e4,gr=50,oi=Math.ceil(pr/gr)});var we=ti((fu,ri)=>{ri.exports={name:"badgerclaw",version:"0.3.4",engines:{node:">=18"},description:"BadgerClaw CLI \u2014 one-click bot provisioning",main:"dist/index.js",bin:{badgerclaw:"./dist/index.js"},files:["dist/","scripts/","assets/","README.md"],scripts:{build:"node build.mjs","verify-dist-version":`node -e "const v=require('./package.json').version; const d=require('fs').readFileSync('./dist/index.js','utf8'); if(!d.includes('version:\\"'+v+'\\"')){console.error('dist/index.js is stale \u2014 rebuild before publish (package.json='+v+')'); process.exit(1);} console.log('dist/index.js OK \u2014 version '+v);"`,prepublishOnly:"rm -rf dist && npm run build && npm run verify-dist-version",preuninstall:"node scripts/preuninstall.cjs",test:"tsx --test 'tests/**/*.test.ts'"},keywords:[],author:"",license:"ISC",dependencies:{"@anthropic-ai/sdk":"^0.105.0","@modelcontextprotocol/sdk":"^1.29.0",axios:"^1.6.0",chalk:"^4.1.2",commander:"^12.0.0",eventsource:"^1.1.2",open:"^8.4.2",ora:"^5.4.1"},devDependencies:{"@types/eventsource":"^1.1.15","@types/node":"^20.0.0",esbuild:"^0.28.0",tsx:"^4.22.0",typescript:"^5.3.0"}}});function Kt(e=ci){try{return Wn.default.readdirSync(e,{withFileTypes:!0}).filter(t=>t.isDirectory()&&t.name.startsWith("badgerclaw-connect-")).map(t=>de.default.join(e,t.name))}catch{return[]}}function ui(){return[...Kt().map(t=>de.default.join(t,"node_modules/@badgerclaw/connect/package.json")),de.default.join(li,"package.json"),de.default.join(br,"node_modules/@badgerclaw/connect/package.json"),de.default.join(br,"package.json")]}function Kn(){return"0.3.4"}function Yt(){for(let e of ui())try{let t=Wn.default.readFileSync(e,"utf-8"),n=JSON.parse(t);if(n.version&&(!n.name||n.name==="@badgerclaw/connect"||n.name==="badgerclaw")||n.version)return n.version}catch{}return null}function Vn(e){let t=e.trim(),n=t.match(/\d+(?:\.\d+){1,3}/);return n?n[0]:t}function K(){if((0,qn.spawnSync)("which",["openclaw"],{encoding:"utf-8"}).status!==0)return null;let t=(0,qn.spawnSync)("openclaw",["--version"],{encoding:"utf-8",timeout:3e3});return t.status!==0||!t.stdout?null:Vn(t.stdout)||null}function di(e,t){let n=e.split(".").map(s=>parseInt(s,10)||0),o=t.split(".").map(s=>parseInt(s,10)||0),r=Math.max(n.length,o.length);for(let s=0;s<r;s++){let a=(n[s]??0)-(o[s]??0);if(a!==0)return a<0?-1:1}return 0}function wr(e,t=K()){return t?di(Vn(t),Vn(e))>=0:!1}async function mi(){let e=new AbortController,t=setTimeout(()=>e.abort(),ai);try{let n=await fetch(si,{signal:e.signal});if(!n.ok)return null;let o=await n.json(),r=o.result&&typeof o.result=="object"?o.result:o;return{cli:r.cli??"unknown",plugin:r.plugin??"unknown",supported_openclaw:r.supported_openclaw??"unknown"}}catch{return null}finally{clearTimeout(t)}}function pi(e){let t=[];if(e.cli&&e.cli!=="unknown"){let o=Kn();o!==e.cli&&t.push({component:"cli",current:o,approved:e.cli})}if(!(K()!==null))return t;if(e.plugin&&e.plugin!=="unknown"){let o=Yt();(o===null||o!==e.plugin)&&t.push({component:"plugin",current:o??"not installed",approved:e.plugin})}if(e.supported_openclaw&&e.supported_openclaw!=="unknown"){let o=K();(o===null||o!==e.supported_openclaw)&&t.push({component:"openclaw",current:o??"not installed",approved:e.supported_openclaw})}return t}function gi(e){return e[2]}function fi(e){return!e||e.startsWith("-")?!0:ii.has(e)}function hi(e){let t=[];t.push(""),t.push(_e.default.red.bold("\u2717 Unsupported versions detected")),t.push("");for(let n of e){let o=n.component.padEnd(8);t.push(` ${o} ${_e.default.yellow(n.current)} \u2192 ${_e.default.green(n.approved)} ${_e.default.dim("(supported)")}`)}return t.push(""),t.push("This command is blocked until your installation matches the supported versions."),t.push(""),t.push(_e.default.green(" To fix, run:")),t.push(_e.default.green.bold(" badgerclaw setup")),t.push(""),t.push(_e.default.dim(" (bypass temporarily: BADGERCLAW_NO_VERSION_CHECK=1 badgerclaw <cmd>)")),t.push(""),t.join(`
3
+ `)}async function _r(e){if(process.env.BADGERCLAW_NO_VERSION_CHECK)return;let t=gi(e);if(fi(t))return;let n=await mi();if(!n)return;let o=pi(n);o.length!==0&&(process.stderr.write(hi(o)),process.exit(1))}var Wn,Wt,de,qn,_e,si,ai,ii,br,li,ci,Ge=q(()=>{"use strict";Wn=m(require("fs")),Wt=m(require("os")),de=m(require("path")),qn=require("child_process"),_e=m(require("chalk"));ie();si=`${N}/api/v1/dashboard/versions/latest`,ai=2500,ii=new Set(["setup","logout","help","--version","-V","--help","-h","heartbeat","watch","autopair","benchmark"]),br=de.default.join(Wt.default.homedir(),".openclaw/extensions/badgerclaw"),li=de.default.join(Wt.default.homedir(),".openclaw/npm/node_modules/@badgerclaw/connect"),ci=de.default.join(Wt.default.homedir(),".openclaw/npm/projects")});var Cr={};Dn(Cr,{HERMES_IMAGE_DEFAULT:()=>qe,detectCapabilities:()=>Se,detectDiskFreeGb:()=>Rr,detectDocker:()=>Jt,detectHermes:()=>zt,detectOpenClaw:()=>kr});function Jt(){if((0,yt.spawnSync)("which",["docker"],{encoding:"utf-8"}).status!==0)return{installed:!1};let t=(0,yt.spawnSync)("docker",["version","--format","{{.Server.Version}}"],{encoding:"utf-8",timeout:3e3});return t.status!==0||!t.stdout.trim()?{installed:!1}:{installed:!0,version:t.stdout.trim()}}function kr(){let e=K();return e?{installed:!0,version:e}:{installed:!1}}function zt(e){if(!e.installed)return{installed:!1};let t=process.env.HERMES_IMAGE||qe;return(0,yt.spawnSync)("docker",["image","inspect","--format","{{.RepoDigests}}",t],{encoding:"utf-8",timeout:3e3}).status!==0?{installed:!1}:{installed:!0,image:t}}function Rr(){let e=vr.default.join(Yn.default.homedir(),".badgerclaw"),t=Sr.default.existsSync(e)?e:Yn.default.homedir();if(process.platform==="win32")return null;let n=(0,yt.spawnSync)("df",["-Pk",t],{encoding:"utf-8",timeout:3e3});if(n.status!==0||!n.stdout)return null;let o=n.stdout.trim().split(`
4
+ `);if(o.length<2)return null;let r=o[1].split(/\s+/),s=parseInt(r[3]||"",10);return Number.isFinite(s)?Math.floor(s/1024/1024):null}function Se(){let e=Jt();return{openclaw:kr(),hermes:zt(e),docker:e,disk_free_gb:Rr(),ports_in_use:[]}}var yt,Sr,Yn,vr,qe,Oe=q(()=>{"use strict";yt=require("child_process"),Sr=m(require("fs")),Yn=m(require("os")),vr=m(require("path"));Ge();qe="hermes-agent-bc:bundled"});function Xt(e){return Y.default.join(yi,`bot-${e}`)}function Pr(e){I.default.existsSync(le)||I.default.mkdirSync(le,{recursive:!0,mode:448}),I.default.writeFileSync(Zt,JSON.stringify(e,null,2)+`
5
+ `,{mode:384});try{I.default.rmSync(en,{force:!0})}catch{}}function wi(){if(!I.default.existsSync(Zt))return null;try{let e=JSON.parse(I.default.readFileSync(Zt,"utf-8"));return e&&e.provider==="ollama"?e:null}catch{return null}}function _i(e){return e==="gemini"||e==="anthropic"||e==="openrouter"}function Er(e){I.default.existsSync(le)||I.default.mkdirSync(le,{recursive:!0,mode:448}),I.default.writeFileSync(en,JSON.stringify(e,null,2)+`
6
+ `,{mode:384});try{I.default.rmSync(Zt,{force:!0})}catch{}}function Si(){if(!I.default.existsSync(en))return null;try{let e=JSON.parse(I.default.readFileSync(en,"utf-8"));return e&&_i(e.provider)&&typeof e.apiKey=="string"&&e.apiKey?{provider:e.provider,apiKey:e.apiKey,model:e.model||void 0}:null}catch{return null}}function zn(e){return`badgerclaw-hermes-bot-${e}`}function Qn(){if(!I.default.existsSync(Jn))return{hermes_bots:{}};try{let e=I.default.readFileSync(Jn,"utf-8"),t=JSON.parse(e);return{hermes_bots:t.hermes_bots&&typeof t.hermes_bots=="object"?t.hermes_bots:{}}}catch{return{hermes_bots:{}}}}function vi(e){I.default.existsSync(le)||I.default.mkdirSync(le,{recursive:!0,mode:448}),I.default.writeFileSync(Jn,JSON.stringify(e,null,2)+`
7
+ `,{mode:384})}function ki(e,t=bi){let n=new Set(Object.values(e.hermes_bots).map(r=>r.port)),o=t;for(;n.has(o)||!Ri(o);)if(o+=1,o-t>1e3)throw new Error(`Could not find a free port near ${t} after 1000 tries \u2014 host is unusually busy`);return o}function Ri(e){let t=Ir.default.createServer(),n=!1;try{t.listen(e,"127.0.0.1"),n=!0}catch{n=!1}finally{try{t.close()}catch{}}return n}function Or(e=process.env){let t=e.BADGERCLAW_LLM_PROVIDER?.toLowerCase(),n=e.BADGERCLAW_LLM_API_KEY;if(t==="ollama")return{provider:"ollama",apiKey:"",baseUrl:e.BADGERCLAW_LLM_BASE_URL||Qt,model:e.BADGERCLAW_LLM_MODEL||void 0};if(t&&n){if(t!=="gemini"&&t!=="anthropic"&&t!=="openrouter")throw new Error(`BADGERCLAW_LLM_PROVIDER must be one of: gemini, anthropic, openrouter, ollama. Got '${t}'.`);return{provider:t,apiKey:n}}let o=wi();if(o)return{provider:"ollama",apiKey:"",baseUrl:o.base_url||Qt,model:o.model||void 0};let r=Si();if(r)return{provider:r.provider,apiKey:r.apiKey,model:r.model||void 0};let s=e.GOOGLE_API_KEY||e.GEMINI_API_KEY;if(s)return{provider:"gemini",apiKey:s};if(e.ANTHROPIC_API_KEY)return{provider:"anthropic",apiKey:e.ANTHROPIC_API_KEY};if(e.OPENROUTER_API_KEY)return{provider:"openrouter",apiKey:e.OPENROUTER_API_KEY}}function bt(e){switch(e){case"gemini":return"gemini-2.5-flash";case"anthropic":return"claude-sonnet-4-6";case"openrouter":return"anthropic/claude-sonnet-4-6";case"ollama":return"qwen2.5:3b"}}function Ci(e){switch(e){case"gemini":return"GOOGLE_API_KEY";case"anthropic":return"ANTHROPIC_API_KEY";case"openrouter":return"OPENROUTER_API_KEY";case"ollama":return"OPENAI_API_KEY"}}function xi(e,t){let n=[`# Generated by badgerclaw CLI for bot ${e.botId}.`,"# Edit at your own risk; subsequent pair operations may overwrite.","",`MATRIX_HOMESERVER=${e.matrixHomeserver}`,`MATRIX_ACCESS_TOKEN=${e.matrixAccessToken}`,`MATRIX_USER_ID=${e.matrixUserId}`,`MATRIX_DEVICE_ID=${e.matrixDeviceId}`,"MATRIX_ENCRYPTION=true",`MATRIX_ALLOWED_USERS=${e.ownerMatrixUserId}`];return e.homeRoomId&&n.push(`MATRIX_HOME_ROOM=${e.homeRoomId}`),e.llm&&(n.push(""),e.llm.provider==="ollama"?(n.push("# Local Ollama (OpenAI-compatible) \u2014 no real API key needed."),n.push(`OPENAI_BASE_URL=${e.llm.baseUrl||Qt}`),n.push("OPENAI_API_KEY=ollama")):(n.push("# LLM provider \u2014 set by the operator's environment at pair time."),n.push("# Hermes reads this directly; model selection lives in config.yaml."),n.push(`${Ci(e.llm.provider)}=${e.llm.apiKey}`))),n.push("","# OpenAI-compatible API surface \u2014 localhost only by default so the","# CLI's daemon can health-check the container without exposing it","# beyond the host loopback.","API_SERVER_ENABLED=true","API_SERVER_HOST=127.0.0.1",`API_SERVER_PORT=${t}`,`API_SERVER_KEY=${(0,$r.randomBytes)(24).toString("hex")}`),n.join(`
7
8
  `)+`
8
- `}function Vs(e){let t=[`# Hermes agent config for BadgerClaw bot ${e.botId}.`,"# Generated by badgerclaw CLI; secrets live in the sibling .env file.",""];if(e.llm){let o=e.llm.model||_o(e.llm.provider);t.push("model:",` default: ${o}`,` provider: ${e.llm.provider}`),e.llm.provider==="ollama"&&t.push(` base_url: ${e.llm.baseUrl||At}`," ollama_num_ctx: 65536"),t.push("")}return t.push("agent:",` name: ${e.botName||"BadgerClaw bot"}`,"terminal:"," backend: local","subagents:"," max_spawn_depth: 1","cron:"," enabled: false",""),t.join(`
9
- `)}function Ks(e){return[`# ${e.botName||"BadgerClaw bot"}`,"","You are a helpful assistant connected to the BadgerClaw platform via Matrix.","Respond concisely. Honour @mentions. Decline to act on rooms you weren't added to.",""].join(`
10
- `)}function Ys(e,t){let o=Et(e.botId);x.default.mkdirSync(o,{recursive:!0,mode:448});let n=V.default.join(o,".env"),r=V.default.join(o,"config.yaml"),s=V.default.join(o,"SOUL.md");return x.default.writeFileSync(n,qs(e,t),{mode:384}),x.default.writeFileSync(r,Vs(e),{mode:384}),x.default.existsSync(s)||x.default.writeFileSync(s,Ks(e),{mode:384}),{dataDir:o,envPath:n,configPath:r,soulPath:s}}function Dt(e){let t=e.run(["network","inspect","bridge","--format","{{range .IPAM.Config}}{{.Subnet}} {{end}}"]);return t.status===0&&!!(t.stdout||"").trim()}function So(e={}){let t=e.env??process.env;return t.BADGERCLAW_HERMES_NETWORK==="host"?!0:t.BADGERCLAW_HERMES_NETWORK==="bridge"?!1:!(e.bridgeUsable??(()=>Dt(Pt)))()}function Js(e){let t=process.getuid?.()??0,o=process.getgid?.()??0,n=["run","-d","--name",e.containerName,"--restart","unless-stopped","-v",`${e.dataDir}:/opt/data`];return e.hostNetwork??process.env.BADGERCLAW_HERMES_NETWORK==="host"?n.push("--network","host"):n.push("-p",`127.0.0.1:${e.port}:${e.port}`),t>0&&n.push("-e",`HERMES_UID=${t}`),o>0&&n.push("-e",`HERMES_GID=${o}`),n.push("--env-file",`${e.dataDir}/.env`,e.image,"gateway","run"),n}function Un(e,t={}){let o=t.docker??Pt,n=e.image||process.env.HERMES_IMAGE||Pe;e.llm||console.warn(`[hermes] no LLM provider configured for bot ${e.botId}. Set BADGERCLAW_LLM_PROVIDER + BADGERCLAW_LLM_API_KEY (or one of GOOGLE_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY) and re-pair, or the bot will join rooms but be unable to reply.`);let r=bo(),s=r.hermes_bots[e.botId],a=s?.port??Fs(r,t.portBase),c=s?.container_name??wo(e.botId);if(Ys(e,a),!t.skipDocker){o.run(["rm","-f",c]);let i=So({bridgeUsable:()=>Dt(o)}),m=Js({containerName:c,dataDir:Et(e.botId),port:a,image:n,hostNetwork:i}),p=o.run(m);if(p.status!==0)throw new Error(`docker run failed (exit ${p.status}): ${p.stderr||p.stdout}`)}let l={bot_id:e.botId,runtime:"hermes",container_name:c,port:a,data_dir:Et(e.botId),image:n,started_at:new Date().toISOString()};return r.hermes_bots[e.botId]=l,Us(r),l}function ko(e={}){let t=e.docker??Pt,o=bo(),n=[];for(let[r,s]of Object.entries(o.hermes_bots)){let a=t.run(["inspect","--format","{{.State.Status}}",s.container_name]),c,l=a.stdout.trim()||null;a.status!==0?(c="missing",l=(a.stderr||a.stdout).trim()||null):l==="running"?c="running":l==="exited"||l==="dead"||l==="created"?c="stopped":c="unknown",n.push({bot_id:r,container_name:s.container_name,status:c,raw:l})}return n}function Fn(e={}){return ko(e).map(o=>({bot_id:o.bot_id,bot_username:"",status:o.status==="running"?"running":o.status==="missing"?"error":"stopped",activity_state:"idle",active_task:null,last_activity_at:null,messages_received:0,messages_sent:0,chunked_messages:0,total_chunks_sent:0,errors:o.status==="missing"?1:0,last_error:o.status==="missing"?o.raw||"container missing":null,last_error_at:null,uptime_seconds:0,rooms_active:0,room_details:[],claude_code_enabled:!1,claude_code_session_id:null,quarantined:!1}))}function Xs(e){let t=e.match(zs);return t?t[1].trim():null}async function vo(e,t,o,n={}){let r={recoveryKey:null,posted:!1,envUpdated:!1};if(!e.backendBotId)return r;let a=(n.docker??Pt).run(["logs",t]),c=`${a.stdout}
11
- ${a.stderr}`,l=Xs(c);if(!l)return r;if(r.recoveryKey=l,n.api)try{let m=await n.api.post(`/api/v1/hermes/bots/${e.backendBotId}/runtime-bootstrap`,{recovery_key:l,image_ref:o});r.posted=m.status>=200&&m.status<300}catch(m){console.warn(`[hermes] failed to POST recovery key for ${e.botId}: ${m.message}. Daemon will retry next beat.`)}let i=n.envPath??V.default.join(Et(e.botId),".env");return x.default.existsSync(i)&&(x.default.readFileSync(i,"utf-8").includes("MATRIX_RECOVERY_KEY=")||(x.default.appendFileSync(i,`
9
+ `}function $i(e){let t=[`# Hermes agent config for BadgerClaw bot ${e.botId}.`,"# Generated by badgerclaw CLI; secrets live in the sibling .env file.",""];if(e.llm){let n=e.llm.model||bt(e.llm.provider);t.push("model:",` default: ${n}`,` provider: ${e.llm.provider}`),e.llm.provider==="ollama"&&t.push(` base_url: ${e.llm.baseUrl||Qt}`," ollama_num_ctx: 65536"),t.push("")}return t.push("agent:",` name: ${e.botName||"BadgerClaw bot"}`,"terminal:"," backend: local","subagents:"," max_spawn_depth: 1","cron:"," enabled: false",""),t.join(`
10
+ `)}function Ii(e){return[`# ${e.botName||"BadgerClaw bot"}`,"","You are a helpful assistant connected to the BadgerClaw platform via Matrix.","Respond concisely. Honour @mentions. Decline to act on rooms you weren't added to.",""].join(`
11
+ `)}function Ai(e,t){let n=Xt(e.botId);I.default.mkdirSync(n,{recursive:!0,mode:448});let o=Y.default.join(n,".env"),r=Y.default.join(n,"config.yaml"),s=Y.default.join(n,"SOUL.md");return I.default.writeFileSync(o,xi(e,t),{mode:384}),I.default.writeFileSync(r,$i(e),{mode:384}),I.default.existsSync(s)||I.default.writeFileSync(s,Ii(e),{mode:384}),{dataDir:n,envPath:o,configPath:r,soulPath:s}}function nn(e){let t=e.run(["network","inspect","bridge","--format","{{range .IPAM.Config}}{{.Subnet}} {{end}}"]);return t.status===0&&!!(t.stdout||"").trim()}function Xn(e={}){let t=e.env??process.env;return t.BADGERCLAW_HERMES_NETWORK==="host"?!0:t.BADGERCLAW_HERMES_NETWORK==="bridge"?!1:!(e.bridgeUsable??(()=>nn(tn)))()}function Pi(e){let t=process.getuid?.()??0,n=process.getgid?.()??0,o=["run","-d","--name",e.containerName,"--restart","unless-stopped","-v",`${e.dataDir}:/opt/data`];return e.hostNetwork??process.env.BADGERCLAW_HERMES_NETWORK==="host"?o.push("--network","host"):o.push("-p",`127.0.0.1:${e.port}:${e.port}`),t>0&&o.push("-e",`HERMES_UID=${t}`),n>0&&o.push("-e",`HERMES_GID=${n}`),o.push("--env-file",`${e.dataDir}/.env`,e.image,"gateway","run"),o}function Lr(e,t={}){let n=t.docker??tn,o=e.image||process.env.HERMES_IMAGE||qe;e.llm||console.warn(`[hermes] no LLM provider configured for bot ${e.botId}. Set BADGERCLAW_LLM_PROVIDER + BADGERCLAW_LLM_API_KEY (or one of GOOGLE_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY) and re-pair, or the bot will join rooms but be unable to reply.`);let r=Qn(),s=r.hermes_bots[e.botId],a=s?.port??ki(r,t.portBase),i=s?.container_name??zn(e.botId);if(Ai(e,a),!t.skipDocker){n.run(["rm","-f",i]);let l=Xn({bridgeUsable:()=>nn(n)}),u=Pi({containerName:i,dataDir:Xt(e.botId),port:a,image:o,hostNetwork:l}),p=n.run(u);if(p.status!==0)throw new Error(`docker run failed (exit ${p.status}): ${p.stderr||p.stdout}`)}let c={bot_id:e.botId,runtime:"hermes",container_name:i,port:a,data_dir:Xt(e.botId),image:o,started_at:new Date().toISOString()};return r.hermes_bots[e.botId]=c,vi(r),c}function Zn(e={}){let t=e.docker??tn,n=Qn(),o=[];for(let[r,s]of Object.entries(n.hermes_bots)){let a=t.run(["inspect","--format","{{.State.Status}}",s.container_name]),i,c=a.stdout.trim()||null;a.status!==0?(i="missing",c=(a.stderr||a.stdout).trim()||null):c==="running"?i="running":c==="exited"||c==="dead"||c==="created"?i="stopped":i="unknown",o.push({bot_id:r,container_name:s.container_name,status:i,raw:c})}return o}function Tr(e={}){return Zn(e).map(n=>({bot_id:n.bot_id,bot_username:"",status:n.status==="running"?"running":n.status==="missing"?"error":"stopped",activity_state:"idle",active_task:null,last_activity_at:null,messages_received:0,messages_sent:0,chunked_messages:0,total_chunks_sent:0,errors:n.status==="missing"?1:0,last_error:n.status==="missing"?n.raw||"container missing":null,last_error_at:null,uptime_seconds:0,rooms_active:0,room_details:[],claude_code_enabled:!1,claude_code_session_id:null,quarantined:!1}))}function Oi(e){let t=e.match(Ei);return t?t[1].trim():null}async function eo(e,t,n,o={}){let r={recoveryKey:null,posted:!1,envUpdated:!1};if(!e.backendBotId)return r;let a=(o.docker??tn).run(["logs",t]),i=`${a.stdout}
12
+ ${a.stderr}`,c=Oi(i);if(!c)return r;if(r.recoveryKey=c,o.api)try{let u=await o.api.post(`/api/v1/hermes/bots/${e.backendBotId}/runtime-bootstrap`,{recovery_key:c,image_ref:n});r.posted=u.status>=200&&u.status<300}catch(u){console.warn(`[hermes] failed to POST recovery key for ${e.botId}: ${u.message}. Daemon will retry next beat.`)}let l=o.envPath??Y.default.join(Xt(e.botId),".env");return I.default.existsSync(l)&&(I.default.readFileSync(l,"utf-8").includes("MATRIX_RECOVERY_KEY=")||(I.default.appendFileSync(l,`
12
13
  # Cross-signing recovery key captured from first-boot logs.
13
14
  # Hermes re-uses this on restart to re-sign the device after
14
15
  # Synapse rotates server keys.
15
- MATRIX_RECOVERY_KEY=${l}
16
- `),r.envUpdated=!0)),r}async function Gn(e={}){let t=bo(),o=[];for(let[n,r]of Object.entries(t.hermes_bots)){let s=V.default.join(r.data_dir,".env"),a=!1;try{x.default.existsSync(s)&&(a=x.default.readFileSync(s,"utf-8").includes("MATRIX_RECOVERY_KEY="))}catch{}if(a){o.push({bot_id:n,attempted:!1,recoveryKeyFound:!0,posted:!1,envUpdated:!1});continue}if(n.startsWith("@")){o.push({bot_id:n,attempted:!1,recoveryKeyFound:!1,posted:!1,envUpdated:!1});continue}try{let c=await vo({botId:n,backendBotId:n},r.container_name,r.image,{docker:e.docker,api:e.api,envPath:s});o.push({bot_id:n,attempted:!0,recoveryKeyFound:c.recoveryKey!==null,posted:c.posted,envUpdated:c.envUpdated})}catch(c){console.warn(`[hermes] recovery-key retry failed for ${n}: ${c.message}`),o.push({bot_id:n,attempted:!0,recoveryKeyFound:!1,posted:!1,envUpdated:!1})}}return o}var Nn,Tn,x,Mn,Bn,V,Se,Bs,ho,js,At,Pt,yo,zs,De=H(()=>{"use strict";Nn=require("child_process"),Tn=require("crypto"),x=u(require("fs")),Mn=u(require("net")),Bn=u(require("os")),V=u(require("path"));_e();Se=V.default.join(Bn.default.homedir(),".badgerclaw"),Bs=V.default.join(Se,"hermes"),ho=V.default.join(Se,"state.json"),js=8642,At="http://127.0.0.1:11434/v1",Pt={run:e=>{let t=(0,Nn.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};yo=V.default.join(Se,"local-llm.json");zs=/SAVE THIS RECOVERY KEY[\s\S]*?key rotation:\s+((?:[A-Za-z0-9]{4}\s+){7,}[A-Za-z0-9]{4})/});function Ot(e){return`'${e.replace(/'/g,"'\\''")}'`}function Qs(){if(de!==null)return de;let e=["/opt/homebrew/lib/node_modules/openclaw/openclaw.mjs","/usr/local/lib/node_modules/openclaw/openclaw.mjs","/usr/lib/node_modules/openclaw/openclaw.mjs"];for(let t of e)if(tt.default.existsSync(t))return de=`${Ot(process.execPath)} ${Ot(t)}`,de;try{let{execSync:t}=require("child_process"),o=t("npm root -g",{encoding:"utf-8",timeout:5e3,stdio:["ignore","pipe","ignore"]}).toString().trim();if(o){let n=Io.default.join(o,"openclaw","openclaw.mjs");if(tt.default.existsSync(n))return de=`${Ot(process.execPath)} ${Ot(n)}`,de}}catch{}return de="openclaw",de}function $o(e,t,o){t?t.fail(K.default.red(o)):e&&console.error(`[autopair] ${o}`)}async function Zs(e){if(!e.owner_matrix_user_id)throw new Error("Hermes redeem response missing owner_matrix_user_id. Update the API or fall back to OpenClaw runtime for this bot.");let t=e.user_id.replace(/[^a-zA-Z0-9_.-]/g,"_"),o={botId:e.bot_id??t,backendBotId:e.bot_id??void 0,matrixHomeserver:e.homeserver,matrixAccessToken:e.access_token,matrixUserId:e.user_id,matrixDeviceId:e.device_id,ownerMatrixUserId:e.owner_matrix_user_id,botName:e.bot_name,llm:Hn()},n=Un(o);if(o.backendBotId){let r=b();if(r){let s=Qe(r.access_token);try{await vo(o,wo(o.botId),n.image,{api:{post:async(a,c)=>{let l=await s.post(a,c);return{status:l.status,data:l.data}}}})}catch(a){console.warn(`[hermes] recovery key capture failed for ${o.botId}: ${a.message}. Daemon will retry next beat.`)}}}}async function ot(e,t,o,n){let r=b();if(!r)return;let s=n?null:(0,Co.default)(`Pairing bot: ${t}...`).start();try{let a=await fetch(`${N}/api/v1/pairing/redeem`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e,instance_id:Z()})});if(!a.ok){if(a.status===410){s?.info(K.default.dim(`${t} already paired (race-loss; another channel redeemed first).`));return}let m=await a.json().catch(()=>({errors:[a.statusText]}));$o(n,s,`Failed to redeem ${t}: ${m.errors?.[0]||a.status}`);return}let c=await a.json(),l=c.result??c;if((l.runtime??"openclaw")==="hermes"){try{await Zs(l),s?.succeed(K.default.green(`\u2705 ${l.bot_name} (${l.user_id}) running on Hermes \u2014 bot is live!`))}catch(m){$o(n,s,`Failed to start Hermes container for ${t}: ${m.message}`)}return}await In(async()=>{let m=l.user_id.split(":")[0].replace("@","").replace(/_bot$/,""),p;try{p=JSON.parse(tt.default.readFileSync(Wn,"utf-8"))}catch{p={}}p.channels||(p.channels={}),p.channels.badgerclaw||(p.channels.badgerclaw={}),p.channels.badgerclaw.accounts||(p.channels.badgerclaw.accounts={});let P={userId:l.user_id,accessToken:l.access_token,homeserver:l.homeserver,encryption:!0,groupPolicy:"open",allowlistOnly:!1,dm:{policy:"open"}};l.device_id&&(P.deviceId=l.device_id),p.channels.badgerclaw.accounts[m]=P,tt.default.writeFileSync(Wn,JSON.stringify(p,null,2),{mode:384})}),await fetch(`${N}/api/v1/openclaw/pending-pairs/${e}/claim`,{method:"POST",headers:{Authorization:`Bearer ${r.access_token}`}}).catch(()=>{}),s?.succeed(K.default.green(`\u2705 ${l.bot_name} (${l.user_id}) paired \u2014 bot is live!`))}catch(a){$o(n,s,`Failed to pair ${t}: ${a.message}`)}}async function nt(e=!1){let t=b();if(!t)return 0;let o=Qe(t.access_token);try{let{data:n}=await o.get("/api/v1/openclaw/pending-pairs");if(!n||n.length===0)return 0;let r=new Map;for(let a of n)r.set(a.bot_user_id,a);for(let a of n)r.get(a.bot_user_id)!==a&&await o.post(`/api/v1/openclaw/pending-pairs/${a.pair_code}/claim`).catch(()=>{});let s=0;for(let a of r.values()){let c=e?null:(0,Co.default)(`Pairing bot: ${a.bot_name} (${a.bot_user_id})`).start();try{await ot(a.pair_code,a.bot_name,a.bot_user_id,e),await o.post(`/api/v1/openclaw/pending-pairs/${a.pair_code}/claim`).catch(()=>{}),s++}catch(l){c?.fail(K.default.red(`Error pairing ${a.bot_name}: ${l}`))}}if(s>0)try{let{execSync:a}=await import("child_process");a(`${Qs()} gateway restart`,{stdio:"ignore"}),e||console.log(K.default.green(`
17
- \u26A1 ${s} bot(s) paired \u2014 gateway restarted, bots are live!`))}catch(a){e?console.error(`[autopair] gateway restart after pair failed: ${a?.message||a}`):console.log(K.default.yellow(`
18
- \u26A1 ${s} bot(s) paired. Run: openclaw gateway restart`))}return s}catch{return 0}}var qn,K,Co,Vn,Io,tt,Wn,de,Kn,rt=H(()=>{"use strict";qn=require("commander"),K=u(require("chalk")),Co=u(require("ora")),Vn=u(require("os")),Io=u(require("path")),tt=u(require("fs"));M();he();oe();xe();Ze();De();Wn=Io.default.join(Vn.default.homedir(),".openclaw","openclaw.json");de=null;Kn=new qn.Command("autopair").description("Check for pending bot pairs and connect them to OpenClaw automatically").action(async()=>{if(!b()){console.log(K.default.yellow("Not logged in. Run `badgerclaw login` first."));return}console.log(K.default.dim("Checking for pending bot pairs...")),await nt(!1)===0&&console.log(K.default.dim("No pending pairs found."))})});async function Oo(){try{return await Mt.default.get(wa,{timeout:2e3,validateStatus:()=>!0}),!0}catch{return!1}}async function lt(){try{let t=(await Mt.default.get(`${sr}/health`,{timeout:5e3})).data;return t.pluginVersion&&t.pluginVersion!=="unknown"&&(Do=t.pluginVersion),t}catch{return{status:await Oo()?"running":"stopped",pid:null,lastRestart:null,pluginVersion:Do,bots:[]}}}function Lo(e){e&&e!=="unknown"&&(Do=e)}async function Be(){try{return{success:!0,message:(await Mt.default.post(`${sr}/restart`,{},{timeout:15e3})).data?.message||"Gateway restart initiated"}}catch(e){try{let{execSync:t}=await import("child_process");return t("openclaw gateway restart",{stdio:"pipe",timeout:15e3}),{success:!0,message:"Gateway restarted via CLI fallback"}}catch{return{success:!1,message:e.message||"Failed to restart gateway"}}}}var Mt,ha,sr,ya,wa,Do,ue=H(()=>{"use strict";Mt=u(require("axios")),ha=7331,sr=`http://localhost:${ha}`,ya=parseInt(process.env.OPENCLAW_GATEWAY_PORT||"",10)||18789,wa=`http://127.0.0.1:${ya}`,Do="unknown"});var Vo={};to(Vo,{getActiveSessions:()=>qo,launchClaudeCode:()=>Fo,launchMCPServer:()=>Uo,recordSession:()=>Go,stopSession:()=>Wo});function Mo(){try{if(B.default.existsSync(To))return JSON.parse(B.default.readFileSync(To,"utf-8"))}catch{}return[]}function Bo(e){B.default.mkdirSync($e,{recursive:!0}),B.default.writeFileSync(To,JSON.stringify(e,null,2))}function Ut(e){try{return process.kill(e,0),!0}catch{return!1}}function ka(){if(process.env.TMUX)return"tmux";try{if((0,re.execSync)(`osascript -e 'tell application "System Events" to (name of processes) contains "iTerm2"'`,{stdio:"pipe",timeout:3e3}),B.default.existsSync("/Applications/iTerm.app"))return"iterm2"}catch{}return process.platform==="darwin"?"terminal":"direct"}function jo(e,t){let o=W.default.join($e,`claude-launcher-${t}.exp`),n=W.default.join($e,`pending-input-${t}.txt`);B.default.writeFileSync(n,"","utf-8");let r=`#!/usr/bin/expect -f
16
+ MATRIX_RECOVERY_KEY=${c}
17
+ `),r.envUpdated=!0)),r}async function Mr(e={}){let t=Qn(),n=[];for(let[o,r]of Object.entries(t.hermes_bots)){let s=Y.default.join(r.data_dir,".env"),a=!1;try{I.default.existsSync(s)&&(a=I.default.readFileSync(s,"utf-8").includes("MATRIX_RECOVERY_KEY="))}catch{}if(a){n.push({bot_id:o,attempted:!1,recoveryKeyFound:!0,posted:!1,envUpdated:!1});continue}if(o.startsWith("@")){n.push({bot_id:o,attempted:!1,recoveryKeyFound:!1,posted:!1,envUpdated:!1});continue}try{let i=await eo({botId:o,backendBotId:o},r.container_name,r.image,{docker:e.docker,api:e.api,envPath:s});n.push({bot_id:o,attempted:!0,recoveryKeyFound:i.recoveryKey!==null,posted:i.posted,envUpdated:i.envUpdated})}catch(i){console.warn(`[hermes] recovery-key retry failed for ${o}: ${i.message}`),n.push({bot_id:o,attempted:!0,recoveryKeyFound:!1,posted:!1,envUpdated:!1})}}return n}var xr,$r,I,Ir,Ar,Y,le,yi,Jn,bi,Qt,tn,Zt,en,Ei,Ve=q(()=>{"use strict";xr=require("child_process"),$r=require("crypto"),I=m(require("fs")),Ir=m(require("net")),Ar=m(require("os")),Y=m(require("path"));Oe();le=Y.default.join(Ar.default.homedir(),".badgerclaw"),yi=Y.default.join(le,"hermes"),Jn=Y.default.join(le,"state.json"),bi=8642,Qt="http://127.0.0.1:11434/v1",tn={run:e=>{let t=(0,xr.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};Zt=Y.default.join(le,"local-llm.json"),en=Y.default.join(le,"cloud-llm.json");Ei=/SAVE THIS RECOVERY KEY[\s\S]*?key rotation:\s+((?:[A-Za-z0-9]{4}\s+){7,}[A-Za-z0-9]{4})/});function on(e){return`'${e.replace(/'/g,"'\\''")}'`}function Li(){if(ve!==null)return ve;let e=["/opt/homebrew/lib/node_modules/openclaw/openclaw.mjs","/usr/local/lib/node_modules/openclaw/openclaw.mjs","/usr/lib/node_modules/openclaw/openclaw.mjs"];for(let t of e)if(wt.default.existsSync(t))return ve=`${on(process.execPath)} ${on(t)}`,ve;try{let{execSync:t}=require("child_process"),n=t("npm root -g",{encoding:"utf-8",timeout:5e3,stdio:["ignore","pipe","ignore"]}).toString().trim();if(n){let o=oo.default.join(n,"openclaw","openclaw.mjs");if(wt.default.existsSync(o))return ve=`${on(process.execPath)} ${on(o)}`,ve}}catch{}return ve="openclaw",ve}function to(e,t,n){t?t.fail(X.default.red(n)):e&&console.error(`[autopair] ${n}`)}async function Ti(e){if(!e.owner_matrix_user_id)throw new Error("Hermes redeem response missing owner_matrix_user_id. Update the API or fall back to OpenClaw runtime for this bot.");let t=e.user_id.replace(/[^a-zA-Z0-9_.-]/g,"_"),n={botId:e.bot_id??t,backendBotId:e.bot_id??void 0,matrixHomeserver:e.homeserver,matrixAccessToken:e.access_token,matrixUserId:e.user_id,matrixDeviceId:e.device_id,ownerMatrixUserId:e.owner_matrix_user_id,botName:e.bot_name,llm:Or()},o=Lr(n);if(n.backendBotId){let r=R();if(r){let s=ft(r.access_token);try{await eo(n,zn(n.botId),o.image,{api:{post:async(a,i)=>{let c=await s.post(a,i);return{status:c.status,data:c.data}}}})}catch(a){console.warn(`[hermes] recovery key capture failed for ${n.botId}: ${a.message}. Daemon will retry next beat.`)}}}}async function _t(e,t,n,o){let r=R();if(!r)return;let s=o?null:(0,no.default)(`Pairing bot: ${t}...`).start();try{let a=await fetch(`${N}/api/v1/pairing/redeem`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e,instance_id:ae()})});if(!a.ok){if(a.status===410){s?.info(X.default.dim(`${t} already paired (race-loss; another channel redeemed first).`));return}let u=await a.json().catch(()=>({errors:[a.statusText]}));to(o,s,`Failed to redeem ${t}: ${u.errors?.[0]||a.status}`);return}let i=await a.json(),c=i.result??i;if((c.runtime??"openclaw")==="hermes"){try{await Ti(c),s?.succeed(X.default.green(`\u2705 ${c.bot_name} (${c.user_id}) running on Hermes \u2014 bot is live!`))}catch(u){to(o,s,`Failed to start Hermes container for ${t}: ${u.message}`)}return}await yr(async()=>{let u=c.user_id.split(":")[0].replace("@","").replace(/_bot$/,""),p;try{p=JSON.parse(wt.default.readFileSync(Dr,"utf-8"))}catch{p={}}p.channels||(p.channels={}),p.channels.badgerclaw||(p.channels.badgerclaw={}),p.channels.badgerclaw.accounts||(p.channels.badgerclaw.accounts={});let S={userId:c.user_id,accessToken:c.access_token,homeserver:c.homeserver,encryption:!0,groupPolicy:"open",allowlistOnly:!1,dm:{policy:"open"}};c.device_id&&(S.deviceId=c.device_id),p.channels.badgerclaw.accounts[u]=S,wt.default.writeFileSync(Dr,JSON.stringify(p,null,2),{mode:384})}),await fetch(`${N}/api/v1/openclaw/pending-pairs/${e}/claim`,{method:"POST",headers:{Authorization:`Bearer ${r.access_token}`}}).catch(()=>{}),s?.succeed(X.default.green(`\u2705 ${c.bot_name} (${c.user_id}) paired \u2014 bot is live!`))}catch(a){to(o,s,`Failed to pair ${t}: ${a.message}`)}}async function St(e=!1){let t=R();if(!t)return 0;let n=ft(t.access_token);try{let{data:o}=await n.get("/api/v1/openclaw/pending-pairs");if(!o||o.length===0)return 0;let r=new Map;for(let a of o)r.set(a.bot_user_id,a);for(let a of o)r.get(a.bot_user_id)!==a&&await n.post(`/api/v1/openclaw/pending-pairs/${a.pair_code}/claim`).catch(()=>{});let s=0;for(let a of r.values()){let i=e?null:(0,no.default)(`Pairing bot: ${a.bot_name} (${a.bot_user_id})`).start();try{await _t(a.pair_code,a.bot_name,a.bot_user_id,e),await n.post(`/api/v1/openclaw/pending-pairs/${a.pair_code}/claim`).catch(()=>{}),s++}catch(c){i?.fail(X.default.red(`Error pairing ${a.bot_name}: ${c}`))}}if(s>0)try{let{execSync:a}=await import("child_process");a(`${Li()} gateway restart`,{stdio:"ignore"}),e||console.log(X.default.green(`
18
+ \u26A1 ${s} bot(s) paired \u2014 gateway restarted, bots are live!`))}catch(a){e?console.error(`[autopair] gateway restart after pair failed: ${a?.message||a}`):console.log(X.default.yellow(`
19
+ \u26A1 ${s} bot(s) paired. Run: openclaw gateway restart`))}return s}catch{return 0}}var Nr,X,no,jr,oo,wt,Dr,ve,Br,vt=q(()=>{"use strict";Nr=require("commander"),X=m(require("chalk")),no=m(require("ora")),jr=m(require("os")),oo=m(require("path")),wt=m(require("fs"));F();Ae();ie();Ie();ht();Ve();Dr=oo.default.join(jr.default.homedir(),".openclaw","openclaw.json");ve=null;Br=new Nr.Command("autopair").description("Check for pending bot pairs and connect them to OpenClaw automatically").action(async()=>{if(!R()){console.log(X.default.yellow("Not logged in. Run `badgerclaw login` first."));return}console.log(X.default.dim("Checking for pending bot pairs...")),await St(!1)===0&&console.log(X.default.dim("No pending pairs found."))})});async function uo(){try{return await ln.default.get(Zi,{timeout:2e3,validateStatus:()=>!0}),!0}catch{return!1}}async function xt(){try{let t=(await ln.default.get(`${Qr}/health`,{timeout:5e3})).data;return t.pluginVersion&&t.pluginVersion!=="unknown"&&(co=t.pluginVersion),t}catch{return{status:await uo()?"running":"stopped",pid:null,lastRestart:null,pluginVersion:co,bots:[]}}}function mo(e){e&&e!=="unknown"&&(co=e)}async function Qe(){try{return{success:!0,message:(await ln.default.post(`${Qr}/restart`,{},{timeout:15e3})).data?.message||"Gateway restart initiated"}}catch(e){try{let{execSync:t}=await import("child_process");return t("openclaw gateway restart",{stdio:"pipe",timeout:15e3}),{success:!0,message:"Gateway restarted via CLI fallback"}}catch{return{success:!1,message:e.message||"Failed to restart gateway"}}}}var ln,Qi,Qr,Xi,Zi,co,ke=q(()=>{"use strict";ln=m(require("axios")),Qi=7331,Qr=`http://localhost:${Qi}`,Xi=parseInt(process.env.OPENCLAW_GATEWAY_PORT||"",10)||18789,Zi=`http://127.0.0.1:${Xi}`,co="unknown"});var Ro={};Dn(Ro,{getActiveSessions:()=>ko,launchClaudeCode:()=>_o,launchMCPServer:()=>wo,recordSession:()=>So,stopSession:()=>vo});function fo(){try{if(H.default.existsSync(go))return JSON.parse(H.default.readFileSync(go,"utf-8"))}catch{}return[]}function ho(e){H.default.mkdirSync(Me,{recursive:!0}),H.default.writeFileSync(go,JSON.stringify(e,null,2))}function mn(e){try{return process.kill(e,0),!0}catch{return!1}}function ol(){if(process.env.TMUX)return"tmux";try{if((0,me.execSync)(`osascript -e 'tell application "System Events" to (name of processes) contains "iTerm2"'`,{stdio:"pipe",timeout:3e3}),H.default.existsSync("/Applications/iTerm.app"))return"iterm2"}catch{}return process.platform==="darwin"?"terminal":"direct"}function yo(e,t){let n=J.default.join(Me,`claude-launcher-${t}.exp`),o=J.default.join(Me,`pending-input-${t}.txt`);H.default.writeFileSync(o,"","utf-8");let r=`#!/usr/bin/expect -f
19
20
  set timeout -1
20
- set msgfile "${n}"
21
+ set msgfile "${o}"
21
22
 
22
23
  proc check_and_send_messages {} {
23
24
  global msgfile
@@ -52,21 +53,21 @@ send "\\r"
52
53
  interact timeout 2 {
53
54
  check_and_send_messages
54
55
  }
55
- `;return B.default.mkdirSync($e,{recursive:!0}),B.default.writeFileSync(o,r,{mode:493}),o}function Ho(e){return Object.entries(e).map(([t,o])=>`export ${t}="${o}"`).join("; ")}function va(e,t,o){let n=jo(e,o.BADGERCLAW_SESSION_ID||"default"),r=Ho(o),s=`
56
+ `;return H.default.mkdirSync(Me,{recursive:!0}),H.default.writeFileSync(n,r,{mode:493}),n}function bo(e){return Object.entries(e).map(([t,n])=>`export ${t}="${n}"`).join("; ")}function rl(e,t,n){let o=yo(e,n.BADGERCLAW_SESSION_ID||"default"),r=bo(n),s=`
56
57
  tell application "iTerm"
57
58
  activate
58
59
  set newWindow to (create window with default profile)
59
60
  tell current session of newWindow
60
- write text "cd ${Ft(t)} && ${r} && ${Ft(n)}"
61
+ write text "cd ${pn(t)} && ${r} && ${pn(o)}"
61
62
  end tell
62
63
  end tell
63
- `;(0,re.execSync)(`osascript -e '${s.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function $a(e,t,o){let n=jo(e,o.BADGERCLAW_SESSION_ID||"default"),r=Ho(o),a=`
64
+ `;(0,me.execSync)(`osascript -e '${s.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function sl(e,t,n){let o=yo(e,n.BADGERCLAW_SESSION_ID||"default"),r=bo(n),a=`
64
65
  tell application "Terminal"
65
66
  activate
66
- do script "${`cd ${Ft(t)} && ${r} && ${Ft(n)}`.replace(/"/g,'\\"')}"
67
+ do script "${`cd ${pn(t)} && ${r} && ${pn(o)}`.replace(/"/g,'\\"')}"
67
68
  end tell
68
- `;(0,re.execSync)(`osascript -e '${a.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function Ca(e,t,o){let n=jo(e,o.BADGERCLAW_SESSION_ID||"default"),r=Ho(o),s=`badgerclaw-${o.BADGERCLAW_SESSION_ID||"default"}`,a=`cd ${t} && ${r} && ${n}`;(0,re.execSync)(`tmux new-session -d -s ${s} "${a}"`,{stdio:"pipe",timeout:1e4})}function Ft(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Uo(e){let t=W.default.join(__dirname,"..","claude-code","mcp-server.js"),o=B.default.existsSync(t)?t:W.default.join(__dirname,"mcp-server.js"),n=(0,re.spawn)("node",[o],{env:{...process.env,BADGERCLAW_MCP_PORT:String(e.port),BADGERCLAW_SESSION_ID:e.sessionId},cwd:e.projectDir,stdio:"ignore",detached:!0});return n.unref(),n}function Fo(e){let t=W.default.join(W.default.dirname(process.argv[1]||""),"..","lib","node_modules","badgerclaw","dist","claude-code","mcp-server.js"),o=W.default.join(__dirname,"..","claude-code","mcp-server.js"),n=W.default.join(__dirname,"mcp-server.js"),r=B.default.existsSync(t)?t:B.default.existsSync(o)?o:n,s={BADGERCLAW_MCP_PORT:String(e.port),BADGERCLAW_SESSION_ID:e.sessionId},a=JSON.stringify({mcpServers:{badgerclaw:{command:"node",args:[r],env:s}}}),c=W.default.join($e,`mcp-config-${e.sessionId}.json`);B.default.mkdirSync($e,{recursive:!0}),B.default.writeFileSync(c,a,"utf-8");let l=`claude --dangerously-skip-permissions --mcp-config ${c}`;switch(ka()){case"iterm2":va(l,e.projectDir,s);break;case"terminal":$a(l,e.projectDir,s);break;case"tmux":Ca(l,e.projectDir,s);break;case"direct":(0,re.spawn)(l,[],{shell:!0,cwd:e.projectDir,env:{...process.env,...s},stdio:"ignore",detached:!0}).unref();break}}function Go(e,t,o,n,r){let s=Mo().filter(a=>a.sessionId!==e);s.push({sessionId:e,pid:t,mcpPid:o,port:n,projectDir:r,startedAt:new Date().toISOString()}),Bo(s)}function Wo(e){let t=Mo(),o=t.find(r=>r.sessionId===e);if(!o)return!1;if(o.mcpPid&&Ut(o.mcpPid))try{process.kill(o.mcpPid,"SIGTERM")}catch{}if(o.pid&&Ut(o.pid))try{process.kill(o.pid,"SIGTERM")}catch{}try{(0,re.execSync)(`tmux kill-session -t badgerclaw-${e} 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let n=t.filter(r=>r.sessionId!==e);return Bo(n),!0}function qo(){let e=Mo(),t=e.filter(o=>Ut(o.mcpPid)||Ut(o.pid));return t.length!==e.length&&Bo(t),t}var re,B,W,lr,$e,To,Gt=H(()=>{"use strict";re=require("child_process"),B=u(require("fs")),W=u(require("path")),lr=u(require("os")),$e=W.default.join(lr.default.homedir(),".badgerclaw"),To=W.default.join($e,"claude-sessions.json")});async function se(e){return e.command_type==="update_cli"?Ra(e.payload?.target_version):e.command_type==="update_plugin"?xa(e.payload?.target_version):e.command_type==="restart_gateway"?Ia():e.command_type==="leave_room"?Ga(e.payload):e.command_type==="start_claude_code"?La(e.payload):e.command_type==="stop_claude_code"?Na(e.payload):e.command_type==="start_claude_control"?Ta(e.payload):e.command_type==="stop_claude_control"?Ma(e.payload):e.command_type==="update_claude_tools"?Ba(e.payload):e.command_type==="bot_share_notify"?ja(e.payload):e.command_type==="bot_share_revoked"?Ha(e.payload):e.command_type==="bot_share_expired"?Ua(e.payload):e.command_type==="bot_refresh"?Fa(e.payload):{success:!1,message:`Unknown command: ${e.command_type}`}}function Ia(){try{return(0,A.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:15e3}),{success:!0,message:"Gateway restarted"}}catch{try{return{success:!0,message:`Gateway restarted via probe: ${(0,A.execSync)("curl -s -X POST http://localhost:7331/restart",{stdio:"pipe",timeout:1e4}).toString()}`}}catch(e){return{success:!1,message:`Gateway restart failed: ${e.message||"unknown error"}`}}}}function Ra(e){let t=e?`badgerclaw@${e}`:"badgerclaw@latest";try{(0,A.execSync)(`npm install -g ${t}`,{stdio:"pipe",timeout:12e4});let o=(0,A.execSync)("npm list -g badgerclaw --json",{stdio:"pipe"}).toString(),r=JSON.parse(o)?.dependencies?.badgerclaw?.version||"unknown";return Ea(),{success:!0,message:`Updated CLI to ${r}`,newVersion:r}}catch(o){let n=o.stderr?.toString()||o.message||"Unknown error";return n.includes("EACCES")||n.includes("permission")?{success:!1,message:"Permission denied. Run: sudo npm install -g badgerclaw"}:{success:!1,message:`CLI update failed: ${n.slice(0,500)}`}}}async function xa(e){let t=$.default.join(Ce.default.homedir(),".openclaw","extensions","badgerclaw"),o=$.default.join(Ce.default.homedir(),".openclaw","npm","node_modules","@badgerclaw","connect"),n=h.default.existsSync(o)?"npm":h.default.existsSync(t)?"legacy":null;if(n===null)return{success:!1,message:"Cannot find plugin install (checked ~/.openclaw/npm/node_modules/@badgerclaw/connect and ~/.openclaw/extensions/badgerclaw). Re-run: badgerclaw setup"};let r=e?`@badgerclaw/connect@${e}`:"@badgerclaw/connect@latest";try{if(n==="npm"){let m=$.default.dirname($.default.dirname($.default.dirname(o)));(0,A.execSync)(`npm install ${r}`,{cwd:m,stdio:"pipe",timeout:12e4});let p=$.default.join(o,"package.json"),P="unknown";h.default.existsSync(p)&&(P=JSON.parse(h.default.readFileSync(p,"utf-8")).version||"unknown"),Lo(P);try{(0,A.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await cr(P)}let s=t;(0,A.execSync)(`npm install ${r}`,{cwd:s,stdio:"pipe",timeout:12e4});let a=$.default.join(s,"node_modules","@badgerclaw","connect"),c=$.default.join(a,"package.json"),l="unknown";h.default.existsSync(c)&&(l=JSON.parse(h.default.readFileSync(c,"utf-8")).version||"unknown"),Lo(l),Aa(a,s);let i=$.default.join(s,"package.json");if(h.default.existsSync(i)&&h.default.existsSync(c))try{let m=JSON.parse(h.default.readFileSync(i,"utf-8")),p=JSON.parse(h.default.readFileSync(c,"utf-8"));m.version=l,p.openclaw&&(m.openclaw={...m.openclaw,...p.openclaw}),h.default.writeFileSync(i,JSON.stringify(m,null,2)+`
69
- `)}catch{}try{(0,A.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await cr(l)}catch(s){return{success:!1,message:`Plugin update failed: ${(s.stderr?.toString()||s.message||"").slice(0,500)}`}}}async function cr(e){for(let t=0;t<15;t++){await new Promise(o=>setTimeout(o,1e3));try{let o=await j.default.get("http://localhost:7331/health",{timeout:3e3});if(o.data?.status==="running"&&o.data?.pluginVersion===e)break}catch{}}return{success:!0,message:`Updated plugin to ${e}, gateway restarted`,newVersion:e}}function Aa(e,t){let o=$.default.join(e,"dist"),n=$.default.join(t,"dist");h.default.existsSync(o)&&(h.default.mkdirSync(n,{recursive:!0}),Ko(o,n));let r=$.default.join(e,"openclaw.plugin.json");h.default.existsSync(r)&&h.default.copyFileSync(r,$.default.join(t,"openclaw.plugin.json"));let s=$.default.join(e,"scripts"),a=$.default.join(t,"scripts");h.default.existsSync(s)&&(h.default.mkdirSync(a,{recursive:!0}),Ko(s,a));for(let c of["index.ts","src","STREAMING.md","SETUP.md","CHANGELOG.md"]){let l=$.default.join(t,c);h.default.existsSync(l)&&(h.default.statSync(l).isDirectory()?h.default.rmSync(l,{recursive:!0,force:!0}):h.default.unlinkSync(l))}}function Ko(e,t){for(let o of h.default.readdirSync(e,{withFileTypes:!0})){let n=$.default.join(e,o.name),r=$.default.join(t,o.name);o.isDirectory()?(h.default.mkdirSync(r,{recursive:!0}),Ko(n,r)):h.default.copyFileSync(n,r)}}function Ea(){try{if(Pa())return;try{(0,A.execSync)('pkill -f "badgerclaw heartbeat"',{stdio:"pipe",timeout:5e3})}catch{}try{(0,A.execSync)('pkill -f "badgerclaw watch"',{stdio:"pipe",timeout:5e3})}catch{}(0,A.execSync)("sleep 1",{stdio:"pipe"});let e=(0,A.execSync)("command -v badgerclaw",{stdio:"pipe",shell:"/bin/sh"}).toString().trim()||"badgerclaw";(0,A.execSync)(`nohup ${e} heartbeat > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"}),(0,A.execSync)(`nohup ${e} watch > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"})}catch{}}function Pa(){let e="";try{e=(0,A.execSync)("supervisorctl status badgerclaw-heartbeat 2>&1",{stdio:"pipe",shell:"/bin/sh",timeout:8e3}).toString()}catch(t){e=(t?.stdout?.toString()||"")+(t?.stderr?.toString()||"")}if(!e.includes("badgerclaw-heartbeat")||/no such process|ERROR/i.test(e))return!1;try{return(0,A.execSync)("nohup supervisorctl restart badgerclaw-heartbeat >/dev/null 2>&1 &",{stdio:"pipe",shell:"/bin/sh",timeout:8e3}),!0}catch{return!1}}function Da(){let e=$.default.join(Ce.default.homedir(),".badgerclaw","workspace");h.default.mkdirSync(e,{recursive:!0});let t=$.default.join(e,".git");return h.default.existsSync(t)||(0,A.execSync)("git init",{cwd:e,stdio:"pipe",timeout:5e3}),h.default.writeFileSync($.default.join(e,"CLAUDE.md"),`You are a chat assistant connected to Matrix rooms via BadgerClaw.
69
+ `;(0,me.execSync)(`osascript -e '${a.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function al(e,t,n){let o=yo(e,n.BADGERCLAW_SESSION_ID||"default"),r=bo(n),s=`badgerclaw-${n.BADGERCLAW_SESSION_ID||"default"}`,a=`cd ${t} && ${r} && ${o}`;(0,me.execSync)(`tmux new-session -d -s ${s} "${a}"`,{stdio:"pipe",timeout:1e4})}function pn(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function wo(e){let t=J.default.join(__dirname,"..","claude-code","mcp-server.js"),n=H.default.existsSync(t)?t:J.default.join(__dirname,"mcp-server.js"),o=(0,me.spawn)("node",[n],{env:{...process.env,BADGERCLAW_MCP_PORT:String(e.port),BADGERCLAW_SESSION_ID:e.sessionId},cwd:e.projectDir,stdio:"ignore",detached:!0});return o.unref(),o}function _o(e){let t=J.default.join(J.default.dirname(process.argv[1]||""),"..","lib","node_modules","badgerclaw","dist","claude-code","mcp-server.js"),n=J.default.join(__dirname,"..","claude-code","mcp-server.js"),o=J.default.join(__dirname,"mcp-server.js"),r=H.default.existsSync(t)?t:H.default.existsSync(n)?n:o,s={BADGERCLAW_MCP_PORT:String(e.port),BADGERCLAW_SESSION_ID:e.sessionId},a=JSON.stringify({mcpServers:{badgerclaw:{command:"node",args:[r],env:s}}}),i=J.default.join(Me,`mcp-config-${e.sessionId}.json`);H.default.mkdirSync(Me,{recursive:!0}),H.default.writeFileSync(i,a,"utf-8");let c=`claude --dangerously-skip-permissions --mcp-config ${i}`;switch(ol()){case"iterm2":rl(c,e.projectDir,s);break;case"terminal":sl(c,e.projectDir,s);break;case"tmux":al(c,e.projectDir,s);break;case"direct":(0,me.spawn)(c,[],{shell:!0,cwd:e.projectDir,env:{...process.env,...s},stdio:"ignore",detached:!0}).unref();break}}function So(e,t,n,o,r){let s=fo().filter(a=>a.sessionId!==e);s.push({sessionId:e,pid:t,mcpPid:n,port:o,projectDir:r,startedAt:new Date().toISOString()}),ho(s)}function vo(e){let t=fo(),n=t.find(r=>r.sessionId===e);if(!n)return!1;if(n.mcpPid&&mn(n.mcpPid))try{process.kill(n.mcpPid,"SIGTERM")}catch{}if(n.pid&&mn(n.pid))try{process.kill(n.pid,"SIGTERM")}catch{}try{(0,me.execSync)(`tmux kill-session -t badgerclaw-${e} 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let o=t.filter(r=>r.sessionId!==e);return ho(o),!0}function ko(){let e=fo(),t=e.filter(n=>mn(n.mcpPid)||mn(n.pid));return t.length!==e.length&&ho(t),t}var me,H,J,es,Me,go,gn=q(()=>{"use strict";me=require("child_process"),H=m(require("fs")),J=m(require("path")),es=m(require("os")),Me=J.default.join(es.default.homedir(),".badgerclaw"),go=J.default.join(Me,"claude-sessions.json")});async function pe(e){return e.command_type==="update_cli"?ll(e.payload?.target_version):e.command_type==="update_plugin"?cl(e.payload?.target_version):e.command_type==="restart_gateway"?il():e.command_type==="leave_room"?Rl(e.payload):e.command_type==="start_claude_code"?fl(e.payload):e.command_type==="stop_claude_code"?hl(e.payload):e.command_type==="start_claude_control"?yl(e.payload):e.command_type==="stop_claude_control"?bl(e.payload):e.command_type==="update_claude_tools"?wl(e.payload):e.command_type==="bot_share_notify"?_l(e.payload):e.command_type==="bot_share_revoked"?Sl(e.payload):e.command_type==="bot_share_expired"?vl(e.payload):e.command_type==="bot_refresh"?kl(e.payload):{success:!1,message:`Unknown command: ${e.command_type}`}}function il(){try{return(0,T.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:15e3}),{success:!0,message:"Gateway restarted"}}catch{try{return{success:!0,message:`Gateway restarted via probe: ${(0,T.execSync)("curl -s -X POST http://localhost:7331/restart",{stdio:"pipe",timeout:1e4}).toString()}`}}catch(e){return{success:!1,message:`Gateway restart failed: ${e.message||"unknown error"}`}}}}function ll(e){let t=e?`badgerclaw@${e}`:"badgerclaw@latest";try{(0,T.execSync)(`npm install -g ${t}`,{stdio:"pipe",timeout:12e4});let n=(0,T.execSync)("npm list -g badgerclaw --json",{stdio:"pipe"}).toString(),r=JSON.parse(n)?.dependencies?.badgerclaw?.version||"unknown";return dl(),{success:!0,message:`Updated CLI to ${r}`,newVersion:r}}catch(n){let o=n.stderr?.toString()||n.message||"Unknown error";return o.includes("EACCES")||o.includes("permission")?{success:!1,message:"Permission denied. Run: sudo npm install -g badgerclaw"}:{success:!1,message:`CLI update failed: ${o.slice(0,500)}`}}}async function cl(e){let t=A.default.join(De.default.homedir(),".openclaw","extensions","badgerclaw"),n=A.default.join(De.default.homedir(),".openclaw","npm","node_modules","@badgerclaw","connect"),o=w.default.existsSync(n)?"npm":w.default.existsSync(t)?"legacy":null;if(o===null)return{success:!1,message:"Cannot find plugin install (checked ~/.openclaw/npm/node_modules/@badgerclaw/connect and ~/.openclaw/extensions/badgerclaw). Re-run: badgerclaw setup"};let r=e?`@badgerclaw/connect@${e}`:"@badgerclaw/connect@latest";try{if(o==="npm"){let u=A.default.dirname(A.default.dirname(A.default.dirname(n)));(0,T.execSync)(`npm install ${r}`,{cwd:u,stdio:"pipe",timeout:12e4});let p=A.default.join(n,"package.json"),S="unknown";w.default.existsSync(p)&&(S=JSON.parse(w.default.readFileSync(p,"utf-8")).version||"unknown"),mo(S);try{(0,T.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await ts(S)}let s=t;(0,T.execSync)(`npm install ${r}`,{cwd:s,stdio:"pipe",timeout:12e4});let a=A.default.join(s,"node_modules","@badgerclaw","connect"),i=A.default.join(a,"package.json"),c="unknown";w.default.existsSync(i)&&(c=JSON.parse(w.default.readFileSync(i,"utf-8")).version||"unknown"),mo(c),ul(a,s);let l=A.default.join(s,"package.json");if(w.default.existsSync(l)&&w.default.existsSync(i))try{let u=JSON.parse(w.default.readFileSync(l,"utf-8")),p=JSON.parse(w.default.readFileSync(i,"utf-8"));u.version=c,p.openclaw&&(u.openclaw={...u.openclaw,...p.openclaw}),w.default.writeFileSync(l,JSON.stringify(u,null,2)+`
70
+ `)}catch{}try{(0,T.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await ts(c)}catch(s){return{success:!1,message:`Plugin update failed: ${(s.stderr?.toString()||s.message||"").slice(0,500)}`}}}async function ts(e){for(let t=0;t<15;t++){await new Promise(n=>setTimeout(n,1e3));try{let n=await G.default.get("http://localhost:7331/health",{timeout:3e3});if(n.data?.status==="running"&&n.data?.pluginVersion===e)break}catch{}}return{success:!0,message:`Updated plugin to ${e}, gateway restarted`,newVersion:e}}function ul(e,t){let n=A.default.join(e,"dist"),o=A.default.join(t,"dist");w.default.existsSync(n)&&(w.default.mkdirSync(o,{recursive:!0}),Co(n,o));let r=A.default.join(e,"openclaw.plugin.json");w.default.existsSync(r)&&w.default.copyFileSync(r,A.default.join(t,"openclaw.plugin.json"));let s=A.default.join(e,"scripts"),a=A.default.join(t,"scripts");w.default.existsSync(s)&&(w.default.mkdirSync(a,{recursive:!0}),Co(s,a));for(let i of["index.ts","src","STREAMING.md","SETUP.md","CHANGELOG.md"]){let c=A.default.join(t,i);w.default.existsSync(c)&&(w.default.statSync(c).isDirectory()?w.default.rmSync(c,{recursive:!0,force:!0}):w.default.unlinkSync(c))}}function Co(e,t){for(let n of w.default.readdirSync(e,{withFileTypes:!0})){let o=A.default.join(e,n.name),r=A.default.join(t,n.name);n.isDirectory()?(w.default.mkdirSync(r,{recursive:!0}),Co(o,r)):w.default.copyFileSync(o,r)}}function dl(){try{if(ml())return;try{(0,T.execSync)('pkill -f "badgerclaw heartbeat"',{stdio:"pipe",timeout:5e3})}catch{}try{(0,T.execSync)('pkill -f "badgerclaw watch"',{stdio:"pipe",timeout:5e3})}catch{}(0,T.execSync)("sleep 1",{stdio:"pipe"});let e=(0,T.execSync)("command -v badgerclaw",{stdio:"pipe",shell:"/bin/sh"}).toString().trim()||"badgerclaw";(0,T.execSync)(`nohup ${e} heartbeat > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"}),(0,T.execSync)(`nohup ${e} watch > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"})}catch{}}function ml(){let e="";try{e=(0,T.execSync)("supervisorctl status badgerclaw-heartbeat 2>&1",{stdio:"pipe",shell:"/bin/sh",timeout:8e3}).toString()}catch(t){e=(t?.stdout?.toString()||"")+(t?.stderr?.toString()||"")}if(!e.includes("badgerclaw-heartbeat")||/no such process|ERROR/i.test(e))return!1;try{return(0,T.execSync)("nohup supervisorctl restart badgerclaw-heartbeat >/dev/null 2>&1 &",{stdio:"pipe",shell:"/bin/sh",timeout:8e3}),!0}catch{return!1}}function pl(){let e=A.default.join(De.default.homedir(),".badgerclaw","workspace");w.default.mkdirSync(e,{recursive:!0});let t=A.default.join(e,".git");return w.default.existsSync(t)||(0,T.execSync)("git init",{cwd:e,stdio:"pipe",timeout:5e3}),w.default.writeFileSync(A.default.join(e,"CLAUDE.md"),`You are a chat assistant connected to Matrix rooms via BadgerClaw.
70
71
 
71
72
  When you receive a message, it will be formatted like:
72
73
  [Room: RoomName] Sender: message text
@@ -75,24 +76,24 @@ Reply using the reply tool with botId="..." and roomId="..."
75
76
  ALWAYS use the \`reply\` MCP tool to send your response back to the chat room.
76
77
  Use the exact botId and roomId provided in the message \u2014 do not modify them.
77
78
  Keep responses concise and helpful.
78
- `),e}function Oa(){try{h.default.mkdirSync($.default.dirname(Wt),{recursive:!0});try{let e=h.default.statSync(Wt);if(Date.now()-e.mtimeMs<6e4)return!1;h.default.unlinkSync(Wt)}catch{}return h.default.writeFileSync(Wt,String(process.pid),{flag:"wx"}),!0}catch{return!1}}async function La(e){if(!e?.bot_id)return{success:!1,message:"Missing bot_id in payload"};if(!Oa())return{success:!0,message:"Claude Code start already in progress, skipping duplicate"};try{let t=e.bot_user_id?.startsWith("@")?e.bot_user_id:await ct(e.bot_id),{launchClaudeCode:o,recordSession:n,getActiveSessions:r,stopSession:s}=(Gt(),ln(Vo)),a=new Set;try{let P=(await j.default.get("http://localhost:7331/claude-code/status",{timeout:5e3})).data?.bots||[];for(let O of P)if(O.botId!==t&&O.enabled!==!1){let f=O.port;typeof f=="number"&&f>=7332&&a.add(f)}}catch{}for(let p=7332;p<=7340;p++)try{(0,A.execSync)(`lsof -ti :${p} >/dev/null 2>&1`,{stdio:"pipe",timeout:2e3}),a.add(p)}catch{}let c=7332;for(;a.has(c);)c++;let l=r();for(let p of l)p.port===c&&(console.log(`[command-executor] Stopping existing session ${p.sessionId} on port ${c}`),s(p.sessionId));try{(0,A.execSync)(`lsof -ti :${c} | xargs kill -9 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let i=e.session_id||`session-${Date.now()}`;await j.default.post("http://localhost:7331/claude-code/toggle",{botId:t,enabled:!0,sessionId:i,port:c},{timeout:1e4});let m=Da();return o({sessionId:i,port:c,projectDir:m}),n(i,0,0,c,m),{success:!0,message:`Claude Code started globally for bot ${t} (session: ${i}, port: ${c})`}}catch(t){return{success:!1,message:`Failed to start Claude Code: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function ct(e){if(e.startsWith("@"))return e;try{let o=(await j.default.get("http://localhost:7331/health",{timeout:1e4})).data?.bots||[],n=$.default.join(Ce.default.homedir(),".badgerclaw","bot-mapping.json");if(h.default.existsSync(n)){let r=JSON.parse(h.default.readFileSync(n,"utf-8"));if(r[e])return r[e]}return o.length===1?o[0].botId:(console.warn(`[command-executor] Could not resolve bot UUID ${e} to Matrix ID, trying as-is`),e)}catch{return e}}async function Na(e){if(!e?.bot_id)return{success:!1,message:"Missing bot_id in payload"};try{let t=e.bot_user_id?.startsWith("@")?e.bot_user_id:await ct(e.bot_id),o=e.session_id;if(!o)try{let n=await j.default.get("http://localhost:7331/claude-code/status",{timeout:5e3}),s=(n.data?.bots||n.data?.rooms||[]).find(a=>a.botId===t);s&&(o=s.sessionId)}catch{}if(await j.default.post("http://localhost:7331/claude-code/toggle",{botId:t,enabled:!1},{timeout:1e4}),o){let{stopSession:n}=(Gt(),ln(Vo));n(o)}return{success:!0,message:"Claude Code stopped"}}catch(t){return{success:!1,message:`Failed to stop Claude Code: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function Ta(e){try{let t=e?.bot_user_id||e?.bot_id;if(!t)return{success:!1,message:"Missing bot_id in payload"};let o=t;o.startsWith("@")||(o=await ct(t));let n=e?.session_id||`cc-${Date.now()}`;return await j.default.post("http://localhost:7331/claude-code/toggle",{botId:o,enabled:!0,sessionId:n,mode:"primary",tools:e?.tools},{timeout:1e4}),console.log(`[claude-control] Primary mode enabled for ${o} (session: ${n})`),{success:!0,message:`Claude Control (primary) started for ${o}`}}catch(t){return{success:!1,message:`Failed to start Claude Control: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function Ma(e){try{let t=e?.bot_user_id||e?.bot_id;if(!t)return{success:!1,message:"Missing bot_id in payload"};let o=t;return o.startsWith("@")||(o=await ct(t)),await j.default.post("http://localhost:7331/claude-code/toggle",{botId:o,enabled:!1},{timeout:1e4}),console.log(`[claude-control] Primary mode disabled for ${o}`),{success:!0,message:`Claude Control stopped for ${o}`}}catch(t){return{success:!1,message:`Failed to stop Claude Control: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function Ba(e){try{let t=e?.bot_user_id||e?.bot_id;if(!t||!e?.tools)return{success:!1,message:"Missing bot_id or tools in payload"};let o=t;return o.startsWith("@")||(o=await ct(t)),await j.default.post("http://localhost:7331/claude-code/tools",{botId:o,tools:e.tools},{timeout:1e4}),{success:!0,message:`Tools updated for ${o}`}}catch(t){return{success:!1,message:`Failed to update tools: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function ja(e){if(!e?.bot_user_id||!e?.shared_with_user_id)return{success:!1,message:"Missing bot_user_id or shared_with_user_id"};try{return await j.default.post("http://localhost:7331/bot-share/notify",{botId:e.bot_user_id,sharedWithUserId:e.shared_with_user_id,ownerDisplayName:e.owner_display_name||void 0,botDisplayName:e.bot_name||void 0,expiresAt:e.expires_at||void 0},{timeout:1e4}),console.log(`[bot-share] Notify: ${e.shared_with_user_id} can now access ${e.bot_user_id}`),{success:!0,message:`Share notification sent for ${e.shared_with_user_id}`}}catch(t){return{success:!1,message:`Failed to notify share: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function Ha(e){if(!e?.bot_user_id||!e?.shared_with_user_id)return{success:!1,message:"Missing bot_user_id or shared_with_user_id"};try{return await j.default.post("http://localhost:7331/bot-share/revoked",{botId:e.bot_user_id,sharedWithUserId:e.shared_with_user_id,botDisplayName:e.bot_name||void 0},{timeout:1e4}),console.log(`[bot-share] Revoked: ${e.shared_with_user_id} lost access to ${e.bot_user_id}`),{success:!0,message:`Share revocation sent for ${e.shared_with_user_id}`}}catch(t){return{success:!1,message:`Failed to revoke share: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function Ua(e){if(!e?.bot_user_id||!e?.shared_with_user_id)return{success:!1,message:"Missing bot_user_id or shared_with_user_id"};try{return await j.default.post("http://localhost:7331/bot-share/expired",{botId:e.bot_user_id,sharedWithUserId:e.shared_with_user_id,botDisplayName:e.bot_name||void 0},{timeout:1e4}),console.log(`[bot-share] Expired: ${e.shared_with_user_id} access to ${e.bot_user_id}`),{success:!0,message:`Share expiry sent for ${e.shared_with_user_id}`}}catch(t){return{success:!1,message:`Failed to expire share: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function Fa(e){let t=e?.bot_user_id||e?.bot_id;if(!t)return{success:!1,message:"Missing bot_id in bot_refresh payload"};let o=t;t.startsWith("@")&&(o=t.split(":")[0].replace("@","").replace(/_bot$/,""));let n=$.default.join(Ce.default.homedir(),".openclaw","badgerclaw","quarantine",`${o}.json`);try{h.default.rmSync(n,{force:!0})}catch{}try{return(0,A.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:15e3}),{success:!0,message:`Bot ${o} quarantine cleared, gateway restarted`}}catch{return{success:!1,message:`Quarantine cleared for ${o} but gateway restart failed`}}}async function Ga(e){if(!e?.bot_id||!e?.room_id)return{success:!1,message:"Missing bot_id or room_id in payload"};try{return{success:!0,message:(await j.default.post("http://localhost:7331/leave-room",{botId:e.bot_id,roomId:e.room_id},{timeout:15e3})).data?.message||"Left room"}}catch(t){return{success:!1,message:`Failed to leave room: ${t.response?.data?.message||t.message||"Unknown error"}`}}}var A,h,$,Ce,j,Wt,Yo=H(()=>{"use strict";A=require("child_process"),h=u(require("fs")),$=u(require("path")),Ce=u(require("os")),j=u(require("axios"));ue();Wt=$.default.join(Ce.default.homedir(),".badgerclaw","claude-code.lock")});var zo={};to(zo,{heartbeatCommand:()=>Jo,pushHeartbeat:()=>T});function Vt(e,t){if(e!=="start_claude_code"&&e!=="stop_claude_code")return!1;let o=`${e}:${t||"unknown"}`,n=Date.now();for(let[r,s]of qt)n-s>Ya&&qt.delete(r);return qt.has(o)?!0:(qt.set(o,n),!1)}function hr(e,t){let o=St(),n=e.bots.map(a=>({bot_id:a.botId,bot_username:a.botUsername,status:a.status,activity_state:a.activityState||"idle",active_task:a.activeTask||null,last_activity_at:a.lastActivity,messages_received:a.messagesReceived,messages_sent:a.messagesSent,chunked_messages:a.chunkedMessages,total_chunks_sent:a.totalChunksSent,errors:a.errors,last_error:a.lastError,last_error_at:a.lastErrorAt,uptime_seconds:a.uptimeSeconds,rooms_active:a.roomsActive,room_details:(a.roomDetails||[]).map(c=>({roomId:c.roomId,roomName:c.roomName,workspaceName:c.workspaceName||null,messagesInRoom:c.messagesInRoom,lastActivityInRoom:c.lastActivityInRoom})),claude_code_enabled:a.claudeCodeEnabled??!1,claude_code_session_id:a.claudeCodeSessionId??null,quarantined:a.quarantined??!1})),r=new Set(n.map(a=>a.bot_id)),s=Fn().filter(a=>!r.has(a.bot_id));return{instance_id:Z(),timestamp:new Date().toISOString(),cli_version:t,plugin_version:e.pluginVersion||"unknown",hostname:o.hostname,os:o.os,arch:o.arch,uptime_seconds:o.uptimeSeconds,mem_free_mb:o.memFreeMb,gateway_status:e.status,gateway_pid:e.pid,last_gateway_restart:e.lastRestart,capabilities:ce(),hermes_containers:ko(),bots:[...n,...s]}}async function T(){let{version:e}=be(),t=await lt(),o=hr(t,e);await L().post(fr,o)}function Ja(e,t){if(!e||e.status!==t.status)return!0;let o=new Map(e.bots.map(n=>[n.botId,n]));for(let n of t.bots){let r=o.get(n.botId);if(!r||r.status!==n.status||r.errors!==n.errors)return!0}return e.bots.length!==t.bots.length}async function mr(){try{let o=(await L().get(Va)).data?.shares||[],n={shares:o.map(r=>({botUserId:r.bot_user_id,sharedWithUserId:r.shared_with_user_id,expiresAt:r.expires_at||null,shareId:r.share_id}))};await gr.default.post("http://localhost:7331/bot-share/sync",n,{timeout:1e4}),console.log(g.default.dim(` [${C()}] Share sync: ${o.length} active share(s) pushed to plugin`))}catch(e){console.log(g.default.dim(` [${C()}] Share sync failed (non-fatal): ${e.message}`))}}async function za(){if(!ur){ur=!0;try{await L().post(qa,{instance_id:Z()},{timeout:Ka}),console.log(g.default.dim(` [${new Date().toISOString()}] Posted disconnect \u2014 dashboard will mark machine offline immediately.`))}catch(e){console.log(g.default.dim(` [${new Date().toISOString()}] Disconnect post failed (non-fatal): ${e?.message||e}`))}}}async function yr(){let e=b();if(!e?.expires_at)return;let t=new Date(e.expires_at).getTime(),o=Date.now(),n=300*1e3;if(t-o<n)if(console.log(g.default.dim(` [${C()}] Token expires soon \u2014 refreshing proactively...`)),await ao())console.log(g.default.green(` [${C()}] Token refreshed successfully`));else{let s=yn()||"unknown reason";console.log(g.default.yellow(` [${C()}] Token refresh failed: ${s}`))}}function Qa(e,t){let o=3e3,n=3e4,r=null;async function s(){try{await yr();let c=b()?.access_token||e,l=require("eventsource"),i=new l(`${N}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${c}`}});i.onopen=()=>{o=3e3,console.log(g.default.dim(` [${C()}] SSE connected \u2014 listening for real-time events`)),r&&clearTimeout(r),r=setTimeout(()=>{console.log(g.default.dim(` [${C()}] SSE proactive reconnect \u2014 refreshing token before expiry`)),i.close(),s()},Xa)},i.onmessage=async m=>{try{let p=JSON.parse(m.data);await Za(p)}catch{}},i.onerror=async()=>{i.close(),r&&(clearTimeout(r),r=null),console.log(g.default.dim(` [${C()}] SSE disconnected \u2014 reconnecting in ${o/1e3}s...`)),setTimeout(s,o),o=Math.min(o*1.5,n)}}catch(a){console.log(g.default.dim(` [${C()}] SSE connection failed: ${a.message}`)),setTimeout(s,o),o=Math.min(o*1.5,n)}}s()}function C(){return new Date().toISOString()}async function Za(e){if(e.type==="pair"){console.log(g.default.cyan(` [${C()}] Pair event: ${e.bot_name}`)),await ot(e.pair_code,e.bot_name,e.bot_user_id,!0);try{let{execSync:t}=await import("child_process");t("openclaw gateway restart",{stdio:"ignore"}),console.log(g.default.green(` [${C()}] Gateway restarted \u2014 ${e.bot_name} is live`))}catch{}try{await T()}catch{}}else if(e.type==="bot.delete"&&e.bot_user_id){let t=e.bot_user_id,o=t.split(":")[0].replace("@","").replace(/_bot$/,"");console.log(g.default.yellow(` [${C()}] Bot deleted: ${t}`));try{let n=await import("fs"),r=await import("path"),s=await import("os"),a=r.join(s.homedir(),".openclaw","openclaw.json");if(we(()=>{let l=JSON.parse(n.readFileSync(a,"utf-8")),i=!1;if(l.channels?.badgerclaw?.accounts?.[o]&&(delete l.channels.badgerclaw.accounts[o],i=!0),l.agents?.list){let m=l.agents.list.length;l.agents.list=l.agents.list.filter(p=>p.id!==o),l.agents.list.length!==m&&(i=!0)}return i&&n.writeFileSync(a,JSON.stringify(l,null,2)),i})){console.log(g.default.green(` [${C()}] Removed "${o}" from openclaw.json`));let{execSync:l}=await import("child_process");try{l("openclaw gateway restart",{stdio:"ignore"}),console.log(g.default.green(` [${C()}] Gateway restarted`))}catch{}}}catch(n){console.log(g.default.red(` [${C()}] Failed to clean up bot: ${n}`))}try{await T()}catch{}}else if(e.type==="gateway-restart"){console.log(g.default.cyan(` [${C()}] Remote gateway-restart received`));let t=await Be();console.log(t.success?g.default.green(` [${C()}] Gateway restarted`):g.default.red(` [${C()}] Gateway restart failed: ${t.message}`));try{await T()}catch{}}else if(e.type==="claude_code.start"&&e.bot_id){if(console.log(g.default.cyan(` [${C()}] Claude Code START: bot=${e.bot_id}`)),Vt("start_claude_code",e.bot_id)){console.log(g.default.dim(` [${C()}] Skipping duplicate start_claude_code (already processed)`));return}try{let t=await se({id:e.command_id||`cc-start-${Date.now()}`,command_type:"start_claude_code",payload:{bot_id:e.bot_id,bot_user_id:e.bot_user_id,room_id:e.room_id,session_id:e.session_id}});e.command_id&&await L().post(`/api/v1/dashboard/commands/${e.command_id}/result`,{status:t.success?"success":"failed",result:t.message}).catch(()=>{})}catch{}try{await T()}catch{}}else if(e.type==="claude_code.stop"&&e.bot_id){if(console.log(g.default.cyan(` [${C()}] Claude Code STOP: bot=${e.bot_id}`)),Vt("stop_claude_code",e.bot_id)){console.log(g.default.dim(` [${C()}] Skipping duplicate stop_claude_code (already processed)`));return}try{let t=await se({id:e.command_id||`cc-stop-${Date.now()}`,command_type:"stop_claude_code",payload:{bot_id:e.bot_id,bot_user_id:e.bot_user_id,room_id:e.room_id,session_id:e.session_id}});e.command_id&&await L().post(`/api/v1/dashboard/commands/${e.command_id}/result`,{status:t.success?"success":"failed",result:t.message}).catch(()=>{})}catch{}try{await T()}catch{}}else if(e.type==="command.execute"&&e.command_id){if(console.log(g.default.cyan(` [${C()}] Command: ${e.command_type} (${e.command_id})`)),Vt(e.command_type,e.payload?.bot_id)){console.log(g.default.dim(` [${C()}] Skipping duplicate ${e.command_type} (already processed)`));return}try{let t=L();await t.post(`/api/v1/dashboard/commands/${e.command_id}/ack`);let o=await se({id:e.command_id,command_type:e.command_type,payload:e.payload});await t.post(`/api/v1/dashboard/commands/${e.command_id}/result`,{status:o.success?"success":"failed",result:o.message,new_version:o.newVersion||null}),e.command_type==="update_cli"&&o.success&&(console.log(g.default.cyan(` [${C()}] CLI updated \u2014 restarting in 2s...`)),setTimeout(()=>process.exit(0),2e3))}catch{}try{await T()}catch{}}}var pr,g,gr,dr,Wa,fr,qa,Va,Ka,ur,qt,Ya,Jo,Xa,je=H(()=>{"use strict";pr=require("commander"),g=u(require("chalk")),gr=u(require("axios"));M();he();xe();_e();De();ue();Yo();oe();rt();ue();Ze();Ee();dr=3e4,Wa=15e4,fr="/api/v1/dashboard/heartbeat",qa="/api/v1/dashboard/disconnect",Va="/api/v1/me/active-shares",Ka=3e3,ur=!1,qt=new Map,Ya=3e4;Jo=new pr.Command("heartbeat").description("Run heartbeat daemon \u2014 reports telemetry to the BadgerClaw dashboard every 30s").action(async()=>{let e=b();e||(console.log(g.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=be();console.log(g.default.green(`Heartbeat daemon started (v${t})`)),console.log(g.default.dim(` Instance: ${Z()}`)),console.log(g.default.dim(` Interval: ${dr/1e3}s`)),console.log(g.default.dim(` Press Ctrl+C to stop.
79
- `));let o=null,n=10,r=0,s=async()=>{try{await yr();let l=await lt(),i=hr(l,t);Ja(o,l)&&o!==null&&console.log(g.default.cyan(` [${new Date().toISOString()}] State change detected \u2014 pushing immediately`));let p=L(),P=await p.post(fr,i);r=0;let O=l.bots.length,f=l.bots.filter(_=>_.status==="running").length;console.log(g.default.dim(` [${new Date().toISOString()}] gateway=${l.status} bots=${f}/${O} running mem=${i.mem_free_mb}MB free`)),o=l;try{let w=await Gn({api:{post:async(X,Ke)=>{let ht=await p.post(X,Ke);return{status:ht.status,data:ht.data}}}});for(let X of w)X.attempted&&(X.posted||X.envUpdated)&&console.log(g.default.cyan(` [${new Date().toISOString()}] Hermes recovery key captured for ${X.bot_id} (posted=${X.posted}, env_updated=${X.envUpdated})`))}catch(_){console.log(g.default.dim(` [${new Date().toISOString()}] Hermes recovery-key retry skipped: ${_.message}`))}let v=P.data?.pending_commands||[],I=!1;for(let _ of v)try{if(console.log(g.default.cyan(` [${new Date().toISOString()}] Received command: ${_.command_type} (${_.id})`)),await p.post(`/api/v1/dashboard/commands/${_.id}/ack`),Vt(_.command_type,_.payload?.bot_id)){console.log(g.default.dim(` [${new Date().toISOString()}] Skipping duplicate ${_.command_type}`));continue}let w=await se(_);console.log(w.success?g.default.green(` [${new Date().toISOString()}] ${w.message}`):g.default.red(` [${new Date().toISOString()}] ${w.message}`)),await p.post(`/api/v1/dashboard/commands/${_.id}/result`,{status:w.success?"success":"failed",result:w.message,new_version:w.newVersion||null}),_.command_type==="update_cli"&&w.success&&(I=!0)}catch(w){console.log(g.default.dim(` [${new Date().toISOString()}] Command ${_.id} error: ${w.message}`))}if(I){console.log(g.default.cyan(` [${new Date().toISOString()}] CLI updated \u2014 restarting in 2s...`));try{await T()}catch{}setTimeout(()=>process.exit(0),2e3);return}}catch(l){l instanceof Ae&&(console.log(g.default.yellow(` [${new Date().toISOString()}] Account deactivated \u2014 signed out. Exiting daemon.`)),process.exit(0)),r+=1,console.log(g.default.dim(` [${new Date().toISOString()}] Heartbeat failed (${r}/${n}): ${l.message}`)),r>=n&&(console.log(g.default.red(` [${new Date().toISOString()}] ${n} consecutive heartbeat failures \u2014 exiting so launchctl/systemd can restart the daemon.`)),process.exit(1))}};await s();let a=G()!==null;a?await mr():console.log(g.default.dim(` [${C()}] Hermes-only host \u2014 share-sync disabled (no plugin to push to).`)),setInterval(s,dr),a&&setInterval(mr,Wa),Qa(e.access_token,t);let c=l=>{console.log(g.default.yellow(`
80
- [${new Date().toISOString()}] Received ${l} \u2014 posting disconnect and exiting.`)),za().finally(()=>{process.exit(0)})};process.on("SIGTERM",c),process.on("SIGINT",c),await new Promise(()=>{})});Xa=2700*1e3});var fs=require("commander");var wr=require("commander"),q=u(require("chalk")),br=u(require("ora")),_r=u(require("open")),Xo=u(require("os"));var oo=u(require("crypto"));function cn(){return oo.default.randomBytes(32).toString("base64url")}function dn(e){return oo.default.createHash("sha256").update(e).digest("base64url")}M();xe();he();oe();rt();var Nt=u(require("os")),J=u(require("fs")),Tt=u(require("path")),ve=require("child_process");var Oe=u(require("fs")),ke=u(require("path")),Ne=u(require("os")),Te=require("child_process"),Yn="ai.badgerclaw.watch",Jn=ke.default.join(Ne.default.homedir(),"Library","LaunchAgents"),Le=ke.default.join(Jn,`${Yn}.plist`);function ea(){try{return(0,Te.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/badgerclaw"}}function ta(){try{return(0,Te.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/node"}}function oa(e){let t=ke.default.join(Ne.default.homedir(),".badgerclaw"),o=ta(),n=ke.default.dirname(o),r=ke.default.dirname(e),s=[n,r,"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"],a=new Set,c=s.filter(l=>!l||a.has(l)?!1:(a.add(l),!0)).join(":");return`<?xml version="1.0" encoding="UTF-8"?>
79
+ `),e}function gl(){try{w.default.mkdirSync(A.default.dirname(fn),{recursive:!0});try{let e=w.default.statSync(fn);if(Date.now()-e.mtimeMs<6e4)return!1;w.default.unlinkSync(fn)}catch{}return w.default.writeFileSync(fn,String(process.pid),{flag:"wx"}),!0}catch{return!1}}async function fl(e){if(!e?.bot_id)return{success:!1,message:"Missing bot_id in payload"};if(!gl())return{success:!0,message:"Claude Code start already in progress, skipping duplicate"};try{let t=e.bot_user_id?.startsWith("@")?e.bot_user_id:await $t(e.bot_id),{launchClaudeCode:n,recordSession:o,getActiveSessions:r,stopSession:s}=(gn(),Zo(Ro)),a=new Set;try{let S=(await G.default.get("http://localhost:7331/claude-code/status",{timeout:5e3})).data?.bots||[];for(let E of S)if(E.botId!==t&&E.enabled!==!1){let g=E.port;typeof g=="number"&&g>=7332&&a.add(g)}}catch{}for(let p=7332;p<=7340;p++)try{(0,T.execSync)(`lsof -ti :${p} >/dev/null 2>&1`,{stdio:"pipe",timeout:2e3}),a.add(p)}catch{}let i=7332;for(;a.has(i);)i++;let c=r();for(let p of c)p.port===i&&(console.log(`[command-executor] Stopping existing session ${p.sessionId} on port ${i}`),s(p.sessionId));try{(0,T.execSync)(`lsof -ti :${i} | xargs kill -9 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let l=e.session_id||`session-${Date.now()}`;await G.default.post("http://localhost:7331/claude-code/toggle",{botId:t,enabled:!0,sessionId:l,port:i},{timeout:1e4});let u=pl();return n({sessionId:l,port:i,projectDir:u}),o(l,0,0,i,u),{success:!0,message:`Claude Code started globally for bot ${t} (session: ${l}, port: ${i})`}}catch(t){return{success:!1,message:`Failed to start Claude Code: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function $t(e){if(e.startsWith("@"))return e;try{let n=(await G.default.get("http://localhost:7331/health",{timeout:1e4})).data?.bots||[],o=A.default.join(De.default.homedir(),".badgerclaw","bot-mapping.json");if(w.default.existsSync(o)){let r=JSON.parse(w.default.readFileSync(o,"utf-8"));if(r[e])return r[e]}return n.length===1?n[0].botId:(console.warn(`[command-executor] Could not resolve bot UUID ${e} to Matrix ID, trying as-is`),e)}catch{return e}}async function hl(e){if(!e?.bot_id)return{success:!1,message:"Missing bot_id in payload"};try{let t=e.bot_user_id?.startsWith("@")?e.bot_user_id:await $t(e.bot_id),n=e.session_id;if(!n)try{let o=await G.default.get("http://localhost:7331/claude-code/status",{timeout:5e3}),s=(o.data?.bots||o.data?.rooms||[]).find(a=>a.botId===t);s&&(n=s.sessionId)}catch{}if(await G.default.post("http://localhost:7331/claude-code/toggle",{botId:t,enabled:!1},{timeout:1e4}),n){let{stopSession:o}=(gn(),Zo(Ro));o(n)}return{success:!0,message:"Claude Code stopped"}}catch(t){return{success:!1,message:`Failed to stop Claude Code: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function yl(e){try{let t=e?.bot_user_id||e?.bot_id;if(!t)return{success:!1,message:"Missing bot_id in payload"};let n=t;n.startsWith("@")||(n=await $t(t));let o=e?.session_id||`cc-${Date.now()}`;return await G.default.post("http://localhost:7331/claude-code/toggle",{botId:n,enabled:!0,sessionId:o,mode:"primary",tools:e?.tools},{timeout:1e4}),console.log(`[claude-control] Primary mode enabled for ${n} (session: ${o})`),{success:!0,message:`Claude Control (primary) started for ${n}`}}catch(t){return{success:!1,message:`Failed to start Claude Control: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function bl(e){try{let t=e?.bot_user_id||e?.bot_id;if(!t)return{success:!1,message:"Missing bot_id in payload"};let n=t;return n.startsWith("@")||(n=await $t(t)),await G.default.post("http://localhost:7331/claude-code/toggle",{botId:n,enabled:!1},{timeout:1e4}),console.log(`[claude-control] Primary mode disabled for ${n}`),{success:!0,message:`Claude Control stopped for ${n}`}}catch(t){return{success:!1,message:`Failed to stop Claude Control: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function wl(e){try{let t=e?.bot_user_id||e?.bot_id;if(!t||!e?.tools)return{success:!1,message:"Missing bot_id or tools in payload"};let n=t;return n.startsWith("@")||(n=await $t(t)),await G.default.post("http://localhost:7331/claude-code/tools",{botId:n,tools:e.tools},{timeout:1e4}),{success:!0,message:`Tools updated for ${n}`}}catch(t){return{success:!1,message:`Failed to update tools: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function _l(e){if(!e?.bot_user_id||!e?.shared_with_user_id)return{success:!1,message:"Missing bot_user_id or shared_with_user_id"};try{return await G.default.post("http://localhost:7331/bot-share/notify",{botId:e.bot_user_id,sharedWithUserId:e.shared_with_user_id,ownerDisplayName:e.owner_display_name||void 0,botDisplayName:e.bot_name||void 0,expiresAt:e.expires_at||void 0},{timeout:1e4}),console.log(`[bot-share] Notify: ${e.shared_with_user_id} can now access ${e.bot_user_id}`),{success:!0,message:`Share notification sent for ${e.shared_with_user_id}`}}catch(t){return{success:!1,message:`Failed to notify share: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function Sl(e){if(!e?.bot_user_id||!e?.shared_with_user_id)return{success:!1,message:"Missing bot_user_id or shared_with_user_id"};try{return await G.default.post("http://localhost:7331/bot-share/revoked",{botId:e.bot_user_id,sharedWithUserId:e.shared_with_user_id,botDisplayName:e.bot_name||void 0},{timeout:1e4}),console.log(`[bot-share] Revoked: ${e.shared_with_user_id} lost access to ${e.bot_user_id}`),{success:!0,message:`Share revocation sent for ${e.shared_with_user_id}`}}catch(t){return{success:!1,message:`Failed to revoke share: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function vl(e){if(!e?.bot_user_id||!e?.shared_with_user_id)return{success:!1,message:"Missing bot_user_id or shared_with_user_id"};try{return await G.default.post("http://localhost:7331/bot-share/expired",{botId:e.bot_user_id,sharedWithUserId:e.shared_with_user_id,botDisplayName:e.bot_name||void 0},{timeout:1e4}),console.log(`[bot-share] Expired: ${e.shared_with_user_id} access to ${e.bot_user_id}`),{success:!0,message:`Share expiry sent for ${e.shared_with_user_id}`}}catch(t){return{success:!1,message:`Failed to expire share: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function kl(e){let t=e?.bot_user_id||e?.bot_id;if(!t)return{success:!1,message:"Missing bot_id in bot_refresh payload"};let n=t;t.startsWith("@")&&(n=t.split(":")[0].replace("@","").replace(/_bot$/,""));let o=A.default.join(De.default.homedir(),".openclaw","badgerclaw","quarantine",`${n}.json`);try{w.default.rmSync(o,{force:!0})}catch{}try{return(0,T.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:15e3}),{success:!0,message:`Bot ${n} quarantine cleared, gateway restarted`}}catch{return{success:!1,message:`Quarantine cleared for ${n} but gateway restart failed`}}}async function Rl(e){if(!e?.bot_id||!e?.room_id)return{success:!1,message:"Missing bot_id or room_id in payload"};try{return{success:!0,message:(await G.default.post("http://localhost:7331/leave-room",{botId:e.bot_id,roomId:e.room_id},{timeout:15e3})).data?.message||"Left room"}}catch(t){return{success:!1,message:`Failed to leave room: ${t.response?.data?.message||t.message||"Unknown error"}`}}}var T,w,A,De,G,fn,xo=q(()=>{"use strict";T=require("child_process"),w=m(require("fs")),A=m(require("path")),De=m(require("os")),G=m(require("axios"));ke();fn=A.default.join(De.default.homedir(),".badgerclaw","claude-code.lock")});var Io={};Dn(Io,{heartbeatCommand:()=>$o,pushHeartbeat:()=>U});function yn(e,t){if(e!=="start_claude_code"&&e!=="stop_claude_code")return!1;let n=`${e}:${t||"unknown"}`,o=Date.now();for(let[r,s]of hn)o-s>Al&&hn.delete(r);return hn.has(n)?!0:(hn.set(n,o),!1)}function ls(e,t){let n=Gt(),o=e.bots.map(a=>({bot_id:a.botId,bot_username:a.botUsername,status:a.status,activity_state:a.activityState||"idle",active_task:a.activeTask||null,last_activity_at:a.lastActivity,messages_received:a.messagesReceived,messages_sent:a.messagesSent,chunked_messages:a.chunkedMessages,total_chunks_sent:a.totalChunksSent,errors:a.errors,last_error:a.lastError,last_error_at:a.lastErrorAt,uptime_seconds:a.uptimeSeconds,rooms_active:a.roomsActive,room_details:(a.roomDetails||[]).map(i=>({roomId:i.roomId,roomName:i.roomName,workspaceName:i.workspaceName||null,messagesInRoom:i.messagesInRoom,lastActivityInRoom:i.lastActivityInRoom})),claude_code_enabled:a.claudeCodeEnabled??!1,claude_code_session_id:a.claudeCodeSessionId??null,quarantined:a.quarantined??!1})),r=new Set(o.map(a=>a.bot_id)),s=Tr().filter(a=>!r.has(a.bot_id));return{instance_id:ae(),timestamp:new Date().toISOString(),cli_version:t,plugin_version:e.pluginVersion||"unknown",hostname:n.hostname,os:n.os,arch:n.arch,uptime_seconds:n.uptimeSeconds,mem_free_mb:n.memFreeMb,gateway_status:e.status,gateway_pid:e.pid,last_gateway_restart:e.lastRestart,capabilities:Se(),hermes_containers:Zn(),bots:[...o,...s]}}async function U(){let{version:e}=we(),t=await xt(),n=ls(t,e);await B().post(is,n)}function Pl(e,t){if(!e||e.status!==t.status)return!0;let n=new Map(e.bots.map(o=>[o.botId,o]));for(let o of t.bots){let r=n.get(o.botId);if(!r||r.status!==o.status||r.errors!==o.errors)return!0}return e.bots.length!==t.bots.length}async function rs(){try{let n=(await B().get($l)).data?.shares||[],o={shares:n.map(r=>({botUserId:r.bot_user_id,sharedWithUserId:r.shared_with_user_id,expiresAt:r.expires_at||null,shareId:r.share_id}))};await as.default.post("http://localhost:7331/bot-share/sync",o,{timeout:1e4}),console.log(f.default.dim(` [${P()}] Share sync: ${n.length} active share(s) pushed to plugin`))}catch(e){console.log(f.default.dim(` [${P()}] Share sync failed (non-fatal): ${e.message}`))}}async function El(){if(!os){os=!0;try{await B().post(xl,{instance_id:ae()},{timeout:Il}),console.log(f.default.dim(` [${new Date().toISOString()}] Posted disconnect \u2014 dashboard will mark machine offline immediately.`))}catch(e){console.log(f.default.dim(` [${new Date().toISOString()}] Disconnect post failed (non-fatal): ${e?.message||e}`))}}}async function cs(){let e=R();if(!e?.expires_at)return;let t=new Date(e.expires_at).getTime(),n=Date.now(),o=300*1e3;if(t-n<o)if(console.log(f.default.dim(` [${P()}] Token expires soon \u2014 refreshing proactively...`)),await Un())console.log(f.default.green(` [${P()}] Token refreshed successfully`));else{let s=lr()||"unknown reason";console.log(f.default.yellow(` [${P()}] Token refresh failed: ${s}`))}}function Ll(e,t){let n=3e3,o=3e4,r=null;async function s(){try{await cs();let i=R()?.access_token||e,c=require("eventsource"),l=new c(`${N}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${i}`}});l.onopen=()=>{n=3e3,console.log(f.default.dim(` [${P()}] SSE connected \u2014 listening for real-time events`)),r&&clearTimeout(r),r=setTimeout(()=>{console.log(f.default.dim(` [${P()}] SSE proactive reconnect \u2014 refreshing token before expiry`)),l.close(),s()},Ol)},l.onmessage=async u=>{try{let p=JSON.parse(u.data);await Tl(p)}catch{}},l.onerror=async()=>{l.close(),r&&(clearTimeout(r),r=null),console.log(f.default.dim(` [${P()}] SSE disconnected \u2014 reconnecting in ${n/1e3}s...`)),setTimeout(s,n),n=Math.min(n*1.5,o)}}catch(a){console.log(f.default.dim(` [${P()}] SSE connection failed: ${a.message}`)),setTimeout(s,n),n=Math.min(n*1.5,o)}}s()}function P(){return new Date().toISOString()}async function Tl(e){if(e.type==="pair"){console.log(f.default.cyan(` [${P()}] Pair event: ${e.bot_name}`)),await _t(e.pair_code,e.bot_name,e.bot_user_id,!0);try{let{execSync:t}=await import("child_process");t("openclaw gateway restart",{stdio:"ignore"}),console.log(f.default.green(` [${P()}] Gateway restarted \u2014 ${e.bot_name} is live`))}catch{}try{await U()}catch{}}else if(e.type==="bot.delete"&&e.bot_user_id){let t=e.bot_user_id,n=t.split(":")[0].replace("@","").replace(/_bot$/,"");console.log(f.default.yellow(` [${P()}] Bot deleted: ${t}`));try{let o=await import("fs"),r=await import("path"),s=await import("os"),a=r.join(s.homedir(),".openclaw","openclaw.json");if(Ee(()=>{let c=JSON.parse(o.readFileSync(a,"utf-8")),l=!1;if(c.channels?.badgerclaw?.accounts?.[n]&&(delete c.channels.badgerclaw.accounts[n],l=!0),c.agents?.list){let u=c.agents.list.length;c.agents.list=c.agents.list.filter(p=>p.id!==n),c.agents.list.length!==u&&(l=!0)}return l&&o.writeFileSync(a,JSON.stringify(c,null,2)),l})){console.log(f.default.green(` [${P()}] Removed "${n}" from openclaw.json`));let{execSync:c}=await import("child_process");try{c("openclaw gateway restart",{stdio:"ignore"}),console.log(f.default.green(` [${P()}] Gateway restarted`))}catch{}}}catch(o){console.log(f.default.red(` [${P()}] Failed to clean up bot: ${o}`))}try{await U()}catch{}}else if(e.type==="gateway-restart"){console.log(f.default.cyan(` [${P()}] Remote gateway-restart received`));let t=await Qe();console.log(t.success?f.default.green(` [${P()}] Gateway restarted`):f.default.red(` [${P()}] Gateway restart failed: ${t.message}`));try{await U()}catch{}}else if(e.type==="claude_code.start"&&e.bot_id){if(console.log(f.default.cyan(` [${P()}] Claude Code START: bot=${e.bot_id}`)),yn("start_claude_code",e.bot_id)){console.log(f.default.dim(` [${P()}] Skipping duplicate start_claude_code (already processed)`));return}try{let t=await pe({id:e.command_id||`cc-start-${Date.now()}`,command_type:"start_claude_code",payload:{bot_id:e.bot_id,bot_user_id:e.bot_user_id,room_id:e.room_id,session_id:e.session_id}});e.command_id&&await B().post(`/api/v1/dashboard/commands/${e.command_id}/result`,{status:t.success?"success":"failed",result:t.message}).catch(()=>{})}catch{}try{await U()}catch{}}else if(e.type==="claude_code.stop"&&e.bot_id){if(console.log(f.default.cyan(` [${P()}] Claude Code STOP: bot=${e.bot_id}`)),yn("stop_claude_code",e.bot_id)){console.log(f.default.dim(` [${P()}] Skipping duplicate stop_claude_code (already processed)`));return}try{let t=await pe({id:e.command_id||`cc-stop-${Date.now()}`,command_type:"stop_claude_code",payload:{bot_id:e.bot_id,bot_user_id:e.bot_user_id,room_id:e.room_id,session_id:e.session_id}});e.command_id&&await B().post(`/api/v1/dashboard/commands/${e.command_id}/result`,{status:t.success?"success":"failed",result:t.message}).catch(()=>{})}catch{}try{await U()}catch{}}else if(e.type==="command.execute"&&e.command_id){if(console.log(f.default.cyan(` [${P()}] Command: ${e.command_type} (${e.command_id})`)),yn(e.command_type,e.payload?.bot_id)){console.log(f.default.dim(` [${P()}] Skipping duplicate ${e.command_type} (already processed)`));return}try{let t=B();await t.post(`/api/v1/dashboard/commands/${e.command_id}/ack`);let n=await pe({id:e.command_id,command_type:e.command_type,payload:e.payload});await t.post(`/api/v1/dashboard/commands/${e.command_id}/result`,{status:n.success?"success":"failed",result:n.message,new_version:n.newVersion||null}),e.command_type==="update_cli"&&n.success&&(console.log(f.default.cyan(` [${P()}] CLI updated \u2014 restarting in 2s...`)),setTimeout(()=>process.exit(0),2e3))}catch{}try{await U()}catch{}}}var ss,f,as,ns,Cl,is,xl,$l,Il,os,hn,Al,$o,Ol,Xe=q(()=>{"use strict";ss=require("commander"),f=m(require("chalk")),as=m(require("axios"));F();Ae();Ie();Oe();Ve();ke();xo();ie();vt();ke();ht();Ge();ns=3e4,Cl=15e4,is="/api/v1/dashboard/heartbeat",xl="/api/v1/dashboard/disconnect",$l="/api/v1/me/active-shares",Il=3e3,os=!1,hn=new Map,Al=3e4;$o=new ss.Command("heartbeat").description("Run heartbeat daemon \u2014 reports telemetry to the BadgerClaw dashboard every 30s").action(async()=>{let e=R();e||(console.log(f.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=we();console.log(f.default.green(`Heartbeat daemon started (v${t})`)),console.log(f.default.dim(` Instance: ${ae()}`)),console.log(f.default.dim(` Interval: ${ns/1e3}s`)),console.log(f.default.dim(` Press Ctrl+C to stop.
80
+ `));let n=null,o=10,r=0,s=async()=>{try{await cs();let c=await xt(),l=ls(c,t);Pl(n,c)&&n!==null&&console.log(f.default.cyan(` [${new Date().toISOString()}] State change detected \u2014 pushing immediately`));let p=B(),S=await p.post(is,l);r=0;let E=c.bots.length,g=c.bots.filter(y=>y.status==="running").length;console.log(f.default.dim(` [${new Date().toISOString()}] gateway=${c.status} bots=${g}/${E} running mem=${l.mem_free_mb}MB free`)),n=c;try{let b=await Mr({api:{post:async(j,oe)=>{let re=await p.post(j,oe);return{status:re.status,data:re.data}}}});for(let j of b)j.attempted&&(j.posted||j.envUpdated)&&console.log(f.default.cyan(` [${new Date().toISOString()}] Hermes recovery key captured for ${j.bot_id} (posted=${j.posted}, env_updated=${j.envUpdated})`))}catch(y){console.log(f.default.dim(` [${new Date().toISOString()}] Hermes recovery-key retry skipped: ${y.message}`))}let v=S.data?.pending_commands||[],h=!1;for(let y of v)try{if(console.log(f.default.cyan(` [${new Date().toISOString()}] Received command: ${y.command_type} (${y.id})`)),await p.post(`/api/v1/dashboard/commands/${y.id}/ack`),yn(y.command_type,y.payload?.bot_id)){console.log(f.default.dim(` [${new Date().toISOString()}] Skipping duplicate ${y.command_type}`));continue}let b=await pe(y);console.log(b.success?f.default.green(` [${new Date().toISOString()}] ${b.message}`):f.default.red(` [${new Date().toISOString()}] ${b.message}`)),await p.post(`/api/v1/dashboard/commands/${y.id}/result`,{status:b.success?"success":"failed",result:b.message,new_version:b.newVersion||null}),y.command_type==="update_cli"&&b.success&&(h=!0)}catch(b){console.log(f.default.dim(` [${new Date().toISOString()}] Command ${y.id} error: ${b.message}`))}if(h){console.log(f.default.cyan(` [${new Date().toISOString()}] CLI updated \u2014 restarting in 2s...`));try{await U()}catch{}setTimeout(()=>process.exit(0),2e3);return}}catch(c){c instanceof He&&(console.log(f.default.yellow(` [${new Date().toISOString()}] Account deactivated \u2014 signed out. Exiting daemon.`)),process.exit(0)),r+=1,console.log(f.default.dim(` [${new Date().toISOString()}] Heartbeat failed (${r}/${o}): ${c.message}`)),r>=o&&(console.log(f.default.red(` [${new Date().toISOString()}] ${o} consecutive heartbeat failures \u2014 exiting so launchctl/systemd can restart the daemon.`)),process.exit(1))}};await s();let a=K()!==null;a?await rs():console.log(f.default.dim(` [${P()}] Hermes-only host \u2014 share-sync disabled (no plugin to push to).`)),setInterval(s,ns),a&&setInterval(rs,Cl),Ll(e.access_token,t);let i=c=>{console.log(f.default.yellow(`
81
+ [${new Date().toISOString()}] Received ${c} \u2014 posting disconnect and exiting.`)),El().finally(()=>{process.exit(0)})};process.on("SIGTERM",i),process.on("SIGINT",i),await new Promise(()=>{})});Ol=2700*1e3});var Ya=require("commander");var us=require("commander"),z=m(require("chalk")),ds=m(require("ora")),ms=m(require("open")),Ao=m(require("os"));var Nn=m(require("crypto"));function er(){return Nn.default.randomBytes(32).toString("base64url")}function tr(e){return Nn.default.createHash("sha256").update(e).digest("base64url")}F();Ie();Ae();ie();vt();var sn=m(require("os")),ee=m(require("fs")),an=m(require("path")),Te=require("child_process");var We=m(require("fs")),Le=m(require("path")),Ye=m(require("os")),Je=require("child_process"),Ur="ai.badgerclaw.watch",Fr=Le.default.join(Ye.default.homedir(),"Library","LaunchAgents"),Ke=Le.default.join(Fr,`${Ur}.plist`);function Mi(){try{return(0,Je.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/badgerclaw"}}function Di(){try{return(0,Je.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/node"}}function Ni(e){let t=Le.default.join(Ye.default.homedir(),".badgerclaw"),n=Di(),o=Le.default.dirname(n),r=Le.default.dirname(e),s=[o,r,"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"],a=new Set,i=s.filter(c=>!c||a.has(c)?!1:(a.add(c),!0)).join(":");return`<?xml version="1.0" encoding="UTF-8"?>
81
82
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
82
83
  <plist version="1.0">
83
84
  <dict>
84
85
  <key>Label</key>
85
- <string>${Yn}</string>
86
+ <string>${Ur}</string>
86
87
  <key>ProgramArguments</key>
87
88
  <array>
88
- <string>${o}</string>
89
+ <string>${n}</string>
89
90
  <string>${e}</string>
90
91
  <string>heartbeat</string>
91
92
  </array>
92
93
  <key>EnvironmentVariables</key>
93
94
  <dict>
94
95
  <key>PATH</key>
95
- <string>${c}</string>
96
+ <string>${i}</string>
96
97
  </dict>
97
98
  <key>RunAtLoad</key>
98
99
  <true/>
@@ -105,7 +106,7 @@ Keep responses concise and helpful.
105
106
  <key>ThrottleInterval</key>
106
107
  <integer>30</integer>
107
108
  </dict>
108
- </plist>`}function zn(){if(Ne.default.platform()==="darwin")try{let e=ea();Oe.default.mkdirSync(Jn,{recursive:!0}),Oe.default.mkdirSync(ke.default.join(Ne.default.homedir(),".badgerclaw"),{recursive:!0}),Oe.default.writeFileSync(Le,oa(e));try{(0,Te.execSync)(`launchctl unload "${Le}" 2>/dev/null`)}catch{}(0,Te.execSync)(`launchctl load "${Le}"`),console.log("\x1B[2mPair-watcher registered as background service (auto-starts on login).\x1B[0m")}catch{console.log("\x1B[2mNote: could not register background service. Run `badgerclaw watch` manually.\x1B[0m")}}function Xn(){if(Ne.default.platform()==="darwin")try{(0,Te.execSync)(`launchctl unload "${Le}" 2>/dev/null`),Oe.default.existsSync(Le)&&Oe.default.unlinkSync(Le)}catch{}}var Me=u(require("fs")),at=u(require("path")),st=u(require("os")),Y=require("child_process"),Lt="badgerclaw-watch.service",Qn=at.default.join(st.default.homedir(),".config","systemd","user"),Ro=at.default.join(Qn,Lt);function na(){try{return(0,Y.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/usr/local/bin/badgerclaw"}}function ra(){try{return(0,Y.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/usr/bin/node"}}function sa(e){let t=ra(),o=at.default.dirname(t);return`[Unit]
109
+ </plist>`}function Hr(){if(Ye.default.platform()==="darwin")try{let e=Mi();We.default.mkdirSync(Fr,{recursive:!0}),We.default.mkdirSync(Le.default.join(Ye.default.homedir(),".badgerclaw"),{recursive:!0}),We.default.writeFileSync(Ke,Ni(e));try{(0,Je.execSync)(`launchctl unload "${Ke}" 2>/dev/null`)}catch{}(0,Je.execSync)(`launchctl load "${Ke}"`),console.log("\x1B[2mPair-watcher registered as background service (auto-starts on login).\x1B[0m")}catch{console.log("\x1B[2mNote: could not register background service. Run `badgerclaw watch` manually.\x1B[0m")}}function Gr(){if(Ye.default.platform()==="darwin")try{(0,Je.execSync)(`launchctl unload "${Ke}" 2>/dev/null`),We.default.existsSync(Ke)&&We.default.unlinkSync(Ke)}catch{}}var ze=m(require("fs")),Rt=m(require("path")),kt=m(require("os")),Z=require("child_process"),rn="badgerclaw-watch.service",qr=Rt.default.join(kt.default.homedir(),".config","systemd","user"),ro=Rt.default.join(qr,rn);function ji(){try{return(0,Z.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/usr/local/bin/badgerclaw"}}function Bi(){try{return(0,Z.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/usr/bin/node"}}function Ui(e){let t=Bi(),n=Rt.default.dirname(t);return`[Unit]
109
110
  Description=BadgerClaw background watcher (heartbeat + pair events)
110
111
  After=network-online.target
111
112
  Wants=network-online.target
@@ -115,55 +116,86 @@ Type=simple
115
116
  ExecStart=${t} ${e} heartbeat
116
117
  Restart=always
117
118
  RestartSec=30
118
- Environment=PATH=${o}:/usr/local/bin:/usr/bin:/bin
119
+ Environment=PATH=${n}:/usr/local/bin:/usr/bin:/bin
119
120
  StandardOutput=append:%h/.badgerclaw/heartbeat.log
120
121
  StandardError=append:%h/.badgerclaw/heartbeat.log
121
122
 
122
123
  [Install]
123
124
  WantedBy=default.target
124
- `}function Zn(){try{return(0,Y.execSync)("systemctl --user --version",{stdio:"ignore"}),!0}catch{return!1}}function er(){if(st.default.platform()!=="linux"||!Zn())return!1;try{let e=na();Me.default.mkdirSync(Qn,{recursive:!0}),Me.default.mkdirSync(at.default.join(st.default.homedir(),".badgerclaw"),{recursive:!0}),Me.default.writeFileSync(Ro,sa(e)),(0,Y.execSync)("systemctl --user daemon-reload",{stdio:"ignore"});try{(0,Y.execSync)(`systemctl --user restart ${Lt}`,{stdio:"ignore"})}catch{}(0,Y.execSync)(`systemctl --user enable --now ${Lt}`,{stdio:"ignore"});try{let t=(0,Y.execSync)("whoami",{encoding:"utf-8"}).trim();(0,Y.execSync)(`loginctl enable-linger ${t}`,{stdio:"ignore"})}catch{}return console.log("\x1B[2mHeartbeat daemon registered as systemd user service (auto-starts on login).\x1B[0m"),!0}catch{return!1}}function tr(){if(st.default.platform()==="linux"&&Zn()){try{(0,Y.execSync)(`systemctl --user disable --now ${Lt}`,{stdio:"ignore"})}catch{}try{Me.default.existsSync(Ro)&&Me.default.unlinkSync(Ro),(0,Y.execSync)("systemctl --user daemon-reload",{stdio:"ignore"})}catch{}}}var xo=Tt.default.join(Nt.default.homedir(),".badgerclaw"),it=Tt.default.join(xo,"heartbeat.pid"),aa=Tt.default.join(xo,"heartbeat.log");function ia(e){if(!e||e.length===0)return!1;let t=s=>/(^|[\\/])node(\.exe)?$/i.test(s||""),o=t(e[0])||t(e[1]),n=e.includes("heartbeat"),r=e.some(s=>/(^|[\\/])badgerclaw($|[\\/. ])/i.test(s)||/[\\/]dist[\\/]index\.js$/.test(s));return o&&n&&r}function la(e){try{if(process.platform==="linux")return J.default.readFileSync(`/proc/${e}/cmdline`).toString("utf-8").split("\0").filter(Boolean);let t=(0,ve.execSync)(`ps -o args= -p ${e}`,{encoding:"utf-8"}).trim();return t.length?t.split(/\s+/).filter(Boolean):null}catch{return null}}function Ao(e){if(!Number.isFinite(e)||e<=0||e===process.pid||e===process.ppid)return!1;let t=la(e);return t?ia(t):!1}function Eo(){let e="";try{e=(0,ve.execSync)("pgrep -f heartbeat",{encoding:"utf-8"})}catch{return[]}return e.split(/\s+/).map(t=>parseInt(t,10)).filter(t=>Number.isFinite(t)&&t>0).filter(t=>Ao(t))}function ca(e){try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,Math.max(0,e))}catch{}}function da(e){try{if(process.platform==="linux"){let r=J.default.readFileSync(`/proc/${e}/status`,"utf-8").match(/^PPid:\s*(\d+)/m),s=r?parseInt(r[1],10):NaN;if(!Number.isFinite(s))return null;let a="";try{a=J.default.readFileSync(`/proc/${s}/comm`,"utf-8").trim()}catch{}return{ppid:s,comm:a}}let t=parseInt((0,ve.execSync)(`ps -o ppid= -p ${e}`,{encoding:"utf-8"}).trim(),10);if(!Number.isFinite(t))return null;let o="";try{o=(0,ve.execSync)(`ps -o comm= -p ${t}`,{encoding:"utf-8"}).trim()}catch{}return{ppid:t,comm:o}}catch{return null}}var ua=/(systemd|supervisord|launchd|runsv|runit|s6-supervise|openrc)/i;function ma(){for(let e of Eo()){let t=da(e);if(t&&ua.test(t.comm))return e}return null}function pa(){try{let e=parseInt(J.default.readFileSync(it,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&Ao(e))return!0}catch{}return nr(),Eo().length>0}function nr(){try{let e=parseInt(J.default.readFileSync(it,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&Ao(e))return}catch{}try{J.default.rmSync(it,{force:!0})}catch{}}function ga(e="SIGTERM"){let t=Eo(),o=0;for(let a of t)try{process.kill(a,e),o++}catch{}if(o===0)return 0;let n=a=>{try{return process.kill(a,0),!0}catch{return!1}},r=Date.now()+4e3,s=t.filter(n);for(;s.length>0&&Date.now()<r;)ca(120),s=s.filter(n);for(let a of s)try{process.kill(a,"SIGKILL")}catch{}return o}function or(){if(pa())return console.log("\x1B[2mHeartbeat already running.\x1B[0m"),!0;try{J.default.mkdirSync(xo,{recursive:!0});let e=J.default.openSync(aa,"a"),t=(0,ve.spawn)(process.execPath,[process.argv[1],"heartbeat"],{detached:!0,stdio:["ignore",e,e]});if(t.pid==null)return console.log("\x1B[2mNote: could not start the heartbeat. Run `badgerclaw heartbeat` manually.\x1B[0m"),!1;try{J.default.writeFileSync(it,String(t.pid))}catch{}return t.unref(),console.log("\x1B[2mHeartbeat started in the background (no service manager on this host; it will not auto-restart after a reboot \u2014 re-run `badgerclaw setup --hermes` or `badgerclaw heartbeat` if the host restarts).\x1B[0m"),!0}catch{return console.log("\x1B[2mNote: could not start the heartbeat. Run `badgerclaw heartbeat` manually.\x1B[0m"),!1}}function Po(){let e=Nt.default.platform();if(e==="darwin"){zn();return}if(e==="linux"){if(er())return;or();return}or()}function fa(){let e=Nt.default.platform();e==="darwin"?Xn():e==="linux"&&tr(),ga();try{J.default.rmSync(it,{force:!0})}catch{}}function rr(e){let t=e.log||(()=>{}),o=ma();if(o!==null){nr(),t(`heartbeat already supervised (pid ${o}) \u2014 left in place; cleared any stale pid file.`);return}fa(),t("removed stale heartbeat hooks from previous installs."),e.loggedIn?(Po(),t("reinstalled a fresh heartbeat daemon for this host.")):t("run `badgerclaw login` to start the heartbeat for this host.")}var me=u(require("fs")),No=u(require("os")),Bt=u(require("path")),ee=require("child_process"),U=u(require("chalk"));Ze();ue();var ar=Bt.default.join(No.default.homedir(),".openclaw","openclaw.json");function ba(){return process.platform!=="linux"?!1:!!(me.default.existsSync("/.dockerenv")||(0,ee.spawnSync)("which",["systemctl"],{encoding:"utf-8"}).status!==0)}function ir(e=!1){let t=null;try{me.default.existsSync(ar)&&(t=JSON.parse(me.default.readFileSync(ar,"utf-8"))?.gateway?.mode??null)}catch{}if(typeof t=="string"&&t.length>0)return!0;e||console.log(U.default.dim(" Setting gateway.mode=local..."));try{return we(()=>((0,ee.execSync)("openclaw config set gateway.mode local",{encoding:"utf-8",timeout:1e4,stdio:"pipe"}),!0))}catch(o){return e||(console.log(U.default.yellow(` \u26A0\uFE0F Could not set gateway.mode automatically: ${o.message}`)),console.log(U.default.yellow(" Run `openclaw config set gateway.mode local` manually."))),!1}}async function jt(e={}){let t=e.verbose!==!1,o=c=>{t&&console.log(c)};if(ba())return Sa(t);o(U.default.dim(" Installing OpenClaw gateway service (if not present)...")),(0,ee.spawnSync)("openclaw",["gateway","install"],{stdio:t?"inherit":"pipe",shell:!0}).status!==0&&o(U.default.yellow(" \u26A0\uFE0F `openclaw gateway install` returned non-zero \u2014 continuing.")),ir(!t),o(U.default.dim(" Starting OpenClaw gateway..."));let r=(0,ee.spawnSync)("openclaw",["gateway","start"],{stdio:t?"inherit":"pipe",shell:!0}),s="started";if(r.status!==0&&(r=(0,ee.spawnSync)("openclaw",["gateway","restart"],{stdio:t?"inherit":"pipe",shell:!0}),s="restarted"),r.status!==0)return{ok:!1,error:"gateway start/restart returned non-zero exit"};o(U.default.dim(" Waiting for the gateway to start answering..."));let a=await _a(2e4);return a||o(U.default.yellow(" \u26A0\uFE0F Gateway start issued but it is not answering yet \u2014 it may still be booting.")),{ok:!0,state:s,ready:a}}async function _a(e,t=Oo,o=500){let n=Date.now()+e;for(;;){if(await t())return!0;if(Date.now()>=n)return!1;await new Promise(r=>setTimeout(r,o))}}async function Sa(e){let t=i=>{e&&console.log(i)};t(U.default.dim(" Container mode (no systemd) \u2014 running gateway in foreground via nohup.")),ir(!e);let o=Bt.default.join(No.default.homedir(),".openclaw","logs");try{me.default.mkdirSync(o,{recursive:!0})}catch{}let n=Bt.default.join(o,"gateway-foreground.log"),r,s;try{r=me.default.openSync(n,"a"),s=me.default.openSync(n,"a")}catch(i){return{ok:!1,error:`cannot open gateway log at ${n}: ${i.message}`}}let a=(0,ee.spawn)("openclaw",["gateway"],{detached:!0,stdio:["ignore",r,s]});if(a.pid==null)return{ok:!1,error:"failed to spawn `openclaw gateway`"};a.unref(),t(U.default.dim(` Gateway PID: ${a.pid}, log: ${n}`));let c=Date.now()+2e4,l=!1;for(;Date.now()<c;){try{let i=me.default.readFileSync(n,"utf-8");if(i.includes("[gateway] ready")){l=!0;break}if(/EADDRINUSE|FATAL|Error:|gateway start blocked/.test(i))return{ok:!1,error:`gateway aborted on startup \u2014 see ${n}`}}catch{}await new Promise(i=>setTimeout(i,200))}return l?{ok:!0,state:"started",ready:!0}:{ok:!1,error:`gateway did not report ready within 20s \u2014 see ${n}`}}function Ht(){if(process.platform!=="linux"||process.getuid?.()!==0)return;let e=(0,ee.spawnSync)("loginctl",["show-user","root","--property=Linger"],{encoding:"utf-8"});e.status===0&&/Linger=no/.test(e.stdout||"")&&(console.log(U.default.yellow(`
125
- \u26A0\uFE0F systemd lingering is OFF for root. The gateway will stop on SSH disconnect.`)),console.log(U.default.dim(" Enable persistence: loginctl enable-linger root")))}Ee();var ei=2e3,ti=12e4,Sr=new wr.Command("login").description("Log in to BadgerClaw via browser").action(async()=>{let e=cn(),t=dn(e),o=`${fn}/cli-auth?code=${t}`;console.log(q.default.yellow("Opening browser for authentication...")),console.log(q.default.dim(`If the browser doesn't open, visit: ${o}`)),await(0,_r.default)(o);let n=(0,br.default)("Waiting for authentication...").start(),r=_n(),s=Date.now();for(;Date.now()-s<ti;){try{let a=await r.post(`/api/v1/openclaw/cli/auth/poll/${t}`,{code_verifier:e,code_challenge:t});if(a.status===429){await new Promise(c=>setTimeout(c,5e3));continue}if(a.data?.access_token){let{access_token:c,user_id:l,expires_at:i,refresh_token:m,email:p}=a.data,P=so(),O=`openclaw-${Xo.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${P}`,f=O;try{let{version:I}=be(),_=await r.post("/api/v1/openclaw/register",{instance_id:O,label:Xo.default.hostname(),version:I,machine_fingerprint:P},{headers:{Authorization:`Bearer ${c}`}}),w=_.data?.result||_.data;w&&typeof w.instance_id=="string"&&w.instance_id.length>0&&(f=w.instance_id)}catch(I){let _=I?.response?.status;if(_===403||_===409){let w=I?.response?.data,X=Array.isArray(w?.errors)&&typeof w.errors[0]=="string"?w.errors[0]:null,Ke=w?.detail,ht=typeof Ke=="string"?Ke:Ke?.error==="downgrade_selection_required"?"Your account has an unresolved plan-change request. Open the BadgerClaw app to finish the downgrade selection, then try again.":null,hs=X||ht||`Login refused (status ${_}). Open the BadgerClaw app to check your subscription state.`;n.fail(q.default.red(hs)),process.exit(1)}}if(wt({access_token:c,user_id:l,instance_id:f,expires_at:i,refresh_token:m,email:p}),n.succeed(q.default.green(`Logged in as ${_t(l)}`)),G()!==null){let I=await jt({verbose:!0});I.ok?I.ready===!1&&console.log(q.default.dim(" Gateway is still coming up \u2014 it should be online shortly.")):console.log(q.default.yellow("\n \u26A0\uFE0F Logged in, but gateway failed to start. Re-run `badgerclaw setup` to repair."))}else console.log(q.default.dim(" Hermes-only host \u2014 skipping OpenClaw gateway bring-up."));let v=await nt(!0);v>0&&console.log(q.default.green(`\u2705 ${v} bot(s) automatically paired to OpenClaw.`)),Po(),Ht();try{let{pushHeartbeat:I}=await Promise.resolve().then(()=>(je(),zo));await I(),console.log(q.default.dim(" Capabilities pushed \u2014 the machine should show online shortly."))}catch(I){console.log(q.default.dim(` Capability push will retry via the heartbeat (${I?.message||I}).`))}return}}catch{}await new Promise(a=>setTimeout(a,ei))}n.fail(q.default.red("Authentication timed out. Please try again.")),process.exit(1)});var vr=require("commander"),dt=u(require("chalk")),Kt=u(require("fs")),He=u(require("os")),mt=u(require("path")),ut=require("child_process");M();he();function oi(){let e=process.platform;if(e==="darwin"){let t=mt.default.join(He.default.homedir(),"Library","LaunchAgents","ai.badgerclaw.watch.plist");(0,ut.spawnSync)("launchctl",["unload",t],{stdio:"ignore"});try{Kt.default.unlinkSync(t)}catch{}}else if(e==="linux"){(0,ut.spawnSync)("systemctl",["--user","disable","--now","badgerclaw-watch.service"],{stdio:"ignore"});let t=mt.default.join(He.default.homedir(),".config","systemd","user","badgerclaw-watch.service");try{Kt.default.unlinkSync(t)}catch{}(0,ut.spawnSync)("systemctl",["--user","daemon-reload"],{stdio:"ignore"})}(0,ut.spawnSync)("pkill",["-f","badgerclaw heartbeat"],{stdio:"ignore"})}function kr(e){try{return Kt.default.rmSync(e,{recursive:!0,force:!0}),!0}catch{return!1}}var $r=new vr.Command("logout").description("Disconnect this machine, log out of BadgerClaw, and wipe local state").option("--keep-state","Only clear auth.json (legacy behaviour); preserve bot-mapping, claude-sessions, heartbeat logs, and plugin quarantine ledger").action(async e=>{let t=b();if(t)try{let a=Qe(t.access_token),{version:c}=be();await a.post("/api/v1/openclaw/register",{instance_id:t.instance_id,label:He.default.hostname(),version:c,online:!1})}catch{}if(oi(),e.keepState){Je(),console.log(dt.default.green("Logged out \u2014 auth cleared. (state preserved with --keep-state)"));return}let o=mt.default.join(He.default.homedir(),".badgerclaw"),n=kr(o),r=mt.default.join(He.default.homedir(),".openclaw","badgerclaw"),s=kr(r);n||s?(console.log(dt.default.green("Logged out \u2014 local state cleared.")),console.log(dt.default.dim(` Removed: ${o}${s?`, ${r}`:""}`))):console.log(dt.default.green("Logged out."))});var Cr=require("commander"),Qo=u(require("chalk"));M();var Ir=new Cr.Command("status").description("Show connected instance info").action(async()=>{let e=b();(!e||!bt())&&(console.log(Qo.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1)),console.log(Qo.default.green("Authenticated")),console.log(` User: ${_t(e.user_id)}`),console.log(` Instance: ${e.instance_id}`),console.log(` Expires: ${new Date(e.expires_at).toLocaleDateString()}`)});var Fe=require("commander"),S=u(require("chalk")),Xt=u(require("ora")),zt=u(require("fs")),Dr=u(require("os")),Or=u(require("path")),Lr=require("child_process");M();he();var Ue=u(require("fs")),Rr=u(require("os")),xr=u(require("path")),Ar=require("child_process");Ze();function Yt(e){let t=e.split(":")[0].replace(/^@/,"").replace(/_bot$/,""),o=xr.join(Rr.homedir(),".openclaw","openclaw.json");return Ue.existsSync(o)?{changed:we(()=>{let r=JSON.parse(Ue.readFileSync(o,"utf-8")),s=!1;if(r.channels?.badgerclaw?.accounts?.[t]&&(delete r.channels.badgerclaw.accounts[t],s=!0),r.agents?.list){let a=r.agents.list.length;r.agents.list=r.agents.list.filter(c=>c.id!==t),r.agents.list.length!==a&&(s=!0)}return s&&Ue.writeFileSync(o,JSON.stringify(r,null,2)),s})}:{changed:!1}}function Jt(){try{return(0,Ar.execSync)("openclaw gateway restart",{stdio:"ignore"}),!0}catch{return!1}}_e();function Er(e){return e.hermes?"hermes":"openclaw"}function Pr(e){return e.openclaw.installed?"openclaw":e.hermes.installed?"hermes":"openclaw"}function en(){bt()||(console.log(S.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1))}function ni(e){return/^[a-z0-9_]{4,20}$/.test(e)}function Nr(e){return e.replace(/_bot$/,"")}var Zo=["openclaw","hermes"],ri=new Fe.Command("create").description("Create a new bot").argument("<name>","Bot name (4-20 chars, lowercase alphanumeric + underscores)").option("-r, --runtime <runtime>",`Bot runtime: ${Zo.join(" | ")}. Default is selected from this host's capabilities (Hermes preferred when available, OpenClaw otherwise \u2014 see \`badgerclaw setup\` output). Hermes requires HERMES_RUNTIME_ENABLED on the backend and a host that advertises Hermes capability via badgerclaw setup. Operator-side LLM credentials (BADGERCLAW_LLM_API_KEY or GOOGLE_API_KEY etc.) must be set at pair time, not at create time.`).action(async(e,t)=>{en(),ni(e)||(console.log(S.default.red("Invalid bot name. Must be 4-20 characters, lowercase alphanumeric and underscores only.")),process.exit(1));let o=t.runtime??Pr(ce());Zo.includes(o)||(console.log(S.default.red(`Invalid --runtime "${t.runtime}". Must be one of: ${Zo.join(", ")}.`)),process.exit(1));let n=(0,Xt.default)(`Creating ${o} bot "${e}"...`).start();try{let r=L();o==="hermes"?await r.post("/api/v1/bots",{bot_name:e,bot_username:e,runtime:"hermes"}):await r.post("/api/v1/openclaw/bots",{username:e}),n.succeed(S.default.green(`Bot "${e}" (${o}) created successfully!`)),o==="hermes"&&console.log(S.default.dim(" Next: generate a pair code from Adminweb (or POST /api/v1/pairing/create),\n then run `badgerclaw autopair` on a Hermes-capable host."))}catch(r){let s=r.response?.data?.errors?.[0]||r.message;n.fail(S.default.red(`Failed to create bot: ${s}`)),process.exit(1)}}),si=new Fe.Command("list").description("List your bots").action(async()=>{en();let e=(0,Xt.default)("Fetching bots...").start();try{let n=(await L().get("/api/v1/openclaw/bots")).data?.bots||[];if(e.stop(),n.length===0){console.log(S.default.yellow("No bots found. Create one with `badgerclaw bot create <name>`."));return}console.log(S.default.green(`Your bots (${n.length}):
126
- `));for(let r of n){let s=Nr(r.username||r.name),a=r.active===!1?S.default.dim("deactivated"):r.openclaw_connected?S.default.green("connected"):S.default.gray("disconnected");console.log(` ${S.default.bold(s)} ${a}`)}}catch(t){let o=t.response?.data?.errors?.[0]||t.message;e.fail(S.default.red(`Failed to list bots: ${o}`)),process.exit(1)}}),ai=new Fe.Command("delete").description("Deactivate a bot").argument("<name>","Bot name to deactivate").action(async e=>{en();let t=(0,Xt.default)(`Deactivating bot "${e}"...`).start();try{await L().delete(`/api/v1/openclaw/bots/${e}`),t.succeed(S.default.green(`Bot "${e}" deactivated.`));let{changed:n}=Yt(e);n&&(console.log(S.default.dim(" Removed from openclaw.json")),Jt()&&console.log(S.default.dim(" Gateway restarted")))}catch(o){let n=o.response?.data?.errors?.[0]||o.message;t.fail(S.default.red(`Failed to deactivate bot: ${n}`)),process.exit(1)}});function ii(e){let t=e.trim();return t.startsWith("@")&&(t=t.slice(1)),t.includes(":")&&(t=t.split(":")[0]),Nr(t)}function li(e){let t=e.replace(/[^a-zA-Z0-9_.-]/g,"_")||"default";return Or.default.join(Dr.default.homedir(),".openclaw","badgerclaw","quarantine",`${t}.json`)}var ci=new Fe.Command("refresh").description("Recover a bot stuck in quarantine \u2014 clears the quarantine ledger and restarts the gateway so the plugin's refresh chain runs from scratch").argument("<name>",'Bot name (e.g. "claude", "claude_bot", or full Matrix ID)').action(async e=>{let t=ii(e);t||(console.log(S.default.red(`Couldn't parse bot name "${e}".`)),process.exit(1));let o=li(t),n=!1;if(zt.default.existsSync(o))try{let r=JSON.parse(zt.default.readFileSync(o,"utf-8")),s=r.failureCount??"?",a=r.quarantinedAt??"?";console.log(S.default.dim(` Quarantine for "${t}" \u2014 ${s} failures, since ${a}`)),zt.default.unlinkSync(o),n=!0}catch(r){console.log(S.default.red(`Failed to clear quarantine ledger at ${o}: ${r.message}`)),process.exit(1)}console.log(n?S.default.green(`\u2705 Cleared quarantine for "${t}"`):S.default.dim(` No quarantine file for "${t}" \u2014 already healthy or never quarantined.`)),console.log(S.default.dim(" Restarting OpenClaw gateway so the refresh chain runs..."));try{(0,Lr.execSync)("openclaw gateway restart",{stdio:"inherit"})}catch(r){console.log(S.default.yellow(` Gateway restart command failed: ${r.message}`)),console.log(S.default.yellow(" Run `openclaw gateway restart` manually.")),process.exit(1)}console.log(S.default.green(`
127
- \u2705 Refresh triggered. Watch the gateway logs for token refresh progress:`)),console.log(S.default.dim(" tail -f ~/.openclaw/logs/*.log")),console.log(S.default.dim(" If the bot fails to recover, the plugin's 4 refresh strategies all hit")),console.log(S.default.dim(" dead ends. Verify SYNAPSE_REGISTRATION_SHARED_SECRET is set on this gateway,")),console.log(S.default.dim(" or re-pair the bot from the BadgerClaw iOS app."))}),Tr=new Fe.Command("bot").description("Manage bots").addCommand(ri).addCommand(si).addCommand(ai).addCommand(ci);rt();var Br=require("commander"),y=u(require("chalk"));M();oe();rt();ue();je();Yo();he();xe();var Mr=3e3,di=6e4,ui=2700*1e3,jr=new Br.Command("watch").description("Watch for bot pair events in real-time (no polling)").action(async()=>{b()||(console.log(y.default.yellow("Not logged in.")),process.exit(1)),await nt(!1),console.log(y.default.green("\u{1F534} Listening for pair events... (Ctrl+C to stop)"));let t=require("eventsource"),o=Mr,n=null,r=null,s=()=>{let a=b();a||(console.log(y.default.red(" Auth missing \u2014 run `badgerclaw login` and re-start `badgerclaw watch`.")),process.exit(1));let c=new t(`${N}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${a.access_token}`}});r=c,c.onopen=()=>{o=Mr,console.log(y.default.dim(" SSE connected \u2014 listening for events")),n&&clearTimeout(n),n=setTimeout(()=>{console.log(y.default.dim(" SSE proactive reconnect \u2014 refreshing token before expiry")),c.close(),s()},ui)},c.onerror=()=>{c.close(),n&&(clearTimeout(n),n=null),console.log(y.default.dim(` SSE disconnected \u2014 reconnecting in ${Math.floor(o/1e3)}s...`)),setTimeout(s,o),o=Math.min(o*1.5,di)},c.onmessage=async l=>{try{let i=JSON.parse(l.data);if(i.type==="pair"){let m=i.target_instance_id;if(m&&m!==Z()){console.log(y.default.dim(`
128
- \u{1F4F1} Pair event for ${i.bot_name} targets ${m} \u2014 not us, skipping`));return}console.log(y.default.cyan(`
129
- \u{1F4F1} Pair event received: ${i.bot_name}`)),await ot(i.pair_code,i.bot_name,i.bot_user_id,!1);try{let{execSync:p}=await import("child_process");p("openclaw gateway restart",{stdio:"ignore"}),console.log(y.default.green(" \u2705 Gateway restarted \u2014 bot is live!"))}catch{console.log(y.default.dim(" Gateway restart failed \u2014 run: openclaw gateway restart"))}}else if(i.type==="gateway-restart"){console.log(y.default.cyan(`
130
- \u{1F504} Remote gateway-restart command received`));let m=await Be();m.success?console.log(y.default.green(` \u2705 Gateway restarted: ${m.message}`)):console.log(y.default.red(` \u274C Gateway restart failed: ${m.message}`));try{await T(),console.log(y.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(y.default.dim(" Could not push heartbeat."))}}else if((i.type==="bot.delete"||i.type==="bot.disconnect")&&i.bot_user_id){let m=i.bot_user_id,p=i.type==="bot.delete"?"deleted":"disconnected",P=i.type==="bot.delete"?"\u{1F5D1}\uFE0F ":"\u{1F50C}";console.log(y.default.yellow(`
131
- ${P} Bot ${p}: ${m} \u2014 removing from OpenClaw config...`));try{let{changed:O}=Yt(m);O?(console.log(y.default.green(" \u2705 Removed from openclaw.json")),Jt()?console.log(y.default.green(" \u2705 Gateway restarted")):console.log(y.default.dim(" Gateway restart failed \u2014 restart manually"))):console.log(y.default.dim(" Account not found in openclaw.json \u2014 nothing to remove"))}catch(O){console.log(y.default.red(` Failed to update openclaw.json: ${O}`))}}else if(i.type==="claude_code.start"&&i.bot_id&&i.room_id){console.log(y.default.cyan(`
132
- \u{1F916} Claude Code START received: bot=${i.bot_id} room=${i.room_id}`));try{let m=await se({id:i.command_id||`cc-start-${Date.now()}`,command_type:"start_claude_code",payload:{bot_id:i.bot_id,room_id:i.room_id,session_id:i.session_id}});if(console.log(m.success?y.default.green(` \u2705 ${m.message}`):y.default.red(` \u274C ${m.message}`)),i.command_id)try{await L().post(`/api/v1/dashboard/commands/${i.command_id}/result`,{status:m.success?"success":"failed",result:m.message})}catch{}try{await T()}catch{}}catch(m){console.log(y.default.red(` Claude Code start error: ${m.message}`))}}else if(i.type==="claude_code.stop"&&i.bot_id&&i.room_id){console.log(y.default.cyan(`
133
- \u{1F916} Claude Code STOP received: bot=${i.bot_id} room=${i.room_id}`));try{let m=await se({id:i.command_id||`cc-stop-${Date.now()}`,command_type:"stop_claude_code",payload:{bot_id:i.bot_id,room_id:i.room_id,session_id:i.session_id}});if(console.log(m.success?y.default.green(` \u2705 ${m.message}`):y.default.red(` \u274C ${m.message}`)),i.command_id)try{await L().post(`/api/v1/dashboard/commands/${i.command_id}/result`,{status:m.success?"success":"failed",result:m.message})}catch{}try{await T()}catch{}}catch(m){console.log(y.default.red(` Claude Code stop error: ${m.message}`))}}else if(i.type==="command.execute"&&i.command_id){console.log(y.default.cyan(`
134
- \u26A1 SSE command received: ${i.command_type} (${i.command_id})`));try{let m=L();await m.post(`/api/v1/dashboard/commands/${i.command_id}/ack`);let p=await se({id:i.command_id,command_type:i.command_type,payload:i.payload});console.log(p.success?y.default.green(` \u2705 ${p.message}`):y.default.red(` \u274C ${p.message}`)),await m.post(`/api/v1/dashboard/commands/${i.command_id}/result`,{status:p.success?"success":"failed",result:p.message,new_version:p.newVersion||null});try{await T()}catch{}i.command_type==="update_cli"&&p.success&&(console.log(y.default.cyan(" CLI updated \u2014 restarting in 2s...")),setTimeout(()=>process.exit(0),2e3))}catch(m){console.log(y.default.red(` Command ${i.command_id} error: ${m.message}`))}}}catch{}}};s(),await new Promise(()=>{})});var as=require("commander"),d=u(require("chalk")),te=require("child_process"),R=u(require("fs")),ft=u(require("os")),ae=u(require("path"));oe();Ee();var pt=u(require("fs")),Ge=u(require("path")),Qt=require("child_process"),mi=["request","request-promise"];function pi(e){let t=e.match(/^(\s*)(?:"([^"]+)"|'([^']+)'|([^:#\s][^:]*?))\s*:/);return t?{indent:t[1].length,key:(t[2]??t[3]??t[4]??"").trim()}:null}function gi(e){let t=e.split(`
135
- `),o=[],n=!1,r=-1,s=!1,a=new Set(mi);for(let c of t){let l=pi(c);if(!n){l&&l.indent===0&&l.key==="overrides"&&(n=!0,r=l.indent),o.push(c);continue}if(l&&l.indent<=r){n=!1,o.push(c);continue}if(l&&l.indent>r&&a.has(l.key)){s=!0;continue}o.push(c)}return s?o.join(`
136
- `):null}function fi(){let e=[],t=(0,Qt.spawnSync)("npm",["root","-g"],{encoding:"utf-8",shell:!0});t.status===0&&t.stdout?.trim()&&e.push(Ge.default.join(t.stdout.trim(),"openclaw","pnpm-workspace.yaml"));let o=(0,Qt.spawnSync)("npm",["prefix","-g"],{encoding:"utf-8",shell:!0});o.status===0&&o.stdout?.trim()&&e.push(Ge.default.join(o.stdout.trim(),"lib","node_modules","openclaw","pnpm-workspace.yaml"));let n=(0,Qt.spawnSync)("which",["openclaw"],{encoding:"utf-8"});if(n.status===0&&n.stdout?.trim()){let r=Ge.default.dirname(Ge.default.dirname(n.stdout.trim()));e.push(Ge.default.join(r,"lib","node_modules","openclaw","pnpm-workspace.yaml"))}for(let r of e)try{if(pt.default.existsSync(r))return r}catch{}return null}function Hr(){let e=fi();if(!e)return null;let t;try{t=pt.default.readFileSync(e,"utf-8")}catch{return null}let o=gi(t);if(o===null)return null;try{pt.default.writeFileSync(e,o)}catch{return null}return{yamlPath:e,original:t}}function Ur(e){if(!e)return!1;try{return pt.default.writeFileSync(e.yamlPath,e.original),!0}catch{return!1}}_e();var qe=require("child_process"),Gr=u(require("fs")),D=u(require("chalk")),F={alreadyUp:!1,install:null,start:null,requiresRoot:!1,networkHostRequired:!1,guidance:null},Fr='On this distro the bare "docker" package is the podman shim (no dockerd). Install Docker Engine from the official docker-ce repository (https://docs.docker.com/engine/install/), then re-run `badgerclaw setup --hermes`.';function hi(e){return e.daemonUp?{...F,alreadyUp:!0}:e.host==="darwin"?e.hasDockerApp?{...F,start:"docker-app"}:e.hasColima?{...F,start:"colima"}:e.binaryPresent?{...F,guidance:"A `docker` CLI is present but no engine we can start (Docker.app / colima) was found and the daemon is not answering. Start your Docker daemon (or `colima start`), then re-run `badgerclaw setup --hermes`."}:e.hasBrew?{...F,install:{tool:"colima",via:"brew"},start:"colima"}:{...F,guidance:"No container engine found and Homebrew is absent. Install Docker Desktop (https://www.docker.com/products/docker-desktop) or Homebrew (https://brew.sh) then colima, and re-run `badgerclaw setup --hermes`."}:e.host==="linux-systemd"?e.binaryPresent?{...F,start:"systemctl",requiresRoot:!0}:e.pkgManager==="apt"?{...F,install:{tool:"docker",via:"apt"},start:"systemctl",requiresRoot:!0}:{...F,guidance:e.pkgManager?Fr:"Docker is not installed and no supported package manager (apt) was found. Install Docker, then re-run."}:e.host==="linux-nosystemd"?e.binaryPresent?{...F,start:"dockerd-restricted",requiresRoot:!0,networkHostRequired:!0}:e.pkgManager==="apt"?{...F,install:{tool:"docker",via:"apt"},start:"dockerd-restricted",requiresRoot:!0,networkHostRequired:!0}:{...F,guidance:e.pkgManager?Fr:"Docker is not installed and no supported package manager (apt) was found. Install Docker (e.g. `apt-get install -y docker.io`), then re-run."}:{...F,guidance:`Automatic Docker setup isn't supported on this platform (${process.platform}). Install + start Docker manually, then re-run.`}}function Wr(e,t,o=8e3){return(0,qe.spawnSync)(e,t,{encoding:"utf-8",timeout:o})}function tn(){let e=Wr("docker",["version","--format","{{.Server.Version}}"],4e3);return e.status===0&&!!(e.stdout||"").trim()}function yi(){return Wr("docker",["--version"],4e3).status===0}function We(e){return(0,qe.spawnSync)("sh",["-c",`command -v ${e}`],{encoding:"utf-8"}).status===0}function wi(){return We("apt-get")?"apt":We("dnf")?"dnf":We("yum")?"yum":null}function bi(){let e=(0,qe.spawnSync)("systemctl",["is-system-running"],{encoding:"utf-8",timeout:4e3});if(e.error)return!1;let t=`${e.stdout||""}${e.stderr||""}`.toLowerCase();return!/failed to connect to bus|not been booted with systemd|no such file/.test(t)}function _i(){return process.platform==="darwin"?"darwin":process.platform==="linux"?bi()?"linux-systemd":"linux-nosystemd":"unsupported"}function Si(){return typeof process.getuid=="function"?process.getuid()===0:!1}function pe(e,t){return t(D.default.dim(` $ ${e}`)),(0,qe.spawnSync)("sh",["-c",e],{stdio:"inherit"}).status===0}function ki(e,t,o){let n=t?"sudo ":"";switch(e.via){case"brew":return o(D.default.dim(" Installing colima + docker CLI via Homebrew...")),pe("brew install colima docker",o);case"apt":return o(D.default.dim(" Installing Docker via apt...")),pe(`${n}apt-get update`,o),pe(`${n}apt-get install -y docker.io`,o);default:return!1}}function vi(e,t,o){let n=t?"sudo ":"";switch(e){case"docker-app":return pe("open -a Docker",o);case"colima":return pe("colima start",o);case"systemctl":return pe(`${n}systemctl enable --now docker`,o);case"dockerd-restricted":{if(!We("dockerd"))return o(D.default.red(" \u274C `dockerd` is not installed (the docker CLI alone is not enough on a no-systemd host).")),!1;if(t&&!pe("sudo -v",o))return o(D.default.red(" \u274C root is required to start dockerd here, but sudo is unavailable.")),!1;pe(`${n}sh -c 'mount -t cgroup2 none /sys/fs/cgroup 2>/dev/null || true'`,o);let r="/tmp/badgerclaw-dockerd.log";o(D.default.dim(` Starting dockerd (restricted: --bridge=none --iptables=false) \u2192 ${r}`));let s=`nohup dockerd --storage-driver=overlay2 --iptables=false --bridge=none > ${r} 2>&1 &`,a=t?`sudo sh -c ${JSON.stringify(s)}`:`sh -c ${JSON.stringify(s)}`;return(0,qe.spawnSync)("sh",["-c",a],{stdio:"ignore"}).status===0}}}async function $i(e,t,o){let n=Date.now()+t;for(;;){if(e())return!0;if(Date.now()>=n)return!1;await new Promise(r=>setTimeout(r,o))}}async function qr(e={}){let t=e.log??(a=>console.log(a));if(process.env.BADGERCLAW_NO_AUTO_DEPS==="1"){let a=tn();return a||(t(D.default.yellow(" BADGERCLAW_NO_AUTO_DEPS=1 \u2014 skipping automatic Docker setup.")),t(D.default.dim(" Start the Docker daemon yourself, then re-run `badgerclaw setup --hermes`."))),{ok:a,daemonUp:a,networkHostRequired:!1}}let o={daemonUp:tn(),binaryPresent:yi(),host:_i(),hasBrew:We("brew"),hasDockerApp:Gr.default.existsSync("/Applications/Docker.app"),hasColima:We("colima"),pkgManager:wi(),isRoot:Si()},n=hi(o);if(n.alreadyUp)return{ok:!0,daemonUp:!0,networkHostRequired:!1};if(n.guidance)return t(D.default.red(` \u274C ${n.guidance}`)),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired};let r=n.requiresRoot&&!o.isRoot;return r&&t(D.default.dim(" (some steps need root \u2014 using sudo; you may be prompted for your password)")),n.install&&!ki(n.install,r,t)?(t(D.default.red(" \u274C Docker install failed (see output above). Install it manually, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired}):vi(n.start,r,t)?(t(D.default.dim(" Waiting for the Docker daemon to answer...")),await $i(tn,12e4,1500)?(t(D.default.green(" \u2705 Docker daemon is up.")),{ok:!0,daemonUp:!0,networkHostRequired:n.networkHostRequired}):(t(D.default.red(" \u274C Docker did not become ready in time.")),n.start==="dockerd-restricted"?t(D.default.dim(" Check /tmp/badgerclaw-dockerd.log for the daemon output.")):n.start==="docker-app"&&t(D.default.dim(" Docker Desktop can take a minute to boot \u2014 re-run once its menu-bar icon is steady.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired})):(t(D.default.red(" \u274C Could not start Docker (see output above). Resolve it, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired})}function Vr(e){let t=e.minMajor??18;if(!Number.isFinite(e.nodeMajor)||e.nodeMajor<t){let o=Number.isFinite(e.nodeMajor)?`Node v${e.nodeMajor}`:"an unknown Node version";return`badgerclaw requires Node.js >= ${t} (this is ${o}). Upgrade Node \u2014 nodesource (https://github.com/nodesource/distributions) or nvm (\`nvm install ${t}\`) \u2014 then re-run \`badgerclaw setup --hermes\`.`}return e.npmPresent?null:`npm was not found on PATH. badgerclaw is installed and updated via npm \u2014 install Node.js ${t}+ (which bundles npm) and re-run \`badgerclaw setup --hermes\`.`}function Kr(e=process.versions.node){return parseInt(String(e).split(".")[0],10)}var on=require("child_process"),Zt=u(require("fs")),Yr=u(require("os")),eo=u(require("path"));_e();De();function Ci(){let e=Jr();for(let t of e)if(Zt.default.existsSync(t))return t;return null}function Jr(){return[eo.default.resolve(__dirname,"..","assets","hermes-agent-bc.Dockerfile"),eo.default.resolve(__dirname,"..","..","assets","hermes-agent-bc.Dockerfile")]}var Ii="nousresearch/hermes-agent";function Ri(e){let t=(process.env.HERMES_UPSTREAM||e?.upstream||"").trim();if(!t)return;if(t.includes("/"))return t;let o=t.includes(":")?t.split(":").pop():t;return`${Ii}:${o}`}var xi={run:e=>{let t=(0,on.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};function Ai(e){return["build",...e.hostNetwork?["--network","host"]:[],...e.upstreamRef?["--build-arg",`UPSTREAM=${e.upstreamRef}`]:[],"-t",e.image,"-f",e.dockerfile,e.ctxDir]}function zr(e){let t=Rt();if(!t.installed)return{status:"no-docker"};let o=process.env.HERMES_IMAGE||Pe;if(xt(t).installed)return{status:"already-present",image:o};let r=Ci();if(!r)return{status:"no-dockerfile",expectedPaths:Jr()};let s=Ri(e),a=So({bridgeUsable:()=>Dt(xi)}),c=Zt.default.mkdtempSync(eo.default.join(Yr.default.tmpdir(),"bc-hermes-build-"));try{let l=(0,on.spawnSync)("docker",Ai({hostNetwork:a,upstreamRef:s,image:o,dockerfile:r,ctxDir:c}),{stdio:"inherit",timeout:6e5});return l.status===0?{status:"built",image:o}:{status:"build-failed",image:o,stderr:`docker build exited ${l.status??"<no-status>"}`}}finally{try{Zt.default.rmSync(c,{recursive:!0,force:!0})}catch{}}}M();var nn=require("child_process"),Ei="https://ollama.com/download",Pi={run:(e,t)=>{let o=(0,nn.spawnSync)(e,t,{encoding:"utf-8",timeout:1e4});return{status:o.status,stdout:o.stdout||"",stderr:o.stderr||""}}};function Xr(e={}){let t=e.runner??Pi,o=t.run("ollama",["--version"]);if(o.status!==0)return{installed:!1,serving:!1};let n=(o.stdout||"").match(/(\d+\.\d+\.\d+)/),r=n?n[1]:void 0;return{installed:!0,serving:t.run("ollama",["list"]).status===0,version:r}}function Qr(e){return e.installed?e.serving?"Ollama is installed and serving.":"Ollama is installed but its server isn't running. Start it with `ollama serve` (or open the Ollama app), then re-run setup.":`Ollama is not installed. Install it from ${Ei}, then re-run setup.`}function Zr(e,t={}){if(t.runner){let n=t.runner.run("ollama",["pull",e]);return n.status===0?{ok:!0}:{ok:!1,error:(n.stderr||n.stdout||`exit ${n.status}`).trim()}}let o=(0,nn.spawnSync)("ollama",["pull",e],{stdio:t.inheritStdio===!1?"pipe":"inherit",encoding:"utf-8"});return o.status===0?{ok:!0}:{ok:!1,error:(o.stderr||`ollama pull ${e} failed (exit ${o.status})`).toString().trim()}}var es=u(require("os")),ts=u(require("readline"));oe();De();function Di(){return Math.round(es.default.totalmem()/1024/1024/1024)}async function Oi(e,t,o={}){let n=o.apiBase??N,r=o.fetchImpl??fetch,s=`${n}/api/v1/dashboard/recommended-models?ram_gb=${encodeURIComponent(e)}&runtime=${encodeURIComponent(t)}`;try{let a=await r(s,{headers:{Accept:"application/json"}});if(!a.ok)return null;let c=await a.json(),l=c.result&&typeof c.result=="object"?c.result:c;return Array.isArray(l.recommended)?l:null}catch{return null}}async function Li(e){let t=ts.default.createInterface({input:process.stdin,output:process.stdout});try{return await new Promise(o=>t.question(e,o))}finally{t.close()}}function Ni(e){let t=e.verdict==="great"?"great":e.verdict==="usable"?"usable":e.verdict,o=e.decode_tps!=null?`${e.decode_tps} tok/s`:"speed not yet benchmarked",n=e.is_top_pick?" (recommended)":"";return`${e.model_name} [${e.ollama_tag}] \u2014 ${t}, ${o}. ${e.why}${n}`}async function Ti(e,t){let o=e.recommended;if(!o||o.length===0)return{tag:null,note:e.note,model:null};let n=o.find(i=>i.is_top_pick)??o[0];if(t.preferredTag){let i=o.find(m=>m.ollama_tag===t.preferredTag);return i?{tag:i.ollama_tag,note:e.note,model:i}:{tag:t.preferredTag,note:e.note,model:null}}if(!t.interactive)return{tag:n.ollama_tag,note:e.note,model:n};let r=t.log??(i=>console.log(i)),s=t.prompt??Li;r(`
137
- Local models that fit ${e.ram_gb} GB (${e.ram_tier}):`),o.forEach((i,m)=>{r(` ${i===n?"*":" "} ${m+1}) ${Ni(i)}`)});let a=o.indexOf(n)+1,c=(await s(` Pick a model [${a}]: `)).trim();if(!c)return{tag:n.ollama_tag,note:e.note,model:n};let l=Number.parseInt(c,10);if(Number.isInteger(l)&&l>=1&&l<=o.length){let i=o[l-1];return{tag:i.ollama_tag,note:e.note,model:i}}return{tag:n.ollama_tag,note:e.note,model:n}}async function os(e){let t=e.ramGb??Di(),o=await Oi(t,e.runtime,{apiBase:e.apiBase,fetchImpl:e.fetchImpl});if(!o)return{tag:e.preferredTag||_o("ollama"),note:"Could not reach the model-recommendation service \u2014 using a safe default model.",ramGb:t,fellBack:!0};let n=await Ti(o,{interactive:e.interactive,preferredTag:e.preferredTag,prompt:e.prompt,log:e.log});return{tag:n.tag,note:n.note,ramGb:t,fellBack:!1}}De();var z=ae.default.join(ft.default.homedir(),".openclaw","openclaw.json"),gt=z+".badgerclaw-stash",is=ae.default.join(ft.default.homedir(),".openclaw","npm"),Mi=ae.default.join(is,"package.json");async function ns(){try{let e=await fetch(`${N}/api/v1/dashboard/versions/latest`,{headers:{Accept:"application/json"}});if(!e.ok)return{cli:null,plugin:null,openclaw:null,hermes:null};let t=await e.json(),o=t.result&&typeof t.result=="object"?t.result:t,n=r=>typeof r!="string"||!r||r==="unknown"?null:r;return{cli:n(o.cli),plugin:n(o.plugin),openclaw:n(o.supported_openclaw),hermes:n(o.supported_hermes)}}catch{return{cli:null,plugin:null,openclaw:null,hermes:null}}}function Bi(){if(!R.default.existsSync(z))return null;try{let e=JSON.parse(R.default.readFileSync(z,"utf-8")),t=e.channels?.badgerclaw;return t?(delete e.channels.badgerclaw,e.plugins?.entries?.badgerclaw&&delete e.plugins.entries.badgerclaw,R.default.writeFileSync(z,JSON.stringify(e,null,2)),R.default.writeFileSync(gt,JSON.stringify(t,null,2)),t):null}catch{return null}}function ji(){if(!R.default.existsSync(z))return null;try{let e=JSON.parse(R.default.readFileSync(z,"utf-8"));return!e.gateway||typeof e.gateway!="object"?null:JSON.parse(JSON.stringify(e.gateway))}catch{return null}}function Hi(e){if(e&&R.default.existsSync(z))try{let t=JSON.parse(R.default.readFileSync(z,"utf-8"));t.gateway={...e,...t.gateway||{}},R.default.writeFileSync(z,JSON.stringify(t,null,2))}catch(t){console.log(d.default.yellow(` \u26A0\uFE0F Could not restore gateway block: ${t.message}`)),console.log(d.default.yellow(" Run `openclaw config set gateway.mode local` manually if the gateway fails to start."))}}function Ui(){if(R.default.existsSync(gt))try{let e=JSON.parse(R.default.readFileSync(gt,"utf-8")),t=JSON.parse(R.default.readFileSync(z,"utf-8"));t.channels=t.channels||{},t.channels.badgerclaw=e,R.default.writeFileSync(z,JSON.stringify(t,null,2)),R.default.unlinkSync(gt)}catch(e){console.log(d.default.yellow(` \u26A0\uFE0F Could not restore config: ${e.message}`)),console.log(d.default.yellow(` Your bot credentials are backed up at: ${gt}`))}}async function rs(e){return new Promise(t=>{let o=(0,te.spawn)("openclaw",["plugins","install",e,"--force","--dangerously-force-unsafe-install"],{stdio:["ignore","pipe","pipe"],shell:!0}),n="",r=!1,s=!1,a=/Installed plugin:|Restart the gateway to load plugins/,c=()=>{r||s||(r=!0,setTimeout(()=>{if(!s){try{o.kill("SIGTERM")}catch{}setTimeout(()=>{if(!s)try{o.kill("SIGKILL")}catch{}},1e3)}},3e3))},l=(i,m)=>{m.write(i),n+=i.toString("utf-8"),a.test(n)&&c()};o.stdout.on("data",i=>l(i,process.stdout)),o.stderr.on("data",i=>l(i,process.stderr)),o.on("exit",i=>{s=!0,t({status:r?0:i??1})}),o.on("error",i=>{s||(s=!0,console.error(d.default.red(` openclaw spawn error: ${i.message}`)),t({status:1}))})})}function ss(e){if(!R.default.existsSync(e))return!1;let t;try{t=JSON.parse(R.default.readFileSync(e,"utf-8"))}catch{return!1}let o=!1;return t.overrides&&typeof t.overrides=="object"&&"uuid"in t.overrides&&(delete t.overrides.uuid,o=!0),t.openclaw&&Array.isArray(t.openclaw.managedOverrides)&&t.openclaw.managedOverrides.includes("uuid")&&(t.openclaw.managedOverrides=t.openclaw.managedOverrides.filter(n=>n!=="uuid"),o=!0),o?(R.default.writeFileSync(e,JSON.stringify(t,null,2)+`
138
- `),!0):!1}function Fi(){let e=[];ss(Mi)&&e.push(is);for(let t of Ct())ss(ae.default.join(t,"package.json"))&&e.push(t);return e}async function Gi(){let{detectCapabilities:e}=await Promise.resolve().then(()=>(_e(),Ln)),{pushHeartbeat:t}=await Promise.resolve().then(()=>(je(),zo));console.log(d.default.green(`
125
+ `}function Vr(){try{return(0,Z.execSync)("systemctl --user --version",{stdio:"ignore"}),!0}catch{return!1}}function Wr(){if(kt.default.platform()!=="linux"||!Vr())return!1;try{let e=ji();ze.default.mkdirSync(qr,{recursive:!0}),ze.default.mkdirSync(Rt.default.join(kt.default.homedir(),".badgerclaw"),{recursive:!0}),ze.default.writeFileSync(ro,Ui(e)),(0,Z.execSync)("systemctl --user daemon-reload",{stdio:"ignore"});try{(0,Z.execSync)(`systemctl --user restart ${rn}`,{stdio:"ignore"})}catch{}(0,Z.execSync)(`systemctl --user enable --now ${rn}`,{stdio:"ignore"});try{let t=(0,Z.execSync)("whoami",{encoding:"utf-8"}).trim();(0,Z.execSync)(`loginctl enable-linger ${t}`,{stdio:"ignore"})}catch{}return console.log("\x1B[2mHeartbeat daemon registered as systemd user service (auto-starts on login).\x1B[0m"),!0}catch{return!1}}function Kr(){if(kt.default.platform()==="linux"&&Vr()){try{(0,Z.execSync)(`systemctl --user disable --now ${rn}`,{stdio:"ignore"})}catch{}try{ze.default.existsSync(ro)&&ze.default.unlinkSync(ro),(0,Z.execSync)("systemctl --user daemon-reload",{stdio:"ignore"})}catch{}}}var so=an.default.join(sn.default.homedir(),".badgerclaw"),Ct=an.default.join(so,"heartbeat.pid"),Fi=an.default.join(so,"heartbeat.log");function Hi(e){if(!e||e.length===0)return!1;let t=s=>/(^|[\\/])node(\.exe)?$/i.test(s||""),n=t(e[0])||t(e[1]),o=e.includes("heartbeat"),r=e.some(s=>/(^|[\\/])badgerclaw($|[\\/. ])/i.test(s)||/[\\/]dist[\\/]index\.js$/.test(s));return n&&o&&r}function Gi(e){try{if(process.platform==="linux")return ee.default.readFileSync(`/proc/${e}/cmdline`).toString("utf-8").split("\0").filter(Boolean);let t=(0,Te.execSync)(`ps -o args= -p ${e}`,{encoding:"utf-8"}).trim();return t.length?t.split(/\s+/).filter(Boolean):null}catch{return null}}function ao(e){if(!Number.isFinite(e)||e<=0||e===process.pid||e===process.ppid)return!1;let t=Gi(e);return t?Hi(t):!1}function io(){let e="";try{e=(0,Te.execSync)("pgrep -f heartbeat",{encoding:"utf-8"})}catch{return[]}return e.split(/\s+/).map(t=>parseInt(t,10)).filter(t=>Number.isFinite(t)&&t>0).filter(t=>ao(t))}function qi(e){try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,Math.max(0,e))}catch{}}function Vi(e){try{if(process.platform==="linux"){let r=ee.default.readFileSync(`/proc/${e}/status`,"utf-8").match(/^PPid:\s*(\d+)/m),s=r?parseInt(r[1],10):NaN;if(!Number.isFinite(s))return null;let a="";try{a=ee.default.readFileSync(`/proc/${s}/comm`,"utf-8").trim()}catch{}return{ppid:s,comm:a}}let t=parseInt((0,Te.execSync)(`ps -o ppid= -p ${e}`,{encoding:"utf-8"}).trim(),10);if(!Number.isFinite(t))return null;let n="";try{n=(0,Te.execSync)(`ps -o comm= -p ${t}`,{encoding:"utf-8"}).trim()}catch{}return{ppid:t,comm:n}}catch{return null}}var Wi=/(systemd|supervisord|launchd|runsv|runit|s6-supervise|openrc)/i;function Ki(){for(let e of io()){let t=Vi(e);if(t&&Wi.test(t.comm))return e}return null}function Yi(){try{let e=parseInt(ee.default.readFileSync(Ct,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&ao(e))return!0}catch{}return Jr(),io().length>0}function Jr(){try{let e=parseInt(ee.default.readFileSync(Ct,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&ao(e))return}catch{}try{ee.default.rmSync(Ct,{force:!0})}catch{}}function Ji(e="SIGTERM"){let t=io(),n=0;for(let a of t)try{process.kill(a,e),n++}catch{}if(n===0)return 0;let o=a=>{try{return process.kill(a,0),!0}catch{return!1}},r=Date.now()+4e3,s=t.filter(o);for(;s.length>0&&Date.now()<r;)qi(120),s=s.filter(o);for(let a of s)try{process.kill(a,"SIGKILL")}catch{}return n}function Yr(){if(Yi())return console.log("\x1B[2mHeartbeat already running.\x1B[0m"),!0;try{ee.default.mkdirSync(so,{recursive:!0});let e=ee.default.openSync(Fi,"a"),t=(0,Te.spawn)(process.execPath,[process.argv[1],"heartbeat"],{detached:!0,stdio:["ignore",e,e]});if(t.pid==null)return console.log("\x1B[2mNote: could not start the heartbeat. Run `badgerclaw heartbeat` manually.\x1B[0m"),!1;try{ee.default.writeFileSync(Ct,String(t.pid))}catch{}return t.unref(),console.log("\x1B[2mHeartbeat started in the background (no service manager on this host; it will not auto-restart after a reboot \u2014 re-run `badgerclaw setup --hermes` or `badgerclaw heartbeat` if the host restarts).\x1B[0m"),!0}catch{return console.log("\x1B[2mNote: could not start the heartbeat. Run `badgerclaw heartbeat` manually.\x1B[0m"),!1}}function lo(){let e=sn.default.platform();if(e==="darwin"){Hr();return}if(e==="linux"){if(Wr())return;Yr();return}Yr()}function zi(){let e=sn.default.platform();e==="darwin"?Gr():e==="linux"&&Kr(),Ji();try{ee.default.rmSync(Ct,{force:!0})}catch{}}function zr(e){let t=e.log||(()=>{}),n=Ki();if(n!==null){Jr(),t(`heartbeat already supervised (pid ${n}) \u2014 left in place; cleared any stale pid file.`);return}zi(),t("removed stale heartbeat hooks from previous installs."),e.loggedIn?(lo(),t("reinstalled a fresh heartbeat daemon for this host.")):t("run `badgerclaw login` to start the heartbeat for this host.")}var Re=m(require("fs")),po=m(require("os")),cn=m(require("path")),ce=require("child_process"),V=m(require("chalk"));ht();ke();var Xr=cn.default.join(po.default.homedir(),".openclaw","openclaw.json");function el(){return process.platform!=="linux"?!1:!!(Re.default.existsSync("/.dockerenv")||(0,ce.spawnSync)("which",["systemctl"],{encoding:"utf-8"}).status!==0)}function Zr(e=!1){let t=null;try{Re.default.existsSync(Xr)&&(t=JSON.parse(Re.default.readFileSync(Xr,"utf-8"))?.gateway?.mode??null)}catch{}if(typeof t=="string"&&t.length>0)return!0;e||console.log(V.default.dim(" Setting gateway.mode=local..."));try{return Ee(()=>((0,ce.execSync)("openclaw config set gateway.mode local",{encoding:"utf-8",timeout:1e4,stdio:"pipe"}),!0))}catch(n){return e||(console.log(V.default.yellow(` \u26A0\uFE0F Could not set gateway.mode automatically: ${n.message}`)),console.log(V.default.yellow(" Run `openclaw config set gateway.mode local` manually."))),!1}}async function un(e={}){let t=e.verbose!==!1,n=i=>{t&&console.log(i)};if(el())return nl(t);n(V.default.dim(" Installing OpenClaw gateway service (if not present)...")),(0,ce.spawnSync)("openclaw",["gateway","install"],{stdio:t?"inherit":"pipe",shell:!0}).status!==0&&n(V.default.yellow(" \u26A0\uFE0F `openclaw gateway install` returned non-zero \u2014 continuing.")),Zr(!t),n(V.default.dim(" Starting OpenClaw gateway..."));let r=(0,ce.spawnSync)("openclaw",["gateway","start"],{stdio:t?"inherit":"pipe",shell:!0}),s="started";if(r.status!==0&&(r=(0,ce.spawnSync)("openclaw",["gateway","restart"],{stdio:t?"inherit":"pipe",shell:!0}),s="restarted"),r.status!==0)return{ok:!1,error:"gateway start/restart returned non-zero exit"};n(V.default.dim(" Waiting for the gateway to start answering..."));let a=await tl(2e4);return a||n(V.default.yellow(" \u26A0\uFE0F Gateway start issued but it is not answering yet \u2014 it may still be booting.")),{ok:!0,state:s,ready:a}}async function tl(e,t=uo,n=500){let o=Date.now()+e;for(;;){if(await t())return!0;if(Date.now()>=o)return!1;await new Promise(r=>setTimeout(r,n))}}async function nl(e){let t=l=>{e&&console.log(l)};t(V.default.dim(" Container mode (no systemd) \u2014 running gateway in foreground via nohup.")),Zr(!e);let n=cn.default.join(po.default.homedir(),".openclaw","logs");try{Re.default.mkdirSync(n,{recursive:!0})}catch{}let o=cn.default.join(n,"gateway-foreground.log"),r,s;try{r=Re.default.openSync(o,"a"),s=Re.default.openSync(o,"a")}catch(l){return{ok:!1,error:`cannot open gateway log at ${o}: ${l.message}`}}let a=(0,ce.spawn)("openclaw",["gateway"],{detached:!0,stdio:["ignore",r,s]});if(a.pid==null)return{ok:!1,error:"failed to spawn `openclaw gateway`"};a.unref(),t(V.default.dim(` Gateway PID: ${a.pid}, log: ${o}`));let i=Date.now()+2e4,c=!1;for(;Date.now()<i;){try{let l=Re.default.readFileSync(o,"utf-8");if(l.includes("[gateway] ready")){c=!0;break}if(/EADDRINUSE|FATAL|Error:|gateway start blocked/.test(l))return{ok:!1,error:`gateway aborted on startup \u2014 see ${o}`}}catch{}await new Promise(l=>setTimeout(l,200))}return c?{ok:!0,state:"started",ready:!0}:{ok:!1,error:`gateway did not report ready within 20s \u2014 see ${o}`}}function dn(){if(process.platform!=="linux"||process.getuid?.()!==0)return;let e=(0,ce.spawnSync)("loginctl",["show-user","root","--property=Linger"],{encoding:"utf-8"});e.status===0&&/Linger=no/.test(e.stdout||"")&&(console.log(V.default.yellow(`
126
+ \u26A0\uFE0F systemd lingering is OFF for root. The gateway will stop on SSH disconnect.`)),console.log(V.default.dim(" Enable persistence: loginctl enable-linger root")))}Ge();var Ml=2e3,Dl=12e4,ps=new us.Command("login").description("Log in to BadgerClaw via browser").action(async()=>{let e=er(),t=tr(e),n=`${ar}/cli-auth?code=${t}`;console.log(z.default.yellow("Opening browser for authentication...")),console.log(z.default.dim(`If the browser doesn't open, visit: ${n}`)),await(0,ms.default)(n);let o=(0,ds.default)("Waiting for authentication...").start(),r=dr(),s=Date.now();for(;Date.now()-s<Dl;){try{let a=await r.post(`/api/v1/openclaw/cli/auth/poll/${t}`,{code_verifier:e,code_challenge:t});if(a.status===429){await new Promise(i=>setTimeout(i,5e3));continue}if(a.data?.access_token){let{access_token:i,user_id:c,expires_at:l,refresh_token:u,email:p}=a.data,S=mt(),E=`openclaw-${Ao.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${S}`,g=E;try{let{version:h}=we(),y=await r.post("/api/v1/openclaw/register",{instance_id:E,label:Ao.default.hostname(),version:h,machine_fingerprint:S},{headers:{Authorization:`Bearer ${i}`}}),b=y.data?.result||y.data;b&&typeof b.instance_id=="string"&&b.instance_id.length>0&&(g=b.instance_id)}catch(h){let y=h?.response?.status;if(y===403||y===409){let b=h?.response?.data,j=Array.isArray(b?.errors)&&typeof b.errors[0]=="string"?b.errors[0]:null,oe=b?.detail,re=typeof oe=="string"?oe:oe?.error==="downgrade_selection_required"?"Your account has an unresolved plan-change request. Open the BadgerClaw app to finish the downgrade selection, then try again.":null,k=j||re||`Login refused (status ${y}). Open the BadgerClaw app to check your subscription state.`;o.fail(z.default.red(k)),process.exit(1)}}if(Ut({access_token:i,user_id:c,instance_id:g,expires_at:l,refresh_token:u,email:p}),o.succeed(z.default.green(`Logged in as ${Ht(c)}`)),K()!==null){let h=await un({verbose:!0});h.ok?h.ready===!1&&console.log(z.default.dim(" Gateway is still coming up \u2014 it should be online shortly.")):console.log(z.default.yellow("\n \u26A0\uFE0F Logged in, but gateway failed to start. Re-run `badgerclaw setup` to repair."))}else console.log(z.default.dim(" Hermes-only host \u2014 skipping OpenClaw gateway bring-up."));let v=await St(!0);v>0&&console.log(z.default.green(`\u2705 ${v} bot(s) automatically paired to OpenClaw.`)),lo(),dn();try{let{pushHeartbeat:h}=await Promise.resolve().then(()=>(Xe(),Io));await h(),console.log(z.default.dim(" Capabilities pushed \u2014 the machine should show online shortly."))}catch(h){console.log(z.default.dim(` Capability push will retry via the heartbeat (${h?.message||h}).`))}return}}catch{}await new Promise(a=>setTimeout(a,Ml))}o.fail(z.default.red("Authentication timed out. Please try again.")),process.exit(1)});var fs=require("commander"),It=m(require("chalk")),bn=m(require("fs")),Ze=m(require("os")),Pt=m(require("path")),At=require("child_process");F();Ae();function Nl(){let e=process.platform;if(e==="darwin"){let t=Pt.default.join(Ze.default.homedir(),"Library","LaunchAgents","ai.badgerclaw.watch.plist");(0,At.spawnSync)("launchctl",["unload",t],{stdio:"ignore"});try{bn.default.unlinkSync(t)}catch{}}else if(e==="linux"){(0,At.spawnSync)("systemctl",["--user","disable","--now","badgerclaw-watch.service"],{stdio:"ignore"});let t=Pt.default.join(Ze.default.homedir(),".config","systemd","user","badgerclaw-watch.service");try{bn.default.unlinkSync(t)}catch{}(0,At.spawnSync)("systemctl",["--user","daemon-reload"],{stdio:"ignore"})}(0,At.spawnSync)("pkill",["-f","badgerclaw heartbeat"],{stdio:"ignore"})}function gs(e){try{return bn.default.rmSync(e,{recursive:!0,force:!0}),!0}catch{return!1}}var hs=new fs.Command("logout").description("Disconnect this machine, log out of BadgerClaw, and wipe local state").option("--keep-state","Only clear auth.json (legacy behaviour); preserve bot-mapping, claude-sessions, heartbeat logs, and plugin quarantine ledger").action(async e=>{let t=R();if(t)try{let a=ft(t.access_token),{version:i}=we();await a.post("/api/v1/openclaw/register",{instance_id:t.instance_id,label:Ze.default.hostname(),version:i,online:!1})}catch{}if(Nl(),e.keepState){dt(),console.log(It.default.green("Logged out \u2014 auth cleared. (state preserved with --keep-state)"));return}let n=Pt.default.join(Ze.default.homedir(),".badgerclaw"),o=gs(n),r=Pt.default.join(Ze.default.homedir(),".openclaw","badgerclaw"),s=gs(r);o||s?(console.log(It.default.green("Logged out \u2014 local state cleared.")),console.log(It.default.dim(` Removed: ${n}${s?`, ${r}`:""}`))):console.log(It.default.green("Logged out."))});var ys=require("commander"),Po=m(require("chalk"));F();var bs=new ys.Command("status").description("Show connected instance info").action(async()=>{let e=R();(!e||!Ft())&&(console.log(Po.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1)),console.log(Po.default.green("Authenticated")),console.log(` User: ${Ht(e.user_id)}`),console.log(` Instance: ${e.instance_id}`),console.log(` Expires: ${new Date(e.expires_at).toLocaleDateString()}`)});var tt=require("commander"),x=m(require("chalk")),vn=m(require("ora")),Sn=m(require("fs")),Rs=m(require("os")),Cs=m(require("path")),xs=require("child_process");F();Ae();var et=m(require("fs")),ws=m(require("os")),_s=m(require("path")),Ss=require("child_process");ht();function wn(e){let t=e.split(":")[0].replace(/^@/,"").replace(/_bot$/,""),n=_s.join(ws.homedir(),".openclaw","openclaw.json");return et.existsSync(n)?{changed:Ee(()=>{let r=JSON.parse(et.readFileSync(n,"utf-8")),s=!1;if(r.channels?.badgerclaw?.accounts?.[t]&&(delete r.channels.badgerclaw.accounts[t],s=!0),r.agents?.list){let a=r.agents.list.length;r.agents.list=r.agents.list.filter(i=>i.id!==t),r.agents.list.length!==a&&(s=!0)}return s&&et.writeFileSync(n,JSON.stringify(r,null,2)),s})}:{changed:!1}}function _n(){try{return(0,Ss.execSync)("openclaw gateway restart",{stdio:"ignore"}),!0}catch{return!1}}Oe();function vs(e){return e.hermes?"hermes":"openclaw"}function ks(e){return e.openclaw.installed?"openclaw":e.hermes.installed?"hermes":"openclaw"}function Oo(){Ft()||(console.log(x.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1))}function jl(e){return/^[a-z0-9_]{4,20}$/.test(e)}function $s(e){return e.replace(/_bot$/,"")}var Eo=["openclaw","hermes"],Bl=new tt.Command("create").description("Create a new bot").argument("<name>","Bot name (4-20 chars, lowercase alphanumeric + underscores)").option("-r, --runtime <runtime>",`Bot runtime: ${Eo.join(" | ")}. Default is selected from this host's capabilities (Hermes preferred when available, OpenClaw otherwise \u2014 see \`badgerclaw setup\` output). Hermes requires HERMES_RUNTIME_ENABLED on the backend and a host that advertises Hermes capability via badgerclaw setup. Operator-side LLM credentials (BADGERCLAW_LLM_API_KEY or GOOGLE_API_KEY etc.) must be set at pair time, not at create time.`).action(async(e,t)=>{Oo(),jl(e)||(console.log(x.default.red("Invalid bot name. Must be 4-20 characters, lowercase alphanumeric and underscores only.")),process.exit(1));let n=t.runtime??ks(Se());Eo.includes(n)||(console.log(x.default.red(`Invalid --runtime "${t.runtime}". Must be one of: ${Eo.join(", ")}.`)),process.exit(1));let o=(0,vn.default)(`Creating ${n} bot "${e}"...`).start();try{let r=B();n==="hermes"?await r.post("/api/v1/bots",{bot_name:e,bot_username:e,runtime:"hermes"}):await r.post("/api/v1/openclaw/bots",{username:e}),o.succeed(x.default.green(`Bot "${e}" (${n}) created successfully!`)),n==="hermes"&&console.log(x.default.dim(" Next: generate a pair code from Adminweb (or POST /api/v1/pairing/create),\n then run `badgerclaw autopair` on a Hermes-capable host."))}catch(r){let s=r.response?.data?.errors?.[0]||r.message;o.fail(x.default.red(`Failed to create bot: ${s}`)),process.exit(1)}}),Ul=new tt.Command("list").description("List your bots").action(async()=>{Oo();let e=(0,vn.default)("Fetching bots...").start();try{let o=(await B().get("/api/v1/openclaw/bots")).data?.bots||[];if(e.stop(),o.length===0){console.log(x.default.yellow("No bots found. Create one with `badgerclaw bot create <name>`."));return}console.log(x.default.green(`Your bots (${o.length}):
127
+ `));for(let r of o){let s=$s(r.username||r.name),a=r.active===!1?x.default.dim("deactivated"):r.openclaw_connected?x.default.green("connected"):x.default.gray("disconnected");console.log(` ${x.default.bold(s)} ${a}`)}}catch(t){let n=t.response?.data?.errors?.[0]||t.message;e.fail(x.default.red(`Failed to list bots: ${n}`)),process.exit(1)}}),Fl=new tt.Command("delete").description("Deactivate a bot").argument("<name>","Bot name to deactivate").action(async e=>{Oo();let t=(0,vn.default)(`Deactivating bot "${e}"...`).start();try{await B().delete(`/api/v1/openclaw/bots/${e}`),t.succeed(x.default.green(`Bot "${e}" deactivated.`));let{changed:o}=wn(e);o&&(console.log(x.default.dim(" Removed from openclaw.json")),_n()&&console.log(x.default.dim(" Gateway restarted")))}catch(n){let o=n.response?.data?.errors?.[0]||n.message;t.fail(x.default.red(`Failed to deactivate bot: ${o}`)),process.exit(1)}});function Hl(e){let t=e.trim();return t.startsWith("@")&&(t=t.slice(1)),t.includes(":")&&(t=t.split(":")[0]),$s(t)}function Gl(e){let t=e.replace(/[^a-zA-Z0-9_.-]/g,"_")||"default";return Cs.default.join(Rs.default.homedir(),".openclaw","badgerclaw","quarantine",`${t}.json`)}var ql=new tt.Command("refresh").description("Recover a bot stuck in quarantine \u2014 clears the quarantine ledger and restarts the gateway so the plugin's refresh chain runs from scratch").argument("<name>",'Bot name (e.g. "claude", "claude_bot", or full Matrix ID)').action(async e=>{let t=Hl(e);t||(console.log(x.default.red(`Couldn't parse bot name "${e}".`)),process.exit(1));let n=Gl(t),o=!1;if(Sn.default.existsSync(n))try{let r=JSON.parse(Sn.default.readFileSync(n,"utf-8")),s=r.failureCount??"?",a=r.quarantinedAt??"?";console.log(x.default.dim(` Quarantine for "${t}" \u2014 ${s} failures, since ${a}`)),Sn.default.unlinkSync(n),o=!0}catch(r){console.log(x.default.red(`Failed to clear quarantine ledger at ${n}: ${r.message}`)),process.exit(1)}console.log(o?x.default.green(`\u2705 Cleared quarantine for "${t}"`):x.default.dim(` No quarantine file for "${t}" \u2014 already healthy or never quarantined.`)),console.log(x.default.dim(" Restarting OpenClaw gateway so the refresh chain runs..."));try{(0,xs.execSync)("openclaw gateway restart",{stdio:"inherit"})}catch(r){console.log(x.default.yellow(` Gateway restart command failed: ${r.message}`)),console.log(x.default.yellow(" Run `openclaw gateway restart` manually.")),process.exit(1)}console.log(x.default.green(`
128
+ \u2705 Refresh triggered. Watch the gateway logs for token refresh progress:`)),console.log(x.default.dim(" tail -f ~/.openclaw/logs/*.log")),console.log(x.default.dim(" If the bot fails to recover, the plugin's 4 refresh strategies all hit")),console.log(x.default.dim(" dead ends. Verify SYNAPSE_REGISTRATION_SHARED_SECRET is set on this gateway,")),console.log(x.default.dim(" or re-pair the bot from the BadgerClaw iOS app."))}),Is=new tt.Command("bot").description("Manage bots").addCommand(Bl).addCommand(Ul).addCommand(Fl).addCommand(ql);vt();var Ps=require("commander"),_=m(require("chalk"));F();ie();vt();ke();Xe();xo();Ae();Ie();var As=3e3,Vl=6e4,Wl=2700*1e3,Es=new Ps.Command("watch").description("Watch for bot pair events in real-time (no polling)").action(async()=>{R()||(console.log(_.default.yellow("Not logged in.")),process.exit(1)),await St(!1),console.log(_.default.green("\u{1F534} Listening for pair events... (Ctrl+C to stop)"));let t=require("eventsource"),n=As,o=null,r=null,s=()=>{let a=R();a||(console.log(_.default.red(" Auth missing \u2014 run `badgerclaw login` and re-start `badgerclaw watch`.")),process.exit(1));let i=new t(`${N}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${a.access_token}`}});r=i,i.onopen=()=>{n=As,console.log(_.default.dim(" SSE connected \u2014 listening for events")),o&&clearTimeout(o),o=setTimeout(()=>{console.log(_.default.dim(" SSE proactive reconnect \u2014 refreshing token before expiry")),i.close(),s()},Wl)},i.onerror=()=>{i.close(),o&&(clearTimeout(o),o=null),console.log(_.default.dim(` SSE disconnected \u2014 reconnecting in ${Math.floor(n/1e3)}s...`)),setTimeout(s,n),n=Math.min(n*1.5,Vl)},i.onmessage=async c=>{try{let l=JSON.parse(c.data);if(l.type==="pair"){let u=l.target_instance_id;if(u&&u!==ae()){console.log(_.default.dim(`
129
+ \u{1F4F1} Pair event for ${l.bot_name} targets ${u} \u2014 not us, skipping`));return}console.log(_.default.cyan(`
130
+ \u{1F4F1} Pair event received: ${l.bot_name}`)),await _t(l.pair_code,l.bot_name,l.bot_user_id,!1);try{let{execSync:p}=await import("child_process");p("openclaw gateway restart",{stdio:"ignore"}),console.log(_.default.green(" \u2705 Gateway restarted \u2014 bot is live!"))}catch{console.log(_.default.dim(" Gateway restart failed \u2014 run: openclaw gateway restart"))}}else if(l.type==="gateway-restart"){console.log(_.default.cyan(`
131
+ \u{1F504} Remote gateway-restart command received`));let u=await Qe();u.success?console.log(_.default.green(` \u2705 Gateway restarted: ${u.message}`)):console.log(_.default.red(` \u274C Gateway restart failed: ${u.message}`));try{await U(),console.log(_.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(_.default.dim(" Could not push heartbeat."))}}else if((l.type==="bot.delete"||l.type==="bot.disconnect")&&l.bot_user_id){let u=l.bot_user_id,p=l.type==="bot.delete"?"deleted":"disconnected",S=l.type==="bot.delete"?"\u{1F5D1}\uFE0F ":"\u{1F50C}";console.log(_.default.yellow(`
132
+ ${S} Bot ${p}: ${u} \u2014 removing from OpenClaw config...`));try{let{changed:E}=wn(u);E?(console.log(_.default.green(" \u2705 Removed from openclaw.json")),_n()?console.log(_.default.green(" \u2705 Gateway restarted")):console.log(_.default.dim(" Gateway restart failed \u2014 restart manually"))):console.log(_.default.dim(" Account not found in openclaw.json \u2014 nothing to remove"))}catch(E){console.log(_.default.red(` Failed to update openclaw.json: ${E}`))}}else if(l.type==="claude_code.start"&&l.bot_id&&l.room_id){console.log(_.default.cyan(`
133
+ \u{1F916} Claude Code START received: bot=${l.bot_id} room=${l.room_id}`));try{let u=await pe({id:l.command_id||`cc-start-${Date.now()}`,command_type:"start_claude_code",payload:{bot_id:l.bot_id,room_id:l.room_id,session_id:l.session_id}});if(console.log(u.success?_.default.green(` \u2705 ${u.message}`):_.default.red(` \u274C ${u.message}`)),l.command_id)try{await B().post(`/api/v1/dashboard/commands/${l.command_id}/result`,{status:u.success?"success":"failed",result:u.message})}catch{}try{await U()}catch{}}catch(u){console.log(_.default.red(` Claude Code start error: ${u.message}`))}}else if(l.type==="claude_code.stop"&&l.bot_id&&l.room_id){console.log(_.default.cyan(`
134
+ \u{1F916} Claude Code STOP received: bot=${l.bot_id} room=${l.room_id}`));try{let u=await pe({id:l.command_id||`cc-stop-${Date.now()}`,command_type:"stop_claude_code",payload:{bot_id:l.bot_id,room_id:l.room_id,session_id:l.session_id}});if(console.log(u.success?_.default.green(` \u2705 ${u.message}`):_.default.red(` \u274C ${u.message}`)),l.command_id)try{await B().post(`/api/v1/dashboard/commands/${l.command_id}/result`,{status:u.success?"success":"failed",result:u.message})}catch{}try{await U()}catch{}}catch(u){console.log(_.default.red(` Claude Code stop error: ${u.message}`))}}else if(l.type==="command.execute"&&l.command_id){console.log(_.default.cyan(`
135
+ \u26A1 SSE command received: ${l.command_type} (${l.command_id})`));try{let u=B();await u.post(`/api/v1/dashboard/commands/${l.command_id}/ack`);let p=await pe({id:l.command_id,command_type:l.command_type,payload:l.payload});console.log(p.success?_.default.green(` \u2705 ${p.message}`):_.default.red(` \u274C ${p.message}`)),await u.post(`/api/v1/dashboard/commands/${l.command_id}/result`,{status:p.success?"success":"failed",result:p.message,new_version:p.newVersion||null});try{await U()}catch{}l.command_type==="update_cli"&&p.success&&(console.log(_.default.cyan(" CLI updated \u2014 restarting in 2s...")),setTimeout(()=>process.exit(0),2e3))}catch(u){console.log(_.default.red(` Command ${l.command_id} error: ${u.message}`))}}}catch{}}};s(),await new Promise(()=>{})});var ia=require("commander"),d=m(require("chalk")),ue=require("child_process"),L=m(require("fs")),Mt=m(require("os")),fe=m(require("path")),la=m(require("readline"));ie();Ge();var Et=m(require("fs")),nt=m(require("path")),kn=require("child_process"),Kl=["request","request-promise"];function Yl(e){let t=e.match(/^(\s*)(?:"([^"]+)"|'([^']+)'|([^:#\s][^:]*?))\s*:/);return t?{indent:t[1].length,key:(t[2]??t[3]??t[4]??"").trim()}:null}function Jl(e){let t=e.split(`
136
+ `),n=[],o=!1,r=-1,s=!1,a=new Set(Kl);for(let i of t){let c=Yl(i);if(!o){c&&c.indent===0&&c.key==="overrides"&&(o=!0,r=c.indent),n.push(i);continue}if(c&&c.indent<=r){o=!1,n.push(i);continue}if(c&&c.indent>r&&a.has(c.key)){s=!0;continue}n.push(i)}return s?n.join(`
137
+ `):null}function zl(){let e=[],t=(0,kn.spawnSync)("npm",["root","-g"],{encoding:"utf-8",shell:!0});t.status===0&&t.stdout?.trim()&&e.push(nt.default.join(t.stdout.trim(),"openclaw","pnpm-workspace.yaml"));let n=(0,kn.spawnSync)("npm",["prefix","-g"],{encoding:"utf-8",shell:!0});n.status===0&&n.stdout?.trim()&&e.push(nt.default.join(n.stdout.trim(),"lib","node_modules","openclaw","pnpm-workspace.yaml"));let o=(0,kn.spawnSync)("which",["openclaw"],{encoding:"utf-8"});if(o.status===0&&o.stdout?.trim()){let r=nt.default.dirname(nt.default.dirname(o.stdout.trim()));e.push(nt.default.join(r,"lib","node_modules","openclaw","pnpm-workspace.yaml"))}for(let r of e)try{if(Et.default.existsSync(r))return r}catch{}return null}function Os(){let e=zl();if(!e)return null;let t;try{t=Et.default.readFileSync(e,"utf-8")}catch{return null}let n=Jl(t);if(n===null)return null;try{Et.default.writeFileSync(e,n)}catch{return null}return{yamlPath:e,original:t}}function Ls(e){if(!e)return!1;try{return Et.default.writeFileSync(e.yamlPath,e.original),!0}catch{return!1}}Oe();var rt=require("child_process"),Ms=m(require("fs")),D=m(require("chalk")),W={alreadyUp:!1,install:null,start:null,requiresRoot:!1,networkHostRequired:!1,guidance:null},Ts='On this distro the bare "docker" package is the podman shim (no dockerd). Install Docker Engine from the official docker-ce repository (https://docs.docker.com/engine/install/), then re-run `badgerclaw setup --hermes`.';function Ql(e){return e.daemonUp?{...W,alreadyUp:!0}:e.host==="darwin"?e.hasDockerApp?{...W,start:"docker-app"}:e.hasColima?{...W,start:"colima"}:e.binaryPresent?{...W,guidance:"A `docker` CLI is present but no engine we can start (Docker.app / colima) was found and the daemon is not answering. Start your Docker daemon (or `colima start`), then re-run `badgerclaw setup --hermes`."}:e.hasBrew?{...W,install:{tool:"colima",via:"brew"},start:"colima"}:{...W,guidance:"No container engine found and Homebrew is absent. Install Docker Desktop (https://www.docker.com/products/docker-desktop) or Homebrew (https://brew.sh) then colima, and re-run `badgerclaw setup --hermes`."}:e.host==="linux-systemd"?e.binaryPresent?{...W,start:"systemctl",requiresRoot:!0}:e.pkgManager==="apt"?{...W,install:{tool:"docker",via:"apt"},start:"systemctl",requiresRoot:!0}:{...W,guidance:e.pkgManager?Ts:"Docker is not installed and no supported package manager (apt) was found. Install Docker, then re-run."}:e.host==="linux-nosystemd"?e.binaryPresent?{...W,start:"dockerd-restricted",requiresRoot:!0,networkHostRequired:!0}:e.pkgManager==="apt"?{...W,install:{tool:"docker",via:"apt"},start:"dockerd-restricted",requiresRoot:!0,networkHostRequired:!0}:{...W,guidance:e.pkgManager?Ts:"Docker is not installed and no supported package manager (apt) was found. Install Docker (e.g. `apt-get install -y docker.io`), then re-run."}:{...W,guidance:`Automatic Docker setup isn't supported on this platform (${process.platform}). Install + start Docker manually, then re-run.`}}function Ds(e,t,n=8e3){return(0,rt.spawnSync)(e,t,{encoding:"utf-8",timeout:n})}function Lo(){let e=Ds("docker",["version","--format","{{.Server.Version}}"],4e3);return e.status===0&&!!(e.stdout||"").trim()}function Xl(){return Ds("docker",["--version"],4e3).status===0}function ot(e){return(0,rt.spawnSync)("sh",["-c",`command -v ${e}`],{encoding:"utf-8"}).status===0}function Zl(){return ot("apt-get")?"apt":ot("dnf")?"dnf":ot("yum")?"yum":null}function ec(){let e=(0,rt.spawnSync)("systemctl",["is-system-running"],{encoding:"utf-8",timeout:4e3});if(e.error)return!1;let t=`${e.stdout||""}${e.stderr||""}`.toLowerCase();return!/failed to connect to bus|not been booted with systemd|no such file/.test(t)}function tc(){return process.platform==="darwin"?"darwin":process.platform==="linux"?ec()?"linux-systemd":"linux-nosystemd":"unsupported"}function nc(){return typeof process.getuid=="function"?process.getuid()===0:!1}function Ce(e,t){return t(D.default.dim(` $ ${e}`)),(0,rt.spawnSync)("sh",["-c",e],{stdio:"inherit"}).status===0}function oc(e,t,n){let o=t?"sudo ":"";switch(e.via){case"brew":return n(D.default.dim(" Installing colima + docker CLI via Homebrew...")),Ce("brew install colima docker",n);case"apt":return n(D.default.dim(" Installing Docker via apt...")),Ce(`${o}apt-get update`,n),Ce(`${o}apt-get install -y docker.io`,n);default:return!1}}function rc(e,t,n){let o=t?"sudo ":"";switch(e){case"docker-app":return Ce("open -a Docker",n);case"colima":return Ce("colima start",n);case"systemctl":return Ce(`${o}systemctl enable --now docker`,n);case"dockerd-restricted":{if(!ot("dockerd"))return n(D.default.red(" \u274C `dockerd` is not installed (the docker CLI alone is not enough on a no-systemd host).")),!1;if(t&&!Ce("sudo -v",n))return n(D.default.red(" \u274C root is required to start dockerd here, but sudo is unavailable.")),!1;Ce(`${o}sh -c 'mount -t cgroup2 none /sys/fs/cgroup 2>/dev/null || true'`,n);let r="/tmp/badgerclaw-dockerd.log";n(D.default.dim(` Starting dockerd (restricted: --bridge=none --iptables=false) \u2192 ${r}`));let s=`nohup dockerd --storage-driver=overlay2 --iptables=false --bridge=none > ${r} 2>&1 &`,a=t?`sudo sh -c ${JSON.stringify(s)}`:`sh -c ${JSON.stringify(s)}`;return(0,rt.spawnSync)("sh",["-c",a],{stdio:"ignore"}).status===0}}}async function sc(e,t,n){let o=Date.now()+t;for(;;){if(e())return!0;if(Date.now()>=o)return!1;await new Promise(r=>setTimeout(r,n))}}async function Ns(e={}){let t=e.log??(a=>console.log(a));if(process.env.BADGERCLAW_NO_AUTO_DEPS==="1"){let a=Lo();return a||(t(D.default.yellow(" BADGERCLAW_NO_AUTO_DEPS=1 \u2014 skipping automatic Docker setup.")),t(D.default.dim(" Start the Docker daemon yourself, then re-run `badgerclaw setup --hermes`."))),{ok:a,daemonUp:a,networkHostRequired:!1}}let n={daemonUp:Lo(),binaryPresent:Xl(),host:tc(),hasBrew:ot("brew"),hasDockerApp:Ms.default.existsSync("/Applications/Docker.app"),hasColima:ot("colima"),pkgManager:Zl(),isRoot:nc()},o=Ql(n);if(o.alreadyUp)return{ok:!0,daemonUp:!0,networkHostRequired:!1};if(o.guidance)return t(D.default.red(` \u274C ${o.guidance}`)),{ok:!1,daemonUp:!1,networkHostRequired:o.networkHostRequired};let r=o.requiresRoot&&!n.isRoot;return r&&t(D.default.dim(" (some steps need root \u2014 using sudo; you may be prompted for your password)")),o.install&&!oc(o.install,r,t)?(t(D.default.red(" \u274C Docker install failed (see output above). Install it manually, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:o.networkHostRequired}):rc(o.start,r,t)?(t(D.default.dim(" Waiting for the Docker daemon to answer...")),await sc(Lo,12e4,1500)?(t(D.default.green(" \u2705 Docker daemon is up.")),{ok:!0,daemonUp:!0,networkHostRequired:o.networkHostRequired}):(t(D.default.red(" \u274C Docker did not become ready in time.")),o.start==="dockerd-restricted"?t(D.default.dim(" Check /tmp/badgerclaw-dockerd.log for the daemon output.")):o.start==="docker-app"&&t(D.default.dim(" Docker Desktop can take a minute to boot \u2014 re-run once its menu-bar icon is steady.")),{ok:!1,daemonUp:!1,networkHostRequired:o.networkHostRequired})):(t(D.default.red(" \u274C Could not start Docker (see output above). Resolve it, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:o.networkHostRequired})}function js(e){let t=e.minMajor??18;if(!Number.isFinite(e.nodeMajor)||e.nodeMajor<t){let n=Number.isFinite(e.nodeMajor)?`Node v${e.nodeMajor}`:"an unknown Node version";return`badgerclaw requires Node.js >= ${t} (this is ${n}). Upgrade Node \u2014 nodesource (https://github.com/nodesource/distributions) or nvm (\`nvm install ${t}\`) \u2014 then re-run \`badgerclaw setup --hermes\`.`}return e.npmPresent?null:`npm was not found on PATH. badgerclaw is installed and updated via npm \u2014 install Node.js ${t}+ (which bundles npm) and re-run \`badgerclaw setup --hermes\`.`}function Bs(e=process.versions.node){return parseInt(String(e).split(".")[0],10)}var To=require("child_process"),Rn=m(require("fs")),Us=m(require("os")),Cn=m(require("path"));Oe();Ve();function ac(){let e=Fs();for(let t of e)if(Rn.default.existsSync(t))return t;return null}function Fs(){return[Cn.default.resolve(__dirname,"..","assets","hermes-agent-bc.Dockerfile"),Cn.default.resolve(__dirname,"..","..","assets","hermes-agent-bc.Dockerfile")]}var ic="nousresearch/hermes-agent";function lc(e){let t=(process.env.HERMES_UPSTREAM||e?.upstream||"").trim();if(!t)return;if(t.includes("/"))return t;let n=t.includes(":")?t.split(":").pop():t;return`${ic}:${n}`}var cc={run:e=>{let t=(0,To.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};function uc(e){return["build",...e.hostNetwork?["--network","host"]:[],...e.upstreamRef?["--build-arg",`UPSTREAM=${e.upstreamRef}`]:[],"-t",e.image,"-f",e.dockerfile,e.ctxDir]}function Hs(e){let t=Jt();if(!t.installed)return{status:"no-docker"};let n=process.env.HERMES_IMAGE||qe;if(zt(t).installed)return{status:"already-present",image:n};let r=ac();if(!r)return{status:"no-dockerfile",expectedPaths:Fs()};let s=lc(e),a=Xn({bridgeUsable:()=>nn(cc)}),i=Rn.default.mkdtempSync(Cn.default.join(Us.default.tmpdir(),"bc-hermes-build-"));try{let c=(0,To.spawnSync)("docker",uc({hostNetwork:a,upstreamRef:s,image:n,dockerfile:r,ctxDir:i}),{stdio:"inherit",timeout:6e5});return c.status===0?{status:"built",image:n}:{status:"build-failed",image:n,stderr:`docker build exited ${c.status??"<no-status>"}`}}finally{try{Rn.default.rmSync(i,{recursive:!0,force:!0})}catch{}}}F();var Mo=m(require("os")),Ot=require("child_process"),Gs="https://ollama.com/download",dc={run:(e,t)=>{let n=(0,Ot.spawnSync)(e,t,{encoding:"utf-8",timeout:1e4});return{status:n.status,stdout:n.stdout||"",stderr:n.stderr||""}}};function st(e={}){let t=e.runner??dc,n=t.run("ollama",["--version"]);if(n.status!==0)return{installed:!1,serving:!1};let o=(n.stdout||"").match(/(\d+\.\d+\.\d+)/),r=o?o[1]:void 0;return{installed:!0,serving:t.run("ollama",["list"]).status===0,version:r}}function qs(e){return e.installed?e.serving?"Ollama is installed and serving.":"Ollama is installed but its server isn't running. Start it with `ollama serve` (or open the Ollama app), then re-run setup.":`Ollama is not installed. Install it from ${Gs}, then re-run setup.`}function xn(e,t={}){if(t.runner){let o=t.runner.run("ollama",["pull",e]);return o.status===0?{ok:!0}:{ok:!1,error:(o.stderr||o.stdout||`exit ${o.status}`).trim()}}let n=(0,Ot.spawnSync)("ollama",["pull",e],{stdio:t.inheritStdio===!1?"pipe":"inherit",encoding:"utf-8"});return n.status===0?{ok:!0}:{ok:!1,error:(n.stderr||`ollama pull ${e} failed (exit ${n.status})`).toString().trim()}}function mc(e={}){let t=Mo.default.platform();if(t!=="darwin"&&t!=="linux")return{ok:!1,error:`Automatic install isn't supported on ${t}. Install from ${Gs}.`};(e.log??(()=>{}))("Installing Ollama via the official installer (https://ollama.com/install.sh)\u2026");let o="curl -fsSL https://ollama.com/install.sh | sh";if(e.runner){let s=e.runner.run("sh",["-c",o]);if(s.status!==0)return{ok:!1,error:(s.stderr||`installer exit ${s.status}`).trim()}}else{let s=(0,Ot.spawnSync)("sh",["-c",o],{stdio:"inherit"});if(s.status!==0)return{ok:!1,error:`installer exited with code ${s.status??"unknown"}`}}return st({runner:e.runner}).installed?{ok:!0}:{ok:!1,error:"installer finished but `ollama` is still not on PATH"}}function pc(e={}){let t=e.runner?(n,o)=>e.runner.run(n,o):(n,o)=>{(0,Ot.spawnSync)(n,o,{stdio:"ignore",timeout:1e4})};Mo.default.platform()==="darwin"?t("open",["-a","Ollama"]):t("sh",["-c","(systemctl start ollama 2>/dev/null) || (nohup ollama serve >/dev/null 2>&1 &)"])}var gc=e=>new Promise(t=>setTimeout(t,e));async function Vs(e){let t=e.log??(()=>{}),n=e.sleepImpl??gc,o=st({runner:e.runner});if(!o.installed){if(!(e.assumeYes||(e.confirmInstall?await e.confirmInstall(" Ollama is not installed. Install it now? [Y/n] "):!1)))return{ready:!1,installed:!1,reason:"install declined"};let s=mc({runner:e.runner,log:t});if(!s.ok)return{ready:!1,installed:!1,reason:s.error};o=st({runner:e.runner})}if(o.installed&&!o.serving){t(" Starting the Ollama server\u2026"),pc({runner:e.runner});let r=e.pollAttempts??20;for(let s=0;s<r&&!o.serving;s++)await n(1e3),o=st({runner:e.runner})}return{ready:o.installed&&o.serving,installed:o.installed,reason:o.installed&&o.serving?void 0:"ollama not serving"}}var ea=m(require("os")),ta=m(require("readline"));ie();Ve();var ge=m(require("os")),Ys=require("child_process");Ie();var Ws=[1,2,4,6,8,12,16];function Ks(e){if(e>16)return"16GB+";let t=Ws[0];for(let n of Ws)e>=n&&(t=n);return`${t}GB`}var Js={run:(e,t)=>{let n=(0,Ys.spawnSync)(e,t,{encoding:"utf-8",timeout:5e3});return{status:n.status,stdout:n.stdout||""}}};function $n(){return Math.round(ge.default.totalmem()/1024/1024/1024)}function zs(e){return e==="x64"?"x86_64":e}function Qs(e,t){if(e==="darwin")return t.run("sysctl",["-n","machdep.cpu.brand_string"]).stdout.trim()||null;if(e==="linux")return t.run("sh",["-c","grep -m1 'model name' /proc/cpuinfo | cut -d: -f2"]).stdout.trim()||null;let n=ge.default.cpus();return n.length?n[0].model.trim():null}function Xs(e,t,n,o){if(e==="darwin"&&t==="arm64")return{accelerator:n?`${n} GPU`:"Apple GPU",vram_gb:null,unified_memory:!0};let r=o.run("nvidia-smi",["--query-gpu=name,memory.total","--format=csv,noheader,nounits"]);if(r.status===0&&r.stdout.trim()){let s=r.stdout.trim().split(`
138
+ `)[0],[a,i]=s.split(",").map(l=>l.trim()),c=Number.parseFloat(i);return{accelerator:a||"NVIDIA GPU",vram_gb:Number.isFinite(c)?Math.round(c/1024*10)/10:null,unified_memory:!1}}return{accelerator:null,vram_gb:null,unified_memory:!1}}function In(e={}){let t=e.runner??Js,n=ge.default.platform(),o=zs(ge.default.arch()),r=Qs(n,t);return Xs(n,o,r,t).accelerator}function Zs(e={}){let t=e.runner??Js,n=ge.default.platform(),o=zs(ge.default.arch()),r=e.ramTotalGbOverride!=null&&Number.isFinite(e.ramTotalGbOverride)&&e.ramTotalGbOverride>0?e.ramTotalGbOverride:null,s=r??$n(),a=Qs(n,t),{accelerator:i,vram_gb:c,unified_memory:l}=Xs(n,o,a,t);return{machine_fingerprint:mt(),ram_total_gb:r!=null?Math.round(r*10)/10:Math.round(ge.default.totalmem()/1024/1024/1024*10)/10,ram_tier:Ks(s),cpu_model:a,core_count:ge.default.cpus().length||null,accelerator:i,vram_gb:c,unified_memory:l,os:n,arch:o}}function Do(){return Math.round(ea.default.totalmem()/1024/1024/1024)}async function Lt(e,t,n={}){let o=n.apiBase??N,r=n.fetchImpl??fetch,s=n.accelerator&&n.accelerator.trim(),a=`${o}/api/v1/dashboard/recommended-models?ram_gb=${encodeURIComponent(e)}&runtime=${encodeURIComponent(t)}`+(s?`&accelerator=${encodeURIComponent(s)}`:"");try{let i=await r(a,{headers:{Accept:"application/json"}});if(!i.ok)return null;let c=await i.json(),l=c.result&&typeof c.result=="object"?c.result:c;return Array.isArray(l.recommended)?l:null}catch{return null}}async function fc(e){let t=ta.default.createInterface({input:process.stdin,output:process.stdout});try{return await new Promise(n=>t.question(e,n))}finally{t.close()}}function hc(e){let t=e.verdict==="great"?"great":e.verdict==="usable"?"usable":e.verdict,n=e.decode_tps!=null?`${e.decode_tps} tok/s`:"speed not yet benchmarked",o=e.is_top_pick?" (recommended)":"";return`${e.model_name} [${e.ollama_tag}] \u2014 ${t}, ${n}. ${e.why}${o}`}async function yc(e,t){let n=e.recommended;if(!n||n.length===0)return{tag:null,note:e.note,model:null};let o=n.find(l=>l.is_top_pick)??n[0];if(t.preferredTag){let l=n.find(u=>u.ollama_tag===t.preferredTag);return l?{tag:l.ollama_tag,note:e.note,model:l}:{tag:t.preferredTag,note:e.note,model:null}}if(!t.interactive)return{tag:o.ollama_tag,note:e.note,model:o};let r=t.log??(l=>console.log(l)),s=t.prompt??fc;r(`
139
+ Local models that fit ${e.ram_gb} GB (${e.ram_tier}):`),n.forEach((l,u)=>{r(` ${l===o?"*":" "} ${u+1}) ${hc(l)}`)});let a=n.indexOf(o)+1,i=(await s(` Pick a model [${a}]: `)).trim();if(!i)return{tag:o.ollama_tag,note:e.note,model:o};let c=Number.parseInt(i,10);if(Number.isInteger(c)&&c>=1&&c<=n.length){let l=n[c-1];return{tag:l.ollama_tag,note:e.note,model:l}}return{tag:o.ollama_tag,note:e.note,model:o}}async function An(e){let t=e.ramGb??Do(),n=e.accelerator===void 0?In():e.accelerator,o=await Lt(t,e.runtime,{apiBase:e.apiBase,fetchImpl:e.fetchImpl,accelerator:n});if(!o)return{tag:e.preferredTag||bt("ollama"),note:"Could not reach the model-recommendation service \u2014 using a safe default model.",ramGb:t,fellBack:!0};let r=await yc(o,{interactive:e.interactive,preferredTag:e.preferredTag,prompt:e.prompt,log:e.log});return{tag:r.tag,note:r.note,ramGb:t,fellBack:!1}}Ve();var te=fe.default.join(Mt.default.homedir(),".openclaw","openclaw.json"),Tt=te+".badgerclaw-stash",ca=fe.default.join(Mt.default.homedir(),".openclaw","npm"),bc=fe.default.join(ca,"package.json");async function na(){try{let e=await fetch(`${N}/api/v1/dashboard/versions/latest`,{headers:{Accept:"application/json"}});if(!e.ok)return{cli:null,plugin:null,openclaw:null,hermes:null};let t=await e.json(),n=t.result&&typeof t.result=="object"?t.result:t,o=r=>typeof r!="string"||!r||r==="unknown"?null:r;return{cli:o(n.cli),plugin:o(n.plugin),openclaw:o(n.supported_openclaw),hermes:o(n.supported_hermes)}}catch{return{cli:null,plugin:null,openclaw:null,hermes:null}}}function wc(){if(!L.default.existsSync(te))return null;try{let e=JSON.parse(L.default.readFileSync(te,"utf-8")),t=e.channels?.badgerclaw;return t?(delete e.channels.badgerclaw,e.plugins?.entries?.badgerclaw&&delete e.plugins.entries.badgerclaw,L.default.writeFileSync(te,JSON.stringify(e,null,2)),L.default.writeFileSync(Tt,JSON.stringify(t,null,2)),t):null}catch{return null}}function _c(){if(!L.default.existsSync(te))return null;try{let e=JSON.parse(L.default.readFileSync(te,"utf-8"));return!e.gateway||typeof e.gateway!="object"?null:JSON.parse(JSON.stringify(e.gateway))}catch{return null}}function Sc(e){if(e&&L.default.existsSync(te))try{let t=JSON.parse(L.default.readFileSync(te,"utf-8"));t.gateway={...e,...t.gateway||{}},L.default.writeFileSync(te,JSON.stringify(t,null,2))}catch(t){console.log(d.default.yellow(` \u26A0\uFE0F Could not restore gateway block: ${t.message}`)),console.log(d.default.yellow(" Run `openclaw config set gateway.mode local` manually if the gateway fails to start."))}}function vc(){if(L.default.existsSync(Tt))try{let e=JSON.parse(L.default.readFileSync(Tt,"utf-8")),t=JSON.parse(L.default.readFileSync(te,"utf-8"));t.channels=t.channels||{},t.channels.badgerclaw=e,L.default.writeFileSync(te,JSON.stringify(t,null,2)),L.default.unlinkSync(Tt)}catch(e){console.log(d.default.yellow(` \u26A0\uFE0F Could not restore config: ${e.message}`)),console.log(d.default.yellow(` Your bot credentials are backed up at: ${Tt}`))}}async function oa(e){return new Promise(t=>{let n=(0,ue.spawn)("openclaw",["plugins","install",e,"--force","--dangerously-force-unsafe-install"],{stdio:["ignore","pipe","pipe"],shell:!0}),o="",r=!1,s=!1,a=/Installed plugin:|Restart the gateway to load plugins/,i=()=>{r||s||(r=!0,setTimeout(()=>{if(!s){try{n.kill("SIGTERM")}catch{}setTimeout(()=>{if(!s)try{n.kill("SIGKILL")}catch{}},1e3)}},3e3))},c=(l,u)=>{u.write(l),o+=l.toString("utf-8"),a.test(o)&&i()};n.stdout.on("data",l=>c(l,process.stdout)),n.stderr.on("data",l=>c(l,process.stderr)),n.on("exit",l=>{s=!0,t({status:r?0:l??1})}),n.on("error",l=>{s||(s=!0,console.error(d.default.red(` openclaw spawn error: ${l.message}`)),t({status:1}))})})}function ra(e){if(!L.default.existsSync(e))return!1;let t;try{t=JSON.parse(L.default.readFileSync(e,"utf-8"))}catch{return!1}let n=!1;return t.overrides&&typeof t.overrides=="object"&&"uuid"in t.overrides&&(delete t.overrides.uuid,n=!0),t.openclaw&&Array.isArray(t.openclaw.managedOverrides)&&t.openclaw.managedOverrides.includes("uuid")&&(t.openclaw.managedOverrides=t.openclaw.managedOverrides.filter(o=>o!=="uuid"),n=!0),n?(L.default.writeFileSync(e,JSON.stringify(t,null,2)+`
140
+ `),!0):!1}function kc(){let e=[];ra(bc)&&e.push(ca);for(let t of Kt())ra(fe.default.join(t,"package.json"))&&e.push(t);return e}async function Rc(){let{detectCapabilities:e}=await Promise.resolve().then(()=>(Oe(),Cr)),{pushHeartbeat:t}=await Promise.resolve().then(()=>(Xe(),Io));console.log(d.default.green(`
139
141
  \u{1F9A1} BadgerClaw \u2014 capability refresh
140
- `));let o=e();console.log(d.default.dim(" Detected on this host:")),console.log(d.default.dim(` OpenClaw : ${rn(o.openclaw)}`)),console.log(d.default.dim(` Hermes : ${rn(o.hermes)}`)),console.log(d.default.dim(` Docker : ${rn(o.docker)}`)),o.disk_free_gb!==null&&console.log(d.default.dim(` Disk free: ${o.disk_free_gb} GB`));try{await t(),console.log(d.default.green(`
141
- \u2705 Capabilities pushed to the API.`)),console.log(d.default.dim(" The backend will route new bot assignments accordingly."))}catch(n){let r=n?.message||String(n);if(r.includes("no auth")||r.includes("401")){console.log(d.default.yellow(`
142
+ `));let n=e();console.log(d.default.dim(" Detected on this host:")),console.log(d.default.dim(` OpenClaw : ${No(n.openclaw)}`)),console.log(d.default.dim(` Hermes : ${No(n.hermes)}`)),console.log(d.default.dim(` Docker : ${No(n.docker)}`)),n.disk_free_gb!==null&&console.log(d.default.dim(` Disk free: ${n.disk_free_gb} GB`));try{await t(),console.log(d.default.green(`
143
+ \u2705 Capabilities pushed to the API.`)),console.log(d.default.dim(" The backend will route new bot assignments accordingly."))}catch(o){let r=o?.message||String(o);if(r.includes("no auth")||r.includes("401")){console.log(d.default.yellow(`
142
144
  \u26A0\uFE0F Not logged in \u2014 capabilities re-scanned locally but not posted to the API.`)),console.log(d.default.dim(" Run `badgerclaw login` first, then re-run `badgerclaw setup --refresh`."));return}console.log(d.default.red(`
143
- \u274C Failed to push capabilities: ${r}`)),process.exit(1)}}function rn(e){return e.installed?e.version?`installed (${e.version})`:e.image?`installed (${e.image})`:"installed":"not installed"}async function Wi(e){console.log(d.default.green(`
145
+ \u274C Failed to push capabilities: ${r}`)),process.exit(1)}}function No(e){return e.installed?e.version?`installed (${e.version})`:e.image?`installed (${e.image})`:"installed":"not installed"}async function sa(e){console.log(d.default.green(`
144
146
  \u{1F9E0} Local LLM (Ollama/Qwen) \u2014 RAM-aware model picker
145
- `));let t=process.stdout.isTTY===!0&&process.stdin.isTTY===!0&&!e.assumeYes,o=process.env.BADGERCLAW_LLM_MODEL||void 0,n=await os({runtime:"hermes",interactive:t,preferredTag:o,log:a=>console.log(d.default.dim(a))});if(console.log(d.default.dim(` Detected RAM: ~${n.ramGb} GB`)),!n.tag){console.log(d.default.yellow(`
146
- \u26A0\uFE0F ${n.note||"Your RAM is too low for a usable local model."}`)),console.log(d.default.dim(" Falling back to the normal cloud-LLM path. Set GOOGLE_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY (or BADGERCLAW_LLM_PROVIDER + BADGERCLAW_LLM_API_KEY) before pairing a bot."));return}n.fellBack&&n.note&&console.log(d.default.yellow(` \u26A0\uFE0F ${n.note}`)),console.log(d.default.dim(` Selected local model: ${d.default.cyan(n.tag)}`));let r=Xr();if(!r.installed||!r.serving){console.log(d.default.yellow(`
147
- \u26A0\uFE0F ${Qr(r)}`)),console.log(d.default.dim(" Local-LLM setup can't continue without Ollama. Falling back to the cloud-LLM path; install/start Ollama and re-run `badgerclaw setup --hermes --local-llm` to switch this host to a local model."));return}console.log(d.default.dim(` Ollama ${r.version||""} detected and serving.`)),console.log(d.default.dim(` Pulling ${n.tag} via Ollama (one-time, can be large)...`));let s=Zr(n.tag);s.ok||(console.log(d.default.red(`
148
- \u274C Failed to pull ${n.tag}: ${s.error}`)),console.log(d.default.dim(` Pull it manually with \`ollama pull ${n.tag}\`, then re-run setup.`)),process.exit(1)),console.log(d.default.green(` \u2705 Model ${n.tag} ready.`)),jn({provider:"ollama",model:n.tag}),console.log(d.default.green(" \u2705 This host will use the local Ollama model for new Hermes bots."))}var ls=new as.Command("setup").description("Install or update the OpenClaw BadgerClaw plugin safely (handles config automatically)").option("--refresh","Skip install steps; re-scan host capabilities and push them to the API immediately. Useful right after installing a second runtime (Docker, Hermes image) so the backend doesn't have to wait for the next heartbeat tick to pick up the change.").option("--hermes","Opt this host into the Hermes runtime instead of OpenClaw. Skips the OpenClaw binary + plugin + gateway install entirely; instead builds the Hermes container image locally from the bundled Dockerfile (against the public nousresearch/hermes-agent base on Docker Hub \u2014 no AWS/ECR credentials needed). Default (no flag) installs OpenClaw \u2014 Hermes is opt-in while it's still being soaked on early-adopter hosts.").option("--local-llm","Use a local LLM (Ollama/Qwen) for this host instead of a cloud provider. Hermes only. Detects this host's RAM, asks the backend which Qwen models fit, lets you pick one (or auto-picks the best fit in non-interactive runs), then pulls it via Ollama and wires Hermes to talk to 127.0.0.1:11434. Also engaged implicitly by BADGERCLAW_LLM_PROVIDER=ollama. Requires Ollama installed + serving (we never auto-install it). When RAM is too low for any usable local model, setup tells you and falls back to the normal cloud path.").option("--yes","Assume defaults for any interactive prompt (e.g. the local-LLM model picker auto-selects the recommended model). Useful for scripted / unattended runs.").action(async e=>{if(e.refresh){await Gi();return}if(console.log(d.default.green(`
147
+ `));let t=process.stdout.isTTY===!0&&process.stdin.isTTY===!0&&!e.assumeYes,n=process.env.BADGERCLAW_LLM_MODEL||void 0,o=await An({runtime:"hermes",interactive:t,preferredTag:n,log:i=>console.log(d.default.dim(i))});if(console.log(d.default.dim(` Detected RAM: ~${o.ramGb} GB`)),!o.tag){console.log(d.default.yellow(`
148
+ \u26A0\uFE0F ${o.note||"Your RAM is too low for a usable local model."}`)),console.log(d.default.dim(" Falling back to the normal cloud-LLM path. Set GOOGLE_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY (or BADGERCLAW_LLM_PROVIDER + BADGERCLAW_LLM_API_KEY) before pairing a bot."));return}o.fellBack&&o.note&&console.log(d.default.yellow(` \u26A0\uFE0F ${o.note}`)),console.log(d.default.dim(` Selected local model: ${d.default.cyan(o.tag)}`));let r=t?async i=>{let c=(await Pn(d.default.cyan(i))).trim().toLowerCase();return c===""||c==="y"||c==="yes"}:void 0,s=await Vs({assumeYes:e.assumeYes,confirmInstall:r,log:i=>console.log(d.default.dim(" "+i))});if(!s.ready){let i=s.reason==="install declined"?"Ollama install skipped.":`Ollama not ready (${s.reason||"unknown"}).`;console.log(d.default.yellow(`
149
+ \u26A0\uFE0F ${i}`)),console.log(d.default.dim(" Falling back to the cloud-LLM path. Install/start Ollama and re-run `badgerclaw setup --hermes --local-llm` to switch this host to a local model."));return}console.log(d.default.dim(" Ollama is installed and serving.")),console.log(d.default.dim(` Pulling ${o.tag} via Ollama (one-time, can be large)...`));let a=xn(o.tag);a.ok||(console.log(d.default.red(`
150
+ \u274C Failed to pull ${o.tag}: ${a.error}`)),console.log(d.default.dim(` Pull it manually with \`ollama pull ${o.tag}\`, then re-run setup.`)),process.exit(1)),console.log(d.default.green(` \u2705 Model ${o.tag} ready.`)),Pr({provider:"ollama",model:o.tag}),console.log(d.default.green(" \u2705 This host will use the local Ollama model for new Hermes bots."))}function aa(e){return e===!0||(process.env.BADGERCLAW_LLM_PROVIDER||"").toLowerCase()==="ollama"}function Pn(e){let t=la.default.createInterface({input:process.stdin,output:process.stdout});return new Promise(n=>t.question(e,o=>{t.close(),n(o)}))}function ua(e){let t=process.stdout.isTTY===!0&&process.stdin.isTTY===!0;return(e.isInteractive??t)&&!e.assumeYes}async function Cc(e){if(!ua(e))return!1;let n=(await(e.prompt??Pn)(d.default.cyan(`
151
+ \u{1F9E0} Run a local LLM (Ollama) on this machine instead of a cloud provider? [y/N] `))).trim().toLowerCase();return n==="y"||n==="yes"}async function xc(e){if(!ua(e))return"skip";let n=(await(e.prompt??Pn)(d.default.cyan(`
152
+ \u{1F9E0} Configure this host's LLM now? [c]loud / [l]ocal / [s]kip (default: skip) `))).trim().toLowerCase();return n==="c"||n==="cloud"?"cloud":n==="l"||n==="local"?"local":"skip"}async function $c(e={}){let t=e.log??(s=>console.log(s)),n=e.ramGb??Do(),o=e.accelerator===void 0?In():e.accelerator;t(d.default.green(`
153
+ \u{1F9E0} Local LLM \u2014 RAM-aware recommendation
154
+ `)),t(d.default.dim(` Detected RAM: ~${n} GB \xB7 ${o||"CPU-only"}`));let r=null;try{r=await Lt(n,"hermes",{accelerator:o,fetchImpl:e.fetchImpl})}catch{r=null}if(!r||r.recommended.length===0)t(d.default.yellow(` \u26A0\uFE0F ${r?.note||"No local model is a good fit for this machine \u2014 use a cloud provider."}`));else{t(d.default.dim(" Local models that run well on this machine:"));for(let s of r.recommended){let a=s.decode_tps!=null?`${s.decode_tps} tok/s`:"speed not yet benchmarked";t(` \u2022 ${d.default.cyan(s.ollama_tag)} \u2014 ${s.verdict}, ${a}`+(s.is_top_pick?" (best fit)":""))}}t(d.default.dim(`
155
+ Note: OpenClaw bots use a cloud LLM provider, so this host won't run a
156
+ local model on the OpenClaw runtime. To actually use one of these models,
157
+ re-run \`badgerclaw setup --hermes --local-llm\` (the Hermes runtime).`))}var jo=[{key:"gemini",label:"Google Gemini",env:"GOOGLE_API_KEY"},{key:"anthropic",label:"Anthropic Claude",env:"ANTHROPIC_API_KEY"},{key:"openrouter",label:"OpenRouter",env:"OPENROUTER_API_KEY"}];async function Ic(e){let t=e.log??(l=>console.log(l)),n=e.prompt??Pn,o=e.env??process.env;t(d.default.green(`
158
+ \u2601\uFE0F Cloud LLM provider
159
+ `)),jo.forEach((l,u)=>t(` ${u+1}) ${l.label}`));let r=(await n(" Pick a provider [1]: ")).trim(),s=r===""?1:Number.parseInt(r,10),a=jo[Number.isInteger(s)&&s>=1&&s<=jo.length?s-1:0],i=(o[a.env]||"").trim();if(i?t(d.default.dim(` Using ${a.env} from your environment.`)):i=(await n(d.default.cyan(` Enter your ${a.label} API key: `))).trim(),!i){t(d.default.yellow(" No API key entered \u2014 skipping cloud-LLM setup. Set it via env before pairing."));return}let c=bt(a.key);Er({provider:a.key,apiKey:i,model:c}),t(d.default.green(` \u2705 This host will use ${a.label} (${c}) for new Hermes bots.`)),t(d.default.dim(" Saved to ~/.badgerclaw/cloud-llm.json (mode 0600)."))}var da=new ia.Command("setup").description("Install or update the OpenClaw BadgerClaw plugin safely (handles config automatically)").option("--refresh","Skip install steps; re-scan host capabilities and push them to the API immediately. Useful right after installing a second runtime (Docker, Hermes image) so the backend doesn't have to wait for the next heartbeat tick to pick up the change.").option("--hermes","Opt this host into the Hermes runtime instead of OpenClaw. Skips the OpenClaw binary + plugin + gateway install entirely; instead builds the Hermes container image locally from the bundled Dockerfile (against the public nousresearch/hermes-agent base on Docker Hub \u2014 no AWS/ECR credentials needed). Default (no flag) installs OpenClaw \u2014 Hermes is opt-in while it's still being soaked on early-adopter hosts.").option("--local-llm","Opt into a local LLM (Ollama/Qwen) for this host. Setup also OFFERS this as an optional, skippable prompt in interactive runs; this flag (or BADGERCLAW_LLM_PROVIDER=ollama) skips the prompt and opts in directly. On HERMES it detects this host's RAM, asks the backend which Qwen models fit, lets you pick one (auto-picks the best fit non-interactively), pulls it via Ollama, and wires Hermes to 127.0.0.1:11434 (requires Ollama installed + serving; never auto-installed). On OPENCLAW (cloud-only runtime) it cannot run a local model, so it only SHOWS the RAM-aware recommendations and points you to `--hermes`. When RAM is too low for any usable model, setup says so.").option("--yes","Assume defaults for any interactive prompt (e.g. the local-LLM model picker auto-selects the recommended model). Useful for scripted / unattended runs.").action(async e=>{if(e.refresh){await Rc();return}if(console.log(d.default.green(`
149
160
  \u{1F9A1} BadgerClaw Setup
150
- `)),Er({hermes:e.hermes})==="hermes"){let f=Vr({nodeMajor:Kr(),npmPresent:(0,te.spawnSync)("sh",["-c","command -v npm"],{encoding:"utf-8"}).status===0});f&&(console.log(d.default.red(`
151
- \u274C ${f}`)),process.exit(1));let v=ce();if(console.log(d.default.dim(` Detected: Docker ${v.docker.installed?"running":"not running"}, Hermes image ${v.hermes.installed?"present":"absent"}.`)),console.log(d.default.dim(` Selected runtime: ${d.default.cyan("hermes")} (via --hermes flag)
152
- `)),!v.docker.installed){console.log(d.default.dim(" Docker is not ready \u2014 bootstrapping it for the Hermes runtime..."));let _=await qr({log:w=>console.log(w)});_.ok||(console.log(d.default.red(`
153
- \u274C Docker is required for the Hermes runtime and could not be started automatically.`)),console.log(d.default.dim(" Resolve the issue above (or set Docker up manually), then re-run `badgerclaw setup --hermes`.")),process.exit(1)),_.networkHostRequired&&console.log(d.default.dim(" \u24D8 No Docker bridge on this host \u2014 Hermes bots will use host networking automatically at pair time.")),v=ce()}if(v.disk_free_gb!==null&&v.disk_free_gb<6&&console.log(d.default.yellow(` \u26A0\uFE0F Low disk: ${v.disk_free_gb} GB free \u2014 the Hermes image build needs ~5 GB and may fail if it runs out.`)),v.hermes.installed)console.log(d.default.dim(` Hermes image already present: ${v.hermes.image}`));else{let _=(await ns()).hermes;_&&console.log(d.default.dim(` Pinned Hermes upstream: ${_}`)),console.log(d.default.dim(" Building Hermes image (one-time, ~2 min)..."));let w=zr({upstream:_});w.status==="built"?console.log(d.default.green(` \u2705 Hermes image built: ${w.image}`)):w.status==="already-present"?console.log(d.default.dim(` Hermes image already present: ${w.image}`)):w.status==="no-dockerfile"?(console.log(d.default.red(`
154
- \u274C Bundled Hermes Dockerfile missing from CLI install.`)),console.log(d.default.dim(" Reinstall: npm install -g badgerclaw@latest")),console.log(d.default.dim(` Looked at: ${w.expectedPaths.join(", ")}`)),process.exit(1)):w.status==="build-failed"?(console.log(d.default.red(`
155
- \u274C Hermes image build failed: ${w.stderr}`)),console.log(d.default.dim(" See the docker output above for details.")),process.exit(1)):w.status==="no-docker"&&(console.log(d.default.red(`
156
- \u274C Docker is not running.`)),process.exit(1))}(e.localLlm===!0||(process.env.BADGERCLAW_LLM_PROVIDER||"").toLowerCase()==="ollama")&&await Wi({assumeYes:e.yes===!0}),console.log(d.default.dim(`
157
- Cleaning up heartbeat hooks from previous installs...`)),rr({loggedIn:b()!==null,log:_=>console.log(d.default.dim(` ${_}`))}),console.log(d.default.dim(`
161
+ `)),vs({hermes:e.hermes})==="hermes"){let g=js({nodeMajor:Bs(),npmPresent:(0,ue.spawnSync)("sh",["-c","command -v npm"],{encoding:"utf-8"}).status===0});g&&(console.log(d.default.red(`
162
+ \u274C ${g}`)),process.exit(1));let v=Se();if(console.log(d.default.dim(` Detected: Docker ${v.docker.installed?"running":"not running"}, Hermes image ${v.hermes.installed?"present":"absent"}.`)),console.log(d.default.dim(` Selected runtime: ${d.default.cyan("hermes")} (via --hermes flag)
163
+ `)),!v.docker.installed){console.log(d.default.dim(" Docker is not ready \u2014 bootstrapping it for the Hermes runtime..."));let h=await Ns({log:y=>console.log(y)});h.ok||(console.log(d.default.red(`
164
+ \u274C Docker is required for the Hermes runtime and could not be started automatically.`)),console.log(d.default.dim(" Resolve the issue above (or set Docker up manually), then re-run `badgerclaw setup --hermes`.")),process.exit(1)),h.networkHostRequired&&console.log(d.default.dim(" \u24D8 No Docker bridge on this host \u2014 Hermes bots will use host networking automatically at pair time.")),v=Se()}if(v.disk_free_gb!==null&&v.disk_free_gb<6&&console.log(d.default.yellow(` \u26A0\uFE0F Low disk: ${v.disk_free_gb} GB free \u2014 the Hermes image build needs ~5 GB and may fail if it runs out.`)),v.hermes.installed)console.log(d.default.dim(` Hermes image already present: ${v.hermes.image}`));else{let h=(await na()).hermes;h&&console.log(d.default.dim(` Pinned Hermes upstream: ${h}`)),console.log(d.default.dim(" Building Hermes image (one-time, ~2 min)..."));let y=Hs({upstream:h});y.status==="built"?console.log(d.default.green(` \u2705 Hermes image built: ${y.image}`)):y.status==="already-present"?console.log(d.default.dim(` Hermes image already present: ${y.image}`)):y.status==="no-dockerfile"?(console.log(d.default.red(`
165
+ \u274C Bundled Hermes Dockerfile missing from CLI install.`)),console.log(d.default.dim(" Reinstall: npm install -g badgerclaw@latest")),console.log(d.default.dim(` Looked at: ${y.expectedPaths.join(", ")}`)),process.exit(1)):y.status==="build-failed"?(console.log(d.default.red(`
166
+ \u274C Hermes image build failed: ${y.stderr}`)),console.log(d.default.dim(" See the docker output above for details.")),process.exit(1)):y.status==="no-docker"&&(console.log(d.default.red(`
167
+ \u274C Docker is not running.`)),process.exit(1))}if(aa(e.localLlm))await sa({assumeYes:e.yes===!0});else{let h=await xc({assumeYes:e.yes===!0});h==="local"?await sa({assumeYes:e.yes===!0}):h==="cloud"&&await Ic({assumeYes:e.yes===!0})}console.log(d.default.dim(`
168
+ Cleaning up heartbeat hooks from previous installs...`)),zr({loggedIn:R()!==null,log:h=>console.log(d.default.dim(` ${h}`))}),console.log(d.default.dim(`
158
169
  Hermes-only mode \u2014 skipping OpenClaw plugin + gateway install.
159
170
  To enable OC bots later, drop the --hermes flag: \`badgerclaw setup\`.
160
- `)),console.log(d.default.green("\u2705 Setup complete (Hermes-only host).")),console.log(d.default.dim("\nNext steps:\n 1. `badgerclaw login` \u2014 authenticate this CLI to the backend.\n 2. `badgerclaw setup --refresh` \u2014 push the Hermes capability so\n the backend (and the iOS app) knows this host can serve\n Hermes bots.\n 3. `badgerclaw bot create <name>` \u2014 defaults to Hermes on this host."));return}let o=await ns();if(o.cli){let f=go();f!==o.cli?(console.log(d.default.dim(` Updating CLI: ${f} \u2192 ${o.cli} (supported)...`)),(0,te.spawnSync)("npm",["install","-g",`badgerclaw@${o.cli}`],{stdio:"inherit",shell:!0}).status!==0&&(console.log(d.default.red("\n\u274C CLI update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(d.default.green(` \u2705 CLI updated to ${o.cli}`))):console.log(d.default.dim(` CLI already at approved version ${f}.`))}if(o.openclaw){let f=G();f!==o.openclaw?(console.log(f===null?d.default.dim(` Installing OpenClaw ${o.openclaw} (supported)...`):d.default.dim(` Updating OpenClaw: ${f} \u2192 ${o.openclaw} (supported)...`)),(0,te.spawnSync)("npm",["install","-g",`openclaw@${o.openclaw}`],{stdio:"inherit",shell:!0}).status!==0&&(console.log(d.default.red("\n\u274C OpenClaw install/update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(d.default.green(` \u2705 OpenClaw at ${o.openclaw}`))):console.log(d.default.dim(` OpenClaw already at approved version ${f}.`))}else G()===null&&(console.log(d.default.yellow(" \u26A0\uFE0F No approved OpenClaw version and none installed \u2014 installing latest from npm.")),(0,te.spawnSync)("npm",["install","-g","openclaw"],{stdio:"inherit",shell:!0}).status!==0&&(console.log(d.default.red(`
161
- \u274C OpenClaw install failed.`)),process.exit(1)));let n=Bi();n&&console.log(d.default.dim(" Existing bot config stashed temporarily..."));let r=ji();(0,te.spawnSync)("openclaw",["gateway","stop"],{stdio:"pipe",shell:!0,timeout:1e4});let s=[ae.default.join(ft.default.homedir(),".openclaw","extensions","badgerclaw"),ae.default.join(ft.default.homedir(),".openclaw","npm","node_modules","@badgerclaw","connect"),...Ct()],a=[],c=[],l=f=>{let v=`${f}.bc-setup-stash-${Date.now()}-${Math.floor(Math.random()*1e6)}`,I=(0,te.spawnSync)("mv",["-f",f,v],{encoding:"utf-8"});return I.status===0?{ok:!0,stash:v}:{ok:!1,error:(I.stderr||"").trim()||`exit ${I.status}`}};for(let f of s)if(R.default.existsSync(f))try{R.default.rmSync(f,{recursive:!0,force:!0}),a.push(f)}catch(v){let I=l(f);I.ok?(c.push(`${f} \u2192 ${I.stash}`),console.log(d.default.yellow(` \u26A0\uFE0F Could not delete ${f} (${v.message}); renamed it aside instead.`))):(console.log(d.default.red(` \u274C Could not delete ${f} (${v.message})`)),console.log(d.default.red(` Could not rename ${f} aside either (${I.error}). Plugin install will likely fail.`)))}a.length>0&&console.log(d.default.dim(` Cleared existing plugin director${a.length>1?"ies":"y"}.`)),c.length>0&&console.log(d.default.dim(` Renamed busy install${c.length>1?"s":""} aside: ${c.join(", ")}`));let i=o.plugin?`@badgerclaw/connect@${o.plugin}`:"@badgerclaw/connect";o.plugin?console.log(d.default.dim(` Installing ${i} (supported)...`)):console.log(d.default.yellow(" \u26A0\uFE0F Allow-list unavailable \u2014 installing @badgerclaw/connect unpinned."));let m=null;xn("2026.6.5")&&(m=Hr(),m&&console.log(d.default.dim(" Adjusted OpenClaw 2026.6.5 npm overrides for a full channel-plugin install.")));let p=await rs(i);if(p.status===0&&o.plugin&&o.plugin!=="unknown"){for(let v=1;v<=2&&!(It()===o.plugin||(console.log(d.default.yellow(` Plugin landed as a hook-pack-only install (not yet visible to \`badgerclaw login\`) \u2014 re-running plugin install (attempt ${v}/2)...`)),p=await rs(i),p.status!==0));v++);p.status===0&&It()!==o.plugin&&console.log(d.default.yellow(" \u26A0\uFE0F Plugin still not detected at the npm install path after 2 attempt(s). If `badgerclaw login` reports it as not installed, re-run `badgerclaw setup`."))}n&&(Ui(),console.log(d.default.dim(" Bot config restored."))),r&&(Hi(r),console.log(d.default.dim(" Gateway config restored."))),m&&Ur(m),p.status!==0&&(console.log(d.default.red(`
171
+ `)),console.log(d.default.green("\u2705 Setup complete (Hermes-only host).")),console.log(d.default.dim("\nNext steps:\n 1. `badgerclaw login` \u2014 authenticate this CLI to the backend.\n 2. `badgerclaw setup --refresh` \u2014 push the Hermes capability so\n the backend (and the iOS app) knows this host can serve\n Hermes bots.\n 3. `badgerclaw bot create <name>` \u2014 defaults to Hermes on this host."));return}let n=await na();if(n.cli){let g=Kn();g!==n.cli?(console.log(d.default.dim(` Updating CLI: ${g} \u2192 ${n.cli} (supported)...`)),(0,ue.spawnSync)("npm",["install","-g",`badgerclaw@${n.cli}`],{stdio:"inherit",shell:!0}).status!==0&&(console.log(d.default.red("\n\u274C CLI update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(d.default.green(` \u2705 CLI updated to ${n.cli}`))):console.log(d.default.dim(` CLI already at approved version ${g}.`))}if(n.openclaw){let g=K();g!==n.openclaw?(console.log(g===null?d.default.dim(` Installing OpenClaw ${n.openclaw} (supported)...`):d.default.dim(` Updating OpenClaw: ${g} \u2192 ${n.openclaw} (supported)...`)),(0,ue.spawnSync)("npm",["install","-g",`openclaw@${n.openclaw}`],{stdio:"inherit",shell:!0}).status!==0&&(console.log(d.default.red("\n\u274C OpenClaw install/update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(d.default.green(` \u2705 OpenClaw at ${n.openclaw}`))):console.log(d.default.dim(` OpenClaw already at approved version ${g}.`))}else K()===null&&(console.log(d.default.yellow(" \u26A0\uFE0F No approved OpenClaw version and none installed \u2014 installing latest from npm.")),(0,ue.spawnSync)("npm",["install","-g","openclaw"],{stdio:"inherit",shell:!0}).status!==0&&(console.log(d.default.red(`
172
+ \u274C OpenClaw install failed.`)),process.exit(1)));let o=wc();o&&console.log(d.default.dim(" Existing bot config stashed temporarily..."));let r=_c();(0,ue.spawnSync)("openclaw",["gateway","stop"],{stdio:"pipe",shell:!0,timeout:1e4});let s=[fe.default.join(Mt.default.homedir(),".openclaw","extensions","badgerclaw"),fe.default.join(Mt.default.homedir(),".openclaw","npm","node_modules","@badgerclaw","connect"),...Kt()],a=[],i=[],c=g=>{let v=`${g}.bc-setup-stash-${Date.now()}-${Math.floor(Math.random()*1e6)}`,h=(0,ue.spawnSync)("mv",["-f",g,v],{encoding:"utf-8"});return h.status===0?{ok:!0,stash:v}:{ok:!1,error:(h.stderr||"").trim()||`exit ${h.status}`}};for(let g of s)if(L.default.existsSync(g))try{L.default.rmSync(g,{recursive:!0,force:!0}),a.push(g)}catch(v){let h=c(g);h.ok?(i.push(`${g} \u2192 ${h.stash}`),console.log(d.default.yellow(` \u26A0\uFE0F Could not delete ${g} (${v.message}); renamed it aside instead.`))):(console.log(d.default.red(` \u274C Could not delete ${g} (${v.message})`)),console.log(d.default.red(` Could not rename ${g} aside either (${h.error}). Plugin install will likely fail.`)))}a.length>0&&console.log(d.default.dim(` Cleared existing plugin director${a.length>1?"ies":"y"}.`)),i.length>0&&console.log(d.default.dim(` Renamed busy install${i.length>1?"s":""} aside: ${i.join(", ")}`));let l=n.plugin?`@badgerclaw/connect@${n.plugin}`:"@badgerclaw/connect";n.plugin?console.log(d.default.dim(` Installing ${l} (supported)...`)):console.log(d.default.yellow(" \u26A0\uFE0F Allow-list unavailable \u2014 installing @badgerclaw/connect unpinned."));let u=null;wr("2026.6.5")&&(u=Os(),u&&console.log(d.default.dim(" Adjusted OpenClaw 2026.6.5 npm overrides for a full channel-plugin install.")));let p=await oa(l);if(p.status===0&&n.plugin&&n.plugin!=="unknown"){for(let v=1;v<=2&&!(Yt()===n.plugin||(console.log(d.default.yellow(` Plugin landed as a hook-pack-only install (not yet visible to \`badgerclaw login\`) \u2014 re-running plugin install (attempt ${v}/2)...`)),p=await oa(l),p.status!==0));v++);p.status===0&&Yt()!==n.plugin&&console.log(d.default.yellow(" \u26A0\uFE0F Plugin still not detected at the npm install path after 2 attempt(s). If `badgerclaw login` reports it as not installed, re-run `badgerclaw setup`."))}o&&(vc(),console.log(d.default.dim(" Bot config restored."))),r&&(Sc(r),console.log(d.default.dim(" Gateway config restored."))),u&&Ls(u),p.status!==0&&(console.log(d.default.red(`
162
173
  \u274C Plugin install failed. Your bot config has been restored.`)),process.exit(1)),console.log(d.default.green(`
163
- \u2705 BadgerClaw plugin installed successfully!`));let P=Fi();for(let f of P){console.log(d.default.dim(` Stripping OpenClaw uuid:14 override in ${f} (breaks request@2.88 in matrix-bot-sdk)...`));try{R.default.rmSync(ae.default.join(f,"node_modules","uuid"),{recursive:!0,force:!0})}catch{}try{R.default.rmSync(ae.default.join(f,"package-lock.json"),{force:!0})}catch{}(0,te.spawnSync)("npm",["install"],{cwd:f,stdio:"inherit",shell:!0}).status!==0&&(console.log(d.default.red(`
164
- \u274C npm install failed after removing uuid override. Bot will not reply correctly until this is resolved.`)),process.exit(1))}P.length>0&&console.log(d.default.green(" \u2705 uuid override stripped + npm tree re-resolved.")),console.log("");let O=await jt({verbose:!0});O.ok||(console.log(d.default.red(`
165
- \u274C Gateway failed to start. Diagnose with:`)),console.log(d.default.dim(" systemctl --user status openclaw-gateway.service # Linux")),console.log(d.default.dim(" launchctl list | grep openclaw # macOS")),console.log(d.default.dim(" openclaw config get gateway.mode")),console.log(d.default.dim(" Then re-run `badgerclaw setup` after fixing the underlying issue.")),process.exit(1)),O.ready===!1?console.log(d.default.yellow(" \u23F3 Gateway started but not answering yet \u2014 it may still be coming up.")):console.log(d.default.green(" \u2705 Gateway is running.")),console.log(d.default.dim("\nNext: run `badgerclaw login` to authenticate.")),Ht()});je();var ds=require("commander"),E=u(require("chalk"));M();xe();ue();var us=new ds.Command("dashboard").description("Show local diagnostic dashboard \u2014 machine health, gateway status, bot telemetry").action(async()=>{b()||(console.log(E.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=be(),o=St(),n=await lt();console.log(E.default.bold.green(`
174
+ \u2705 BadgerClaw plugin installed successfully!`));let S=kc();for(let g of S){console.log(d.default.dim(` Stripping OpenClaw uuid:14 override in ${g} (breaks request@2.88 in matrix-bot-sdk)...`));try{L.default.rmSync(fe.default.join(g,"node_modules","uuid"),{recursive:!0,force:!0})}catch{}try{L.default.rmSync(fe.default.join(g,"package-lock.json"),{force:!0})}catch{}(0,ue.spawnSync)("npm",["install"],{cwd:g,stdio:"inherit",shell:!0}).status!==0&&(console.log(d.default.red(`
175
+ \u274C npm install failed after removing uuid override. Bot will not reply correctly until this is resolved.`)),process.exit(1))}S.length>0&&console.log(d.default.green(" \u2705 uuid override stripped + npm tree re-resolved.")),console.log("");let E=await un({verbose:!0});E.ok||(console.log(d.default.red(`
176
+ \u274C Gateway failed to start. Diagnose with:`)),console.log(d.default.dim(" systemctl --user status openclaw-gateway.service # Linux")),console.log(d.default.dim(" launchctl list | grep openclaw # macOS")),console.log(d.default.dim(" openclaw config get gateway.mode")),console.log(d.default.dim(" Then re-run `badgerclaw setup` after fixing the underlying issue.")),process.exit(1)),E.ready===!1?console.log(d.default.yellow(" \u23F3 Gateway started but not answering yet \u2014 it may still be coming up.")):console.log(d.default.green(" \u2705 Gateway is running.")),(aa(e.localLlm)||await Cc({assumeYes:e.yes===!0}))&&await $c(),console.log(d.default.dim("\nNext: run `badgerclaw login` to authenticate.")),dn()});Xe();var pa=require("commander"),M=m(require("chalk"));F();Ie();ke();var ga=new pa.Command("dashboard").description("Show local diagnostic dashboard \u2014 machine health, gateway status, bot telemetry").action(async()=>{R()||(console.log(M.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=we(),n=Gt(),o=await xt();console.log(M.default.bold.green(`
166
177
  BadgerClaw Dashboard
167
- `)),console.log(E.default.bold(" Instance")),console.log(` ID: ${Z()}`),console.log(` CLI Version: ${t}`),console.log(` Plugin: ${n.pluginVersion}`),console.log(),console.log(E.default.bold(" Machine")),console.log(` Hostname: ${o.hostname}`),console.log(` OS: ${o.os} / ${o.arch}`),console.log(` Uptime: ${cs(o.uptimeSeconds)}`),console.log(` Free Memory: ${o.memFreeMb} MB`),console.log();let r=n.status==="running"?E.default.green:n.status==="error"?E.default.red:E.default.yellow;if(console.log(E.default.bold(" Gateway")),console.log(` Status: ${r(n.status)}`),console.log(` PID: ${n.pid??"N/A"}`),console.log(` Last Restart: ${n.lastRestart??"N/A"}`),console.log(),n.bots.length===0)console.log(E.default.bold(" Bots")),console.log(E.default.dim(" No bots detected. Pair bots at https://badgerclaw.ai")),console.log();else{console.log(E.default.bold(` Bots (${n.bots.length})`)),console.log();for(let s of n.bots){let a=s.status==="running"?E.default.green:s.status==="error"?E.default.red:E.default.yellow;if(console.log(` ${E.default.bold(s.botUsername)} ${a(`[${s.status}]`)}`),console.log(` ID: ${s.botId}`),console.log(` Uptime: ${cs(s.uptimeSeconds)}`),console.log(` Messages: ${s.messagesReceived} in / ${s.messagesSent} out`),s.chunkedMessages>0&&console.log(` Chunked: ${s.chunkedMessages} messages, ${s.totalChunksSent} chunks`),console.log(` Rooms: ${s.roomsActive} active`),console.log(` Errors: ${s.errors}`),s.lastError&&(console.log(` Last Error: ${E.default.red(s.lastError)}`),console.log(` Error At: ${s.lastErrorAt}`)),console.log(` Last Active: ${s.lastActivity??"N/A"}`),s.roomDetails&&s.roomDetails.length>0){console.log(E.default.dim(" Rooms:"));for(let c of s.roomDetails)console.log(E.default.dim(` ${c.roomName} \u2014 ${c.messagesInRoom} msgs, last: ${c.lastActivityInRoom??"N/A"}`))}console.log()}}console.log(E.default.dim(` Last checked: ${new Date().toISOString()}`)),console.log()});function cs(e){if(e<60)return`${e}s`;if(e<3600)return`${Math.floor(e/60)}m ${e%60}s`;let t=Math.floor(e/3600),o=Math.floor(e%3600/60);return t<24?`${t}h ${o}m`:`${Math.floor(t/24)}d ${t%24}h ${o}m`}var sn=require("commander"),Ve=u(require("chalk")),ms=u(require("ora"));M();ue();je();var qi=new sn.Command("restart").description("Restart the OpenClaw gateway via the plugin probe endpoint").action(async()=>{b()||(console.log(Ve.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,ms.default)("Restarting gateway...").start(),o=await Be();if(o.success){t.succeed(Ve.default.green(`Gateway restarted: ${o.message}`));try{await T(),console.log(Ve.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(Ve.default.dim(" Could not push heartbeat \u2014 daemon may not be running."))}}else t.fail(Ve.default.red(`Gateway restart failed: ${o.message}`)),process.exit(1)}),ps=new sn.Command("gateway").description("Manage the OpenClaw gateway").addCommand(qi);var fe=require("commander"),k=u(require("chalk")),Re=u(require("ora")),ge=u(require("axios"));Gt();M();var Ie="http://localhost:7331",Vi=new fe.Command("start").description("Start a Claude Code session for a bot+room").requiredOption("--bot <botId>","Bot ID or username").requiredOption("--room <roomId>","Matrix room ID").option("--session-id <id>","Session ID (default: auto-generated)").option("--port <port>","MCP server port (default: 7332)","7332").option("--project <dir>","Project directory",process.cwd()).action(async e=>{b()||(console.log(k.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let o=e.sessionId||`session-${Date.now()}`,n=parseInt(e.port,10),r=e.project.replace(/^~/,process.env.HOME||""),s=(0,Re.default)("Starting Claude Code session...").start();try{await ge.default.post(`${Ie}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:o},{timeout:1e4}),s.text="Gateway toggled \u2014 launching MCP server...";let c=Uo({sessionId:o,port:n,projectDir:r}).pid||0;await new Promise(l=>setTimeout(l,1500)),s.text="MCP server running \u2014 launching Claude Code...",Fo({sessionId:o,port:n,projectDir:r}),Go(o,0,c,n,r),s.succeed(k.default.green("Claude Code session started")+k.default.dim(` (session: ${o}, port: ${n})`)),console.log(k.default.dim(` Bot: ${e.bot}`)),console.log(k.default.dim(` Room: ${e.room}`)),console.log(k.default.dim(` Project: ${r}`)),console.log(k.default.dim(" Claude Code should open in a new terminal window."))}catch(a){let c=a.response?.data?.message||a.message||"Unknown error";s.fail(k.default.red(`Failed to start Claude Code: ${c}`)),process.exit(1)}}),Ki=new fe.Command("stop").description("Stop a Claude Code session").option("--bot <botId>","Bot ID or username").option("--room <roomId>","Matrix room ID").option("--session-id <id>","Session ID to stop").action(async e=>{b()||(console.log(k.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let o=(0,Re.default)("Stopping Claude Code session...").start();try{e.bot&&e.room&&await ge.default.post(`${Ie}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!1},{timeout:1e4});let n=e.sessionId;if(!n)try{let a=((await ge.default.get(`${Ie}/claude-code/status`,{timeout:5e3})).data?.rooms||[]).find(c=>c.botId===e.bot&&c.roomId===e.room);a&&(n=a.sessionId)}catch{}n?(Wo(n),o.succeed(k.default.green(`Claude Code session stopped (${n})`))):(o.succeed(k.default.green("Claude Code toggled off at gateway")),console.log(k.default.dim(" No local session found to kill \u2014 may need to close Claude Code manually.")))}catch(n){let r=n.response?.data?.message||n.message||"Unknown error";o.fail(k.default.red(`Failed to stop Claude Code: ${r}`)),process.exit(1)}}),Yi=new fe.Command("status").description("Show active Claude Code sessions").action(async()=>{b()||(console.log(k.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,Re.default)("Fetching Claude Code status...").start();try{let o=[];try{o=(await ge.default.get(`${Ie}/claude-code/status`,{timeout:5e3})).data?.rooms||[]}catch{}let n=qo();if(t.stop(),o.length===0&&n.length===0){console.log(k.default.dim("No active Claude Code sessions."));return}if(o.length>0){console.log(k.default.bold(`
168
- Gateway Claude Code Rooms:`)),console.log(k.default.dim(" Bot".padEnd(30)+"Room".padEnd(30)+"Session".padEnd(20)+"Enabled")),console.log(k.default.dim(" "+"-".repeat(88)));for(let r of o){let s=r.enabled?k.default.green("ON"):k.default.dim("OFF");console.log(` ${(r.botId||"").padEnd(30)}${(r.roomName||r.roomId||"").padEnd(30)}${(r.sessionId||"-").padEnd(20)}${s}`)}}if(n.length>0){console.log(k.default.bold(`
169
- Local Sessions:`)),console.log(k.default.dim(" Session".padEnd(25)+"Port".padEnd(8)+"MCP PID".padEnd(10)+"Project".padEnd(40)+"Started")),console.log(k.default.dim(" "+"-".repeat(90)));for(let r of n)console.log(` ${r.sessionId.padEnd(25)}${String(r.port).padEnd(8)}${String(r.mcpPid).padEnd(10)}${r.projectDir.padEnd(40)}${r.startedAt}`)}console.log("")}catch(o){t.fail(k.default.red(`Failed to get status: ${o.message}`)),process.exit(1)}}),Ji=new fe.Command("group").description("Group bots/rooms into a shared Claude Code session").requiredOption("--session <id>","Session ID to group under").requiredOption("--bot <botId>","Bot ID or username").requiredOption("--room <roomId>","Matrix room ID").action(async e=>{let t=(0,Re.default)("Grouping bot+room into session...").start();try{await ge.default.post(`${Ie}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:e.session},{timeout:1e4}),t.succeed(k.default.green(`Grouped ${e.bot} + ${e.room} into session "${e.session}"`))}catch(o){let n=o.response?.data?.message||o.message||"Unknown error";t.fail(k.default.red(`Failed to group: ${n}`)),process.exit(1)}}),zi=new fe.Command("allow").description("Add a user to the Claude Code allowlist for a bot+room").requiredOption("--bot <botId>","Bot ID or username").requiredOption("--room <roomId>","Matrix room ID").requiredOption("--user <userId>","Matrix user ID to allow (e.g. @alice:server)").action(async e=>{let t=(0,Re.default)("Adding user to allowlist...").start();try{await ge.default.post(`${Ie}/claude-code/allow`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(k.default.green(`Added ${e.user} to allowlist for ${e.bot} in ${e.room}`))}catch(o){let n=o.response?.data?.message||o.message||"Unknown error";t.fail(k.default.red(`Failed to add user: ${n}`)),process.exit(1)}}),Xi=new fe.Command("revoke").description("Remove a user from the Claude Code allowlist for a bot+room").requiredOption("--bot <botId>","Bot ID or username").requiredOption("--room <roomId>","Matrix room ID").requiredOption("--user <userId>","Matrix user ID to revoke").action(async e=>{let t=(0,Re.default)("Removing user from allowlist...").start();try{await ge.default.post(`${Ie}/claude-code/revoke`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(k.default.green(`Removed ${e.user} from allowlist for ${e.bot} in ${e.room}`))}catch(o){let n=o.response?.data?.message||o.message||"Unknown error";t.fail(k.default.red(`Failed to revoke user: ${n}`)),process.exit(1)}}),gs=new fe.Command("claude-code").description("Manage Claude Code sessions (relay Matrix messages to local Claude Code)").addCommand(Vi).addCommand(Ki).addCommand(Yi).addCommand(Ji).addCommand(zi).addCommand(Xi);Ee();async function Qi(){await An(process.argv);let e=new fs.Command;e.name("badgerclaw").description("BadgerClaw CLI \u2014 one-click bot provisioning").version("0.3.2"),e.addCommand(Sr),e.addCommand($r),e.addCommand(Ir),e.addCommand(Tr),e.addCommand(Kn),e.addCommand(jr),e.addCommand(ls),e.addCommand(Jo),e.addCommand(us),e.addCommand(ps),e.addCommand(gs),e.parse(process.argv)}Qi().catch(e=>{console.error(e),process.exit(1)});
178
+ `)),console.log(M.default.bold(" Instance")),console.log(` ID: ${ae()}`),console.log(` CLI Version: ${t}`),console.log(` Plugin: ${o.pluginVersion}`),console.log(),console.log(M.default.bold(" Machine")),console.log(` Hostname: ${n.hostname}`),console.log(` OS: ${n.os} / ${n.arch}`),console.log(` Uptime: ${ma(n.uptimeSeconds)}`),console.log(` Free Memory: ${n.memFreeMb} MB`),console.log();let r=o.status==="running"?M.default.green:o.status==="error"?M.default.red:M.default.yellow;if(console.log(M.default.bold(" Gateway")),console.log(` Status: ${r(o.status)}`),console.log(` PID: ${o.pid??"N/A"}`),console.log(` Last Restart: ${o.lastRestart??"N/A"}`),console.log(),o.bots.length===0)console.log(M.default.bold(" Bots")),console.log(M.default.dim(" No bots detected. Pair bots at https://badgerclaw.ai")),console.log();else{console.log(M.default.bold(` Bots (${o.bots.length})`)),console.log();for(let s of o.bots){let a=s.status==="running"?M.default.green:s.status==="error"?M.default.red:M.default.yellow;if(console.log(` ${M.default.bold(s.botUsername)} ${a(`[${s.status}]`)}`),console.log(` ID: ${s.botId}`),console.log(` Uptime: ${ma(s.uptimeSeconds)}`),console.log(` Messages: ${s.messagesReceived} in / ${s.messagesSent} out`),s.chunkedMessages>0&&console.log(` Chunked: ${s.chunkedMessages} messages, ${s.totalChunksSent} chunks`),console.log(` Rooms: ${s.roomsActive} active`),console.log(` Errors: ${s.errors}`),s.lastError&&(console.log(` Last Error: ${M.default.red(s.lastError)}`),console.log(` Error At: ${s.lastErrorAt}`)),console.log(` Last Active: ${s.lastActivity??"N/A"}`),s.roomDetails&&s.roomDetails.length>0){console.log(M.default.dim(" Rooms:"));for(let i of s.roomDetails)console.log(M.default.dim(` ${i.roomName} \u2014 ${i.messagesInRoom} msgs, last: ${i.lastActivityInRoom??"N/A"}`))}console.log()}}console.log(M.default.dim(` Last checked: ${new Date().toISOString()}`)),console.log()});function ma(e){if(e<60)return`${e}s`;if(e<3600)return`${Math.floor(e/60)}m ${e%60}s`;let t=Math.floor(e/3600),n=Math.floor(e%3600/60);return t<24?`${t}h ${n}m`:`${Math.floor(t/24)}d ${t%24}h ${n}m`}var Bo=require("commander"),at=m(require("chalk")),fa=m(require("ora"));F();ke();Xe();var Ac=new Bo.Command("restart").description("Restart the OpenClaw gateway via the plugin probe endpoint").action(async()=>{R()||(console.log(at.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,fa.default)("Restarting gateway...").start(),n=await Qe();if(n.success){t.succeed(at.default.green(`Gateway restarted: ${n.message}`));try{await U(),console.log(at.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(at.default.dim(" Could not push heartbeat \u2014 daemon may not be running."))}}else t.fail(at.default.red(`Gateway restart failed: ${n.message}`)),process.exit(1)}),ha=new Bo.Command("gateway").description("Manage the OpenClaw gateway").addCommand(Ac);var $e=require("commander"),$=m(require("chalk")),je=m(require("ora")),xe=m(require("axios"));gn();F();var Ne="http://localhost:7331",Pc=new $e.Command("start").description("Start a Claude Code session for a bot+room").requiredOption("--bot <botId>","Bot ID or username").requiredOption("--room <roomId>","Matrix room ID").option("--session-id <id>","Session ID (default: auto-generated)").option("--port <port>","MCP server port (default: 7332)","7332").option("--project <dir>","Project directory",process.cwd()).action(async e=>{R()||(console.log($.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let n=e.sessionId||`session-${Date.now()}`,o=parseInt(e.port,10),r=e.project.replace(/^~/,process.env.HOME||""),s=(0,je.default)("Starting Claude Code session...").start();try{await xe.default.post(`${Ne}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:n},{timeout:1e4}),s.text="Gateway toggled \u2014 launching MCP server...";let i=wo({sessionId:n,port:o,projectDir:r}).pid||0;await new Promise(c=>setTimeout(c,1500)),s.text="MCP server running \u2014 launching Claude Code...",_o({sessionId:n,port:o,projectDir:r}),So(n,0,i,o,r),s.succeed($.default.green("Claude Code session started")+$.default.dim(` (session: ${n}, port: ${o})`)),console.log($.default.dim(` Bot: ${e.bot}`)),console.log($.default.dim(` Room: ${e.room}`)),console.log($.default.dim(` Project: ${r}`)),console.log($.default.dim(" Claude Code should open in a new terminal window."))}catch(a){let i=a.response?.data?.message||a.message||"Unknown error";s.fail($.default.red(`Failed to start Claude Code: ${i}`)),process.exit(1)}}),Ec=new $e.Command("stop").description("Stop a Claude Code session").option("--bot <botId>","Bot ID or username").option("--room <roomId>","Matrix room ID").option("--session-id <id>","Session ID to stop").action(async e=>{R()||(console.log($.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let n=(0,je.default)("Stopping Claude Code session...").start();try{e.bot&&e.room&&await xe.default.post(`${Ne}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!1},{timeout:1e4});let o=e.sessionId;if(!o)try{let a=((await xe.default.get(`${Ne}/claude-code/status`,{timeout:5e3})).data?.rooms||[]).find(i=>i.botId===e.bot&&i.roomId===e.room);a&&(o=a.sessionId)}catch{}o?(vo(o),n.succeed($.default.green(`Claude Code session stopped (${o})`))):(n.succeed($.default.green("Claude Code toggled off at gateway")),console.log($.default.dim(" No local session found to kill \u2014 may need to close Claude Code manually.")))}catch(o){let r=o.response?.data?.message||o.message||"Unknown error";n.fail($.default.red(`Failed to stop Claude Code: ${r}`)),process.exit(1)}}),Oc=new $e.Command("status").description("Show active Claude Code sessions").action(async()=>{R()||(console.log($.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,je.default)("Fetching Claude Code status...").start();try{let n=[];try{n=(await xe.default.get(`${Ne}/claude-code/status`,{timeout:5e3})).data?.rooms||[]}catch{}let o=ko();if(t.stop(),n.length===0&&o.length===0){console.log($.default.dim("No active Claude Code sessions."));return}if(n.length>0){console.log($.default.bold(`
179
+ Gateway Claude Code Rooms:`)),console.log($.default.dim(" Bot".padEnd(30)+"Room".padEnd(30)+"Session".padEnd(20)+"Enabled")),console.log($.default.dim(" "+"-".repeat(88)));for(let r of n){let s=r.enabled?$.default.green("ON"):$.default.dim("OFF");console.log(` ${(r.botId||"").padEnd(30)}${(r.roomName||r.roomId||"").padEnd(30)}${(r.sessionId||"-").padEnd(20)}${s}`)}}if(o.length>0){console.log($.default.bold(`
180
+ Local Sessions:`)),console.log($.default.dim(" Session".padEnd(25)+"Port".padEnd(8)+"MCP PID".padEnd(10)+"Project".padEnd(40)+"Started")),console.log($.default.dim(" "+"-".repeat(90)));for(let r of o)console.log(` ${r.sessionId.padEnd(25)}${String(r.port).padEnd(8)}${String(r.mcpPid).padEnd(10)}${r.projectDir.padEnd(40)}${r.startedAt}`)}console.log("")}catch(n){t.fail($.default.red(`Failed to get status: ${n.message}`)),process.exit(1)}}),Lc=new $e.Command("group").description("Group bots/rooms into a shared Claude Code session").requiredOption("--session <id>","Session ID to group under").requiredOption("--bot <botId>","Bot ID or username").requiredOption("--room <roomId>","Matrix room ID").action(async e=>{let t=(0,je.default)("Grouping bot+room into session...").start();try{await xe.default.post(`${Ne}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:e.session},{timeout:1e4}),t.succeed($.default.green(`Grouped ${e.bot} + ${e.room} into session "${e.session}"`))}catch(n){let o=n.response?.data?.message||n.message||"Unknown error";t.fail($.default.red(`Failed to group: ${o}`)),process.exit(1)}}),Tc=new $e.Command("allow").description("Add a user to the Claude Code allowlist for a bot+room").requiredOption("--bot <botId>","Bot ID or username").requiredOption("--room <roomId>","Matrix room ID").requiredOption("--user <userId>","Matrix user ID to allow (e.g. @alice:server)").action(async e=>{let t=(0,je.default)("Adding user to allowlist...").start();try{await xe.default.post(`${Ne}/claude-code/allow`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed($.default.green(`Added ${e.user} to allowlist for ${e.bot} in ${e.room}`))}catch(n){let o=n.response?.data?.message||n.message||"Unknown error";t.fail($.default.red(`Failed to add user: ${o}`)),process.exit(1)}}),Mc=new $e.Command("revoke").description("Remove a user from the Claude Code allowlist for a bot+room").requiredOption("--bot <botId>","Bot ID or username").requiredOption("--room <roomId>","Matrix room ID").requiredOption("--user <userId>","Matrix user ID to revoke").action(async e=>{let t=(0,je.default)("Removing user from allowlist...").start();try{await xe.default.post(`${Ne}/claude-code/revoke`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed($.default.green(`Removed ${e.user} from allowlist for ${e.bot} in ${e.room}`))}catch(n){let o=n.response?.data?.message||n.message||"Unknown error";t.fail($.default.red(`Failed to revoke user: ${o}`)),process.exit(1)}}),ya=new $e.Command("claude-code").description("Manage Claude Code sessions (relay Matrix messages to local Claude Code)").addCommand(Pc).addCommand(Ec).addCommand(Oc).addCommand(Lc).addCommand(Tc).addCommand(Mc);var Va=require("commander"),C=m(require("chalk")),Wa=m(require("path"));ie();var ba=require("child_process"),Dc="http://127.0.0.1:11434";function Uo(){let e=process.env.OLLAMA_HOST?.trim();return e?/^https?:\/\//.test(e)?e.replace(/\/$/,""):`http://${e}`.replace(/\/$/,""):Dc}function Be(e,t){return{num_ctx:e,num_predict:t,temperature:0,seed:42,top_p:1,top_k:0}}async function wa(e,t,n={}){let o=n.host??Uo(),r=n.fetchImpl??fetch,s=new AbortController,a=setTimeout(()=>s.abort(),n.timeoutMs??3e5);try{let i=await r(`${o}${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),signal:s.signal});if(!i.ok){let c=await i.text().catch(()=>"");throw new Error(`ollama ${e} \u2192 HTTP ${i.status} ${c.slice(0,200)}`)}return await i.json()}finally{clearTimeout(a)}}async function Ue(e,t={}){let n={model:e.model,messages:e.messages,stream:!1,options:e.options,keep_alive:e.keepAlive??"5m"};return e.tools&&e.tools.length&&(n.tools=e.tools),wa("/api/chat",n,t)}async function _a(e,t={}){return wa("/api/show",{model:e},{...t,timeoutMs:15e3})}async function Sa(e={}){try{let t=e.host??Uo(),o=await(e.fetchImpl??fetch)(`${t}/api/version`);return o.ok?(await o.json()).version??null:null}catch{return null}}async function va(e={}){try{let t=e.host??Uo(),o=await(e.fetchImpl??fetch)(`${t}/api/tags`);return o.ok?((await o.json()).models??[]).map(s=>s.name):[]}catch{return[]}}function ka(e){try{(0,ba.spawnSync)("ollama",["stop",e],{encoding:"utf-8",timeout:15e3})}catch{}}function Ra(e){if(!e)return null;let t=e.trim().match(/([\d.]+)\s*([BM])/i);if(!t)return null;let n=Number.parseFloat(t[1]);return Number.isFinite(n)?t[2].toUpperCase()==="M"?Math.round(n/1e3*100)/100:n:null}var xa=require("child_process");function ne(e,t=2){let n=10**t;return Math.round(e*n)/n}function En(e){let t=e.filter(o=>Number.isFinite(o)).sort((o,r)=>o-r);if(t.length===0)return null;let n=Math.floor(t.length/2);return t.length%2?t[n]:(t[n-1]+t[n])/2}function Fo(e,t){let n=e.filter(i=>Number.isFinite(i)).sort((i,c)=>i-c);if(n.length===0)return null;if(n.length===1)return n[0];let o=t*(n.length-1),r=Math.floor(o),s=Math.ceil(o);if(r===s)return n[r];let a=o-r;return n[r]+(n[s]-n[r])*a}var Nc="You are assisting an engineer who is integrating a local language model into a chat application. The application runs on consumer hardware and must stay responsive. Background: the system pairs a small assistant model with a set of tools for sending messages, looking up records, and scheduling tasks. The assistant should be concise, accurate, and avoid unnecessary preamble. It coordinates with a gateway process that forwards requests and collects telemetry every thirty seconds. Latency budgets are tight: a typical turn should begin streaming within a second and sustain a steady token rate. Reliability matters more than cleverness, and the model must follow instructions exactly even under load. Operators benchmark candidate models "+"across a range of memory tiers to decide which ones run well locally. ".repeat(2)+`
181
+
182
+ Task: In about one hundred words, explain why steady decode throughput and low time-to-first-token both matter for an interactive local assistant.`,Ho=class{constructor(t){this.timer=null;this.peakMb=0;this.sawAny=!1;this.runner=t??((n,o)=>{let r=(0,xa.spawnSync)(n,o,{encoding:"utf-8",timeout:3e3});return{status:r.status,stdout:r.stdout||""}})}sampleOnce(){let t=this.runner("ps",["-axo","rss=,comm="]);if(t.status!==0)return null;let n=0,o=!1;for(let r of t.stdout.split(`
183
+ `)){if(!/ollama/i.test(r))continue;let s=r.trim().match(/^(\d+)/);s&&(n+=Number.parseInt(s[1],10),o=!0)}return o?n/1024:null}start(){let t=()=>{let n=this.sampleOnce();n!=null&&(this.sawAny=!0,n>this.peakMb&&(this.peakMb=n))};t(),this.timer=setInterval(t,250),typeof this.timer.unref=="function"&&this.timer.unref()}stop(){return this.timer&&clearInterval(this.timer),this.timer=null,this.sawAny?Math.round(this.peakMb):null}};function jc(e){return e.eval_count&&e.eval_duration?e.eval_count/(e.eval_duration/1e9):null}function Bc(e){return e.prompt_eval_count&&e.prompt_eval_duration?e.prompt_eval_count/(e.prompt_eval_duration/1e9):null}function Uc(e){return e.prompt_eval_duration?e.prompt_eval_duration/1e6:null}var Ca=[{role:"user",content:Nc}];async function $a(e){let{model:t,numCtx:n,warmTrials:o}=e,r=e.warmupTrials??2,s=e.perfOpts??{},a=s.log??(()=>{}),i=e.sampler??new Ho;ka(t),a(" cold load trial\u2026");let c=null;try{let b=await Ue({model:t,messages:[{role:"user",content:"Reply with: OK"}],options:Be(n,8)},s);c=b.load_duration?b.load_duration/1e6:null}catch(b){a(` cold trial failed: ${b.message}`)}for(let b=0;b<r;b++)a(` warmup ${b+1}/${r}\u2026`),await Ue({model:t,messages:Ca,options:Be(n,64)},s);let l=[],u=[],p=[],S=null;i.start();try{for(let b=0;b<o;b++){a(` trial ${b+1}/${o}\u2026`);let j=await Ue({model:t,messages:Ca,options:Be(n,128)},s),oe=jc(j),re=Uc(j),k=Bc(j);oe!=null&&l.push(oe),re!=null&&u.push(re),k!=null&&p.push(k)}}finally{S=i.stop()}let E=En(l),g=Fo(l,.95),v=En(u),h=Fo(u,.95),y=En(p);return{decode_tps_median:E!=null?ne(E):null,decode_tps_p95:g!=null?ne(g):null,prefill_tps_median:y!=null?ne(y):null,ttft_ms_median:v!=null?ne(v):null,ttft_ms_p95:h!=null?ne(h):null,peak_ram_mb:S,load_ms:c!=null?ne(c):null,max_context:null,num_ctx:n}}async function Ia(e){let{model:t}=e,n=e.probes??[8192,16384,32768],o=e.perfOpts??{},r=o.log??(()=>{}),s=null;for(let a of n)try{r(` max-context probe ${a}\u2026`);let i=await Ue({model:t,messages:[{role:"user",content:"Reply with: OK"}],options:Be(a,8)},o);if(i.eval_count&&i.eval_count>0)s=a;else break}catch{break}return s}var Aa=require("child_process");function Fc(e){let t=e.match(/```(?:javascript|js)?\s*([\s\S]*?)```/i);return t?t[1].trim():e.trim()}function Go(e,t,n,o={}){let s=`${Fc(e)}
184
+ const __out = [${t.join(", ")}];
185
+ process.stdout.write(JSON.stringify(__out));`,a=o.exec??(u=>(0,Aa.execFileSync)(process.execPath,["-e",u],{timeout:5e3,encoding:"utf-8",env:{PATH:process.env.PATH??""},stdio:["ignore","pipe","ignore"]}));if(n.length===0)return{score:0,passed:!1,ran:!1};let i;try{let u=a(s);if(i=JSON.parse(u),!Array.isArray(i))throw new Error("non-array output")}catch{return{score:0,passed:!1,ran:!1}}let c=0;for(let u=0;u<n.length;u++)Pa(i[u],n[u])&&c++;return{score:Math.round(c/n.length*100),passed:c===n.length,ran:!0}}function Pa(e,t){return e===t?!0:typeof e!=typeof t?!1:Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((n,o)=>Pa(n,t[o])):!1}var Vo={tool_call:.4,instruction:.2,coding:.15,summarization:.15,chat:.1},On={type:"function",function:{name:"get_weather",description:"Get the current weather for a location.",parameters:{type:"object",properties:{location:{type:"string",description:'City, e.g. "Paris, France"'}},required:["location"]}}},Hc={type:"function",function:{name:"send_email",description:"Send an email to a recipient.",parameters:{type:"object",properties:{to:{type:"string",description:"Recipient email address"},subject:{type:"string"},body:{type:"string"}},required:["to","subject","body"]}}},Gc={type:"function",function:{name:"search_web",description:"Search the web for a query.",parameters:{type:"object",properties:{query:{type:"string"}},required:["query"]}}};function Ln(e){let t=e.message?.tool_calls?.[0];if(!t)return null;let n=t.function.arguments;if(typeof n=="string")try{n=JSON.parse(n)}catch{n={}}return{name:t.function.name,args:n||{}}}function Q(e){return(e.message?.content??"").trim()}function qo(e){return JSON.stringify(e).toLowerCase()}function qc(e){let t=e.match(/```(?:json)?\s*([\s\S]*?)```/i),o=(t?t[1]:e).match(/\{[\s\S]*\}/);if(!o)return null;try{return JSON.parse(o[0])}catch{return null}}function Ea(e){return e.split(/[.!?]+/).map(t=>t.trim()).filter(Boolean).length}var Vc=/\b(can'?t|cannot|won'?t|unable|not able|sorry|i'?m sorry)\b/i,Oa="The Voyager 1 probe launched in 1977 and became the first human-made object to enter interstellar space in 2012. It carries a golden record with sounds and images selected to portray life on Earth. As of recent years it remains in contact with NASA, transmitting data from beyond the heliosphere.",La=["voyager","1977","interstellar","golden record","nasa"],Wo=[{id:"tool_call:single_arg",category:"tool_call",tools:[On],numPredict:256,messages:[{role:"user",content:"What is the current weather in Paris, France? Use the available tool."}],gradeProgrammatic:e=>{let t=Ln(e),n=!!t&&t.name==="get_weather"&&/paris/.test(qo(t.args));return{score:n?100:t?.name==="get_weather"?50:0,passed:n}}},{id:"tool_call:select_among_many",category:"tool_call",tools:[On,Hc,Gc],numPredict:256,messages:[{role:"user",content:'Send an email to bob@example.com with subject "Hello" and body "Hi Bob". Use the available tools.'}],gradeProgrammatic:e=>{let t=Ln(e),n=!!t&&t.name==="send_email",o=n&&/bob@example\.com/.test(qo(t.args));return{score:o?100:n?50:0,passed:o}}},{id:"tool_call:no_tool_needed",category:"tool_call",tools:[On],numPredict:64,messages:[{role:"user",content:"What is 2 + 2? Answer directly with just the number. Do not call any tool."}],gradeProgrammatic:e=>{if(Ln(e))return{score:0,passed:!1};let n=/\b4\b/.test(Q(e));return{score:n?100:50,passed:n}}},{id:"tool_call:arg_from_context",category:"tool_call",tools:[On],numPredict:256,messages:[{role:"user",content:"I am currently in Tokyo, Japan. What is the weather where I am right now? Use the tool."}],gradeProgrammatic:e=>{let t=Ln(e),n=!!t&&t.name==="get_weather"&&/tokyo/.test(qo(t.args));return{score:n?100:t?.name==="get_weather"?50:0,passed:n}}},{id:"instruction:format",category:"instruction",numPredict:16,messages:[{role:"user",content:"Respond with exactly this and nothing else: PONG"}],gradeProgrammatic:e=>{let t=Q(e);return t==="PONG"?{score:100,passed:!0}:{score:/\bPONG\b/.test(t)?50:0,passed:!1}}},{id:"instruction:length_constraint",category:"instruction",numPredict:16,messages:[{role:"user",content:"In exactly one word, what color is a clear daytime sky? Reply with only that one word, no punctuation."}],gradeProgrammatic:e=>{let t=Q(e).replace(/[.!?,]/g,"").trim(),o=t.split(/\s+/).filter(Boolean).length===1,r=/blue/i.test(t);return{score:o&&r?100:r?60:o?40:0,passed:o&&r}}},{id:"instruction:refusal_shape",category:"instruction",numPredict:32,messages:[{role:"system",content:"You are a calculator that ONLY performs arithmetic. If the user asks for anything that is not an arithmetic calculation, reply with exactly the single word: REFUSED"},{role:"user",content:"What is the capital of France?"}],gradeProgrammatic:e=>{let t=Q(e);return t==="REFUSED"?{score:100,passed:!0}:{score:/REFUSED/i.test(t)?60:0,passed:!1}}},{id:"coding:implement",category:"coding",numPredict:512,messages:[{role:"user",content:"Write a JavaScript function named add that takes two numbers and returns their sum. Output ONLY the function definition as code, with no explanation and no markdown code fences."}],gradeProgrammatic:e=>{let t=Go(Q(e),["add(2,3)","add(-4,9)","add(0,0)"],[5,5,0]);return{score:t.score,passed:t.passed}}},{id:"coding:bugfix",category:"coding",numPredict:512,messages:[{role:"user",content:`The following JavaScript function should return true when n is even, but it is buggy:
186
+
187
+ function isEven(n) { return n % 2 === 1; }
188
+
189
+ Return a corrected version named isEven. Output ONLY the function definition as code, no explanation, no markdown fences.`}],gradeProgrammatic:e=>{let t=Go(Q(e),["isEven(2)","isEven(3)","isEven(0)","isEven(7)"],[!0,!1,!0,!1]);return{score:t.score,passed:t.passed}}},{id:"extraction:json",category:"summarization",numPredict:128,messages:[{role:"user",content:`Extract the person's name and email from this text and return ONLY a JSON object with keys "name" and "email":
190
+
191
+ "Please reach out to Jane Doe at jane.doe@example.com regarding the invoice."`}],gradeProgrammatic:e=>{let t=qc(Q(e));if(!t)return{score:0,passed:!1};let n=String(t.name??"").toLowerCase(),o=String(t.email??"").toLowerCase(),r=0;return n.includes("jane")&&n.includes("doe")&&(r+=50),o==="jane.doe@example.com"&&(r+=50),{score:r,passed:r===100}}},{id:"summarization:two_sentence",category:"summarization",numPredict:256,messages:[{role:"user",content:`Summarize the following text in exactly two sentences. Be faithful \u2014 do not add information.
192
+
193
+ `+Oa}],gradeProgrammatic:e=>{let t=Q(e).toLowerCase(),o=La.filter(i=>t.includes(i)).length/La.length*100,r=Ea(Q(e)),s=r>=1&&r<=3;return{score:Math.round(s?o:o*.7),passed:o>=60&&s}},judge:{dimension:"faithfulness",source:Oa,instruction:"Score 0\u2013100 how faithful the SUMMARY is to the SOURCE: 100 = every claim is supported by the source and nothing is invented; 0 = contradicts or fabricates. Also judge whether it is a reasonable 2-sentence summary.",getOutput:e=>Q(e),combine:(e,t)=>Math.round(((e??0)+t)/2)}},{id:"chat:helpfulness",category:"chat",numPredict:128,messages:[{role:"user",content:'A user says: "My home WiFi disconnects every few minutes." In one sentence, give one specific first troubleshooting step.'}],gradeProgrammatic:e=>{let t=Q(e);return{score:null,passed:t.length>0&&!Vc.test(t)&&Ea(t)<=3}},judge:{dimension:"helpfulness",instruction:"Score 0\u2013100 how helpful and specific this single-step WiFi troubleshooting reply is: 100 = a concrete, correct, actionable first step in ~one sentence; 0 = vague, wrong, or off-topic.",getOutput:e=>Q(e),combine:(e,t)=>t}}];var Dt=class extends Error{constructor(t){super(t),this.name="JudgeUnavailableError"}};function Yo(){return process.env.BENCHMARK_JUDGE_MODEL?.trim()||"claude-opus-4-8"}function Tn(){return!!(process.env.ANTHROPIC_API_KEY||process.env.ANTHROPIC_AUTH_TOKEN)}var Ko=null;function Wc(){if(!Tn())throw new Dt("LLM-judge needs ANTHROPIC_API_KEY (set it for official runs, or pass --no-judge).");if(!Ko){let e=require("@anthropic-ai/sdk"),t=e.default??e;Ko=new t}return Ko}var Kc={type:"object",properties:{score:{type:"integer",description:"0 (worst) to 100 (best)"},passed:{type:"boolean"},reason:{type:"string",description:"one short sentence"}},required:["score","passed","reason"],additionalProperties:!1};function Yc(e){return Number.isFinite(e)?Math.max(0,Math.min(100,Math.round(e))):0}function Jc(e){let t=null;try{t=JSON.parse(e)}catch{let n=e.match(/\{[\s\S]*\}/);if(n)try{t=JSON.parse(n[0])}catch{t=null}}if(!t)throw new Error(`judge returned non-JSON: ${e.slice(0,120)}`);return{score:Yc(Number(t.score)),passed:!!t.passed,reason:String(t.reason??"").slice(0,300)}}async function Ta(e){if(e.impl)return e.impl(e);let t=Wc(),n=[`You are an impartial grader. Dimension: ${e.dimension}.`,e.instruction,e.source?`
194
+ SOURCE:
195
+ ${e.source}`:"",`
196
+ OUTPUT TO GRADE:
197
+ ${e.output}`,`
198
+ Return a JSON object with keys "score" (integer 0-100), "passed" (boolean), and "reason" (one short sentence). Output only the JSON.`].filter(Boolean),r=(await t.messages.create({model:Yo(),max_tokens:1024,messages:[{role:"user",content:n.join(`
199
+ `)}],output_config:{effort:"low",format:{type:"json_schema",schema:Kc}}})).content.find(s=>s.type==="text");if(!r?.text)throw new Error("judge returned no text block");return Jc(r.text)}var Jo="badgerclaw.benchmark.v1";function zc(){let e={tool_call:0,instruction:0,coding:0,summarization:0,chat:0};for(let t of Wo)e[t.category]++;return e}async function Qc(e,t,n){let o=t.log??(()=>{}),r=t.chatImpl??(u=>Ue(u,{host:t.host,fetchImpl:t.fetchImpl})),s;try{o(` task ${e.id}\u2026`),s=await r({model:t.model,messages:e.messages,options:Be(t.numCtx,e.numPredict),tools:e.tools})}catch(u){return o(` task ${e.id} chat failed: ${u.message}`),{id:e.id,category:e.category,score:0,weight:n,passed:!1}}let a=e.gradeProgrammatic(s),i=a.score,c=!1,l=a.passed;if(t.useJudge&&e.judge){let u=a.score===null&&a.passed===!1;try{let p=await Ta({dimension:e.judge.dimension,instruction:e.judge.instruction,source:e.judge.source,output:e.judge.getOutput(s),impl:t.judgeImpl});c=!0;let S=e.judge.combine??((E,g)=>g);i=u?0:S(a.score,p.score),l=i>=60}catch(p){p instanceof Dt?o(` judge unavailable for ${e.id} \u2014 using programmatic score only`):o(` judge error for ${e.id}: ${p.message}`),i=u?0:a.score}}return{id:e.id,category:e.category,score:i,weight:n,passed:l,judged:c}}async function Ma(e){let t=zc(),n=[];for(let l of Wo){let u=ne(Vo[l.category]/t[l.category],4);n.push(await Qc(l,e,u))}let o={},r=new Map;for(let l of n){if(l.score==null)continue;let u=r.get(l.category)??[];u.push(l.score),r.set(l.category,u)}for(let[l,u]of r)o[l]=ne(u.reduce((p,S)=>p+S,0)/u.length,1);let s=0,a=0;for(let l of Object.keys(o)){let u=Vo[l];s+=o[l]*u,a+=u}let i=a>0?ne(s/a,1):null,c={categories:o,tasks:n,suite_version:"v1",judged:n.some(l=>l.judged)};return{overall_score:i,quality_json:c}}var Mn=require("fs"),ja=m(require("path")),Ba=m(require("axios"));function Xc(e,t){let n=e??0,o=t??0;return n>=20&&o>=75?"great":n>=8&&o>=60?"usable":n>=4?"marginal":"wont_run"}function Zc(e,t){if(t==null)return e;let n=["wont_run","marginal","usable","great"],o=r=>{let s=n.indexOf(e),a=n.indexOf(r);return s>a?r:e};return t>8e3?o("marginal"):t>3e3?o("usable"):e}function Da(e){return e.status==="oom"||e.status==="skipped"||e.maxContext!=null&&e.maxContext<8192||e.peakRamMb!=null&&e.ramTotalGb!=null&&e.peakRamMb>e.ramTotalGb*1024-1024?"wont_run":e.decodeTps==null?"untested":Zc(Xc(e.decodeTps,e.qualityScore),e.ttftMs)}function Na(e,t){return!t||e.decode_tps_median==null?"error":e.decode_tps_median<4?"too_slow":"ok"}function Qo(e){let{specs:t,perf:n,quality:o,model:r}=e,s=n.decode_tps_median!=null,a=e.statusOverride??Na(n,s);return{runtime:e.runtime,model_name:r.model_name,model_size_total:r.model_size_total,model_size_active:r.model_size_active,quant:r.quant,inference_engine:"ollama",engine_version:r.engine_version,num_ctx:n.num_ctx,num_gpu_layers:r.num_gpu_layers??null,source:e.official?"official":"community",machine_fingerprint:t.machine_fingerprint,submitted_by:e.official?e.submittedBy??null:null,ram_total_gb:t.ram_total_gb,ram_tier:t.ram_tier,cpu_model:t.cpu_model,core_count:t.core_count,accelerator:t.accelerator,vram_gb:t.vram_gb,unified_memory:t.unified_memory,os:t.os,arch:t.arch,decode_tps_median:n.decode_tps_median,decode_tps_p95:n.decode_tps_p95,prefill_tps_median:n.prefill_tps_median,ttft_ms_median:n.ttft_ms_median,ttft_ms_p95:n.ttft_ms_p95,peak_ram_mb:n.peak_ram_mb,load_ms:n.load_ms,max_context:n.max_context,status:a,overall_score:o?.overall_score??null,quality_json:o?.quality_json??null,quality_suite_version:o?"v1":null,thermal_throttled:null,on_battery:e.onBattery??null,concurrent_load:null,confidence:e.official?"high":"community",benchmark_schema_version:Jo,cli_version:e.cliVersion,harness_version:Jo,started_at:e.startedAt,finished_at:e.finishedAt}}function Ua(e,t){let n=ja.default.dirname(e);return n&&(0,Mn.mkdirSync)(n,{recursive:!0}),(0,Mn.writeFileSync)(e,JSON.stringify(t,null,2)+`
200
+ `),e}async function Fa(e){let t={"Content-Type":"application/json","X-Benchmark-Webhook-Secret":e.secret};e.officialToken&&(t["X-Benchmark-Official-Token"]=e.officialToken);try{let n=await Ba.default.post(e.webhookUrl,e.report,{headers:t,timeout:15e3,validateStatus:()=>!0}),o=n.status>=200&&n.status<300;return{ok:o,status:n.status,body:o?n.data:void 0,error:o?void 0:typeof n.data=="object"?JSON.stringify(n.data):String(n.data)}}catch(n){return{ok:!1,error:n.message}}}function Ha(e){return`${e.replace(/\/$/,"")}/api/v1/admin/benchmark-runs`}var Ga=8;function eu(e,t){return t.push(e),t}function qa(){try{return we().version}catch{return"0.0.0"}}function tu(e){return{decode_tps_median:null,decode_tps_p95:null,prefill_tps_median:null,ttft_ms_median:null,ttft_ms_p95:null,peak_ram_mb:null,load_ms:null,max_context:null,num_ctx:e}}var Ka=new Va.Command("benchmark").description("Benchmark local Ollama models (perf + quality) and optionally publish results").option("-m, --model <tag>","Ollama model tag to benchmark (repeatable)",eu,[]).option("--all","benchmark every model recommended for this machine (CPU-aware set)",!1).option("--force","with --model, benchmark a named tag even if too big for CPU-only hardware",!1).option("--num-ctx <n>","context window for the perf/quality trials","8192").option("--trials <n>","measured warm trials (>=7 for official)","7").option("--ram-total-gb <n>","record this RAM tier instead of the host's physical RAM (for memory-constrained tier sweeps); constrain memory externally for faithful numbers").option("--runtime <runtime>","runtime the local LLM targets: hermes | openclaw","hermes").option("--official","publish as an OFFICIAL run (needs BENCHMARK_OFFICIAL_TOKEN)",!1).option("--share-results","publish as a community run (opt-in telemetry)",!1).option("--no-post","never POST \u2014 only write report.json").option("--no-judge","skip the LLM-judge even on official runs").option("--max-context","run the slow max-context staircase probe",!1).option("--output <dir>","directory for report.json files","./benchmark-reports").option("--api-base <url>","API base URL (default: env BADGERCLAW_API_URL or prod)").option("--submitted-by <id>","team identity recorded on official runs (e.g. team:fahed)").action(async e=>{let t=e.apiBase||N,n=Number.parseInt(e.numCtx,10)||8192,o=Number.parseInt(e.trials,10)||7,r=e.runtime==="openclaw"?"openclaw":"hermes",s=!!e.official,a=k=>console.log(C.default.gray(k)),i=st();if(!i.installed||!i.serving){console.error(C.default.red(qs(i))),process.exitCode=1;return}let c=e.ramTotalGb!=null?Number.parseFloat(e.ramTotalGb):null,l=c!=null&&Number.isFinite(c)&&c>0?c:null,u=Zs(l!=null?{ramTotalGbOverride:l}:{});l!=null&&console.log(C.default.yellow(`RAM override: recording tier ${u.ram_tier} (${u.ram_total_gb} GB) \u2014 ensure memory is constrained externally for a faithful run.`)),console.log(C.default.bold("Machine: ")+`${u.cpu_model??"unknown CPU"} \xB7 ${u.ram_total_gb} GB (${u.ram_tier}) \xB7 ${u.accelerator??"no accelerator"} \xB7 ${u.os}/${u.arch}`),console.log(C.default.gray(`fingerprint: ${u.machine_fingerprint}`));let p=!u.accelerator;p&&console.log(C.default.gray("no accelerator detected \u2014 treating this as a CPU-only machine."));let S=e.model;if(S.length===0)if(e.all){let k=await Lt($n(),r,{apiBase:t,accelerator:u.accelerator});if(S=k?.recommended.map(Fe=>Fe.ollama_tag)??[],S.length===0){console.error(C.default.red(`No recommended models for this machine (${k?.note??"endpoint unreachable"}). Pass --model <tag>.`)),process.exitCode=1;return}console.log(C.default.gray(`--all: benchmarking the ${S.length} recommended models: ${S.join(", ")}`))}else{let k=await An({runtime:r,interactive:!1,ramGb:$n(),apiBase:t,accelerator:u.accelerator});if(k.tag)S=[k.tag],console.log(C.default.gray(`no --model given; benchmarking the recommended pick: ${k.tag}`));else{console.error(C.default.red(`No model to benchmark (recommendation: ${k.note??"none"}). Pass --model <tag>.`)),process.exitCode=1;return}}let E=process.env.BENCHMARK_WEBHOOK_SECRET?.trim(),g=process.env.BENCHMARK_OFFICIAL_TOKEN?.trim(),v=process.env.BENCHMARK_WEBHOOK_URL?.trim()||Ha(t),h=s&&!!g,y=e.post!==!1&&(s||e.shareResults);y&&!E&&(console.log(C.default.yellow("BENCHMARK_WEBHOOK_SECRET not set \u2014 writing report.json locally but NOT posting.")),y=!1),s&&!g&&console.log(C.default.yellow("BENCHMARK_OFFICIAL_TOKEN not set \u2014 the server will record these as community runs."));let b=h&&e.judge!==!1&&Tn();h&&e.judge!==!1&&!Tn()&&console.log(C.default.yellow("ANTHROPIC_API_KEY not set \u2014 skipping the LLM-judge; chat + summarization scored programmatically only.")),b&&console.log(C.default.gray(`LLM-judge: ${Yo()}`)),y&&console.log(C.default.gray("Publishing: hardware class, model tags, numeric perf + quality scores, and a pseudonymous machine fingerprint. No hostname, account, or prompt text is sent.")),console.log(C.default.gray("Tip: do not run a live bot on this Ollama while benchmarking \u2014 it skews results."));let j=await Sa(),oe=await va(),re=async k=>{let Fe=k.model_name.replace(/[^a-z0-9.]+/gi,"_"),he=k.started_at.replace(/[:.]/g,"-"),it=Wa.default.join(e.output,`${Fe}-${he}.json`);if(Ua(it,k),console.log(C.default.gray(`report: ${it}`)),y&&E){let ye=await Fa({webhookUrl:v,secret:E,officialToken:h?g:null,report:k});ye.ok?console.log(C.default.green(` posted \u2192 id=${ye.body?.id} (${ye.body?.created?"created":"updated"}), source=${h?"official":"community"}`)):console.error(C.default.red(` webhook failed: ${ye.status??""} ${ye.error??""}`.trim()))}else console.log(C.default.gray(" (not posted \u2014 pass --official or --share-results to publish)"))};for(let k of S){if(console.log(`
201
+ `+C.default.bold.cyan(`\u25B6 ${k}`)),!oe.includes(k)){console.log(C.default.gray(`pulling ${k}\u2026`));let O=xn(k);if(!O.ok){console.error(C.default.red(`pull failed: ${O.error}`));continue}}let Fe="Q4_K_M",he=null;try{let O=await _a(k);O.details?.quantization_level&&(Fe=O.details.quantization_level),he=Ra(O.details?.parameter_size)}catch(O){console.log(C.default.gray(`ollama show failed (${O.message}); using defaults`))}if(p&&he!=null&&he>Ga&&!e.force){console.log(C.default.yellow(` skip: ${k} is ${he}B \u2014 too slow to be usable on CPU-only hardware (>${Ga}B). Pass --force to benchmark it anyway.`));continue}let it=new Date().toISOString(),ye={model_name:k,quant:Fe,model_size_total:he,model_size_active:he,engine_version:j};try{console.log(C.default.gray("perf suite\u2026"));let O=await $a({model:k,numCtx:n,warmTrials:o,perfOpts:{log:a}});e.maxContext&&(console.log(C.default.gray("max-context staircase\u2026")),O.max_context=await Ia({model:k,perfOpts:{log:a}})),console.log(C.default.gray("quality suite\u2026"));let lt=await Ma({model:k,numCtx:n,useJudge:b,log:a}),Nt=new Date().toISOString(),ct=Qo({specs:u,perf:O,quality:lt,model:ye,runtime:r,official:h,submittedBy:e.submittedBy,cliVersion:qa(),startedAt:it,finishedAt:Nt}),jt=Da({status:ct.status,decodeTps:O.decode_tps_median,qualityScore:lt.overall_score,ttftMs:O.ttft_ms_median,peakRamMb:O.peak_ram_mb,ramTotalGb:u.ram_total_gb,maxContext:O.max_context});console.log(C.default.bold(` ${k}: `)+`decode ${O.decode_tps_median??"\u2014"} tok/s (p95 ${O.decode_tps_p95??"\u2014"}), ttft ${O.ttft_ms_median??"\u2014"} ms, peak ${O.peak_ram_mb??"\u2014"} MB, quality ${lt.overall_score??"\u2014"}, `+C.default.bold(`verdict ${jt}`)+` (status ${ct.status})`),await re(ct)}catch(O){let lt=new Date().toISOString(),Nt=O?.message??String(O),ct=/memory|oom|killed|terminated|runner|HTTP 5\d\d|ECONNREFUSED|connection|fetch failed|aborted/i.test(Nt),jt=l!=null||ct?"oom":"error";console.error(C.default.red(` ${k}: run failed \u2192 status ${jt} (${Nt.slice(0,160)})`));let Ja=Qo({specs:u,perf:tu(n),quality:null,model:ye,runtime:r,official:h,submittedBy:e.submittedBy,cliVersion:qa(),startedAt:it,finishedAt:lt,statusOverride:jt});await re(Ja)}}});Ge();async function nu(){await _r(process.argv);let e=new Ya.Command;e.name("badgerclaw").description("BadgerClaw CLI \u2014 one-click bot provisioning").version("0.3.4"),e.addCommand(ps),e.addCommand(hs),e.addCommand(bs),e.addCommand(Is),e.addCommand(Br),e.addCommand(Es),e.addCommand(da),e.addCommand($o),e.addCommand(ga),e.addCommand(ha),e.addCommand(ya),e.addCommand(Ka),e.parse(process.argv)}nu().catch(e=>{console.error(e),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "badgerclaw",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "engines": {
5
5
  "node": ">=18"
6
6
  },
@@ -26,6 +26,7 @@
26
26
  "author": "",
27
27
  "license": "ISC",
28
28
  "dependencies": {
29
+ "@anthropic-ai/sdk": "^0.105.0",
29
30
  "@modelcontextprotocol/sdk": "^1.29.0",
30
31
  "axios": "^1.6.0",
31
32
  "chalk": "^4.1.2",