badgerclaw 0.3.1 → 0.3.3

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 +89 -60
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -1,22 +1,23 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var as=Object.create;var ft=Object.defineProperty;var is=Object.getOwnPropertyDescriptor;var cs=Object.getOwnPropertyNames;var ls=Object.getPrototypeOf,ds=Object.prototype.hasOwnProperty;var M=(e,t)=>()=>(e&&(t=e(e=0)),t);var us=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),eo=(e,t)=>{for(var o in t)ft(e,o,{get:t[o],enumerable:!0})},on=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of cs(t))!ds.call(e,r)&&r!==o&&ft(e,r,{get:()=>t[r],enumerable:!(n=is(t,r))||n.enumerable});return e};var d=(e,t,o)=>(o=e!=null?as(ls(e)):{},on(t||!e||!e.__esModule?ft(o,"default",{value:e,enumerable:!0}):o,e)),nn=e=>on(ft({},"__esModule",{value:!0}),e);function _(){try{let e=Ve.default.readFileSync(no,"utf-8");return JSON.parse(e)}catch{return null}}function ht(e){Ve.default.mkdirSync(cn,{recursive:!0}),Ve.default.writeFileSync(no,JSON.stringify(e,null,2),{mode:384})}function Ke(){try{Ve.default.unlinkSync(no)}catch{}}function yt(){let e=_();return e?new Date(e.expires_at)>new Date:!1}function wt(e){let t=e.match(/^@?([^:]+)/);return t?t[1]:e}var Ve,oo,an,cn,no,L=M(()=>{"use strict";Ve=d(require("fs")),oo=d(require("path")),an=d(require("os")),cn=oo.default.join(an.default.homedir(),".badgerclaw"),no=oo.default.join(cn,"auth.json")});function ro(){return ln.default.createHash("sha256").update(`${X.default.hostname()}-${X.default.platform()}-${X.default.arch()}`).digest("hex").slice(0,16)}function Q(){let e=_();if(e?.instance_id)return e.instance_id;let t=ro();return`openclaw-${X.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${t}`}function bt(){return{hostname:X.default.hostname(),os:X.default.platform(),arch:X.default.arch(),uptimeSeconds:Math.floor(X.default.uptime()),memFreeMb:Math.floor(X.default.freemem()/1024/1024)}}var X,ln,xe=M(()=>{"use strict";X=d(require("os")),ln=d(require("crypto"));L()});var dn,H,un,ae=M(()=>{"use strict";dn=process.env.BADGERCLAW_ENV==="local",H=process.env.BADGERCLAW_API_URL??(dn?"http://localhost:8000":"https://api.badger.signout.io"),un=process.env.BADGERCLAW_AUTH_URL??(dn?"http://localhost:5500":"https://badgerclaw.ai")});function pn(){return Je}function ms(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 so(){let e=_();if(!e?.refresh_token||!e?.email)return Je=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=ms(e.access_token);try{let o=await Ye.default.post(`${St}/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 Je="server returned no access_token",null;let s=n.expires_in||3600,a=new Date(Date.now()+s*1e3).toISOString();return ht({...e,access_token:r,expires_at:a}),Je=null,r}catch(o){let n=o?.response?.status,r=o?.response?.data?.errors?.[0]||o?.response?.data?.detail||o?.message||"unknown error";Je=n?`HTTP ${n}: ${r}`:`network error: ${r}`;let s=o?.response?.data?.errors?.[0]||o?.response?.data?.detail||o?.message||"";if(n===403&&mn.test(s))throw Ke(),new Re(s);return null}}function ao(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 gn(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(mn.test(n))return Ke(),Promise.reject(new Re(n))}return Promise.reject(t)}),e}function fn(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,_t||(_t=so().finally(()=>{_t=null}));let n=await _t;return n?(o.headers.Authorization=`Bearer ${n}`,e.request(o)):Promise.reject(t)}),e}function O(){let e=_(),t={"Content-Type":"application/json"};e&&(t.Authorization=`Bearer ${e.access_token}`);let o=Ye.default.create({baseURL:St,headers:t});return ao(o),fn(o),gn(o),o}function hn(){return ao(Ye.default.create({baseURL:St,headers:{"Content-Type":"application/json"}}))}function ze(e){let t=Ye.default.create({baseURL:St,headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});return ao(t),fn(t),gn(t),t}var Ye,St,Re,mn,_t,Je,he=M(()=>{"use strict";Ye=d(require("axios"));L();ae();St=H,Re=class extends Error{constructor(o){super(o);this.code="DEACTIVATED";this.name="DeactivatedError"}},mn=/account\s+has\s+been\s+(deleted|deactivated)/i,_t=null,Je=null});function _n(){try{let e=ie.default.statSync(ye);return Date.now()-e.mtimeMs>wn}catch{return!0}}function io(){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 Sn(){try{ie.default.unlinkSync(ye)}catch{}}async function kn(e){let t=!1;for(let o=0;o<ps;o++){if(io()){t=!0;break}await new Promise(n=>setTimeout(n,bn))}t||console.warn("[config-lock] Could not acquire lock after timeout \u2014 proceeding without lock");try{return await e()}finally{t&&Sn()}}function we(e){let t=io();if(!t&&_n()){try{ie.default.unlinkSync(ye)}catch{}t=io()}try{return e()}finally{t&&Sn()}}var ie,yn,co,ye,wn,bn,ps,Xe=M(()=>{"use strict";ie=d(require("fs")),yn=d(require("os")),co=d(require("path")),ye=co.default.join(yn.default.homedir(),".openclaw","openclaw.json.lock"),wn=1e4,bn=50,ps=Math.ceil(wn/bn)});var be=us((Vi,gs)=>{gs.exports={name:"badgerclaw",version:"0.3.1",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 vt(e=bs){try{return mo.default.readdirSync(e,{withFileTypes:!0}).filter(t=>t.isDirectory()&&t.name.startsWith("badgerclaw-connect-")).map(t=>oe.default.join(e,t.name))}catch{return[]}}function _s(){return[...vt().map(t=>oe.default.join(t,"node_modules/@badgerclaw/connect/package.json")),oe.default.join(ws,"package.json"),oe.default.join(vn,"node_modules/@badgerclaw/connect/package.json"),oe.default.join(vn,"package.json")]}function po(){return"0.3.1"}function $t(){for(let e of _s())try{let t=mo.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 uo(e){let t=e.trim(),o=t.match(/\d+(?:\.\d+){1,3}/);return o?o[0]:t}function G(){if((0,lo.spawnSync)("which",["openclaw"],{encoding:"utf-8"}).status!==0)return null;let t=(0,lo.spawnSync)("openclaw",["--version"],{encoding:"utf-8",timeout:3e3});return t.status!==0||!t.stdout?null:uo(t.stdout)||null}function Ss(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 $n(e,t=G()){return t?Ss(uo(t),uo(e))>=0:!1}async function ks(){let e=new AbortController,t=setTimeout(()=>e.abort(),hs);try{let o=await fetch(fs,{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 vs(e){let t=[];if(e.cli&&e.cli!=="unknown"){let n=po();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=$t();(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 $s(e){return e[2]}function Cs(e){return!e||e.startsWith("-")?!0:ys.has(e)}function Is(e){let t=[];t.push(""),t.push(ce.default.red.bold("\u2717 Unsupported versions detected")),t.push("");for(let o of e){let n=o.component.padEnd(8);t.push(` ${n} ${ce.default.yellow(o.current)} \u2192 ${ce.default.green(o.approved)} ${ce.default.dim("(supported)")}`)}return t.push(""),t.push("This command is blocked until your installation matches the supported versions."),t.push(""),t.push(ce.default.green(" To fix, run:")),t.push(ce.default.green.bold(" badgerclaw setup")),t.push(""),t.push(ce.default.dim(" (bypass temporarily: BADGERCLAW_NO_VERSION_CHECK=1 badgerclaw <cmd>)")),t.push(""),t.join(`
3
- `)}async function Cn(e){if(process.env.BADGERCLAW_NO_VERSION_CHECK)return;let t=$s(e);if(Cs(t))return;let o=await ks();if(!o)return;let n=vs(o);n.length!==0&&(process.stderr.write(Is(n)),process.exit(1))}var mo,kt,oe,lo,ce,fs,hs,ys,vn,ws,bs,Ae=M(()=>{"use strict";mo=d(require("fs")),kt=d(require("os")),oe=d(require("path")),lo=require("child_process"),ce=d(require("chalk"));ae();fs=`${H}/api/v1/dashboard/versions/latest`,hs=2500,ys=new Set(["setup","logout","help","--version","-V","--help","-h","heartbeat","watch","autopair"]),vn=oe.default.join(kt.default.homedir(),".openclaw/extensions/badgerclaw"),ws=oe.default.join(kt.default.homedir(),".openclaw/npm/node_modules/@badgerclaw/connect"),bs=oe.default.join(kt.default.homedir(),".openclaw/npm/projects")});var En={};eo(En,{HERMES_IMAGE_DEFAULT:()=>Ee,detectCapabilities:()=>le,detectDiskFreeGb:()=>An,detectDocker:()=>Ct,detectHermes:()=>It,detectOpenClaw:()=>Rn});function Ct(){if((0,Qe.spawnSync)("which",["docker"],{encoding:"utf-8"}).status!==0)return{installed:!1};let t=(0,Qe.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 Rn(){let e=G();return e?{installed:!0,version:e}:{installed:!1}}function It(e){if(!e.installed)return{installed:!1};let t=process.env.HERMES_IMAGE||Ee;return(0,Qe.spawnSync)("docker",["image","inspect","--format","{{.RepoDigests}}",t],{encoding:"utf-8",timeout:3e3}).status!==0?{installed:!1}:{installed:!0,image:t}}function An(){let e=xn.default.join(go.default.homedir(),".badgerclaw"),t=In.default.existsSync(e)?e:go.default.homedir();if(process.platform==="win32")return null;let o=(0,Qe.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 le(){let e=Ct();return{openclaw:Rn(),hermes:It(e),docker:e,disk_free_gb:An(),ports_in_use:[]}}var Qe,In,go,xn,Ee,_e=M(()=>{"use strict";Qe=require("child_process"),In=d(require("fs")),go=d(require("os")),xn=d(require("path"));Ae();Ee="hermes-agent-bc:bundled"});function Rt(e){return Z.default.join(xs,`bot-${e}`)}function ho(e){return`badgerclaw-hermes-bot-${e}`}function yo(){if(!N.default.existsSync(fo))return{hermes_bots:{}};try{let e=N.default.readFileSync(fo,"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 As(e){N.default.existsSync(xt)||N.default.mkdirSync(xt,{recursive:!0,mode:448}),N.default.writeFileSync(fo,JSON.stringify(e,null,2)+`
5
- `,{mode:384})}function Es(e,t=Rs){let o=new Set(Object.values(e.hermes_bots).map(r=>r.port)),n=t;for(;o.has(n)||!Ps(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 Ps(e){let t=On.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 Tn(e=process.env){let t=e.BADGERCLAW_LLM_PROVIDER?.toLowerCase(),o=e.BADGERCLAW_LLM_API_KEY;if(t&&o){if(t!=="gemini"&&t!=="anthropic"&&t!=="openrouter")throw new Error(`BADGERCLAW_LLM_PROVIDER must be one of: gemini, anthropic, openrouter. Got '${t}'.`);return{provider:t,apiKey:o}}let n=e.GOOGLE_API_KEY||e.GEMINI_API_KEY;if(n)return{provider:"gemini",apiKey:n};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 Ds(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"}}function Os(e){switch(e){case"gemini":return"GOOGLE_API_KEY";case"anthropic":return"ANTHROPIC_API_KEY";case"openrouter":return"OPENROUTER_API_KEY"}}function Ns(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(""),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(`${Os(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,Dn.randomBytes)(24).toString("hex")}`),o.join(`
2
+ "use strict";var Na=Object.create;var At=Object.defineProperty;var ja=Object.getOwnPropertyDescriptor;var Ba=Object.getOwnPropertyNames;var Ua=Object.getPrototypeOf,Fa=Object.prototype.hasOwnProperty;var V=(e,t)=>()=>(e&&(t=e(e=0)),t);var Ha=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),xn=(e,t)=>{for(var n in t)At(e,n,{get:t[n],enumerable:!0})},Ho=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Ba(t))!Fa.call(e,r)&&r!==n&&At(e,r,{get:()=>t[r],enumerable:!(o=ja(t,r))||o.enumerable});return e};var d=(e,t,n)=>(n=e!=null?Na(Ua(e)):{},Ho(t||!e||!e.__esModule?At(n,"default",{value:e,enumerable:!0}):n,e)),Go=e=>Ho(At({},"__esModule",{value:!0}),e);function k(){try{let e=rt.default.readFileSync(In,"utf-8");return JSON.parse(e)}catch{return null}}function Et(e){rt.default.mkdirSync(Ko,{recursive:!0}),rt.default.writeFileSync(In,JSON.stringify(e,null,2),{mode:384})}function st(){try{rt.default.unlinkSync(In)}catch{}}function Pt(){let e=k();return e?new Date(e.expires_at)>new Date:!1}function Ot(e){let t=e.match(/^@?([^:]+)/);return t?t[1]:e}var rt,$n,Wo,Ko,In,F=V(()=>{"use strict";rt=d(require("fs")),$n=d(require("path")),Wo=d(require("os")),Ko=$n.default.join(Wo.default.homedir(),".badgerclaw"),In=$n.default.join(Ko,"auth.json")});function at(){return Jo.default.createHash("sha256").update(`${se.default.hostname()}-${se.default.platform()}-${se.default.arch()}`).digest("hex").slice(0,16)}function ae(){let e=k();if(e?.instance_id)return e.instance_id;let t=at();return`openclaw-${se.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${t}`}function Tt(){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,Jo,Ce=V(()=>{"use strict";se=d(require("os")),Jo=d(require("crypto"));F()});var Yo,M,zo,ie=V(()=>{"use strict";Yo=process.env.BADGERCLAW_ENV==="local",M=process.env.BADGERCLAW_API_URL??(Yo?"http://localhost:8000":"https://api.badger.signout.io"),zo=process.env.BADGERCLAW_AUTH_URL??(Yo?"http://localhost:5500":"https://badgerclaw.ai")});function Xo(){return it}function Ga(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 An(){let e=k();if(!e?.refresh_token||!e?.email)return it=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=Ga(e.access_token);try{let n=await lt.default.post(`${Lt}/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 it="server returned no access_token",null;let s=o.expires_in||3600,a=new Date(Date.now()+s*1e3).toISOString();return Et({...e,access_token:r,expires_at:a}),it=null,r}catch(n){let o=n?.response?.status,r=n?.response?.data?.errors?.[0]||n?.response?.data?.detail||n?.message||"unknown error";it=o?`HTTP ${o}: ${r}`:`network error: ${r}`;let s=n?.response?.data?.errors?.[0]||n?.response?.data?.detail||n?.message||"";if(o===403&&Qo.test(s))throw st(),new Ue(s);return null}}function En(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 Zo(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(Qo.test(o))return st(),Promise.reject(new Ue(o))}return Promise.reject(t)}),e}function er(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,Dt||(Dt=An().finally(()=>{Dt=null}));let o=await Dt;return o?(n.headers.Authorization=`Bearer ${o}`,e.request(n)):Promise.reject(t)}),e}function N(){let e=k(),t={"Content-Type":"application/json"};e&&(t.Authorization=`Bearer ${e.access_token}`);let n=lt.default.create({baseURL:Lt,headers:t});return En(n),er(n),Zo(n),n}function tr(){return En(lt.default.create({baseURL:Lt,headers:{"Content-Type":"application/json"}}))}function ct(e){let t=lt.default.create({baseURL:Lt,headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});return En(t),er(t),Zo(t),t}var lt,Lt,Ue,Qo,Dt,it,$e=V(()=>{"use strict";lt=d(require("axios"));F();ie();Lt=M,Ue=class extends Error{constructor(n){super(n);this.code="DEACTIVATED";this.name="DeactivatedError"}},Qo=/account\s+has\s+been\s+(deleted|deactivated)/i,Dt=null,it=null});function sr(){try{let e=fe.default.statSync(Ie);return Date.now()-e.mtimeMs>or}catch{return!0}}function Pn(){try{return fe.default.mkdirSync(On.default.dirname(Ie),{recursive:!0}),fe.default.writeFileSync(Ie,String(process.pid),{flag:"wx"}),!0}catch{if(sr())try{return fe.default.unlinkSync(Ie),fe.default.writeFileSync(Ie,String(process.pid),{flag:"wx"}),!0}catch{return!1}return!1}}function ar(){try{fe.default.unlinkSync(Ie)}catch{}}async function ir(e){let t=!1;for(let n=0;n<qa;n++){if(Pn()){t=!0;break}await new Promise(o=>setTimeout(o,rr))}t||console.warn("[config-lock] Could not acquire lock after timeout \u2014 proceeding without lock");try{return await e()}finally{t&&ar()}}function Ae(e){let t=Pn();if(!t&&sr()){try{fe.default.unlinkSync(Ie)}catch{}t=Pn()}try{return e()}finally{t&&ar()}}var fe,nr,On,Ie,or,rr,qa,ut=V(()=>{"use strict";fe=d(require("fs")),nr=d(require("os")),On=d(require("path")),Ie=On.default.join(nr.default.homedir(),".openclaw","openclaw.json.lock"),or=1e4,rr=50,qa=Math.ceil(or/rr)});var he=Ha((Qc,Va)=>{Va.exports={name:"badgerclaw",version:"0.3.3",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 Nt(e=za){try{return Ln.default.readdirSync(e,{withFileTypes:!0}).filter(t=>t.isDirectory()&&t.name.startsWith("badgerclaw-connect-")).map(t=>ue.default.join(e,t.name))}catch{return[]}}function Qa(){return[...Nt().map(t=>ue.default.join(t,"node_modules/@badgerclaw/connect/package.json")),ue.default.join(Ya,"package.json"),ue.default.join(lr,"node_modules/@badgerclaw/connect/package.json"),ue.default.join(lr,"package.json")]}function Mn(){return"0.3.3"}function jt(){for(let e of Qa())try{let t=Ln.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 Dn(e){let t=e.trim(),n=t.match(/\d+(?:\.\d+){1,3}/);return n?n[0]:t}function J(){if((0,Tn.spawnSync)("which",["openclaw"],{encoding:"utf-8"}).status!==0)return null;let t=(0,Tn.spawnSync)("openclaw",["--version"],{encoding:"utf-8",timeout:3e3});return t.status!==0||!t.stdout?null:Dn(t.stdout)||null}function Xa(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 cr(e,t=J()){return t?Xa(Dn(t),Dn(e))>=0:!1}async function Za(){let e=new AbortController,t=setTimeout(()=>e.abort(),Ka);try{let n=await fetch(Wa,{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 ei(e){let t=[];if(e.cli&&e.cli!=="unknown"){let o=Mn();o!==e.cli&&t.push({component:"cli",current:o,approved:e.cli})}if(!(J()!==null))return t;if(e.plugin&&e.plugin!=="unknown"){let o=jt();(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=J();(o===null||o!==e.supported_openclaw)&&t.push({component:"openclaw",current:o??"not installed",approved:e.supported_openclaw})}return t}function ti(e){return e[2]}function ni(e){return!e||e.startsWith("-")?!0:Ja.has(e)}function oi(e){let t=[];t.push(""),t.push(ye.default.red.bold("\u2717 Unsupported versions detected")),t.push("");for(let n of e){let o=n.component.padEnd(8);t.push(` ${o} ${ye.default.yellow(n.current)} \u2192 ${ye.default.green(n.approved)} ${ye.default.dim("(supported)")}`)}return t.push(""),t.push("This command is blocked until your installation matches the supported versions."),t.push(""),t.push(ye.default.green(" To fix, run:")),t.push(ye.default.green.bold(" badgerclaw setup")),t.push(""),t.push(ye.default.dim(" (bypass temporarily: BADGERCLAW_NO_VERSION_CHECK=1 badgerclaw <cmd>)")),t.push(""),t.join(`
3
+ `)}async function ur(e){if(process.env.BADGERCLAW_NO_VERSION_CHECK)return;let t=ti(e);if(ni(t))return;let n=await Za();if(!n)return;let o=ei(n);o.length!==0&&(process.stderr.write(oi(o)),process.exit(1))}var Ln,Mt,ue,Tn,ye,Wa,Ka,Ja,lr,Ya,za,Fe=V(()=>{"use strict";Ln=d(require("fs")),Mt=d(require("os")),ue=d(require("path")),Tn=require("child_process"),ye=d(require("chalk"));ie();Wa=`${M}/api/v1/dashboard/versions/latest`,Ka=2500,Ja=new Set(["setup","logout","help","--version","-V","--help","-h","heartbeat","watch","autopair","benchmark"]),lr=ue.default.join(Mt.default.homedir(),".openclaw/extensions/badgerclaw"),Ya=ue.default.join(Mt.default.homedir(),".openclaw/npm/node_modules/@badgerclaw/connect"),za=ue.default.join(Mt.default.homedir(),".openclaw/npm/projects")});var fr={};xn(fr,{HERMES_IMAGE_DEFAULT:()=>He,detectCapabilities:()=>be,detectDiskFreeGb:()=>gr,detectDocker:()=>Bt,detectHermes:()=>Ut,detectOpenClaw:()=>pr});function Bt(){if((0,dt.spawnSync)("which",["docker"],{encoding:"utf-8"}).status!==0)return{installed:!1};let t=(0,dt.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 pr(){let e=J();return e?{installed:!0,version:e}:{installed:!1}}function Ut(e){if(!e.installed)return{installed:!1};let t=process.env.HERMES_IMAGE||He;return(0,dt.spawnSync)("docker",["image","inspect","--format","{{.RepoDigests}}",t],{encoding:"utf-8",timeout:3e3}).status!==0?{installed:!1}:{installed:!0,image:t}}function gr(){let e=mr.default.join(Nn.default.homedir(),".badgerclaw"),t=dr.default.existsSync(e)?e:Nn.default.homedir();if(process.platform==="win32")return null;let n=(0,dt.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 be(){let e=Bt();return{openclaw:pr(),hermes:Ut(e),docker:e,disk_free_gb:gr(),ports_in_use:[]}}var dt,dr,Nn,mr,He,Ee=V(()=>{"use strict";dt=require("child_process"),dr=d(require("fs")),Nn=d(require("os")),mr=d(require("path"));Fe();He="hermes-agent-bc:bundled"});function Ht(e){return X.default.join(ri,`bot-${e}`)}function _r(e){O.default.existsSync(Pe)||O.default.mkdirSync(Pe,{recursive:!0,mode:448}),O.default.writeFileSync(Bn,JSON.stringify(e,null,2)+`
5
+ `,{mode:384})}function ai(){if(!O.default.existsSync(Bn))return null;try{let e=JSON.parse(O.default.readFileSync(Bn,"utf-8"));return e&&e.provider==="ollama"?e:null}catch{return null}}function Un(e){return`badgerclaw-hermes-bot-${e}`}function Fn(){if(!O.default.existsSync(jn))return{hermes_bots:{}};try{let e=O.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 ii(e){O.default.existsSync(Pe)||O.default.mkdirSync(Pe,{recursive:!0,mode:448}),O.default.writeFileSync(jn,JSON.stringify(e,null,2)+`
6
+ `,{mode:384})}function li(e,t=si){let n=new Set(Object.values(e.hermes_bots).map(r=>r.port)),o=t;for(;n.has(o)||!ci(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 ci(e){let t=br.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 Sr(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||Ft,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=ai();if(o)return{provider:"ollama",apiKey:"",baseUrl:o.base_url||Ft,model:o.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 Hn(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 ui(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 di(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||Ft}`),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(`${ui(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,yr.randomBytes)(24).toString("hex")}`),n.join(`
6
7
  `)+`
7
- `}function Ts(e){let t=[`# Hermes agent config for BadgerClaw bot ${e.botId}.`,"# Generated by badgerclaw CLI; secrets live in the sibling .env file.",""];return e.llm&&t.push("model:",` default: ${Ds(e.llm.provider)}`,` provider: ${e.llm.provider}`,""),t.push("agent:",` name: ${e.botName||"BadgerClaw bot"}`,"terminal:"," backend: local","subagents:"," max_spawn_depth: 1","cron:"," enabled: false",""),t.join(`
8
- `)}function Ls(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(`
9
- `)}function Bs(e,t){let o=Rt(e.botId);N.default.mkdirSync(o,{recursive:!0,mode:448});let n=Z.default.join(o,".env"),r=Z.default.join(o,"config.yaml"),s=Z.default.join(o,"SOUL.md");return N.default.writeFileSync(n,Ns(e,t),{mode:384}),N.default.writeFileSync(r,Ts(e),{mode:384}),N.default.existsSync(s)||N.default.writeFileSync(s,Ls(e),{mode:384}),{dataDir:o,envPath:n,configPath:r,soulPath:s}}function Et(e){let t=e.run(["network","inspect","bridge","--format","{{range .IPAM.Config}}{{.Subnet}} {{end}}"]);return t.status===0&&!!(t.stdout||"").trim()}function wo(e={}){let t=e.env??process.env;return t.BADGERCLAW_HERMES_NETWORK==="host"?!0:t.BADGERCLAW_HERMES_NETWORK==="bridge"?!1:!(e.bridgeUsable??(()=>Et(At)))()}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 Ln(e,t={}){let o=t.docker??At,n=e.image||process.env.HERMES_IMAGE||Ee;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=yo(),s=r.hermes_bots[e.botId],a=s?.port??Es(r,t.portBase),c=s?.container_name??ho(e.botId);if(Bs(e,a),!t.skipDocker){o.run(["rm","-f",c]);let l=wo({bridgeUsable:()=>Et(o)}),m=js({containerName:c,dataDir:Rt(e.botId),port:a,image:n,hostNetwork:l}),p=o.run(m);if(p.status!==0)throw new Error(`docker run failed (exit ${p.status}): ${p.stderr||p.stdout}`)}let i={bot_id:e.botId,runtime:"hermes",container_name:c,port:a,data_dir:Rt(e.botId),image:n,started_at:new Date().toISOString()};return r.hermes_bots[e.botId]=i,As(r),i}function bo(e={}){let t=e.docker??At,o=yo(),n=[];for(let[r,s]of Object.entries(o.hermes_bots)){let a=t.run(["inspect","--format","{{.State.Status}}",s.container_name]),c,i=a.stdout.trim()||null;a.status!==0?(c="missing",i=(a.stderr||a.stdout).trim()||null):i==="running"?c="running":i==="exited"||i==="dead"||i==="created"?c="stopped":c="unknown",n.push({bot_id:r,container_name:s.container_name,status:c,raw:i})}return n}function Bn(e={}){return bo(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 Hs(e){let t=e.match(Ms);return t?t[1].trim():null}async function _o(e,t,o,n={}){let r={recoveryKey:null,posted:!1,envUpdated:!1};if(!e.backendBotId)return r;let a=(n.docker??At).run(["logs",t]),c=`${a.stdout}
10
- ${a.stderr}`,i=Hs(c);if(!i)return r;if(r.recoveryKey=i,n.api)try{let m=await n.api.post(`/api/v1/hermes/bots/${e.backendBotId}/runtime-bootstrap`,{recovery_key:i,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 l=n.envPath??Z.default.join(Rt(e.botId),".env");return N.default.existsSync(l)&&(N.default.readFileSync(l,"utf-8").includes("MATRIX_RECOVERY_KEY=")||(N.default.appendFileSync(l,`
8
+ `}function mi(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||Hn(e.llm.provider);t.push("model:",` default: ${n}`,` provider: ${e.llm.provider}`),e.llm.provider==="ollama"&&t.push(` base_url: ${e.llm.baseUrl||Ft}`," 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 pi(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 gi(e,t){let n=Ht(e.botId);O.default.mkdirSync(n,{recursive:!0,mode:448});let o=X.default.join(n,".env"),r=X.default.join(n,"config.yaml"),s=X.default.join(n,"SOUL.md");return O.default.writeFileSync(o,di(e,t),{mode:384}),O.default.writeFileSync(r,mi(e),{mode:384}),O.default.existsSync(s)||O.default.writeFileSync(s,pi(e),{mode:384}),{dataDir:n,envPath:o,configPath:r,soulPath:s}}function qt(e){let t=e.run(["network","inspect","bridge","--format","{{range .IPAM.Config}}{{.Subnet}} {{end}}"]);return t.status===0&&!!(t.stdout||"").trim()}function Gn(e={}){let t=e.env??process.env;return t.BADGERCLAW_HERMES_NETWORK==="host"?!0:t.BADGERCLAW_HERMES_NETWORK==="bridge"?!1:!(e.bridgeUsable??(()=>qt(Gt)))()}function fi(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 kr(e,t={}){let n=t.docker??Gt,o=e.image||process.env.HERMES_IMAGE||He;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=Fn(),s=r.hermes_bots[e.botId],a=s?.port??li(r,t.portBase),c=s?.container_name??Un(e.botId);if(gi(e,a),!t.skipDocker){n.run(["rm","-f",c]);let l=Gn({bridgeUsable:()=>qt(n)}),u=fi({containerName:c,dataDir:Ht(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 i={bot_id:e.botId,runtime:"hermes",container_name:c,port:a,data_dir:Ht(e.botId),image:o,started_at:new Date().toISOString()};return r.hermes_bots[e.botId]=i,ii(r),i}function qn(e={}){let t=e.docker??Gt,n=Fn(),o=[];for(let[r,s]of Object.entries(n.hermes_bots)){let a=t.run(["inspect","--format","{{.State.Status}}",s.container_name]),c,i=a.stdout.trim()||null;a.status!==0?(c="missing",i=(a.stderr||a.stdout).trim()||null):i==="running"?c="running":i==="exited"||i==="dead"||i==="created"?c="stopped":c="unknown",o.push({bot_id:r,container_name:s.container_name,status:c,raw:i})}return o}function vr(e={}){return qn(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 yi(e){let t=e.match(hi);return t?t[1].trim():null}async function Vn(e,t,n,o={}){let r={recoveryKey:null,posted:!1,envUpdated:!1};if(!e.backendBotId)return r;let a=(o.docker??Gt).run(["logs",t]),c=`${a.stdout}
11
+ ${a.stderr}`,i=yi(c);if(!i)return r;if(r.recoveryKey=i,o.api)try{let u=await o.api.post(`/api/v1/hermes/bots/${e.backendBotId}/runtime-bootstrap`,{recovery_key:i,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??X.default.join(Ht(e.botId),".env");return O.default.existsSync(l)&&(O.default.readFileSync(l,"utf-8").includes("MATRIX_RECOVERY_KEY=")||(O.default.appendFileSync(l,`
11
12
  # Cross-signing recovery key captured from first-boot logs.
12
13
  # Hermes re-uses this on restart to re-sign the device after
13
14
  # Synapse rotates server keys.
14
15
  MATRIX_RECOVERY_KEY=${i}
15
- `),r.envUpdated=!0)),r}async function jn(e={}){let t=yo(),o=[];for(let[n,r]of Object.entries(t.hermes_bots)){let s=Z.default.join(r.data_dir,".env"),a=!1;try{N.default.existsSync(s)&&(a=N.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 _o({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 Pn,Dn,N,On,Nn,Z,xt,xs,fo,Rs,At,Ms,Pt=M(()=>{"use strict";Pn=require("child_process"),Dn=require("crypto"),N=d(require("fs")),On=d(require("net")),Nn=d(require("os")),Z=d(require("path"));_e();xt=Z.default.join(Nn.default.homedir(),".badgerclaw"),xs=Z.default.join(xt,"hermes"),fo=Z.default.join(xt,"state.json"),Rs=8642,At={run:e=>{let t=(0,Pn.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};Ms=/SAVE THIS RECOVERY KEY[\s\S]*?key rotation:\s+((?:[A-Za-z0-9]{4}\s+){7,}[A-Za-z0-9]{4})/});function Dt(e){return`'${e.replace(/'/g,"'\\''")}'`}function Us(){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(Ze.default.existsSync(t))return de=`${Dt(process.execPath)} ${Dt(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=vo.default.join(o,"openclaw","openclaw.mjs");if(Ze.default.existsSync(n))return de=`${Dt(process.execPath)} ${Dt(n)}`,de}}catch{}return de="openclaw",de}function So(e,t,o){t?t.fail(V.default.red(o)):e&&console.error(`[autopair] ${o}`)}async function Fs(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:Tn()},n=Ln(o);if(o.backendBotId){let r=_();if(r){let s=ze(r.access_token);try{await _o(o,ho(o.botId),n.image,{api:{post:async(a,c)=>{let i=await s.post(a,c);return{status:i.status,data:i.data}}}})}catch(a){console.warn(`[hermes] recovery key capture failed for ${o.botId}: ${a.message}. Daemon will retry next beat.`)}}}}async function et(e,t,o,n){let r=_();if(!r)return;let s=n?null:(0,ko.default)(`Pairing bot: ${t}...`).start();try{let a=await fetch(`${H}/api/v1/pairing/redeem`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e,instance_id:Q()})});if(!a.ok){if(a.status===410){s?.info(V.default.dim(`${t} already paired (race-loss; another channel redeemed first).`));return}let m=await a.json().catch(()=>({errors:[a.statusText]}));So(n,s,`Failed to redeem ${t}: ${m.errors?.[0]||a.status}`);return}let c=await a.json(),i=c.result??c;if((i.runtime??"openclaw")==="hermes"){try{await Fs(i),s?.succeed(V.default.green(`\u2705 ${i.bot_name} (${i.user_id}) running on Hermes \u2014 bot is live!`))}catch(m){So(n,s,`Failed to start Hermes container for ${t}: ${m.message}`)}return}await kn(async()=>{let m=i.user_id.split(":")[0].replace("@","").replace(/_bot$/,""),p;try{p=JSON.parse(Ze.default.readFileSync(Mn,"utf-8"))}catch{p={}}p.channels||(p.channels={}),p.channels.badgerclaw||(p.channels.badgerclaw={}),p.channels.badgerclaw.accounts||(p.channels.badgerclaw.accounts={});let E={userId:i.user_id,accessToken:i.access_token,homeserver:i.homeserver,encryption:!0,groupPolicy:"open",allowlistOnly:!1,dm:{policy:"open"}};i.device_id&&(E.deviceId=i.device_id),p.channels.badgerclaw.accounts[m]=E,Ze.default.writeFileSync(Mn,JSON.stringify(p,null,2),{mode:384})}),await fetch(`${H}/api/v1/openclaw/pending-pairs/${e}/claim`,{method:"POST",headers:{Authorization:`Bearer ${r.access_token}`}}).catch(()=>{}),s?.succeed(V.default.green(`\u2705 ${i.bot_name} (${i.user_id}) paired \u2014 bot is live!`))}catch(a){So(n,s,`Failed to pair ${t}: ${a.message}`)}}async function tt(e=!1){let t=_();if(!t)return 0;let o=ze(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,ko.default)(`Pairing bot: ${a.bot_name} (${a.bot_user_id})`).start();try{await et(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(i){c?.fail(V.default.red(`Error pairing ${a.bot_name}: ${i}`))}}if(s>0)try{let{execSync:a}=await import("child_process");a(`${Us()} gateway restart`,{stdio:"ignore"}),e||console.log(V.default.green(`
16
- \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(V.default.yellow(`
17
- \u26A1 ${s} bot(s) paired. Run: openclaw gateway restart`))}return s}catch{return 0}}var Hn,V,ko,Un,vo,Ze,Mn,de,Fn,ot=M(()=>{"use strict";Hn=require("commander"),V=d(require("chalk")),ko=d(require("ora")),Un=d(require("os")),vo=d(require("path")),Ze=d(require("fs"));L();he();ae();xe();Xe();Pt();Mn=vo.default.join(Un.default.homedir(),".openclaw","openclaw.json");de=null;Fn=new Hn.Command("autopair").description("Check for pending bot pairs and connect them to OpenClaw automatically").action(async()=>{if(!_()){console.log(V.default.yellow("Not logged in. Run `badgerclaw login` first."));return}console.log(V.default.dim("Checking for pending bot pairs...")),await tt(!1)===0&&console.log(V.default.dim("No pending pairs found."))})});async function Eo(){try{return await Lt.default.get(ia,{timeout:2e3,validateStatus:()=>!0}),!0}catch{return!1}}async function at(){try{let t=(await Lt.default.get(`${er}/health`,{timeout:5e3})).data;return t.pluginVersion&&t.pluginVersion!=="unknown"&&(Ao=t.pluginVersion),t}catch{return{status:await Eo()?"running":"stopped",pid:null,lastRestart:null,pluginVersion:Ao,bots:[]}}}function Po(e){e&&e!=="unknown"&&(Ao=e)}async function Le(){try{return{success:!0,message:(await Lt.default.post(`${er}/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 Lt,sa,er,aa,ia,Ao,ue=M(()=>{"use strict";Lt=d(require("axios")),sa=7331,er=`http://localhost:${sa}`,aa=parseInt(process.env.OPENCLAW_GATEWAY_PORT||"",10)||18789,ia=`http://127.0.0.1:${aa}`,Ao="unknown"});var Go={};eo(Go,{getActiveSessions:()=>Fo,launchClaudeCode:()=>Mo,launchMCPServer:()=>jo,recordSession:()=>Ho,stopSession:()=>Uo});function No(){try{if(B.default.existsSync(Oo))return JSON.parse(B.default.readFileSync(Oo,"utf-8"))}catch{}return[]}function To(e){B.default.mkdirSync(ve,{recursive:!0}),B.default.writeFileSync(Oo,JSON.stringify(e,null,2))}function Ht(e){try{return process.kill(e,0),!0}catch{return!1}}function ua(){if(process.env.TMUX)return"tmux";try{if((0,ne.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 Lo(e,t){let o=W.default.join(ve,`claude-launcher-${t}.exp`),n=W.default.join(ve,`pending-input-${t}.txt`);B.default.writeFileSync(n,"","utf-8");let r=`#!/usr/bin/expect -f
16
+ `),r.envUpdated=!0)),r}async function Rr(e={}){let t=Fn(),n=[];for(let[o,r]of Object.entries(t.hermes_bots)){let s=X.default.join(r.data_dir,".env"),a=!1;try{O.default.existsSync(s)&&(a=O.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 c=await Vn({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:c.recoveryKey!==null,posted:c.posted,envUpdated:c.envUpdated})}catch(c){console.warn(`[hermes] recovery-key retry failed for ${o}: ${c.message}`),n.push({bot_id:o,attempted:!0,recoveryKeyFound:!1,posted:!1,envUpdated:!1})}}return n}var hr,yr,O,br,wr,X,Pe,ri,jn,si,Ft,Gt,Bn,hi,Ge=V(()=>{"use strict";hr=require("child_process"),yr=require("crypto"),O=d(require("fs")),br=d(require("net")),wr=d(require("os")),X=d(require("path"));Ee();Pe=X.default.join(wr.default.homedir(),".badgerclaw"),ri=X.default.join(Pe,"hermes"),jn=X.default.join(Pe,"state.json"),si=8642,Ft="http://127.0.0.1:11434/v1",Gt={run:e=>{let t=(0,hr.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};Bn=X.default.join(Pe,"local-llm.json");hi=/SAVE THIS RECOVERY KEY[\s\S]*?key rotation:\s+((?:[A-Za-z0-9]{4}\s+){7,}[A-Za-z0-9]{4})/});function Vt(e){return`'${e.replace(/'/g,"'\\''")}'`}function bi(){if(we!==null)return we;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(mt.default.existsSync(t))return we=`${Vt(process.execPath)} ${Vt(t)}`,we;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=Jn.default.join(n,"openclaw","openclaw.mjs");if(mt.default.existsSync(o))return we=`${Vt(process.execPath)} ${Vt(o)}`,we}}catch{}return we="openclaw",we}function Wn(e,t,n){t?t.fail(Z.default.red(n)):e&&console.error(`[autopair] ${n}`)}async function wi(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:Sr()},o=kr(n);if(n.backendBotId){let r=k();if(r){let s=ct(r.access_token);try{await Vn(n,Un(n.botId),o.image,{api:{post:async(a,c)=>{let i=await s.post(a,c);return{status:i.status,data:i.data}}}})}catch(a){console.warn(`[hermes] recovery key capture failed for ${n.botId}: ${a.message}. Daemon will retry next beat.`)}}}}async function pt(e,t,n,o){let r=k();if(!r)return;let s=o?null:(0,Kn.default)(`Pairing bot: ${t}...`).start();try{let a=await fetch(`${M}/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(Z.default.dim(`${t} already paired (race-loss; another channel redeemed first).`));return}let u=await a.json().catch(()=>({errors:[a.statusText]}));Wn(o,s,`Failed to redeem ${t}: ${u.errors?.[0]||a.status}`);return}let c=await a.json(),i=c.result??c;if((i.runtime??"openclaw")==="hermes"){try{await wi(i),s?.succeed(Z.default.green(`\u2705 ${i.bot_name} (${i.user_id}) running on Hermes \u2014 bot is live!`))}catch(u){Wn(o,s,`Failed to start Hermes container for ${t}: ${u.message}`)}return}await ir(async()=>{let u=i.user_id.split(":")[0].replace("@","").replace(/_bot$/,""),p;try{p=JSON.parse(mt.default.readFileSync(xr,"utf-8"))}catch{p={}}p.channels||(p.channels={}),p.channels.badgerclaw||(p.channels.badgerclaw={}),p.channels.badgerclaw.accounts||(p.channels.badgerclaw.accounts={});let $={userId:i.user_id,accessToken:i.access_token,homeserver:i.homeserver,encryption:!0,groupPolicy:"open",allowlistOnly:!1,dm:{policy:"open"}};i.device_id&&($.deviceId=i.device_id),p.channels.badgerclaw.accounts[u]=$,mt.default.writeFileSync(xr,JSON.stringify(p,null,2),{mode:384})}),await fetch(`${M}/api/v1/openclaw/pending-pairs/${e}/claim`,{method:"POST",headers:{Authorization:`Bearer ${r.access_token}`}}).catch(()=>{}),s?.succeed(Z.default.green(`\u2705 ${i.bot_name} (${i.user_id}) paired \u2014 bot is live!`))}catch(a){Wn(o,s,`Failed to pair ${t}: ${a.message}`)}}async function gt(e=!1){let t=k();if(!t)return 0;let n=ct(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 c=e?null:(0,Kn.default)(`Pairing bot: ${a.bot_name} (${a.bot_user_id})`).start();try{await pt(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(i){c?.fail(Z.default.red(`Error pairing ${a.bot_name}: ${i}`))}}if(s>0)try{let{execSync:a}=await import("child_process");a(`${bi()} gateway restart`,{stdio:"ignore"}),e||console.log(Z.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(Z.default.yellow(`
18
+ \u26A1 ${s} bot(s) paired. Run: openclaw gateway restart`))}return s}catch{return 0}}var Cr,Z,Kn,$r,Jn,mt,xr,we,Ir,ft=V(()=>{"use strict";Cr=require("commander"),Z=d(require("chalk")),Kn=d(require("ora")),$r=d(require("os")),Jn=d(require("path")),mt=d(require("fs"));F();$e();ie();Ce();ut();Ge();xr=Jn.default.join($r.default.homedir(),".openclaw","openclaw.json");we=null;Ir=new Cr.Command("autopair").description("Check for pending bot pairs and connect them to OpenClaw automatically").action(async()=>{if(!k()){console.log(Z.default.yellow("Not logged in. Run `badgerclaw login` first."));return}console.log(Z.default.dim("Checking for pending bot pairs...")),await gt(!1)===0&&console.log(Z.default.dim("No pending pairs found."))})});async function to(){try{return await Yt.default.get(ji,{timeout:2e3,validateStatus:()=>!0}),!0}catch{return!1}}async function wt(){try{let t=(await Yt.default.get(`${Ur}/health`,{timeout:5e3})).data;return t.pluginVersion&&t.pluginVersion!=="unknown"&&(eo=t.pluginVersion),t}catch{return{status:await to()?"running":"stopped",pid:null,lastRestart:null,pluginVersion:eo,bots:[]}}}function no(e){e&&e!=="unknown"&&(eo=e)}async function Ye(){try{return{success:!0,message:(await Yt.default.post(`${Ur}/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 Yt,Mi,Ur,Ni,ji,eo,_e=V(()=>{"use strict";Yt=d(require("axios")),Mi=7331,Ur=`http://localhost:${Mi}`,Ni=parseInt(process.env.OPENCLAW_GATEWAY_PORT||"",10)||18789,ji=`http://127.0.0.1:${Ni}`,eo="unknown"});var fo={};xn(fo,{getActiveSessions:()=>go,launchClaudeCode:()=>uo,launchMCPServer:()=>co,recordSession:()=>mo,stopSession:()=>po});function so(){try{if(H.default.existsSync(ro))return JSON.parse(H.default.readFileSync(ro,"utf-8"))}catch{}return[]}function ao(e){H.default.mkdirSync(De,{recursive:!0}),H.default.writeFileSync(ro,JSON.stringify(e,null,2))}function Zt(e){try{return process.kill(e,0),!0}catch{return!1}}function Hi(){if(process.env.TMUX)return"tmux";try{if((0,de.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 io(e,t){let n=Y.default.join(De,`claude-launcher-${t}.exp`),o=Y.default.join(De,`pending-input-${t}.txt`);H.default.writeFileSync(o,"","utf-8");let r=`#!/usr/bin/expect -f
18
19
  set timeout -1
19
- set msgfile "${n}"
20
+ set msgfile "${o}"
20
21
 
21
22
  proc check_and_send_messages {} {
22
23
  global msgfile
@@ -51,21 +52,21 @@ send "\\r"
51
52
  interact timeout 2 {
52
53
  check_and_send_messages
53
54
  }
54
- `;return B.default.mkdirSync(ve,{recursive:!0}),B.default.writeFileSync(o,r,{mode:493}),o}function Bo(e){return Object.entries(e).map(([t,o])=>`export ${t}="${o}"`).join("; ")}function ma(e,t,o){let n=Lo(e,o.BADGERCLAW_SESSION_ID||"default"),r=Bo(o),s=`
55
+ `;return H.default.mkdirSync(De,{recursive:!0}),H.default.writeFileSync(n,r,{mode:493}),n}function lo(e){return Object.entries(e).map(([t,n])=>`export ${t}="${n}"`).join("; ")}function Gi(e,t,n){let o=io(e,n.BADGERCLAW_SESSION_ID||"default"),r=lo(n),s=`
55
56
  tell application "iTerm"
56
57
  activate
57
58
  set newWindow to (create window with default profile)
58
59
  tell current session of newWindow
59
- write text "cd ${Ut(t)} && ${r} && ${Ut(n)}"
60
+ write text "cd ${en(t)} && ${r} && ${en(o)}"
60
61
  end tell
61
62
  end tell
62
- `;(0,ne.execSync)(`osascript -e '${s.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function pa(e,t,o){let n=Lo(e,o.BADGERCLAW_SESSION_ID||"default"),r=Bo(o),a=`
63
+ `;(0,de.execSync)(`osascript -e '${s.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function qi(e,t,n){let o=io(e,n.BADGERCLAW_SESSION_ID||"default"),r=lo(n),a=`
63
64
  tell application "Terminal"
64
65
  activate
65
- do script "${`cd ${Ut(t)} && ${r} && ${Ut(n)}`.replace(/"/g,'\\"')}"
66
+ do script "${`cd ${en(t)} && ${r} && ${en(o)}`.replace(/"/g,'\\"')}"
66
67
  end tell
67
- `;(0,ne.execSync)(`osascript -e '${a.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function ga(e,t,o){let n=Lo(e,o.BADGERCLAW_SESSION_ID||"default"),r=Bo(o),s=`badgerclaw-${o.BADGERCLAW_SESSION_ID||"default"}`,a=`cd ${t} && ${r} && ${n}`;(0,ne.execSync)(`tmux new-session -d -s ${s} "${a}"`,{stdio:"pipe",timeout:1e4})}function Ut(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function jo(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,ne.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 Mo(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(ve,`mcp-config-${e.sessionId}.json`);B.default.mkdirSync(ve,{recursive:!0}),B.default.writeFileSync(c,a,"utf-8");let i=`claude --dangerously-skip-permissions --mcp-config ${c}`;switch(ua()){case"iterm2":ma(i,e.projectDir,s);break;case"terminal":pa(i,e.projectDir,s);break;case"tmux":ga(i,e.projectDir,s);break;case"direct":(0,ne.spawn)(i,[],{shell:!0,cwd:e.projectDir,env:{...process.env,...s},stdio:"ignore",detached:!0}).unref();break}}function Ho(e,t,o,n,r){let s=No().filter(a=>a.sessionId!==e);s.push({sessionId:e,pid:t,mcpPid:o,port:n,projectDir:r,startedAt:new Date().toISOString()}),To(s)}function Uo(e){let t=No(),o=t.find(r=>r.sessionId===e);if(!o)return!1;if(o.mcpPid&&Ht(o.mcpPid))try{process.kill(o.mcpPid,"SIGTERM")}catch{}if(o.pid&&Ht(o.pid))try{process.kill(o.pid,"SIGTERM")}catch{}try{(0,ne.execSync)(`tmux kill-session -t badgerclaw-${e} 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let n=t.filter(r=>r.sessionId!==e);return To(n),!0}function Fo(){let e=No(),t=e.filter(o=>Ht(o.mcpPid)||Ht(o.pid));return t.length!==e.length&&To(t),t}var ne,B,W,nr,ve,Oo,Ft=M(()=>{"use strict";ne=require("child_process"),B=d(require("fs")),W=d(require("path")),nr=d(require("os")),ve=W.default.join(nr.default.homedir(),".badgerclaw"),Oo=W.default.join(ve,"claude-sessions.json")});async function re(e){return e.command_type==="update_cli"?ha(e.payload?.target_version):e.command_type==="update_plugin"?ya(e.payload?.target_version):e.command_type==="restart_gateway"?fa():e.command_type==="leave_room"?Da(e.payload):e.command_type==="start_claude_code"?va(e.payload):e.command_type==="stop_claude_code"?$a(e.payload):e.command_type==="start_claude_control"?Ca(e.payload):e.command_type==="stop_claude_control"?Ia(e.payload):e.command_type==="update_claude_tools"?xa(e.payload):e.command_type==="bot_share_notify"?Ra(e.payload):e.command_type==="bot_share_revoked"?Aa(e.payload):e.command_type==="bot_share_expired"?Ea(e.payload):e.command_type==="bot_refresh"?Pa(e.payload):{success:!1,message:`Unknown command: ${e.command_type}`}}function fa(){try{return(0,R.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:15e3}),{success:!0,message:"Gateway restarted"}}catch{try{return{success:!0,message:`Gateway restarted via probe: ${(0,R.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 ha(e){let t=e?`badgerclaw@${e}`:"badgerclaw@latest";try{(0,R.execSync)(`npm install -g ${t}`,{stdio:"pipe",timeout:12e4});let o=(0,R.execSync)("npm list -g badgerclaw --json",{stdio:"pipe"}).toString(),r=JSON.parse(o)?.dependencies?.badgerclaw?.version||"unknown";return ba(),{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 ya(e){let t=$.default.join($e.default.homedir(),".openclaw","extensions","badgerclaw"),o=$.default.join($e.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,R.execSync)(`npm install ${r}`,{cwd:m,stdio:"pipe",timeout:12e4});let p=$.default.join(o,"package.json"),E="unknown";h.default.existsSync(p)&&(E=JSON.parse(h.default.readFileSync(p,"utf-8")).version||"unknown"),Po(E);try{(0,R.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await rr(E)}let s=t;(0,R.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"),i="unknown";h.default.existsSync(c)&&(i=JSON.parse(h.default.readFileSync(c,"utf-8")).version||"unknown"),Po(i),wa(a,s);let l=$.default.join(s,"package.json");if(h.default.existsSync(l)&&h.default.existsSync(c))try{let m=JSON.parse(h.default.readFileSync(l,"utf-8")),p=JSON.parse(h.default.readFileSync(c,"utf-8"));m.version=i,p.openclaw&&(m.openclaw={...m.openclaw,...p.openclaw}),h.default.writeFileSync(l,JSON.stringify(m,null,2)+`
68
- `)}catch{}try{(0,R.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await rr(i)}catch(s){return{success:!1,message:`Plugin update failed: ${(s.stderr?.toString()||s.message||"").slice(0,500)}`}}}async function rr(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 wa(e,t){let o=$.default.join(e,"dist"),n=$.default.join(t,"dist");h.default.existsSync(o)&&(h.default.mkdirSync(n,{recursive:!0}),Wo(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}),Wo(s,a));for(let c of["index.ts","src","STREAMING.md","SETUP.md","CHANGELOG.md"]){let i=$.default.join(t,c);h.default.existsSync(i)&&(h.default.statSync(i).isDirectory()?h.default.rmSync(i,{recursive:!0,force:!0}):h.default.unlinkSync(i))}}function Wo(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}),Wo(n,r)):h.default.copyFileSync(n,r)}}function ba(){try{if(_a())return;try{(0,R.execSync)('pkill -f "badgerclaw heartbeat"',{stdio:"pipe",timeout:5e3})}catch{}try{(0,R.execSync)('pkill -f "badgerclaw watch"',{stdio:"pipe",timeout:5e3})}catch{}(0,R.execSync)("sleep 1",{stdio:"pipe"});let e=(0,R.execSync)("command -v badgerclaw",{stdio:"pipe",shell:"/bin/sh"}).toString().trim()||"badgerclaw";(0,R.execSync)(`nohup ${e} heartbeat > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"}),(0,R.execSync)(`nohup ${e} watch > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"})}catch{}}function _a(){let e="";try{e=(0,R.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,R.execSync)("nohup supervisorctl restart badgerclaw-heartbeat >/dev/null 2>&1 &",{stdio:"pipe",shell:"/bin/sh",timeout:8e3}),!0}catch{return!1}}function Sa(){let e=$.default.join($e.default.homedir(),".badgerclaw","workspace");h.default.mkdirSync(e,{recursive:!0});let t=$.default.join(e,".git");return h.default.existsSync(t)||(0,R.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.
68
+ `;(0,de.execSync)(`osascript -e '${a.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function Vi(e,t,n){let o=io(e,n.BADGERCLAW_SESSION_ID||"default"),r=lo(n),s=`badgerclaw-${n.BADGERCLAW_SESSION_ID||"default"}`,a=`cd ${t} && ${r} && ${o}`;(0,de.execSync)(`tmux new-session -d -s ${s} "${a}"`,{stdio:"pipe",timeout:1e4})}function en(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function co(e){let t=Y.default.join(__dirname,"..","claude-code","mcp-server.js"),n=H.default.existsSync(t)?t:Y.default.join(__dirname,"mcp-server.js"),o=(0,de.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 uo(e){let t=Y.default.join(Y.default.dirname(process.argv[1]||""),"..","lib","node_modules","badgerclaw","dist","claude-code","mcp-server.js"),n=Y.default.join(__dirname,"..","claude-code","mcp-server.js"),o=Y.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}}}),c=Y.default.join(De,`mcp-config-${e.sessionId}.json`);H.default.mkdirSync(De,{recursive:!0}),H.default.writeFileSync(c,a,"utf-8");let i=`claude --dangerously-skip-permissions --mcp-config ${c}`;switch(Hi()){case"iterm2":Gi(i,e.projectDir,s);break;case"terminal":qi(i,e.projectDir,s);break;case"tmux":Vi(i,e.projectDir,s);break;case"direct":(0,de.spawn)(i,[],{shell:!0,cwd:e.projectDir,env:{...process.env,...s},stdio:"ignore",detached:!0}).unref();break}}function mo(e,t,n,o,r){let s=so().filter(a=>a.sessionId!==e);s.push({sessionId:e,pid:t,mcpPid:n,port:o,projectDir:r,startedAt:new Date().toISOString()}),ao(s)}function po(e){let t=so(),n=t.find(r=>r.sessionId===e);if(!n)return!1;if(n.mcpPid&&Zt(n.mcpPid))try{process.kill(n.mcpPid,"SIGTERM")}catch{}if(n.pid&&Zt(n.pid))try{process.kill(n.pid,"SIGTERM")}catch{}try{(0,de.execSync)(`tmux kill-session -t badgerclaw-${e} 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let o=t.filter(r=>r.sessionId!==e);return ao(o),!0}function go(){let e=so(),t=e.filter(n=>Zt(n.mcpPid)||Zt(n.pid));return t.length!==e.length&&ao(t),t}var de,H,Y,Gr,De,ro,tn=V(()=>{"use strict";de=require("child_process"),H=d(require("fs")),Y=d(require("path")),Gr=d(require("os")),De=Y.default.join(Gr.default.homedir(),".badgerclaw"),ro=Y.default.join(De,"claude-sessions.json")});async function me(e){return e.command_type==="update_cli"?Ki(e.payload?.target_version):e.command_type==="update_plugin"?Ji(e.payload?.target_version):e.command_type==="restart_gateway"?Wi():e.command_type==="leave_room"?cl(e.payload):e.command_type==="start_claude_code"?el(e.payload):e.command_type==="stop_claude_code"?tl(e.payload):e.command_type==="start_claude_control"?nl(e.payload):e.command_type==="stop_claude_control"?ol(e.payload):e.command_type==="update_claude_tools"?rl(e.payload):e.command_type==="bot_share_notify"?sl(e.payload):e.command_type==="bot_share_revoked"?al(e.payload):e.command_type==="bot_share_expired"?il(e.payload):e.command_type==="bot_refresh"?ll(e.payload):{success:!1,message:`Unknown command: ${e.command_type}`}}function Wi(){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 Ki(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 zi(),{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 Ji(e){let t=I.default.join(Le.default.homedir(),".openclaw","extensions","badgerclaw"),n=I.default.join(Le.default.homedir(),".openclaw","npm","node_modules","@badgerclaw","connect"),o=_.default.existsSync(n)?"npm":_.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=I.default.dirname(I.default.dirname(I.default.dirname(n)));(0,T.execSync)(`npm install ${r}`,{cwd:u,stdio:"pipe",timeout:12e4});let p=I.default.join(n,"package.json"),$="unknown";_.default.existsSync(p)&&($=JSON.parse(_.default.readFileSync(p,"utf-8")).version||"unknown"),no($);try{(0,T.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await qr($)}let s=t;(0,T.execSync)(`npm install ${r}`,{cwd:s,stdio:"pipe",timeout:12e4});let a=I.default.join(s,"node_modules","@badgerclaw","connect"),c=I.default.join(a,"package.json"),i="unknown";_.default.existsSync(c)&&(i=JSON.parse(_.default.readFileSync(c,"utf-8")).version||"unknown"),no(i),Yi(a,s);let l=I.default.join(s,"package.json");if(_.default.existsSync(l)&&_.default.existsSync(c))try{let u=JSON.parse(_.default.readFileSync(l,"utf-8")),p=JSON.parse(_.default.readFileSync(c,"utf-8"));u.version=i,p.openclaw&&(u.openclaw={...u.openclaw,...p.openclaw}),_.default.writeFileSync(l,JSON.stringify(u,null,2)+`
69
+ `)}catch{}try{(0,T.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await qr(i)}catch(s){return{success:!1,message:`Plugin update failed: ${(s.stderr?.toString()||s.message||"").slice(0,500)}`}}}async function qr(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 Yi(e,t){let n=I.default.join(e,"dist"),o=I.default.join(t,"dist");_.default.existsSync(n)&&(_.default.mkdirSync(o,{recursive:!0}),ho(n,o));let r=I.default.join(e,"openclaw.plugin.json");_.default.existsSync(r)&&_.default.copyFileSync(r,I.default.join(t,"openclaw.plugin.json"));let s=I.default.join(e,"scripts"),a=I.default.join(t,"scripts");_.default.existsSync(s)&&(_.default.mkdirSync(a,{recursive:!0}),ho(s,a));for(let c of["index.ts","src","STREAMING.md","SETUP.md","CHANGELOG.md"]){let i=I.default.join(t,c);_.default.existsSync(i)&&(_.default.statSync(i).isDirectory()?_.default.rmSync(i,{recursive:!0,force:!0}):_.default.unlinkSync(i))}}function ho(e,t){for(let n of _.default.readdirSync(e,{withFileTypes:!0})){let o=I.default.join(e,n.name),r=I.default.join(t,n.name);n.isDirectory()?(_.default.mkdirSync(r,{recursive:!0}),ho(o,r)):_.default.copyFileSync(o,r)}}function zi(){try{if(Qi())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 Qi(){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 Xi(){let e=I.default.join(Le.default.homedir(),".badgerclaw","workspace");_.default.mkdirSync(e,{recursive:!0});let t=I.default.join(e,".git");return _.default.existsSync(t)||(0,T.execSync)("git init",{cwd:e,stdio:"pipe",timeout:5e3}),_.default.writeFileSync(I.default.join(e,"CLAUDE.md"),`You are a chat assistant connected to Matrix rooms via BadgerClaw.
69
70
 
70
71
  When you receive a message, it will be formatted like:
71
72
  [Room: RoomName] Sender: message text
@@ -74,17 +75,17 @@ Reply using the reply tool with botId="..." and roomId="..."
74
75
  ALWAYS use the \`reply\` MCP tool to send your response back to the chat room.
75
76
  Use the exact botId and roomId provided in the message \u2014 do not modify them.
76
77
  Keep responses concise and helpful.
77
- `),e}function ka(){try{h.default.mkdirSync($.default.dirname(Gt),{recursive:!0});try{let e=h.default.statSync(Gt);if(Date.now()-e.mtimeMs<6e4)return!1;h.default.unlinkSync(Gt)}catch{}return h.default.writeFileSync(Gt,String(process.pid),{flag:"wx"}),!0}catch{return!1}}async function va(e){if(!e?.bot_id)return{success:!1,message:"Missing bot_id in payload"};if(!ka())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 it(e.bot_id),{launchClaudeCode:o,recordSession:n,getActiveSessions:r,stopSession:s}=(Ft(),nn(Go)),a=new Set;try{let E=(await j.default.get("http://localhost:7331/claude-code/status",{timeout:5e3})).data?.bots||[];for(let D of E)if(D.botId!==t&&D.enabled!==!1){let f=D.port;typeof f=="number"&&f>=7332&&a.add(f)}}catch{}for(let p=7332;p<=7340;p++)try{(0,R.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 i=r();for(let p of i)p.port===c&&(console.log(`[command-executor] Stopping existing session ${p.sessionId} on port ${c}`),s(p.sessionId));try{(0,R.execSync)(`lsof -ti :${c} | xargs kill -9 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let l=e.session_id||`session-${Date.now()}`;await j.default.post("http://localhost:7331/claude-code/toggle",{botId:t,enabled:!0,sessionId:l,port:c},{timeout:1e4});let m=Sa();return o({sessionId:l,port:c,projectDir:m}),n(l,0,0,c,m),{success:!0,message:`Claude Code started globally for bot ${t} (session: ${l}, port: ${c})`}}catch(t){return{success:!1,message:`Failed to start Claude Code: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function it(e){if(e.startsWith("@"))return e;try{let o=(await j.default.get("http://localhost:7331/health",{timeout:1e4})).data?.bots||[],n=$.default.join($e.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 $a(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 it(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}=(Ft(),nn(Go));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 Ca(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 it(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 Ia(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 it(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 xa(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 it(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 Ra(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 Aa(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 Ea(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 Pa(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($e.default.homedir(),".openclaw","badgerclaw","quarantine",`${o}.json`);try{h.default.rmSync(n,{force:!0})}catch{}try{return(0,R.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 Da(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 R,h,$,$e,j,Gt,qo=M(()=>{"use strict";R=require("child_process"),h=d(require("fs")),$=d(require("path")),$e=d(require("os")),j=d(require("axios"));ue();Gt=$.default.join($e.default.homedir(),".badgerclaw","claude-code.lock")});var Ko={};eo(Ko,{heartbeatCommand:()=>Vo,pushHeartbeat:()=>T});function qt(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 Wt)n-s>Ba&&Wt.delete(r);return Wt.has(o)?!0:(Wt.set(o,n),!1)}function ur(e,t){let o=bt(),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=Bn().filter(a=>!r.has(a.bot_id));return{instance_id:Q(),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:le(),hermes_containers:bo(),bots:[...n,...s]}}async function T(){let{version:e}=be(),t=await at(),o=ur(t,e);await O().post(dr,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 ir(){try{let o=(await O().get(Ta)).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 lr.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 Ma(){if(!ar){ar=!0;try{await O().post(Na,{instance_id:Q()},{timeout:La}),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 mr(){let e=_();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 so())console.log(g.default.green(` [${C()}] Token refreshed successfully`));else{let s=pn()||"unknown reason";console.log(g.default.yellow(` [${C()}] Token refresh failed: ${s}`))}}function Ua(e,t){let o=3e3,n=3e4,r=null;async function s(){try{await mr();let c=_()?.access_token||e,i=require("eventsource"),l=new i(`${H}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${c}`}});l.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`)),l.close(),s()},Ha)},l.onmessage=async m=>{try{let p=JSON.parse(m.data);await Fa(p)}catch{}},l.onerror=async()=>{l.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 Fa(e){if(e.type==="pair"){console.log(g.default.cyan(` [${C()}] Pair event: ${e.bot_name}`)),await et(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 i=JSON.parse(n.readFileSync(a,"utf-8")),l=!1;if(i.channels?.badgerclaw?.accounts?.[o]&&(delete i.channels.badgerclaw.accounts[o],l=!0),i.agents?.list){let m=i.agents.list.length;i.agents.list=i.agents.list.filter(p=>p.id!==o),i.agents.list.length!==m&&(l=!0)}return l&&n.writeFileSync(a,JSON.stringify(i,null,2)),l})){console.log(g.default.green(` [${C()}] Removed "${o}" from openclaw.json`));let{execSync:i}=await import("child_process");try{i("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 Le();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}`)),qt("start_claude_code",e.bot_id)){console.log(g.default.dim(` [${C()}] Skipping duplicate start_claude_code (already processed)`));return}try{let t=await re({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 O().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}`)),qt("stop_claude_code",e.bot_id)){console.log(g.default.dim(` [${C()}] Skipping duplicate stop_claude_code (already processed)`));return}try{let t=await re({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 O().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})`)),qt(e.command_type,e.payload?.bot_id)){console.log(g.default.dim(` [${C()}] Skipping duplicate ${e.command_type} (already processed)`));return}try{let t=O();await t.post(`/api/v1/dashboard/commands/${e.command_id}/ack`);let o=await re({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 cr,g,lr,sr,Oa,dr,Na,Ta,La,ar,Wt,Ba,Vo,Ha,Be=M(()=>{"use strict";cr=require("commander"),g=d(require("chalk")),lr=d(require("axios"));L();he();xe();_e();Pt();ue();qo();ae();ot();ue();Xe();Ae();sr=3e4,Oa=15e4,dr="/api/v1/dashboard/heartbeat",Na="/api/v1/dashboard/disconnect",Ta="/api/v1/me/active-shares",La=3e3,ar=!1,Wt=new Map,Ba=3e4;Vo=new cr.Command("heartbeat").description("Run heartbeat daemon \u2014 reports telemetry to the BadgerClaw dashboard every 30s").action(async()=>{let e=_();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: ${Q()}`)),console.log(g.default.dim(` Interval: ${sr/1e3}s`)),console.log(g.default.dim(` Press Ctrl+C to stop.
78
- `));let o=null,n=10,r=0,s=async()=>{try{await mr();let i=await at(),l=ur(i,t);ja(o,i)&&o!==null&&console.log(g.default.cyan(` [${new Date().toISOString()}] State change detected \u2014 pushing immediately`));let p=O(),E=await p.post(dr,l);r=0;let D=i.bots.length,f=i.bots.filter(w=>w.status==="running").length;console.log(g.default.dim(` [${new Date().toISOString()}] gateway=${i.status} bots=${f}/${D} running mem=${l.mem_free_mb}MB free`)),o=i;try{let x=await jn({api:{post:async(z,qe)=>{let gt=await p.post(z,qe);return{status:gt.status,data:gt.data}}}});for(let z of x)z.attempted&&(z.posted||z.envUpdated)&&console.log(g.default.cyan(` [${new Date().toISOString()}] Hermes recovery key captured for ${z.bot_id} (posted=${z.posted}, env_updated=${z.envUpdated})`))}catch(w){console.log(g.default.dim(` [${new Date().toISOString()}] Hermes recovery-key retry skipped: ${w.message}`))}let v=E.data?.pending_commands||[],b=!1;for(let w of v)try{if(console.log(g.default.cyan(` [${new Date().toISOString()}] Received command: ${w.command_type} (${w.id})`)),await p.post(`/api/v1/dashboard/commands/${w.id}/ack`),qt(w.command_type,w.payload?.bot_id)){console.log(g.default.dim(` [${new Date().toISOString()}] Skipping duplicate ${w.command_type}`));continue}let x=await re(w);console.log(x.success?g.default.green(` [${new Date().toISOString()}] ${x.message}`):g.default.red(` [${new Date().toISOString()}] ${x.message}`)),await p.post(`/api/v1/dashboard/commands/${w.id}/result`,{status:x.success?"success":"failed",result:x.message,new_version:x.newVersion||null}),w.command_type==="update_cli"&&x.success&&(b=!0)}catch(x){console.log(g.default.dim(` [${new Date().toISOString()}] Command ${w.id} error: ${x.message}`))}if(b){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(i){i instanceof Re&&(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}): ${i.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 ir():console.log(g.default.dim(` [${C()}] Hermes-only host \u2014 share-sync disabled (no plugin to push to).`)),setInterval(s,sr),a&&setInterval(ir,Oa),Ua(e.access_token,t);let c=i=>{console.log(g.default.yellow(`
79
- [${new Date().toISOString()}] Received ${i} \u2014 posting disconnect and exiting.`)),Ma().finally(()=>{process.exit(0)})};process.on("SIGTERM",c),process.on("SIGINT",c),await new Promise(()=>{})});Ha=2700*1e3});var rs=require("commander");var pr=require("commander"),q=d(require("chalk")),gr=d(require("ora")),fr=d(require("open")),Jo=d(require("os"));var to=d(require("crypto"));function rn(){return to.default.randomBytes(32).toString("base64url")}function sn(e){return to.default.createHash("sha256").update(e).digest("base64url")}L();xe();he();ae();ot();var Nt=d(require("os")),J=d(require("fs")),Tt=d(require("path")),ke=require("child_process");var Pe=d(require("fs")),Se=d(require("path")),Oe=d(require("os")),Ne=require("child_process"),Gn="ai.badgerclaw.watch",Wn=Se.default.join(Oe.default.homedir(),"Library","LaunchAgents"),De=Se.default.join(Wn,`${Gn}.plist`);function Gs(){try{return(0,Ne.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/badgerclaw"}}function Ws(){try{return(0,Ne.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/node"}}function qs(e){let t=Se.default.join(Oe.default.homedir(),".badgerclaw"),o=Ws(),n=Se.default.dirname(o),r=Se.default.dirname(e),s=[n,r,"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"],a=new Set,c=s.filter(i=>!i||a.has(i)?!1:(a.add(i),!0)).join(":");return`<?xml version="1.0" encoding="UTF-8"?>
78
+ `),e}function Zi(){try{_.default.mkdirSync(I.default.dirname(nn),{recursive:!0});try{let e=_.default.statSync(nn);if(Date.now()-e.mtimeMs<6e4)return!1;_.default.unlinkSync(nn)}catch{}return _.default.writeFileSync(nn,String(process.pid),{flag:"wx"}),!0}catch{return!1}}async function el(e){if(!e?.bot_id)return{success:!1,message:"Missing bot_id in payload"};if(!Zi())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}=(tn(),Go(fo)),a=new Set;try{let $=(await G.default.get("http://localhost:7331/claude-code/status",{timeout:5e3})).data?.bots||[];for(let E of $)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 c=7332;for(;a.has(c);)c++;let i=r();for(let p of i)p.port===c&&(console.log(`[command-executor] Stopping existing session ${p.sessionId} on port ${c}`),s(p.sessionId));try{(0,T.execSync)(`lsof -ti :${c} | 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:c},{timeout:1e4});let u=Xi();return n({sessionId:l,port:c,projectDir:u}),o(l,0,0,c,u),{success:!0,message:`Claude Code started globally for bot ${t} (session: ${l}, port: ${c})`}}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=I.default.join(Le.default.homedir(),".badgerclaw","bot-mapping.json");if(_.default.existsSync(o)){let r=JSON.parse(_.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 tl(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}=(tn(),Go(fo));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 nl(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 ol(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 rl(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 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/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 al(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 il(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 ll(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=I.default.join(Le.default.homedir(),".openclaw","badgerclaw","quarantine",`${n}.json`);try{_.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 cl(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,_,I,Le,G,nn,yo=V(()=>{"use strict";T=require("child_process"),_=d(require("fs")),I=d(require("path")),Le=d(require("os")),G=d(require("axios"));_e();nn=I.default.join(Le.default.homedir(),".badgerclaw","claude-code.lock")});var wo={};xn(wo,{heartbeatCommand:()=>bo,pushHeartbeat:()=>j});function rn(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 on)o-s>gl&&on.delete(r);return on.has(n)?!0:(on.set(n,o),!1)}function Qr(e,t){let n=Tt(),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(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(o.map(a=>a.bot_id)),s=vr().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:be(),hermes_containers:qn(),bots:[...o,...s]}}async function j(){let{version:e}=he(),t=await wt(),n=Qr(t,e);await N().post(zr,n)}function fl(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 Kr(){try{let n=(await N().get(ml)).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 Yr.default.post("http://localhost:7331/bot-share/sync",o,{timeout:1e4}),console.log(h.default.dim(` [${A()}] Share sync: ${n.length} active share(s) pushed to plugin`))}catch(e){console.log(h.default.dim(` [${A()}] Share sync failed (non-fatal): ${e.message}`))}}async function hl(){if(!Wr){Wr=!0;try{await N().post(dl,{instance_id:ae()},{timeout:pl}),console.log(h.default.dim(` [${new Date().toISOString()}] Posted disconnect \u2014 dashboard will mark machine offline immediately.`))}catch(e){console.log(h.default.dim(` [${new Date().toISOString()}] Disconnect post failed (non-fatal): ${e?.message||e}`))}}}async function Xr(){let e=k();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(h.default.dim(` [${A()}] Token expires soon \u2014 refreshing proactively...`)),await An())console.log(h.default.green(` [${A()}] Token refreshed successfully`));else{let s=Xo()||"unknown reason";console.log(h.default.yellow(` [${A()}] Token refresh failed: ${s}`))}}function bl(e,t){let n=3e3,o=3e4,r=null;async function s(){try{await Xr();let c=k()?.access_token||e,i=require("eventsource"),l=new i(`${M}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${c}`}});l.onopen=()=>{n=3e3,console.log(h.default.dim(` [${A()}] SSE connected \u2014 listening for real-time events`)),r&&clearTimeout(r),r=setTimeout(()=>{console.log(h.default.dim(` [${A()}] SSE proactive reconnect \u2014 refreshing token before expiry`)),l.close(),s()},yl)},l.onmessage=async u=>{try{let p=JSON.parse(u.data);await wl(p)}catch{}},l.onerror=async()=>{l.close(),r&&(clearTimeout(r),r=null),console.log(h.default.dim(` [${A()}] SSE disconnected \u2014 reconnecting in ${n/1e3}s...`)),setTimeout(s,n),n=Math.min(n*1.5,o)}}catch(a){console.log(h.default.dim(` [${A()}] SSE connection failed: ${a.message}`)),setTimeout(s,n),n=Math.min(n*1.5,o)}}s()}function A(){return new Date().toISOString()}async function wl(e){if(e.type==="pair"){console.log(h.default.cyan(` [${A()}] Pair event: ${e.bot_name}`)),await pt(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(h.default.green(` [${A()}] Gateway restarted \u2014 ${e.bot_name} is live`))}catch{}try{await j()}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(h.default.yellow(` [${A()}] 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(Ae(()=>{let i=JSON.parse(o.readFileSync(a,"utf-8")),l=!1;if(i.channels?.badgerclaw?.accounts?.[n]&&(delete i.channels.badgerclaw.accounts[n],l=!0),i.agents?.list){let u=i.agents.list.length;i.agents.list=i.agents.list.filter(p=>p.id!==n),i.agents.list.length!==u&&(l=!0)}return l&&o.writeFileSync(a,JSON.stringify(i,null,2)),l})){console.log(h.default.green(` [${A()}] Removed "${n}" from openclaw.json`));let{execSync:i}=await import("child_process");try{i("openclaw gateway restart",{stdio:"ignore"}),console.log(h.default.green(` [${A()}] Gateway restarted`))}catch{}}}catch(o){console.log(h.default.red(` [${A()}] Failed to clean up bot: ${o}`))}try{await j()}catch{}}else if(e.type==="gateway-restart"){console.log(h.default.cyan(` [${A()}] Remote gateway-restart received`));let t=await Ye();console.log(t.success?h.default.green(` [${A()}] Gateway restarted`):h.default.red(` [${A()}] Gateway restart failed: ${t.message}`));try{await j()}catch{}}else if(e.type==="claude_code.start"&&e.bot_id){if(console.log(h.default.cyan(` [${A()}] Claude Code START: bot=${e.bot_id}`)),rn("start_claude_code",e.bot_id)){console.log(h.default.dim(` [${A()}] Skipping duplicate start_claude_code (already processed)`));return}try{let t=await me({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 N().post(`/api/v1/dashboard/commands/${e.command_id}/result`,{status:t.success?"success":"failed",result:t.message}).catch(()=>{})}catch{}try{await j()}catch{}}else if(e.type==="claude_code.stop"&&e.bot_id){if(console.log(h.default.cyan(` [${A()}] Claude Code STOP: bot=${e.bot_id}`)),rn("stop_claude_code",e.bot_id)){console.log(h.default.dim(` [${A()}] Skipping duplicate stop_claude_code (already processed)`));return}try{let t=await me({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 N().post(`/api/v1/dashboard/commands/${e.command_id}/result`,{status:t.success?"success":"failed",result:t.message}).catch(()=>{})}catch{}try{await j()}catch{}}else if(e.type==="command.execute"&&e.command_id){if(console.log(h.default.cyan(` [${A()}] Command: ${e.command_type} (${e.command_id})`)),rn(e.command_type,e.payload?.bot_id)){console.log(h.default.dim(` [${A()}] Skipping duplicate ${e.command_type} (already processed)`));return}try{let t=N();await t.post(`/api/v1/dashboard/commands/${e.command_id}/ack`);let n=await me({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(h.default.cyan(` [${A()}] CLI updated \u2014 restarting in 2s...`)),setTimeout(()=>process.exit(0),2e3))}catch{}try{await j()}catch{}}}var Jr,h,Yr,Vr,ul,zr,dl,ml,pl,Wr,on,gl,bo,yl,ze=V(()=>{"use strict";Jr=require("commander"),h=d(require("chalk")),Yr=d(require("axios"));F();$e();Ce();Ee();Ge();_e();yo();ie();ft();_e();ut();Fe();Vr=3e4,ul=15e4,zr="/api/v1/dashboard/heartbeat",dl="/api/v1/dashboard/disconnect",ml="/api/v1/me/active-shares",pl=3e3,Wr=!1,on=new Map,gl=3e4;bo=new Jr.Command("heartbeat").description("Run heartbeat daemon \u2014 reports telemetry to the BadgerClaw dashboard every 30s").action(async()=>{let e=k();e||(console.log(h.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=he();console.log(h.default.green(`Heartbeat daemon started (v${t})`)),console.log(h.default.dim(` Instance: ${ae()}`)),console.log(h.default.dim(` Interval: ${Vr/1e3}s`)),console.log(h.default.dim(` Press Ctrl+C to stop.
79
+ `));let n=null,o=10,r=0,s=async()=>{try{await Xr();let i=await wt(),l=Qr(i,t);fl(n,i)&&n!==null&&console.log(h.default.cyan(` [${new Date().toISOString()}] State change detected \u2014 pushing immediately`));let p=N(),$=await p.post(zr,l);r=0;let E=i.bots.length,g=i.bots.filter(b=>b.status==="running").length;console.log(h.default.dim(` [${new Date().toISOString()}] gateway=${i.status} bots=${g}/${E} running mem=${l.mem_free_mb}MB free`)),n=i;try{let f=await Rr({api:{post:async(y,q)=>{let B=await p.post(y,q);return{status:B.status,data:B.data}}}});for(let y of f)y.attempted&&(y.posted||y.envUpdated)&&console.log(h.default.cyan(` [${new Date().toISOString()}] Hermes recovery key captured for ${y.bot_id} (posted=${y.posted}, env_updated=${y.envUpdated})`))}catch(b){console.log(h.default.dim(` [${new Date().toISOString()}] Hermes recovery-key retry skipped: ${b.message}`))}let w=$.data?.pending_commands||[],x=!1;for(let b of w)try{if(console.log(h.default.cyan(` [${new Date().toISOString()}] Received command: ${b.command_type} (${b.id})`)),await p.post(`/api/v1/dashboard/commands/${b.id}/ack`),rn(b.command_type,b.payload?.bot_id)){console.log(h.default.dim(` [${new Date().toISOString()}] Skipping duplicate ${b.command_type}`));continue}let f=await me(b);console.log(f.success?h.default.green(` [${new Date().toISOString()}] ${f.message}`):h.default.red(` [${new Date().toISOString()}] ${f.message}`)),await p.post(`/api/v1/dashboard/commands/${b.id}/result`,{status:f.success?"success":"failed",result:f.message,new_version:f.newVersion||null}),b.command_type==="update_cli"&&f.success&&(x=!0)}catch(f){console.log(h.default.dim(` [${new Date().toISOString()}] Command ${b.id} error: ${f.message}`))}if(x){console.log(h.default.cyan(` [${new Date().toISOString()}] CLI updated \u2014 restarting in 2s...`));try{await j()}catch{}setTimeout(()=>process.exit(0),2e3);return}}catch(i){i instanceof Ue&&(console.log(h.default.yellow(` [${new Date().toISOString()}] Account deactivated \u2014 signed out. Exiting daemon.`)),process.exit(0)),r+=1,console.log(h.default.dim(` [${new Date().toISOString()}] Heartbeat failed (${r}/${o}): ${i.message}`)),r>=o&&(console.log(h.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=J()!==null;a?await Kr():console.log(h.default.dim(` [${A()}] Hermes-only host \u2014 share-sync disabled (no plugin to push to).`)),setInterval(s,Vr),a&&setInterval(Kr,ul),bl(e.access_token,t);let c=i=>{console.log(h.default.yellow(`
80
+ [${new Date().toISOString()}] Received ${i} \u2014 posting disconnect and exiting.`)),hl().finally(()=>{process.exit(0)})};process.on("SIGTERM",c),process.on("SIGINT",c),await new Promise(()=>{})});yl=2700*1e3});var Pa=require("commander");var Zr=require("commander"),z=d(require("chalk")),es=d(require("ora")),ts=d(require("open")),_o=d(require("os"));var Cn=d(require("crypto"));function qo(){return Cn.default.randomBytes(32).toString("base64url")}function Vo(e){return Cn.default.createHash("sha256").update(e).digest("base64url")}F();Ce();$e();ie();ft();var Kt=d(require("os")),te=d(require("fs")),Jt=d(require("path")),Te=require("child_process");var qe=d(require("fs")),Oe=d(require("path")),We=d(require("os")),Ke=require("child_process"),Ar="ai.badgerclaw.watch",Er=Oe.default.join(We.default.homedir(),"Library","LaunchAgents"),Ve=Oe.default.join(Er,`${Ar}.plist`);function _i(){try{return(0,Ke.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/badgerclaw"}}function Si(){try{return(0,Ke.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/node"}}function ki(e){let t=Oe.default.join(We.default.homedir(),".badgerclaw"),n=Si(),o=Oe.default.dirname(n),r=Oe.default.dirname(e),s=[o,r,"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"],a=new Set,c=s.filter(i=>!i||a.has(i)?!1:(a.add(i),!0)).join(":");return`<?xml version="1.0" encoding="UTF-8"?>
80
81
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
81
82
  <plist version="1.0">
82
83
  <dict>
83
84
  <key>Label</key>
84
- <string>${Gn}</string>
85
+ <string>${Ar}</string>
85
86
  <key>ProgramArguments</key>
86
87
  <array>
87
- <string>${o}</string>
88
+ <string>${n}</string>
88
89
  <string>${e}</string>
89
90
  <string>heartbeat</string>
90
91
  </array>
@@ -104,7 +105,7 @@ Keep responses concise and helpful.
104
105
  <key>ThrottleInterval</key>
105
106
  <integer>30</integer>
106
107
  </dict>
107
- </plist>`}function qn(){if(Oe.default.platform()==="darwin")try{let e=Gs();Pe.default.mkdirSync(Wn,{recursive:!0}),Pe.default.mkdirSync(Se.default.join(Oe.default.homedir(),".badgerclaw"),{recursive:!0}),Pe.default.writeFileSync(De,qs(e));try{(0,Ne.execSync)(`launchctl unload "${De}" 2>/dev/null`)}catch{}(0,Ne.execSync)(`launchctl load "${De}"`),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 Vn(){if(Oe.default.platform()==="darwin")try{(0,Ne.execSync)(`launchctl unload "${De}" 2>/dev/null`),Pe.default.existsSync(De)&&Pe.default.unlinkSync(De)}catch{}}var Te=d(require("fs")),rt=d(require("path")),nt=d(require("os")),K=require("child_process"),Ot="badgerclaw-watch.service",Kn=rt.default.join(nt.default.homedir(),".config","systemd","user"),$o=rt.default.join(Kn,Ot);function Vs(){try{return(0,K.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/usr/local/bin/badgerclaw"}}function Ks(){try{return(0,K.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/usr/bin/node"}}function Js(e){let t=Ks(),o=rt.default.dirname(t);return`[Unit]
108
+ </plist>`}function Pr(){if(We.default.platform()==="darwin")try{let e=_i();qe.default.mkdirSync(Er,{recursive:!0}),qe.default.mkdirSync(Oe.default.join(We.default.homedir(),".badgerclaw"),{recursive:!0}),qe.default.writeFileSync(Ve,ki(e));try{(0,Ke.execSync)(`launchctl unload "${Ve}" 2>/dev/null`)}catch{}(0,Ke.execSync)(`launchctl load "${Ve}"`),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 Or(){if(We.default.platform()==="darwin")try{(0,Ke.execSync)(`launchctl unload "${Ve}" 2>/dev/null`),qe.default.existsSync(Ve)&&qe.default.unlinkSync(Ve)}catch{}}var Je=d(require("fs")),yt=d(require("path")),ht=d(require("os")),ee=require("child_process"),Wt="badgerclaw-watch.service",Tr=yt.default.join(ht.default.homedir(),".config","systemd","user"),Yn=yt.default.join(Tr,Wt);function vi(){try{return(0,ee.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/usr/local/bin/badgerclaw"}}function Ri(){try{return(0,ee.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/usr/bin/node"}}function xi(e){let t=Ri(),n=yt.default.dirname(t);return`[Unit]
108
109
  Description=BadgerClaw background watcher (heartbeat + pair events)
109
110
  After=network-online.target
110
111
  Wants=network-online.target
@@ -114,49 +115,77 @@ Type=simple
114
115
  ExecStart=${t} ${e} heartbeat
115
116
  Restart=always
116
117
  RestartSec=30
117
- Environment=PATH=${o}:/usr/local/bin:/usr/bin:/bin
118
+ Environment=PATH=${n}:/usr/local/bin:/usr/bin:/bin
118
119
  StandardOutput=append:%h/.badgerclaw/heartbeat.log
119
120
  StandardError=append:%h/.badgerclaw/heartbeat.log
120
121
 
121
122
  [Install]
122
123
  WantedBy=default.target
123
- `}function Jn(){try{return(0,K.execSync)("systemctl --user --version",{stdio:"ignore"}),!0}catch{return!1}}function Yn(){if(nt.default.platform()!=="linux"||!Jn())return!1;try{let e=Vs();Te.default.mkdirSync(Kn,{recursive:!0}),Te.default.mkdirSync(rt.default.join(nt.default.homedir(),".badgerclaw"),{recursive:!0}),Te.default.writeFileSync($o,Js(e)),(0,K.execSync)("systemctl --user daemon-reload",{stdio:"ignore"});try{(0,K.execSync)(`systemctl --user restart ${Ot}`,{stdio:"ignore"})}catch{}(0,K.execSync)(`systemctl --user enable --now ${Ot}`,{stdio:"ignore"});try{let t=(0,K.execSync)("whoami",{encoding:"utf-8"}).trim();(0,K.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 zn(){if(nt.default.platform()==="linux"&&Jn()){try{(0,K.execSync)(`systemctl --user disable --now ${Ot}`,{stdio:"ignore"})}catch{}try{Te.default.existsSync($o)&&Te.default.unlinkSync($o),(0,K.execSync)("systemctl --user daemon-reload",{stdio:"ignore"})}catch{}}}var Co=Tt.default.join(Nt.default.homedir(),".badgerclaw"),st=Tt.default.join(Co,"heartbeat.pid"),Ys=Tt.default.join(Co,"heartbeat.log");function zs(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 Xs(e){try{if(process.platform==="linux")return J.default.readFileSync(`/proc/${e}/cmdline`).toString("utf-8").split("\0").filter(Boolean);let t=(0,ke.execSync)(`ps -o args= -p ${e}`,{encoding:"utf-8"}).trim();return t.length?t.split(/\s+/).filter(Boolean):null}catch{return null}}function Io(e){if(!Number.isFinite(e)||e<=0||e===process.pid||e===process.ppid)return!1;let t=Xs(e);return t?zs(t):!1}function xo(){let e="";try{e=(0,ke.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=>Io(t))}function Qs(e){try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,Math.max(0,e))}catch{}}function Zs(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,ke.execSync)(`ps -o ppid= -p ${e}`,{encoding:"utf-8"}).trim(),10);if(!Number.isFinite(t))return null;let o="";try{o=(0,ke.execSync)(`ps -o comm= -p ${t}`,{encoding:"utf-8"}).trim()}catch{}return{ppid:t,comm:o}}catch{return null}}var ea=/(systemd|supervisord|launchd|runsv|runit|s6-supervise|openrc)/i;function ta(){for(let e of xo()){let t=Zs(e);if(t&&ea.test(t.comm))return e}return null}function oa(){try{let e=parseInt(J.default.readFileSync(st,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&Io(e))return!0}catch{}return Qn(),xo().length>0}function Qn(){try{let e=parseInt(J.default.readFileSync(st,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&Io(e))return}catch{}try{J.default.rmSync(st,{force:!0})}catch{}}function na(e="SIGTERM"){let t=xo(),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;)Qs(120),s=s.filter(n);for(let a of s)try{process.kill(a,"SIGKILL")}catch{}return o}function Xn(){if(oa())return console.log("\x1B[2mHeartbeat already running.\x1B[0m"),!0;try{J.default.mkdirSync(Co,{recursive:!0});let e=J.default.openSync(Ys,"a"),t=(0,ke.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(st,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 Ro(){let e=Nt.default.platform();if(e==="darwin"){qn();return}if(e==="linux"){if(Yn())return;Xn();return}Xn()}function ra(){let e=Nt.default.platform();e==="darwin"?Vn():e==="linux"&&zn(),na();try{J.default.rmSync(st,{force:!0})}catch{}}function Zn(e){let t=e.log||(()=>{}),o=ta();if(o!==null){Qn(),t(`heartbeat already supervised (pid ${o}) \u2014 left in place; cleared any stale pid file.`);return}ra(),t("removed stale heartbeat hooks from previous installs."),e.loggedIn?(Ro(),t("reinstalled a fresh heartbeat daemon for this host.")):t("run `badgerclaw login` to start the heartbeat for this host.")}var me=d(require("fs")),Do=d(require("os")),Bt=d(require("path")),ee=require("child_process"),U=d(require("chalk"));Xe();ue();var tr=Bt.default.join(Do.default.homedir(),".openclaw","openclaw.json");function ca(){return process.platform!=="linux"?!1:!!(me.default.existsSync("/.dockerenv")||(0,ee.spawnSync)("which",["systemctl"],{encoding:"utf-8"}).status!==0)}function or(e=!1){let t=null;try{me.default.existsSync(tr)&&(t=JSON.parse(me.default.readFileSync(tr,"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(ca())return da(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.")),or(!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 la(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 la(e,t=Eo,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 da(e){let t=l=>{e&&console.log(l)};t(U.default.dim(" Container mode (no systemd) \u2014 running gateway in foreground via nohup.")),or(!e);let o=Bt.default.join(Do.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(l){return{ok:!1,error:`cannot open gateway log at ${n}: ${l.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,i=!1;for(;Date.now()<c;){try{let l=me.default.readFileSync(n,"utf-8");if(l.includes("[gateway] ready")){i=!0;break}if(/EADDRINUSE|FATAL|Error:|gateway start blocked/.test(l))return{ok:!1,error:`gateway aborted on startup \u2014 see ${n}`}}catch{}await new Promise(l=>setTimeout(l,200))}return i?{ok:!0,state:"started",ready:!0}:{ok:!1,error:`gateway did not report ready within 20s \u2014 see ${n}`}}function Mt(){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(`
124
- \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")))}Ae();var Ga=2e3,Wa=12e4,hr=new pr.Command("login").description("Log in to BadgerClaw via browser").action(async()=>{let e=rn(),t=sn(e),o=`${un}/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,fr.default)(o);let n=(0,gr.default)("Waiting for authentication...").start(),r=hn(),s=Date.now();for(;Date.now()-s<Wa;){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:i,expires_at:l,refresh_token:m,email:p}=a.data,E=ro(),D=`openclaw-${Jo.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${E}`,f=D;try{let{version:b}=be(),w=await r.post("/api/v1/openclaw/register",{instance_id:D,label:Jo.default.hostname(),version:b,machine_fingerprint:E},{headers:{Authorization:`Bearer ${c}`}}),x=w.data?.result||w.data;x&&typeof x.instance_id=="string"&&x.instance_id.length>0&&(f=x.instance_id)}catch(b){let w=b?.response?.status;if(w===403||w===409){let x=b?.response?.data,z=Array.isArray(x?.errors)&&typeof x.errors[0]=="string"?x.errors[0]:null,qe=x?.detail,gt=typeof qe=="string"?qe:qe?.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,ss=z||gt||`Login refused (status ${w}). Open the BadgerClaw app to check your subscription state.`;n.fail(q.default.red(ss)),process.exit(1)}}if(ht({access_token:c,user_id:i,instance_id:f,expires_at:l,refresh_token:m,email:p}),n.succeed(q.default.green(`Logged in as ${wt(i)}`)),G()!==null){let b=await jt({verbose:!0});b.ok?b.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 tt(!0);v>0&&console.log(q.default.green(`\u2705 ${v} bot(s) automatically paired to OpenClaw.`)),Ro(),Mt();try{let{pushHeartbeat:b}=await Promise.resolve().then(()=>(Be(),Ko));await b(),console.log(q.default.dim(" Capabilities pushed \u2014 the machine should show online shortly."))}catch(b){console.log(q.default.dim(` Capability push will retry via the heartbeat (${b?.message||b}).`))}return}}catch{}await new Promise(a=>setTimeout(a,Ga))}n.fail(q.default.red("Authentication timed out. Please try again.")),process.exit(1)});var wr=require("commander"),ct=d(require("chalk")),Vt=d(require("fs")),je=d(require("os")),dt=d(require("path")),lt=require("child_process");L();he();function qa(){let e=process.platform;if(e==="darwin"){let t=dt.default.join(je.default.homedir(),"Library","LaunchAgents","ai.badgerclaw.watch.plist");(0,lt.spawnSync)("launchctl",["unload",t],{stdio:"ignore"});try{Vt.default.unlinkSync(t)}catch{}}else if(e==="linux"){(0,lt.spawnSync)("systemctl",["--user","disable","--now","badgerclaw-watch.service"],{stdio:"ignore"});let t=dt.default.join(je.default.homedir(),".config","systemd","user","badgerclaw-watch.service");try{Vt.default.unlinkSync(t)}catch{}(0,lt.spawnSync)("systemctl",["--user","daemon-reload"],{stdio:"ignore"})}(0,lt.spawnSync)("pkill",["-f","badgerclaw heartbeat"],{stdio:"ignore"})}function yr(e){try{return Vt.default.rmSync(e,{recursive:!0,force:!0}),!0}catch{return!1}}var br=new wr.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=_();if(t)try{let a=ze(t.access_token),{version:c}=be();await a.post("/api/v1/openclaw/register",{instance_id:t.instance_id,label:je.default.hostname(),version:c,online:!1})}catch{}if(qa(),e.keepState){Ke(),console.log(ct.default.green("Logged out \u2014 auth cleared. (state preserved with --keep-state)"));return}let o=dt.default.join(je.default.homedir(),".badgerclaw"),n=yr(o),r=dt.default.join(je.default.homedir(),".openclaw","badgerclaw"),s=yr(r);n||s?(console.log(ct.default.green("Logged out \u2014 local state cleared.")),console.log(ct.default.dim(` Removed: ${o}${s?`, ${r}`:""}`))):console.log(ct.default.green("Logged out."))});var _r=require("commander"),Yo=d(require("chalk"));L();var Sr=new _r.Command("status").description("Show connected instance info").action(async()=>{let e=_();(!e||!yt())&&(console.log(Yo.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1)),console.log(Yo.default.green("Authenticated")),console.log(` User: ${wt(e.user_id)}`),console.log(` Instance: ${e.instance_id}`),console.log(` Expires: ${new Date(e.expires_at).toLocaleDateString()}`)});var He=require("commander"),S=d(require("chalk")),zt=d(require("ora")),Yt=d(require("fs")),xr=d(require("os")),Rr=d(require("path")),Ar=require("child_process");L();he();var Me=d(require("fs")),kr=d(require("os")),vr=d(require("path")),$r=require("child_process");Xe();function Kt(e){let t=e.split(":")[0].replace(/^@/,"").replace(/_bot$/,""),o=vr.join(kr.homedir(),".openclaw","openclaw.json");return Me.existsSync(o)?{changed:we(()=>{let r=JSON.parse(Me.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&&Me.writeFileSync(o,JSON.stringify(r,null,2)),s})}:{changed:!1}}function Jt(){try{return(0,$r.execSync)("openclaw gateway restart",{stdio:"ignore"}),!0}catch{return!1}}_e();function Cr(e){return e.hermes?"hermes":"openclaw"}function Ir(e){return e.openclaw.installed?"openclaw":e.hermes.installed?"hermes":"openclaw"}function Xo(){yt()||(console.log(S.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1))}function Va(e){return/^[a-z0-9_]{4,20}$/.test(e)}function Er(e){return e.replace(/_bot$/,"")}var zo=["openclaw","hermes"],Ka=new He.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)=>{Xo(),Va(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??Ir(le());zo.includes(o)||(console.log(S.default.red(`Invalid --runtime "${t.runtime}". Must be one of: ${zo.join(", ")}.`)),process.exit(1));let n=(0,zt.default)(`Creating ${o} bot "${e}"...`).start();try{let r=O();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)}}),Ja=new He.Command("list").description("List your bots").action(async()=>{Xo();let e=(0,zt.default)("Fetching bots...").start();try{let n=(await O().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}):
125
- `));for(let r of n){let s=Er(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)}}),Ya=new He.Command("delete").description("Deactivate a bot").argument("<name>","Bot name to deactivate").action(async e=>{Xo();let t=(0,zt.default)(`Deactivating bot "${e}"...`).start();try{await O().delete(`/api/v1/openclaw/bots/${e}`),t.succeed(S.default.green(`Bot "${e}" deactivated.`));let{changed:n}=Kt(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 za(e){let t=e.trim();return t.startsWith("@")&&(t=t.slice(1)),t.includes(":")&&(t=t.split(":")[0]),Er(t)}function Xa(e){let t=e.replace(/[^a-zA-Z0-9_.-]/g,"_")||"default";return Rr.default.join(xr.default.homedir(),".openclaw","badgerclaw","quarantine",`${t}.json`)}var Qa=new He.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=za(e);t||(console.log(S.default.red(`Couldn't parse bot name "${e}".`)),process.exit(1));let o=Xa(t),n=!1;if(Yt.default.existsSync(o))try{let r=JSON.parse(Yt.default.readFileSync(o,"utf-8")),s=r.failureCount??"?",a=r.quarantinedAt??"?";console.log(S.default.dim(` Quarantine for "${t}" \u2014 ${s} failures, since ${a}`)),Yt.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,Ar.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(`
126
- \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."))}),Pr=new He.Command("bot").description("Manage bots").addCommand(Ka).addCommand(Ja).addCommand(Ya).addCommand(Qa);ot();var Or=require("commander"),y=d(require("chalk"));L();ae();ot();ue();Be();qo();he();xe();var Dr=3e3,Za=6e4,ei=2700*1e3,Nr=new Or.Command("watch").description("Watch for bot pair events in real-time (no polling)").action(async()=>{_()||(console.log(y.default.yellow("Not logged in.")),process.exit(1)),await tt(!1),console.log(y.default.green("\u{1F534} Listening for pair events... (Ctrl+C to stop)"));let t=require("eventsource"),o=Dr,n=null,r=null,s=()=>{let a=_();a||(console.log(y.default.red(" Auth missing \u2014 run `badgerclaw login` and re-start `badgerclaw watch`.")),process.exit(1));let c=new t(`${H}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${a.access_token}`}});r=c,c.onopen=()=>{o=Dr,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()},ei)},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,Za)},c.onmessage=async i=>{try{let l=JSON.parse(i.data);if(l.type==="pair"){let m=l.target_instance_id;if(m&&m!==Q()){console.log(y.default.dim(`
127
- \u{1F4F1} Pair event for ${l.bot_name} targets ${m} \u2014 not us, skipping`));return}console.log(y.default.cyan(`
128
- \u{1F4F1} Pair event received: ${l.bot_name}`)),await et(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(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(l.type==="gateway-restart"){console.log(y.default.cyan(`
129
- \u{1F504} Remote gateway-restart command received`));let m=await Le();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((l.type==="bot.delete"||l.type==="bot.disconnect")&&l.bot_user_id){let m=l.bot_user_id,p=l.type==="bot.delete"?"deleted":"disconnected",E=l.type==="bot.delete"?"\u{1F5D1}\uFE0F ":"\u{1F50C}";console.log(y.default.yellow(`
130
- ${E} Bot ${p}: ${m} \u2014 removing from OpenClaw config...`));try{let{changed:D}=Kt(m);D?(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(D){console.log(y.default.red(` Failed to update openclaw.json: ${D}`))}}else if(l.type==="claude_code.start"&&l.bot_id&&l.room_id){console.log(y.default.cyan(`
131
- \u{1F916} Claude Code START received: bot=${l.bot_id} room=${l.room_id}`));try{let m=await re({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(m.success?y.default.green(` \u2705 ${m.message}`):y.default.red(` \u274C ${m.message}`)),l.command_id)try{await O().post(`/api/v1/dashboard/commands/${l.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(l.type==="claude_code.stop"&&l.bot_id&&l.room_id){console.log(y.default.cyan(`
132
- \u{1F916} Claude Code STOP received: bot=${l.bot_id} room=${l.room_id}`));try{let m=await re({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(m.success?y.default.green(` \u2705 ${m.message}`):y.default.red(` \u274C ${m.message}`)),l.command_id)try{await O().post(`/api/v1/dashboard/commands/${l.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(l.type==="command.execute"&&l.command_id){console.log(y.default.cyan(`
133
- \u26A1 SSE command received: ${l.command_type} (${l.command_id})`));try{let m=O();await m.post(`/api/v1/dashboard/commands/${l.command_id}/ack`);let p=await re({id:l.command_id,command_type:l.command_type,payload:l.payload});console.log(p.success?y.default.green(` \u2705 ${p.message}`):y.default.red(` \u274C ${p.message}`)),await m.post(`/api/v1/dashboard/commands/${l.command_id}/result`,{status:p.success?"success":"failed",result:p.message,new_version:p.newVersion||null});try{await T()}catch{}l.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 ${l.command_id} error: ${m.message}`))}}}catch{}}};s(),await new Promise(()=>{})});var Yr=require("commander"),u=d(require("chalk")),te=require("child_process"),I=d(require("fs")),pt=d(require("os")),se=d(require("path"));ae();Ae();var ut=d(require("fs")),Ue=d(require("path")),Xt=require("child_process"),ti=["request","request-promise"];function oi(e){let t=e.match(/^(\s*)(?:"([^"]+)"|'([^']+)'|([^:#\s][^:]*?))\s*:/);return t?{indent:t[1].length,key:(t[2]??t[3]??t[4]??"").trim()}:null}function ni(e){let t=e.split(`
134
- `),o=[],n=!1,r=-1,s=!1,a=new Set(ti);for(let c of t){let i=oi(c);if(!n){i&&i.indent===0&&i.key==="overrides"&&(n=!0,r=i.indent),o.push(c);continue}if(i&&i.indent<=r){n=!1,o.push(c);continue}if(i&&i.indent>r&&a.has(i.key)){s=!0;continue}o.push(c)}return s?o.join(`
135
- `):null}function ri(){let e=[],t=(0,Xt.spawnSync)("npm",["root","-g"],{encoding:"utf-8",shell:!0});t.status===0&&t.stdout?.trim()&&e.push(Ue.default.join(t.stdout.trim(),"openclaw","pnpm-workspace.yaml"));let o=(0,Xt.spawnSync)("npm",["prefix","-g"],{encoding:"utf-8",shell:!0});o.status===0&&o.stdout?.trim()&&e.push(Ue.default.join(o.stdout.trim(),"lib","node_modules","openclaw","pnpm-workspace.yaml"));let n=(0,Xt.spawnSync)("which",["openclaw"],{encoding:"utf-8"});if(n.status===0&&n.stdout?.trim()){let r=Ue.default.dirname(Ue.default.dirname(n.stdout.trim()));e.push(Ue.default.join(r,"lib","node_modules","openclaw","pnpm-workspace.yaml"))}for(let r of e)try{if(ut.default.existsSync(r))return r}catch{}return null}function Tr(){let e=ri();if(!e)return null;let t;try{t=ut.default.readFileSync(e,"utf-8")}catch{return null}let o=ni(t);if(o===null)return null;try{ut.default.writeFileSync(e,o)}catch{return null}return{yamlPath:e,original:t}}function Lr(e){if(!e)return!1;try{return ut.default.writeFileSync(e.yamlPath,e.original),!0}catch{return!1}}_e();var Ge=require("child_process"),jr=d(require("fs")),P=d(require("chalk")),F={alreadyUp:!1,install:null,start:null,requiresRoot:!1,networkHostRequired:!1,guidance:null},Br='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 si(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?Br:"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?Br:"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 Mr(e,t,o=8e3){return(0,Ge.spawnSync)(e,t,{encoding:"utf-8",timeout:o})}function Qo(){let e=Mr("docker",["version","--format","{{.Server.Version}}"],4e3);return e.status===0&&!!(e.stdout||"").trim()}function ai(){return Mr("docker",["--version"],4e3).status===0}function Fe(e){return(0,Ge.spawnSync)("sh",["-c",`command -v ${e}`],{encoding:"utf-8"}).status===0}function ii(){return Fe("apt-get")?"apt":Fe("dnf")?"dnf":Fe("yum")?"yum":null}function ci(){let e=(0,Ge.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 li(){return process.platform==="darwin"?"darwin":process.platform==="linux"?ci()?"linux-systemd":"linux-nosystemd":"unsupported"}function di(){return typeof process.getuid=="function"?process.getuid()===0:!1}function pe(e,t){return t(P.default.dim(` $ ${e}`)),(0,Ge.spawnSync)("sh",["-c",e],{stdio:"inherit"}).status===0}function ui(e,t,o){let n=t?"sudo ":"";switch(e.via){case"brew":return o(P.default.dim(" Installing colima + docker CLI via Homebrew...")),pe("brew install colima docker",o);case"apt":return o(P.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 mi(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(!Fe("dockerd"))return o(P.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(P.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(P.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,Ge.spawnSync)("sh",["-c",a],{stdio:"ignore"}).status===0}}}async function pi(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 Hr(e={}){let t=e.log??(a=>console.log(a));if(process.env.BADGERCLAW_NO_AUTO_DEPS==="1"){let a=Qo();return a||(t(P.default.yellow(" BADGERCLAW_NO_AUTO_DEPS=1 \u2014 skipping automatic Docker setup.")),t(P.default.dim(" Start the Docker daemon yourself, then re-run `badgerclaw setup --hermes`."))),{ok:a,daemonUp:a,networkHostRequired:!1}}let o={daemonUp:Qo(),binaryPresent:ai(),host:li(),hasBrew:Fe("brew"),hasDockerApp:jr.default.existsSync("/Applications/Docker.app"),hasColima:Fe("colima"),pkgManager:ii(),isRoot:di()},n=si(o);if(n.alreadyUp)return{ok:!0,daemonUp:!0,networkHostRequired:!1};if(n.guidance)return t(P.default.red(` \u274C ${n.guidance}`)),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired};let r=n.requiresRoot&&!o.isRoot;return r&&t(P.default.dim(" (some steps need root \u2014 using sudo; you may be prompted for your password)")),n.install&&!ui(n.install,r,t)?(t(P.default.red(" \u274C Docker install failed (see output above). Install it manually, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired}):mi(n.start,r,t)?(t(P.default.dim(" Waiting for the Docker daemon to answer...")),await pi(Qo,12e4,1500)?(t(P.default.green(" \u2705 Docker daemon is up.")),{ok:!0,daemonUp:!0,networkHostRequired:n.networkHostRequired}):(t(P.default.red(" \u274C Docker did not become ready in time.")),n.start==="dockerd-restricted"?t(P.default.dim(" Check /tmp/badgerclaw-dockerd.log for the daemon output.")):n.start==="docker-app"&&t(P.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(P.default.red(" \u274C Could not start Docker (see output above). Resolve it, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired})}function Ur(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 Fr(e=process.versions.node){return parseInt(String(e).split(".")[0],10)}var Zo=require("child_process"),Qt=d(require("fs")),Gr=d(require("os")),Zt=d(require("path"));_e();Pt();function gi(){let e=Wr();for(let t of e)if(Qt.default.existsSync(t))return t;return null}function Wr(){return[Zt.default.resolve(__dirname,"..","assets","hermes-agent-bc.Dockerfile"),Zt.default.resolve(__dirname,"..","..","assets","hermes-agent-bc.Dockerfile")]}var fi="nousresearch/hermes-agent";function hi(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`${fi}:${o}`}var yi={run:e=>{let t=(0,Zo.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};function wi(e){return["build",...e.hostNetwork?["--network","host"]:[],...e.upstreamRef?["--build-arg",`UPSTREAM=${e.upstreamRef}`]:[],"-t",e.image,"-f",e.dockerfile,e.ctxDir]}function qr(e){let t=Ct();if(!t.installed)return{status:"no-docker"};let o=process.env.HERMES_IMAGE||Ee;if(It(t).installed)return{status:"already-present",image:o};let r=gi();if(!r)return{status:"no-dockerfile",expectedPaths:Wr()};let s=hi(e),a=wo({bridgeUsable:()=>Et(yi)}),c=Qt.default.mkdtempSync(Zt.default.join(Gr.default.tmpdir(),"bc-hermes-build-"));try{let i=(0,Zo.spawnSync)("docker",wi({hostNetwork:a,upstreamRef:s,image:o,dockerfile:r,ctxDir:c}),{stdio:"inherit",timeout:6e5});return i.status===0?{status:"built",image:o}:{status:"build-failed",image:o,stderr:`docker build exited ${i.status??"<no-status>"}`}}finally{try{Qt.default.rmSync(c,{recursive:!0,force:!0})}catch{}}}L();var Y=se.default.join(pt.default.homedir(),".openclaw","openclaw.json"),mt=Y+".badgerclaw-stash",zr=se.default.join(pt.default.homedir(),".openclaw","npm"),bi=se.default.join(zr,"package.json");async function Vr(){try{let e=await fetch(`${H}/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 _i(){if(!I.default.existsSync(Y))return null;try{let e=JSON.parse(I.default.readFileSync(Y,"utf-8")),t=e.channels?.badgerclaw;return t?(delete e.channels.badgerclaw,e.plugins?.entries?.badgerclaw&&delete e.plugins.entries.badgerclaw,I.default.writeFileSync(Y,JSON.stringify(e,null,2)),I.default.writeFileSync(mt,JSON.stringify(t,null,2)),t):null}catch{return null}}function Si(){if(!I.default.existsSync(Y))return null;try{let e=JSON.parse(I.default.readFileSync(Y,"utf-8"));return!e.gateway||typeof e.gateway!="object"?null:JSON.parse(JSON.stringify(e.gateway))}catch{return null}}function ki(e){if(e&&I.default.existsSync(Y))try{let t=JSON.parse(I.default.readFileSync(Y,"utf-8"));t.gateway={...e,...t.gateway||{}},I.default.writeFileSync(Y,JSON.stringify(t,null,2))}catch(t){console.log(u.default.yellow(` \u26A0\uFE0F Could not restore gateway block: ${t.message}`)),console.log(u.default.yellow(" Run `openclaw config set gateway.mode local` manually if the gateway fails to start."))}}function vi(){if(I.default.existsSync(mt))try{let e=JSON.parse(I.default.readFileSync(mt,"utf-8")),t=JSON.parse(I.default.readFileSync(Y,"utf-8"));t.channels=t.channels||{},t.channels.badgerclaw=e,I.default.writeFileSync(Y,JSON.stringify(t,null,2)),I.default.unlinkSync(mt)}catch(e){console.log(u.default.yellow(` \u26A0\uFE0F Could not restore config: ${e.message}`)),console.log(u.default.yellow(` Your bot credentials are backed up at: ${mt}`))}}async function Kr(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))},i=(l,m)=>{m.write(l),n+=l.toString("utf-8"),a.test(n)&&c()};o.stdout.on("data",l=>i(l,process.stdout)),o.stderr.on("data",l=>i(l,process.stderr)),o.on("exit",l=>{s=!0,t({status:r?0:l??1})}),o.on("error",l=>{s||(s=!0,console.error(u.default.red(` openclaw spawn error: ${l.message}`)),t({status:1}))})})}function Jr(e){if(!I.default.existsSync(e))return!1;let t;try{t=JSON.parse(I.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?(I.default.writeFileSync(e,JSON.stringify(t,null,2)+`
136
- `),!0):!1}function $i(){let e=[];Jr(bi)&&e.push(zr);for(let t of vt())Jr(se.default.join(t,"package.json"))&&e.push(t);return e}async function Ci(){let{detectCapabilities:e}=await Promise.resolve().then(()=>(_e(),En)),{pushHeartbeat:t}=await Promise.resolve().then(()=>(Be(),Ko));console.log(u.default.green(`
124
+ `}function Dr(){try{return(0,ee.execSync)("systemctl --user --version",{stdio:"ignore"}),!0}catch{return!1}}function Lr(){if(ht.default.platform()!=="linux"||!Dr())return!1;try{let e=vi();Je.default.mkdirSync(Tr,{recursive:!0}),Je.default.mkdirSync(yt.default.join(ht.default.homedir(),".badgerclaw"),{recursive:!0}),Je.default.writeFileSync(Yn,xi(e)),(0,ee.execSync)("systemctl --user daemon-reload",{stdio:"ignore"});try{(0,ee.execSync)(`systemctl --user restart ${Wt}`,{stdio:"ignore"})}catch{}(0,ee.execSync)(`systemctl --user enable --now ${Wt}`,{stdio:"ignore"});try{let t=(0,ee.execSync)("whoami",{encoding:"utf-8"}).trim();(0,ee.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 Mr(){if(ht.default.platform()==="linux"&&Dr()){try{(0,ee.execSync)(`systemctl --user disable --now ${Wt}`,{stdio:"ignore"})}catch{}try{Je.default.existsSync(Yn)&&Je.default.unlinkSync(Yn),(0,ee.execSync)("systemctl --user daemon-reload",{stdio:"ignore"})}catch{}}}var zn=Jt.default.join(Kt.default.homedir(),".badgerclaw"),bt=Jt.default.join(zn,"heartbeat.pid"),Ci=Jt.default.join(zn,"heartbeat.log");function $i(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 Ii(e){try{if(process.platform==="linux")return te.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 Qn(e){if(!Number.isFinite(e)||e<=0||e===process.pid||e===process.ppid)return!1;let t=Ii(e);return t?$i(t):!1}function Xn(){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=>Qn(t))}function Ai(e){try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,Math.max(0,e))}catch{}}function Ei(e){try{if(process.platform==="linux"){let r=te.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=te.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 Pi=/(systemd|supervisord|launchd|runsv|runit|s6-supervise|openrc)/i;function Oi(){for(let e of Xn()){let t=Ei(e);if(t&&Pi.test(t.comm))return e}return null}function Ti(){try{let e=parseInt(te.default.readFileSync(bt,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&Qn(e))return!0}catch{}return jr(),Xn().length>0}function jr(){try{let e=parseInt(te.default.readFileSync(bt,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&Qn(e))return}catch{}try{te.default.rmSync(bt,{force:!0})}catch{}}function Di(e="SIGTERM"){let t=Xn(),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;)Ai(120),s=s.filter(o);for(let a of s)try{process.kill(a,"SIGKILL")}catch{}return n}function Nr(){if(Ti())return console.log("\x1B[2mHeartbeat already running.\x1B[0m"),!0;try{te.default.mkdirSync(zn,{recursive:!0});let e=te.default.openSync(Ci,"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{te.default.writeFileSync(bt,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 Zn(){let e=Kt.default.platform();if(e==="darwin"){Pr();return}if(e==="linux"){if(Lr())return;Nr();return}Nr()}function Li(){let e=Kt.default.platform();e==="darwin"?Or():e==="linux"&&Mr(),Di();try{te.default.rmSync(bt,{force:!0})}catch{}}function Br(e){let t=e.log||(()=>{}),n=Oi();if(n!==null){jr(),t(`heartbeat already supervised (pid ${n}) \u2014 left in place; cleared any stale pid file.`);return}Li(),t("removed stale heartbeat hooks from previous installs."),e.loggedIn?(Zn(),t("reinstalled a fresh heartbeat daemon for this host.")):t("run `badgerclaw login` to start the heartbeat for this host.")}var Se=d(require("fs")),oo=d(require("os")),zt=d(require("path")),le=require("child_process"),W=d(require("chalk"));ut();_e();var Fr=zt.default.join(oo.default.homedir(),".openclaw","openclaw.json");function Bi(){return process.platform!=="linux"?!1:!!(Se.default.existsSync("/.dockerenv")||(0,le.spawnSync)("which",["systemctl"],{encoding:"utf-8"}).status!==0)}function Hr(e=!1){let t=null;try{Se.default.existsSync(Fr)&&(t=JSON.parse(Se.default.readFileSync(Fr,"utf-8"))?.gateway?.mode??null)}catch{}if(typeof t=="string"&&t.length>0)return!0;e||console.log(W.default.dim(" Setting gateway.mode=local..."));try{return Ae(()=>((0,le.execSync)("openclaw config set gateway.mode local",{encoding:"utf-8",timeout:1e4,stdio:"pipe"}),!0))}catch(n){return e||(console.log(W.default.yellow(` \u26A0\uFE0F Could not set gateway.mode automatically: ${n.message}`)),console.log(W.default.yellow(" Run `openclaw config set gateway.mode local` manually."))),!1}}async function Qt(e={}){let t=e.verbose!==!1,n=c=>{t&&console.log(c)};if(Bi())return Fi(t);n(W.default.dim(" Installing OpenClaw gateway service (if not present)...")),(0,le.spawnSync)("openclaw",["gateway","install"],{stdio:t?"inherit":"pipe",shell:!0}).status!==0&&n(W.default.yellow(" \u26A0\uFE0F `openclaw gateway install` returned non-zero \u2014 continuing.")),Hr(!t),n(W.default.dim(" Starting OpenClaw gateway..."));let r=(0,le.spawnSync)("openclaw",["gateway","start"],{stdio:t?"inherit":"pipe",shell:!0}),s="started";if(r.status!==0&&(r=(0,le.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(W.default.dim(" Waiting for the gateway to start answering..."));let a=await Ui(2e4);return a||n(W.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 Ui(e,t=to,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 Fi(e){let t=l=>{e&&console.log(l)};t(W.default.dim(" Container mode (no systemd) \u2014 running gateway in foreground via nohup.")),Hr(!e);let n=zt.default.join(oo.default.homedir(),".openclaw","logs");try{Se.default.mkdirSync(n,{recursive:!0})}catch{}let o=zt.default.join(n,"gateway-foreground.log"),r,s;try{r=Se.default.openSync(o,"a"),s=Se.default.openSync(o,"a")}catch(l){return{ok:!1,error:`cannot open gateway log at ${o}: ${l.message}`}}let a=(0,le.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(W.default.dim(` Gateway PID: ${a.pid}, log: ${o}`));let c=Date.now()+2e4,i=!1;for(;Date.now()<c;){try{let l=Se.default.readFileSync(o,"utf-8");if(l.includes("[gateway] ready")){i=!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 i?{ok:!0,state:"started",ready:!0}:{ok:!1,error:`gateway did not report ready within 20s \u2014 see ${o}`}}function Xt(){if(process.platform!=="linux"||process.getuid?.()!==0)return;let e=(0,le.spawnSync)("loginctl",["show-user","root","--property=Linger"],{encoding:"utf-8"});e.status===0&&/Linger=no/.test(e.stdout||"")&&(console.log(W.default.yellow(`
125
+ \u26A0\uFE0F systemd lingering is OFF for root. The gateway will stop on SSH disconnect.`)),console.log(W.default.dim(" Enable persistence: loginctl enable-linger root")))}Fe();var _l=2e3,Sl=12e4,ns=new Zr.Command("login").description("Log in to BadgerClaw via browser").action(async()=>{let e=qo(),t=Vo(e),n=`${zo}/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,ts.default)(n);let o=(0,es.default)("Waiting for authentication...").start(),r=tr(),s=Date.now();for(;Date.now()-s<Sl;){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:i,expires_at:l,refresh_token:u,email:p}=a.data,$=at(),E=`openclaw-${_o.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${$}`,g=E;try{let{version:x}=he(),b=await r.post("/api/v1/openclaw/register",{instance_id:E,label:_o.default.hostname(),version:x,machine_fingerprint:$},{headers:{Authorization:`Bearer ${c}`}}),f=b.data?.result||b.data;f&&typeof f.instance_id=="string"&&f.instance_id.length>0&&(g=f.instance_id)}catch(x){let b=x?.response?.status;if(b===403||b===409){let f=x?.response?.data,y=Array.isArray(f?.errors)&&typeof f.errors[0]=="string"?f.errors[0]:null,q=f?.detail,B=typeof q=="string"?q:q?.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,xe=y||B||`Login refused (status ${b}). Open the BadgerClaw app to check your subscription state.`;o.fail(z.default.red(xe)),process.exit(1)}}if(Et({access_token:c,user_id:i,instance_id:g,expires_at:l,refresh_token:u,email:p}),o.succeed(z.default.green(`Logged in as ${Ot(i)}`)),J()!==null){let x=await Qt({verbose:!0});x.ok?x.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 w=await gt(!0);w>0&&console.log(z.default.green(`\u2705 ${w} bot(s) automatically paired to OpenClaw.`)),Zn(),Xt();try{let{pushHeartbeat:x}=await Promise.resolve().then(()=>(ze(),wo));await x(),console.log(z.default.dim(" Capabilities pushed \u2014 the machine should show online shortly."))}catch(x){console.log(z.default.dim(` Capability push will retry via the heartbeat (${x?.message||x}).`))}return}}catch{}await new Promise(a=>setTimeout(a,_l))}o.fail(z.default.red("Authentication timed out. Please try again.")),process.exit(1)});var rs=require("commander"),St=d(require("chalk")),sn=d(require("fs")),Qe=d(require("os")),vt=d(require("path")),kt=require("child_process");F();$e();function kl(){let e=process.platform;if(e==="darwin"){let t=vt.default.join(Qe.default.homedir(),"Library","LaunchAgents","ai.badgerclaw.watch.plist");(0,kt.spawnSync)("launchctl",["unload",t],{stdio:"ignore"});try{sn.default.unlinkSync(t)}catch{}}else if(e==="linux"){(0,kt.spawnSync)("systemctl",["--user","disable","--now","badgerclaw-watch.service"],{stdio:"ignore"});let t=vt.default.join(Qe.default.homedir(),".config","systemd","user","badgerclaw-watch.service");try{sn.default.unlinkSync(t)}catch{}(0,kt.spawnSync)("systemctl",["--user","daemon-reload"],{stdio:"ignore"})}(0,kt.spawnSync)("pkill",["-f","badgerclaw heartbeat"],{stdio:"ignore"})}function os(e){try{return sn.default.rmSync(e,{recursive:!0,force:!0}),!0}catch{return!1}}var ss=new rs.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=k();if(t)try{let a=ct(t.access_token),{version:c}=he();await a.post("/api/v1/openclaw/register",{instance_id:t.instance_id,label:Qe.default.hostname(),version:c,online:!1})}catch{}if(kl(),e.keepState){st(),console.log(St.default.green("Logged out \u2014 auth cleared. (state preserved with --keep-state)"));return}let n=vt.default.join(Qe.default.homedir(),".badgerclaw"),o=os(n),r=vt.default.join(Qe.default.homedir(),".openclaw","badgerclaw"),s=os(r);o||s?(console.log(St.default.green("Logged out \u2014 local state cleared.")),console.log(St.default.dim(` Removed: ${n}${s?`, ${r}`:""}`))):console.log(St.default.green("Logged out."))});var as=require("commander"),So=d(require("chalk"));F();var is=new as.Command("status").description("Show connected instance info").action(async()=>{let e=k();(!e||!Pt())&&(console.log(So.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1)),console.log(So.default.green("Authenticated")),console.log(` User: ${Ot(e.user_id)}`),console.log(` Instance: ${e.instance_id}`),console.log(` Expires: ${new Date(e.expires_at).toLocaleDateString()}`)});var Ze=require("commander"),v=d(require("chalk")),un=d(require("ora")),cn=d(require("fs")),ps=d(require("os")),gs=d(require("path")),fs=require("child_process");F();$e();var Xe=d(require("fs")),ls=d(require("os")),cs=d(require("path")),us=require("child_process");ut();function an(e){let t=e.split(":")[0].replace(/^@/,"").replace(/_bot$/,""),n=cs.join(ls.homedir(),".openclaw","openclaw.json");return Xe.existsSync(n)?{changed:Ae(()=>{let r=JSON.parse(Xe.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(c=>c.id!==t),r.agents.list.length!==a&&(s=!0)}return s&&Xe.writeFileSync(n,JSON.stringify(r,null,2)),s})}:{changed:!1}}function ln(){try{return(0,us.execSync)("openclaw gateway restart",{stdio:"ignore"}),!0}catch{return!1}}Ee();function ds(e){return e.hermes?"hermes":"openclaw"}function ms(e){return e.openclaw.installed?"openclaw":e.hermes.installed?"hermes":"openclaw"}function vo(){Pt()||(console.log(v.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1))}function vl(e){return/^[a-z0-9_]{4,20}$/.test(e)}function hs(e){return e.replace(/_bot$/,"")}var ko=["openclaw","hermes"],Rl=new Ze.Command("create").description("Create a new bot").argument("<name>","Bot name (4-20 chars, lowercase alphanumeric + underscores)").option("-r, --runtime <runtime>",`Bot runtime: ${ko.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)=>{vo(),vl(e)||(console.log(v.default.red("Invalid bot name. Must be 4-20 characters, lowercase alphanumeric and underscores only.")),process.exit(1));let n=t.runtime??ms(be());ko.includes(n)||(console.log(v.default.red(`Invalid --runtime "${t.runtime}". Must be one of: ${ko.join(", ")}.`)),process.exit(1));let o=(0,un.default)(`Creating ${n} bot "${e}"...`).start();try{let r=N();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(v.default.green(`Bot "${e}" (${n}) created successfully!`)),n==="hermes"&&console.log(v.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(v.default.red(`Failed to create bot: ${s}`)),process.exit(1)}}),xl=new Ze.Command("list").description("List your bots").action(async()=>{vo();let e=(0,un.default)("Fetching bots...").start();try{let o=(await N().get("/api/v1/openclaw/bots")).data?.bots||[];if(e.stop(),o.length===0){console.log(v.default.yellow("No bots found. Create one with `badgerclaw bot create <name>`."));return}console.log(v.default.green(`Your bots (${o.length}):
126
+ `));for(let r of o){let s=hs(r.username||r.name),a=r.active===!1?v.default.dim("deactivated"):r.openclaw_connected?v.default.green("connected"):v.default.gray("disconnected");console.log(` ${v.default.bold(s)} ${a}`)}}catch(t){let n=t.response?.data?.errors?.[0]||t.message;e.fail(v.default.red(`Failed to list bots: ${n}`)),process.exit(1)}}),Cl=new Ze.Command("delete").description("Deactivate a bot").argument("<name>","Bot name to deactivate").action(async e=>{vo();let t=(0,un.default)(`Deactivating bot "${e}"...`).start();try{await N().delete(`/api/v1/openclaw/bots/${e}`),t.succeed(v.default.green(`Bot "${e}" deactivated.`));let{changed:o}=an(e);o&&(console.log(v.default.dim(" Removed from openclaw.json")),ln()&&console.log(v.default.dim(" Gateway restarted")))}catch(n){let o=n.response?.data?.errors?.[0]||n.message;t.fail(v.default.red(`Failed to deactivate bot: ${o}`)),process.exit(1)}});function $l(e){let t=e.trim();return t.startsWith("@")&&(t=t.slice(1)),t.includes(":")&&(t=t.split(":")[0]),hs(t)}function Il(e){let t=e.replace(/[^a-zA-Z0-9_.-]/g,"_")||"default";return gs.default.join(ps.default.homedir(),".openclaw","badgerclaw","quarantine",`${t}.json`)}var Al=new Ze.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=$l(e);t||(console.log(v.default.red(`Couldn't parse bot name "${e}".`)),process.exit(1));let n=Il(t),o=!1;if(cn.default.existsSync(n))try{let r=JSON.parse(cn.default.readFileSync(n,"utf-8")),s=r.failureCount??"?",a=r.quarantinedAt??"?";console.log(v.default.dim(` Quarantine for "${t}" \u2014 ${s} failures, since ${a}`)),cn.default.unlinkSync(n),o=!0}catch(r){console.log(v.default.red(`Failed to clear quarantine ledger at ${n}: ${r.message}`)),process.exit(1)}console.log(o?v.default.green(`\u2705 Cleared quarantine for "${t}"`):v.default.dim(` No quarantine file for "${t}" \u2014 already healthy or never quarantined.`)),console.log(v.default.dim(" Restarting OpenClaw gateway so the refresh chain runs..."));try{(0,fs.execSync)("openclaw gateway restart",{stdio:"inherit"})}catch(r){console.log(v.default.yellow(` Gateway restart command failed: ${r.message}`)),console.log(v.default.yellow(" Run `openclaw gateway restart` manually.")),process.exit(1)}console.log(v.default.green(`
127
+ \u2705 Refresh triggered. Watch the gateway logs for token refresh progress:`)),console.log(v.default.dim(" tail -f ~/.openclaw/logs/*.log")),console.log(v.default.dim(" If the bot fails to recover, the plugin's 4 refresh strategies all hit")),console.log(v.default.dim(" dead ends. Verify SYNAPSE_REGISTRATION_SHARED_SECRET is set on this gateway,")),console.log(v.default.dim(" or re-pair the bot from the BadgerClaw iOS app."))}),ys=new Ze.Command("bot").description("Manage bots").addCommand(Rl).addCommand(xl).addCommand(Cl).addCommand(Al);ft();var ws=require("commander"),S=d(require("chalk"));F();ie();ft();_e();ze();yo();$e();Ce();var bs=3e3,El=6e4,Pl=2700*1e3,_s=new ws.Command("watch").description("Watch for bot pair events in real-time (no polling)").action(async()=>{k()||(console.log(S.default.yellow("Not logged in.")),process.exit(1)),await gt(!1),console.log(S.default.green("\u{1F534} Listening for pair events... (Ctrl+C to stop)"));let t=require("eventsource"),n=bs,o=null,r=null,s=()=>{let a=k();a||(console.log(S.default.red(" Auth missing \u2014 run `badgerclaw login` and re-start `badgerclaw watch`.")),process.exit(1));let c=new t(`${M}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${a.access_token}`}});r=c,c.onopen=()=>{n=bs,console.log(S.default.dim(" SSE connected \u2014 listening for events")),o&&clearTimeout(o),o=setTimeout(()=>{console.log(S.default.dim(" SSE proactive reconnect \u2014 refreshing token before expiry")),c.close(),s()},Pl)},c.onerror=()=>{c.close(),o&&(clearTimeout(o),o=null),console.log(S.default.dim(` SSE disconnected \u2014 reconnecting in ${Math.floor(n/1e3)}s...`)),setTimeout(s,n),n=Math.min(n*1.5,El)},c.onmessage=async i=>{try{let l=JSON.parse(i.data);if(l.type==="pair"){let u=l.target_instance_id;if(u&&u!==ae()){console.log(S.default.dim(`
128
+ \u{1F4F1} Pair event for ${l.bot_name} targets ${u} \u2014 not us, skipping`));return}console.log(S.default.cyan(`
129
+ \u{1F4F1} Pair event received: ${l.bot_name}`)),await pt(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(S.default.green(" \u2705 Gateway restarted \u2014 bot is live!"))}catch{console.log(S.default.dim(" Gateway restart failed \u2014 run: openclaw gateway restart"))}}else if(l.type==="gateway-restart"){console.log(S.default.cyan(`
130
+ \u{1F504} Remote gateway-restart command received`));let u=await Ye();u.success?console.log(S.default.green(` \u2705 Gateway restarted: ${u.message}`)):console.log(S.default.red(` \u274C Gateway restart failed: ${u.message}`));try{await j(),console.log(S.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(S.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",$=l.type==="bot.delete"?"\u{1F5D1}\uFE0F ":"\u{1F50C}";console.log(S.default.yellow(`
131
+ ${$} Bot ${p}: ${u} \u2014 removing from OpenClaw config...`));try{let{changed:E}=an(u);E?(console.log(S.default.green(" \u2705 Removed from openclaw.json")),ln()?console.log(S.default.green(" \u2705 Gateway restarted")):console.log(S.default.dim(" Gateway restart failed \u2014 restart manually"))):console.log(S.default.dim(" Account not found in openclaw.json \u2014 nothing to remove"))}catch(E){console.log(S.default.red(` Failed to update openclaw.json: ${E}`))}}else if(l.type==="claude_code.start"&&l.bot_id&&l.room_id){console.log(S.default.cyan(`
132
+ \u{1F916} Claude Code START received: bot=${l.bot_id} room=${l.room_id}`));try{let u=await me({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?S.default.green(` \u2705 ${u.message}`):S.default.red(` \u274C ${u.message}`)),l.command_id)try{await N().post(`/api/v1/dashboard/commands/${l.command_id}/result`,{status:u.success?"success":"failed",result:u.message})}catch{}try{await j()}catch{}}catch(u){console.log(S.default.red(` Claude Code start error: ${u.message}`))}}else if(l.type==="claude_code.stop"&&l.bot_id&&l.room_id){console.log(S.default.cyan(`
133
+ \u{1F916} Claude Code STOP received: bot=${l.bot_id} room=${l.room_id}`));try{let u=await me({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?S.default.green(` \u2705 ${u.message}`):S.default.red(` \u274C ${u.message}`)),l.command_id)try{await N().post(`/api/v1/dashboard/commands/${l.command_id}/result`,{status:u.success?"success":"failed",result:u.message})}catch{}try{await j()}catch{}}catch(u){console.log(S.default.red(` Claude Code stop error: ${u.message}`))}}else if(l.type==="command.execute"&&l.command_id){console.log(S.default.cyan(`
134
+ \u26A1 SSE command received: ${l.command_type} (${l.command_id})`));try{let u=N();await u.post(`/api/v1/dashboard/commands/${l.command_id}/ack`);let p=await me({id:l.command_id,command_type:l.command_type,payload:l.payload});console.log(p.success?S.default.green(` \u2705 ${p.message}`):S.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 j()}catch{}l.command_type==="update_cli"&&p.success&&(console.log(S.default.cyan(" CLI updated \u2014 restarting in 2s...")),setTimeout(()=>process.exit(0),2e3))}catch(u){console.log(S.default.red(` Command ${l.command_id} error: ${u.message}`))}}}catch{}}};s(),await new Promise(()=>{})});var Ws=require("commander"),m=d(require("chalk")),ce=require("child_process"),P=d(require("fs")),Ct=d(require("os")),ge=d(require("path"));ie();Fe();var Rt=d(require("fs")),et=d(require("path")),dn=require("child_process"),Ol=["request","request-promise"];function Tl(e){let t=e.match(/^(\s*)(?:"([^"]+)"|'([^']+)'|([^:#\s][^:]*?))\s*:/);return t?{indent:t[1].length,key:(t[2]??t[3]??t[4]??"").trim()}:null}function Dl(e){let t=e.split(`
135
+ `),n=[],o=!1,r=-1,s=!1,a=new Set(Ol);for(let c of t){let i=Tl(c);if(!o){i&&i.indent===0&&i.key==="overrides"&&(o=!0,r=i.indent),n.push(c);continue}if(i&&i.indent<=r){o=!1,n.push(c);continue}if(i&&i.indent>r&&a.has(i.key)){s=!0;continue}n.push(c)}return s?n.join(`
136
+ `):null}function Ll(){let e=[],t=(0,dn.spawnSync)("npm",["root","-g"],{encoding:"utf-8",shell:!0});t.status===0&&t.stdout?.trim()&&e.push(et.default.join(t.stdout.trim(),"openclaw","pnpm-workspace.yaml"));let n=(0,dn.spawnSync)("npm",["prefix","-g"],{encoding:"utf-8",shell:!0});n.status===0&&n.stdout?.trim()&&e.push(et.default.join(n.stdout.trim(),"lib","node_modules","openclaw","pnpm-workspace.yaml"));let o=(0,dn.spawnSync)("which",["openclaw"],{encoding:"utf-8"});if(o.status===0&&o.stdout?.trim()){let r=et.default.dirname(et.default.dirname(o.stdout.trim()));e.push(et.default.join(r,"lib","node_modules","openclaw","pnpm-workspace.yaml"))}for(let r of e)try{if(Rt.default.existsSync(r))return r}catch{}return null}function Ss(){let e=Ll();if(!e)return null;let t;try{t=Rt.default.readFileSync(e,"utf-8")}catch{return null}let n=Dl(t);if(n===null)return null;try{Rt.default.writeFileSync(e,n)}catch{return null}return{yamlPath:e,original:t}}function ks(e){if(!e)return!1;try{return Rt.default.writeFileSync(e.yamlPath,e.original),!0}catch{return!1}}Ee();var nt=require("child_process"),Rs=d(require("fs")),L=d(require("chalk")),K={alreadyUp:!1,install:null,start:null,requiresRoot:!1,networkHostRequired:!1,guidance:null},vs='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 Ml(e){return e.daemonUp?{...K,alreadyUp:!0}:e.host==="darwin"?e.hasDockerApp?{...K,start:"docker-app"}:e.hasColima?{...K,start:"colima"}:e.binaryPresent?{...K,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?{...K,install:{tool:"colima",via:"brew"},start:"colima"}:{...K,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?{...K,start:"systemctl",requiresRoot:!0}:e.pkgManager==="apt"?{...K,install:{tool:"docker",via:"apt"},start:"systemctl",requiresRoot:!0}:{...K,guidance:e.pkgManager?vs:"Docker is not installed and no supported package manager (apt) was found. Install Docker, then re-run."}:e.host==="linux-nosystemd"?e.binaryPresent?{...K,start:"dockerd-restricted",requiresRoot:!0,networkHostRequired:!0}:e.pkgManager==="apt"?{...K,install:{tool:"docker",via:"apt"},start:"dockerd-restricted",requiresRoot:!0,networkHostRequired:!0}:{...K,guidance:e.pkgManager?vs:"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."}:{...K,guidance:`Automatic Docker setup isn't supported on this platform (${process.platform}). Install + start Docker manually, then re-run.`}}function xs(e,t,n=8e3){return(0,nt.spawnSync)(e,t,{encoding:"utf-8",timeout:n})}function Ro(){let e=xs("docker",["version","--format","{{.Server.Version}}"],4e3);return e.status===0&&!!(e.stdout||"").trim()}function Nl(){return xs("docker",["--version"],4e3).status===0}function tt(e){return(0,nt.spawnSync)("sh",["-c",`command -v ${e}`],{encoding:"utf-8"}).status===0}function jl(){return tt("apt-get")?"apt":tt("dnf")?"dnf":tt("yum")?"yum":null}function Bl(){let e=(0,nt.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 Ul(){return process.platform==="darwin"?"darwin":process.platform==="linux"?Bl()?"linux-systemd":"linux-nosystemd":"unsupported"}function Fl(){return typeof process.getuid=="function"?process.getuid()===0:!1}function ke(e,t){return t(L.default.dim(` $ ${e}`)),(0,nt.spawnSync)("sh",["-c",e],{stdio:"inherit"}).status===0}function Hl(e,t,n){let o=t?"sudo ":"";switch(e.via){case"brew":return n(L.default.dim(" Installing colima + docker CLI via Homebrew...")),ke("brew install colima docker",n);case"apt":return n(L.default.dim(" Installing Docker via apt...")),ke(`${o}apt-get update`,n),ke(`${o}apt-get install -y docker.io`,n);default:return!1}}function Gl(e,t,n){let o=t?"sudo ":"";switch(e){case"docker-app":return ke("open -a Docker",n);case"colima":return ke("colima start",n);case"systemctl":return ke(`${o}systemctl enable --now docker`,n);case"dockerd-restricted":{if(!tt("dockerd"))return n(L.default.red(" \u274C `dockerd` is not installed (the docker CLI alone is not enough on a no-systemd host).")),!1;if(t&&!ke("sudo -v",n))return n(L.default.red(" \u274C root is required to start dockerd here, but sudo is unavailable.")),!1;ke(`${o}sh -c 'mount -t cgroup2 none /sys/fs/cgroup 2>/dev/null || true'`,n);let r="/tmp/badgerclaw-dockerd.log";n(L.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,nt.spawnSync)("sh",["-c",a],{stdio:"ignore"}).status===0}}}async function ql(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 Cs(e={}){let t=e.log??(a=>console.log(a));if(process.env.BADGERCLAW_NO_AUTO_DEPS==="1"){let a=Ro();return a||(t(L.default.yellow(" BADGERCLAW_NO_AUTO_DEPS=1 \u2014 skipping automatic Docker setup.")),t(L.default.dim(" Start the Docker daemon yourself, then re-run `badgerclaw setup --hermes`."))),{ok:a,daemonUp:a,networkHostRequired:!1}}let n={daemonUp:Ro(),binaryPresent:Nl(),host:Ul(),hasBrew:tt("brew"),hasDockerApp:Rs.default.existsSync("/Applications/Docker.app"),hasColima:tt("colima"),pkgManager:jl(),isRoot:Fl()},o=Ml(n);if(o.alreadyUp)return{ok:!0,daemonUp:!0,networkHostRequired:!1};if(o.guidance)return t(L.default.red(` \u274C ${o.guidance}`)),{ok:!1,daemonUp:!1,networkHostRequired:o.networkHostRequired};let r=o.requiresRoot&&!n.isRoot;return r&&t(L.default.dim(" (some steps need root \u2014 using sudo; you may be prompted for your password)")),o.install&&!Hl(o.install,r,t)?(t(L.default.red(" \u274C Docker install failed (see output above). Install it manually, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:o.networkHostRequired}):Gl(o.start,r,t)?(t(L.default.dim(" Waiting for the Docker daemon to answer...")),await ql(Ro,12e4,1500)?(t(L.default.green(" \u2705 Docker daemon is up.")),{ok:!0,daemonUp:!0,networkHostRequired:o.networkHostRequired}):(t(L.default.red(" \u274C Docker did not become ready in time.")),o.start==="dockerd-restricted"?t(L.default.dim(" Check /tmp/badgerclaw-dockerd.log for the daemon output.")):o.start==="docker-app"&&t(L.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(L.default.red(" \u274C Could not start Docker (see output above). Resolve it, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:o.networkHostRequired})}function $s(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 Is(e=process.versions.node){return parseInt(String(e).split(".")[0],10)}var xo=require("child_process"),mn=d(require("fs")),As=d(require("os")),pn=d(require("path"));Ee();Ge();function Vl(){let e=Es();for(let t of e)if(mn.default.existsSync(t))return t;return null}function Es(){return[pn.default.resolve(__dirname,"..","assets","hermes-agent-bc.Dockerfile"),pn.default.resolve(__dirname,"..","..","assets","hermes-agent-bc.Dockerfile")]}var Wl="nousresearch/hermes-agent";function Kl(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`${Wl}:${n}`}var Jl={run:e=>{let t=(0,xo.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};function Yl(e){return["build",...e.hostNetwork?["--network","host"]:[],...e.upstreamRef?["--build-arg",`UPSTREAM=${e.upstreamRef}`]:[],"-t",e.image,"-f",e.dockerfile,e.ctxDir]}function Ps(e){let t=Bt();if(!t.installed)return{status:"no-docker"};let n=process.env.HERMES_IMAGE||He;if(Ut(t).installed)return{status:"already-present",image:n};let r=Vl();if(!r)return{status:"no-dockerfile",expectedPaths:Es()};let s=Kl(e),a=Gn({bridgeUsable:()=>qt(Jl)}),c=mn.default.mkdtempSync(pn.default.join(As.default.tmpdir(),"bc-hermes-build-"));try{let i=(0,xo.spawnSync)("docker",Yl({hostNetwork:a,upstreamRef:s,image:n,dockerfile:r,ctxDir:c}),{stdio:"inherit",timeout:6e5});return i.status===0?{status:"built",image:n}:{status:"build-failed",image:n,stderr:`docker build exited ${i.status??"<no-status>"}`}}finally{try{mn.default.rmSync(c,{recursive:!0,force:!0})}catch{}}}F();var Co=require("child_process"),zl="https://ollama.com/download",Ql={run:(e,t)=>{let n=(0,Co.spawnSync)(e,t,{encoding:"utf-8",timeout:1e4});return{status:n.status,stdout:n.stdout||"",stderr:n.stderr||""}}};function gn(e={}){let t=e.runner??Ql,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 fn(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 ${zl}, then re-run setup.`}function hn(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,Co.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()}}var Fs=d(require("os")),Hs=d(require("readline"));ie();Ge();var pe=d(require("os")),Ds=require("child_process");Ce();var Os=[1,2,4,6,8,12,16];function Ts(e){if(e>16)return"16GB+";let t=Os[0];for(let n of Os)e>=n&&(t=n);return`${t}GB`}var Ls={run:(e,t)=>{let n=(0,Ds.spawnSync)(e,t,{encoding:"utf-8",timeout:5e3});return{status:n.status,stdout:n.stdout||""}}};function yn(){return Math.round(pe.default.totalmem()/1024/1024/1024)}function Ms(e){return e==="x64"?"x86_64":e}function Ns(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=pe.default.cpus();return n.length?n[0].model.trim():null}function js(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(`
137
+ `)[0],[a,c]=s.split(",").map(l=>l.trim()),i=Number.parseFloat(c);return{accelerator:a||"NVIDIA GPU",vram_gb:Number.isFinite(i)?Math.round(i/1024*10)/10:null,unified_memory:!1}}return{accelerator:null,vram_gb:null,unified_memory:!1}}function Bs(e={}){let t=e.runner??Ls,n=pe.default.platform(),o=Ms(pe.default.arch()),r=Ns(n,t);return js(n,o,r,t).accelerator}function Us(e={}){let t=e.runner??Ls,n=pe.default.platform(),o=Ms(pe.default.arch()),r=yn(),s=Ns(n,t),{accelerator:a,vram_gb:c,unified_memory:i}=js(n,o,s,t);return{machine_fingerprint:at(),ram_total_gb:Math.round(pe.default.totalmem()/1024/1024/1024*10)/10,ram_tier:Ts(r),cpu_model:s,core_count:pe.default.cpus().length||null,accelerator:a,vram_gb:c,unified_memory:i,os:n,arch:o}}function Xl(){return Math.round(Fs.default.totalmem()/1024/1024/1024)}async function $o(e,t,n={}){let o=n.apiBase??M,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 c=await r(a,{headers:{Accept:"application/json"}});if(!c.ok)return null;let i=await c.json(),l=i.result&&typeof i.result=="object"?i.result:i;return Array.isArray(l.recommended)?l:null}catch{return null}}async function Zl(e){let t=Hs.default.createInterface({input:process.stdin,output:process.stdout});try{return await new Promise(n=>t.question(e,n))}finally{t.close()}}function ec(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 tc(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??Zl;r(`
138
+ Local models that fit ${e.ram_gb} GB (${e.ram_tier}):`),n.forEach((l,u)=>{r(` ${l===o?"*":" "} ${u+1}) ${ec(l)}`)});let a=n.indexOf(o)+1,c=(await s(` Pick a model [${a}]: `)).trim();if(!c)return{tag:o.ollama_tag,note:e.note,model:o};let i=Number.parseInt(c,10);if(Number.isInteger(i)&&i>=1&&i<=n.length){let l=n[i-1];return{tag:l.ollama_tag,note:e.note,model:l}}return{tag:o.ollama_tag,note:e.note,model:o}}async function bn(e){let t=e.ramGb??Xl(),n=e.accelerator===void 0?Bs():e.accelerator,o=await $o(t,e.runtime,{apiBase:e.apiBase,fetchImpl:e.fetchImpl,accelerator:n});if(!o)return{tag:e.preferredTag||Hn("ollama"),note:"Could not reach the model-recommendation service \u2014 using a safe default model.",ramGb:t,fellBack:!0};let r=await tc(o,{interactive:e.interactive,preferredTag:e.preferredTag,prompt:e.prompt,log:e.log});return{tag:r.tag,note:r.note,ramGb:t,fellBack:!1}}Ge();var ne=ge.default.join(Ct.default.homedir(),".openclaw","openclaw.json"),xt=ne+".badgerclaw-stash",Ks=ge.default.join(Ct.default.homedir(),".openclaw","npm"),nc=ge.default.join(Ks,"package.json");async function Gs(){try{let e=await fetch(`${M}/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 oc(){if(!P.default.existsSync(ne))return null;try{let e=JSON.parse(P.default.readFileSync(ne,"utf-8")),t=e.channels?.badgerclaw;return t?(delete e.channels.badgerclaw,e.plugins?.entries?.badgerclaw&&delete e.plugins.entries.badgerclaw,P.default.writeFileSync(ne,JSON.stringify(e,null,2)),P.default.writeFileSync(xt,JSON.stringify(t,null,2)),t):null}catch{return null}}function rc(){if(!P.default.existsSync(ne))return null;try{let e=JSON.parse(P.default.readFileSync(ne,"utf-8"));return!e.gateway||typeof e.gateway!="object"?null:JSON.parse(JSON.stringify(e.gateway))}catch{return null}}function sc(e){if(e&&P.default.existsSync(ne))try{let t=JSON.parse(P.default.readFileSync(ne,"utf-8"));t.gateway={...e,...t.gateway||{}},P.default.writeFileSync(ne,JSON.stringify(t,null,2))}catch(t){console.log(m.default.yellow(` \u26A0\uFE0F Could not restore gateway block: ${t.message}`)),console.log(m.default.yellow(" Run `openclaw config set gateway.mode local` manually if the gateway fails to start."))}}function ac(){if(P.default.existsSync(xt))try{let e=JSON.parse(P.default.readFileSync(xt,"utf-8")),t=JSON.parse(P.default.readFileSync(ne,"utf-8"));t.channels=t.channels||{},t.channels.badgerclaw=e,P.default.writeFileSync(ne,JSON.stringify(t,null,2)),P.default.unlinkSync(xt)}catch(e){console.log(m.default.yellow(` \u26A0\uFE0F Could not restore config: ${e.message}`)),console.log(m.default.yellow(` Your bot credentials are backed up at: ${xt}`))}}async function qs(e){return new Promise(t=>{let n=(0,ce.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/,c=()=>{r||s||(r=!0,setTimeout(()=>{if(!s){try{n.kill("SIGTERM")}catch{}setTimeout(()=>{if(!s)try{n.kill("SIGKILL")}catch{}},1e3)}},3e3))},i=(l,u)=>{u.write(l),o+=l.toString("utf-8"),a.test(o)&&c()};n.stdout.on("data",l=>i(l,process.stdout)),n.stderr.on("data",l=>i(l,process.stderr)),n.on("exit",l=>{s=!0,t({status:r?0:l??1})}),n.on("error",l=>{s||(s=!0,console.error(m.default.red(` openclaw spawn error: ${l.message}`)),t({status:1}))})})}function Vs(e){if(!P.default.existsSync(e))return!1;let t;try{t=JSON.parse(P.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?(P.default.writeFileSync(e,JSON.stringify(t,null,2)+`
139
+ `),!0):!1}function ic(){let e=[];Vs(nc)&&e.push(Ks);for(let t of Nt())Vs(ge.default.join(t,"package.json"))&&e.push(t);return e}async function lc(){let{detectCapabilities:e}=await Promise.resolve().then(()=>(Ee(),fr)),{pushHeartbeat:t}=await Promise.resolve().then(()=>(ze(),wo));console.log(m.default.green(`
137
140
  \u{1F9A1} BadgerClaw \u2014 capability refresh
138
- `));let o=e();console.log(u.default.dim(" Detected on this host:")),console.log(u.default.dim(` OpenClaw : ${en(o.openclaw)}`)),console.log(u.default.dim(` Hermes : ${en(o.hermes)}`)),console.log(u.default.dim(` Docker : ${en(o.docker)}`)),o.disk_free_gb!==null&&console.log(u.default.dim(` Disk free: ${o.disk_free_gb} GB`));try{await t(),console.log(u.default.green(`
139
- \u2705 Capabilities pushed to the API.`)),console.log(u.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(u.default.yellow(`
140
- \u26A0\uFE0F Not logged in \u2014 capabilities re-scanned locally but not posted to the API.`)),console.log(u.default.dim(" Run `badgerclaw login` first, then re-run `badgerclaw setup --refresh`."));return}console.log(u.default.red(`
141
- \u274C Failed to push capabilities: ${r}`)),process.exit(1)}}function en(e){return e.installed?e.version?`installed (${e.version})`:e.image?`installed (${e.image})`:"installed":"not installed"}var Xr=new Yr.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.").action(async e=>{if(e.refresh){await Ci();return}if(console.log(u.default.green(`
141
+ `));let n=e();console.log(m.default.dim(" Detected on this host:")),console.log(m.default.dim(` OpenClaw : ${Io(n.openclaw)}`)),console.log(m.default.dim(` Hermes : ${Io(n.hermes)}`)),console.log(m.default.dim(` Docker : ${Io(n.docker)}`)),n.disk_free_gb!==null&&console.log(m.default.dim(` Disk free: ${n.disk_free_gb} GB`));try{await t(),console.log(m.default.green(`
142
+ \u2705 Capabilities pushed to the API.`)),console.log(m.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(m.default.yellow(`
143
+ \u26A0\uFE0F Not logged in \u2014 capabilities re-scanned locally but not posted to the API.`)),console.log(m.default.dim(" Run `badgerclaw login` first, then re-run `badgerclaw setup --refresh`."));return}console.log(m.default.red(`
144
+ \u274C Failed to push capabilities: ${r}`)),process.exit(1)}}function Io(e){return e.installed?e.version?`installed (${e.version})`:e.image?`installed (${e.image})`:"installed":"not installed"}async function cc(e){console.log(m.default.green(`
145
+ \u{1F9E0} Local LLM (Ollama/Qwen) \u2014 RAM-aware model picker
146
+ `));let t=process.stdout.isTTY===!0&&process.stdin.isTTY===!0&&!e.assumeYes,n=process.env.BADGERCLAW_LLM_MODEL||void 0,o=await bn({runtime:"hermes",interactive:t,preferredTag:n,log:a=>console.log(m.default.dim(a))});if(console.log(m.default.dim(` Detected RAM: ~${o.ramGb} GB`)),!o.tag){console.log(m.default.yellow(`
147
+ \u26A0\uFE0F ${o.note||"Your RAM is too low for a usable local model."}`)),console.log(m.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(m.default.yellow(` \u26A0\uFE0F ${o.note}`)),console.log(m.default.dim(` Selected local model: ${m.default.cyan(o.tag)}`));let r=gn();if(!r.installed||!r.serving){console.log(m.default.yellow(`
148
+ \u26A0\uFE0F ${fn(r)}`)),console.log(m.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(m.default.dim(` Ollama ${r.version||""} detected and serving.`)),console.log(m.default.dim(` Pulling ${o.tag} via Ollama (one-time, can be large)...`));let s=hn(o.tag);s.ok||(console.log(m.default.red(`
149
+ \u274C Failed to pull ${o.tag}: ${s.error}`)),console.log(m.default.dim(` Pull it manually with \`ollama pull ${o.tag}\`, then re-run setup.`)),process.exit(1)),console.log(m.default.green(` \u2705 Model ${o.tag} ready.`)),_r({provider:"ollama",model:o.tag}),console.log(m.default.green(" \u2705 This host will use the local Ollama model for new Hermes bots."))}var Js=new Ws.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 lc();return}if(console.log(m.default.green(`
142
150
  \u{1F9A1} BadgerClaw Setup
143
- `)),Cr({hermes:e.hermes})==="hermes"){let f=Ur({nodeMajor:Fr(),npmPresent:(0,te.spawnSync)("sh",["-c","command -v npm"],{encoding:"utf-8"}).status===0});f&&(console.log(u.default.red(`
144
- \u274C ${f}`)),process.exit(1));let v=le();if(console.log(u.default.dim(` Detected: Docker ${v.docker.installed?"running":"not running"}, Hermes image ${v.hermes.installed?"present":"absent"}.`)),console.log(u.default.dim(` Selected runtime: ${u.default.cyan("hermes")} (via --hermes flag)
145
- `)),!v.docker.installed){console.log(u.default.dim(" Docker is not ready \u2014 bootstrapping it for the Hermes runtime..."));let b=await Hr({log:w=>console.log(w)});b.ok||(console.log(u.default.red(`
146
- \u274C Docker is required for the Hermes runtime and could not be started automatically.`)),console.log(u.default.dim(" Resolve the issue above (or set Docker up manually), then re-run `badgerclaw setup --hermes`.")),process.exit(1)),b.networkHostRequired&&console.log(u.default.dim(" \u24D8 No Docker bridge on this host \u2014 Hermes bots will use host networking automatically at pair time.")),v=le()}if(v.disk_free_gb!==null&&v.disk_free_gb<6&&console.log(u.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(u.default.dim(` Hermes image already present: ${v.hermes.image}`));else{let b=(await Vr()).hermes;b&&console.log(u.default.dim(` Pinned Hermes upstream: ${b}`)),console.log(u.default.dim(" Building Hermes image (one-time, ~2 min)..."));let w=qr({upstream:b});w.status==="built"?console.log(u.default.green(` \u2705 Hermes image built: ${w.image}`)):w.status==="already-present"?console.log(u.default.dim(` Hermes image already present: ${w.image}`)):w.status==="no-dockerfile"?(console.log(u.default.red(`
147
- \u274C Bundled Hermes Dockerfile missing from CLI install.`)),console.log(u.default.dim(" Reinstall: npm install -g badgerclaw@latest")),console.log(u.default.dim(` Looked at: ${w.expectedPaths.join(", ")}`)),process.exit(1)):w.status==="build-failed"?(console.log(u.default.red(`
148
- \u274C Hermes image build failed: ${w.stderr}`)),console.log(u.default.dim(" See the docker output above for details.")),process.exit(1)):w.status==="no-docker"&&(console.log(u.default.red(`
149
- \u274C Docker is not running.`)),process.exit(1))}console.log(u.default.dim(`
150
- Cleaning up heartbeat hooks from previous installs...`)),Zn({loggedIn:_()!==null,log:b=>console.log(u.default.dim(` ${b}`))}),console.log(u.default.dim(`
151
+ `)),ds({hermes:e.hermes})==="hermes"){let g=$s({nodeMajor:Is(),npmPresent:(0,ce.spawnSync)("sh",["-c","command -v npm"],{encoding:"utf-8"}).status===0});g&&(console.log(m.default.red(`
152
+ \u274C ${g}`)),process.exit(1));let w=be();if(console.log(m.default.dim(` Detected: Docker ${w.docker.installed?"running":"not running"}, Hermes image ${w.hermes.installed?"present":"absent"}.`)),console.log(m.default.dim(` Selected runtime: ${m.default.cyan("hermes")} (via --hermes flag)
153
+ `)),!w.docker.installed){console.log(m.default.dim(" Docker is not ready \u2014 bootstrapping it for the Hermes runtime..."));let b=await Cs({log:f=>console.log(f)});b.ok||(console.log(m.default.red(`
154
+ \u274C Docker is required for the Hermes runtime and could not be started automatically.`)),console.log(m.default.dim(" Resolve the issue above (or set Docker up manually), then re-run `badgerclaw setup --hermes`.")),process.exit(1)),b.networkHostRequired&&console.log(m.default.dim(" \u24D8 No Docker bridge on this host \u2014 Hermes bots will use host networking automatically at pair time.")),w=be()}if(w.disk_free_gb!==null&&w.disk_free_gb<6&&console.log(m.default.yellow(` \u26A0\uFE0F Low disk: ${w.disk_free_gb} GB free \u2014 the Hermes image build needs ~5 GB and may fail if it runs out.`)),w.hermes.installed)console.log(m.default.dim(` Hermes image already present: ${w.hermes.image}`));else{let b=(await Gs()).hermes;b&&console.log(m.default.dim(` Pinned Hermes upstream: ${b}`)),console.log(m.default.dim(" Building Hermes image (one-time, ~2 min)..."));let f=Ps({upstream:b});f.status==="built"?console.log(m.default.green(` \u2705 Hermes image built: ${f.image}`)):f.status==="already-present"?console.log(m.default.dim(` Hermes image already present: ${f.image}`)):f.status==="no-dockerfile"?(console.log(m.default.red(`
155
+ \u274C Bundled Hermes Dockerfile missing from CLI install.`)),console.log(m.default.dim(" Reinstall: npm install -g badgerclaw@latest")),console.log(m.default.dim(` Looked at: ${f.expectedPaths.join(", ")}`)),process.exit(1)):f.status==="build-failed"?(console.log(m.default.red(`
156
+ \u274C Hermes image build failed: ${f.stderr}`)),console.log(m.default.dim(" See the docker output above for details.")),process.exit(1)):f.status==="no-docker"&&(console.log(m.default.red(`
157
+ \u274C Docker is not running.`)),process.exit(1))}(e.localLlm===!0||(process.env.BADGERCLAW_LLM_PROVIDER||"").toLowerCase()==="ollama")&&await cc({assumeYes:e.yes===!0}),console.log(m.default.dim(`
158
+ Cleaning up heartbeat hooks from previous installs...`)),Br({loggedIn:k()!==null,log:b=>console.log(m.default.dim(` ${b}`))}),console.log(m.default.dim(`
151
159
  Hermes-only mode \u2014 skipping OpenClaw plugin + gateway install.
152
160
  To enable OC bots later, drop the --hermes flag: \`badgerclaw setup\`.
153
- `)),console.log(u.default.green("\u2705 Setup complete (Hermes-only host).")),console.log(u.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 Vr();if(o.cli){let f=po();f!==o.cli?(console.log(u.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(u.default.red("\n\u274C CLI update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(u.default.green(` \u2705 CLI updated to ${o.cli}`))):console.log(u.default.dim(` CLI already at approved version ${f}.`))}if(o.openclaw){let f=G();f!==o.openclaw?(console.log(f===null?u.default.dim(` Installing OpenClaw ${o.openclaw} (supported)...`):u.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(u.default.red("\n\u274C OpenClaw install/update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(u.default.green(` \u2705 OpenClaw at ${o.openclaw}`))):console.log(u.default.dim(` OpenClaw already at approved version ${f}.`))}else G()===null&&(console.log(u.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(u.default.red(`
154
- \u274C OpenClaw install failed.`)),process.exit(1)));let n=_i();n&&console.log(u.default.dim(" Existing bot config stashed temporarily..."));let r=Si();(0,te.spawnSync)("openclaw",["gateway","stop"],{stdio:"pipe",shell:!0,timeout:1e4});let s=[se.default.join(pt.default.homedir(),".openclaw","extensions","badgerclaw"),se.default.join(pt.default.homedir(),".openclaw","npm","node_modules","@badgerclaw","connect"),...vt()],a=[],c=[],i=f=>{let v=`${f}.bc-setup-stash-${Date.now()}-${Math.floor(Math.random()*1e6)}`,b=(0,te.spawnSync)("mv",["-f",f,v],{encoding:"utf-8"});return b.status===0?{ok:!0,stash:v}:{ok:!1,error:(b.stderr||"").trim()||`exit ${b.status}`}};for(let f of s)if(I.default.existsSync(f))try{I.default.rmSync(f,{recursive:!0,force:!0}),a.push(f)}catch(v){let b=i(f);b.ok?(c.push(`${f} \u2192 ${b.stash}`),console.log(u.default.yellow(` \u26A0\uFE0F Could not delete ${f} (${v.message}); renamed it aside instead.`))):(console.log(u.default.red(` \u274C Could not delete ${f} (${v.message})`)),console.log(u.default.red(` Could not rename ${f} aside either (${b.error}). Plugin install will likely fail.`)))}a.length>0&&console.log(u.default.dim(` Cleared existing plugin director${a.length>1?"ies":"y"}.`)),c.length>0&&console.log(u.default.dim(` Renamed busy install${c.length>1?"s":""} aside: ${c.join(", ")}`));let l=o.plugin?`@badgerclaw/connect@${o.plugin}`:"@badgerclaw/connect";o.plugin?console.log(u.default.dim(` Installing ${l} (supported)...`)):console.log(u.default.yellow(" \u26A0\uFE0F Allow-list unavailable \u2014 installing @badgerclaw/connect unpinned."));let m=null;$n("2026.6.5")&&(m=Tr(),m&&console.log(u.default.dim(" Adjusted OpenClaw 2026.6.5 npm overrides for a full channel-plugin install.")));let p=await Kr(l);if(p.status===0&&o.plugin&&o.plugin!=="unknown"){for(let v=1;v<=2&&!($t()===o.plugin||(console.log(u.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 Kr(l),p.status!==0));v++);p.status===0&&$t()!==o.plugin&&console.log(u.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&&(vi(),console.log(u.default.dim(" Bot config restored."))),r&&(ki(r),console.log(u.default.dim(" Gateway config restored."))),m&&Lr(m),p.status!==0&&(console.log(u.default.red(`
155
- \u274C Plugin install failed. Your bot config has been restored.`)),process.exit(1)),console.log(u.default.green(`
156
- \u2705 BadgerClaw plugin installed successfully!`));let E=$i();for(let f of E){console.log(u.default.dim(` Stripping OpenClaw uuid:14 override in ${f} (breaks request@2.88 in matrix-bot-sdk)...`));try{I.default.rmSync(se.default.join(f,"node_modules","uuid"),{recursive:!0,force:!0})}catch{}try{I.default.rmSync(se.default.join(f,"package-lock.json"),{force:!0})}catch{}(0,te.spawnSync)("npm",["install"],{cwd:f,stdio:"inherit",shell:!0}).status!==0&&(console.log(u.default.red(`
157
- \u274C npm install failed after removing uuid override. Bot will not reply correctly until this is resolved.`)),process.exit(1))}E.length>0&&console.log(u.default.green(" \u2705 uuid override stripped + npm tree re-resolved.")),console.log("");let D=await jt({verbose:!0});D.ok||(console.log(u.default.red(`
158
- \u274C Gateway failed to start. Diagnose with:`)),console.log(u.default.dim(" systemctl --user status openclaw-gateway.service # Linux")),console.log(u.default.dim(" launchctl list | grep openclaw # macOS")),console.log(u.default.dim(" openclaw config get gateway.mode")),console.log(u.default.dim(" Then re-run `badgerclaw setup` after fixing the underlying issue.")),process.exit(1)),D.ready===!1?console.log(u.default.yellow(" \u23F3 Gateway started but not answering yet \u2014 it may still be coming up.")):console.log(u.default.green(" \u2705 Gateway is running.")),console.log(u.default.dim("\nNext: run `badgerclaw login` to authenticate.")),Mt()});Be();var Zr=require("commander"),A=d(require("chalk"));L();xe();ue();var es=new Zr.Command("dashboard").description("Show local diagnostic dashboard \u2014 machine health, gateway status, bot telemetry").action(async()=>{_()||(console.log(A.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=be(),o=bt(),n=await at();console.log(A.default.bold.green(`
161
+ `)),console.log(m.default.green("\u2705 Setup complete (Hermes-only host).")),console.log(m.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 Gs();if(n.cli){let g=Mn();g!==n.cli?(console.log(m.default.dim(` Updating CLI: ${g} \u2192 ${n.cli} (supported)...`)),(0,ce.spawnSync)("npm",["install","-g",`badgerclaw@${n.cli}`],{stdio:"inherit",shell:!0}).status!==0&&(console.log(m.default.red("\n\u274C CLI update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(m.default.green(` \u2705 CLI updated to ${n.cli}`))):console.log(m.default.dim(` CLI already at approved version ${g}.`))}if(n.openclaw){let g=J();g!==n.openclaw?(console.log(g===null?m.default.dim(` Installing OpenClaw ${n.openclaw} (supported)...`):m.default.dim(` Updating OpenClaw: ${g} \u2192 ${n.openclaw} (supported)...`)),(0,ce.spawnSync)("npm",["install","-g",`openclaw@${n.openclaw}`],{stdio:"inherit",shell:!0}).status!==0&&(console.log(m.default.red("\n\u274C OpenClaw install/update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(m.default.green(` \u2705 OpenClaw at ${n.openclaw}`))):console.log(m.default.dim(` OpenClaw already at approved version ${g}.`))}else J()===null&&(console.log(m.default.yellow(" \u26A0\uFE0F No approved OpenClaw version and none installed \u2014 installing latest from npm.")),(0,ce.spawnSync)("npm",["install","-g","openclaw"],{stdio:"inherit",shell:!0}).status!==0&&(console.log(m.default.red(`
162
+ \u274C OpenClaw install failed.`)),process.exit(1)));let o=oc();o&&console.log(m.default.dim(" Existing bot config stashed temporarily..."));let r=rc();(0,ce.spawnSync)("openclaw",["gateway","stop"],{stdio:"pipe",shell:!0,timeout:1e4});let s=[ge.default.join(Ct.default.homedir(),".openclaw","extensions","badgerclaw"),ge.default.join(Ct.default.homedir(),".openclaw","npm","node_modules","@badgerclaw","connect"),...Nt()],a=[],c=[],i=g=>{let w=`${g}.bc-setup-stash-${Date.now()}-${Math.floor(Math.random()*1e6)}`,x=(0,ce.spawnSync)("mv",["-f",g,w],{encoding:"utf-8"});return x.status===0?{ok:!0,stash:w}:{ok:!1,error:(x.stderr||"").trim()||`exit ${x.status}`}};for(let g of s)if(P.default.existsSync(g))try{P.default.rmSync(g,{recursive:!0,force:!0}),a.push(g)}catch(w){let x=i(g);x.ok?(c.push(`${g} \u2192 ${x.stash}`),console.log(m.default.yellow(` \u26A0\uFE0F Could not delete ${g} (${w.message}); renamed it aside instead.`))):(console.log(m.default.red(` \u274C Could not delete ${g} (${w.message})`)),console.log(m.default.red(` Could not rename ${g} aside either (${x.error}). Plugin install will likely fail.`)))}a.length>0&&console.log(m.default.dim(` Cleared existing plugin director${a.length>1?"ies":"y"}.`)),c.length>0&&console.log(m.default.dim(` Renamed busy install${c.length>1?"s":""} aside: ${c.join(", ")}`));let l=n.plugin?`@badgerclaw/connect@${n.plugin}`:"@badgerclaw/connect";n.plugin?console.log(m.default.dim(` Installing ${l} (supported)...`)):console.log(m.default.yellow(" \u26A0\uFE0F Allow-list unavailable \u2014 installing @badgerclaw/connect unpinned."));let u=null;cr("2026.6.5")&&(u=Ss(),u&&console.log(m.default.dim(" Adjusted OpenClaw 2026.6.5 npm overrides for a full channel-plugin install.")));let p=await qs(l);if(p.status===0&&n.plugin&&n.plugin!=="unknown"){for(let w=1;w<=2&&!(jt()===n.plugin||(console.log(m.default.yellow(` Plugin landed as a hook-pack-only install (not yet visible to \`badgerclaw login\`) \u2014 re-running plugin install (attempt ${w}/2)...`)),p=await qs(l),p.status!==0));w++);p.status===0&&jt()!==n.plugin&&console.log(m.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&&(ac(),console.log(m.default.dim(" Bot config restored."))),r&&(sc(r),console.log(m.default.dim(" Gateway config restored."))),u&&ks(u),p.status!==0&&(console.log(m.default.red(`
163
+ \u274C Plugin install failed. Your bot config has been restored.`)),process.exit(1)),console.log(m.default.green(`
164
+ \u2705 BadgerClaw plugin installed successfully!`));let $=ic();for(let g of $){console.log(m.default.dim(` Stripping OpenClaw uuid:14 override in ${g} (breaks request@2.88 in matrix-bot-sdk)...`));try{P.default.rmSync(ge.default.join(g,"node_modules","uuid"),{recursive:!0,force:!0})}catch{}try{P.default.rmSync(ge.default.join(g,"package-lock.json"),{force:!0})}catch{}(0,ce.spawnSync)("npm",["install"],{cwd:g,stdio:"inherit",shell:!0}).status!==0&&(console.log(m.default.red(`
165
+ \u274C npm install failed after removing uuid override. Bot will not reply correctly until this is resolved.`)),process.exit(1))}$.length>0&&console.log(m.default.green(" \u2705 uuid override stripped + npm tree re-resolved.")),console.log("");let E=await Qt({verbose:!0});E.ok||(console.log(m.default.red(`
166
+ \u274C Gateway failed to start. Diagnose with:`)),console.log(m.default.dim(" systemctl --user status openclaw-gateway.service # Linux")),console.log(m.default.dim(" launchctl list | grep openclaw # macOS")),console.log(m.default.dim(" openclaw config get gateway.mode")),console.log(m.default.dim(" Then re-run `badgerclaw setup` after fixing the underlying issue.")),process.exit(1)),E.ready===!1?console.log(m.default.yellow(" \u23F3 Gateway started but not answering yet \u2014 it may still be coming up.")):console.log(m.default.green(" \u2705 Gateway is running.")),console.log(m.default.dim("\nNext: run `badgerclaw login` to authenticate.")),Xt()});ze();var zs=require("commander"),D=d(require("chalk"));F();Ce();_e();var Qs=new zs.Command("dashboard").description("Show local diagnostic dashboard \u2014 machine health, gateway status, bot telemetry").action(async()=>{k()||(console.log(D.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=he(),n=Tt(),o=await wt();console.log(D.default.bold.green(`
159
167
  BadgerClaw Dashboard
160
- `)),console.log(A.default.bold(" Instance")),console.log(` ID: ${Q()}`),console.log(` CLI Version: ${t}`),console.log(` Plugin: ${n.pluginVersion}`),console.log(),console.log(A.default.bold(" Machine")),console.log(` Hostname: ${o.hostname}`),console.log(` OS: ${o.os} / ${o.arch}`),console.log(` Uptime: ${Qr(o.uptimeSeconds)}`),console.log(` Free Memory: ${o.memFreeMb} MB`),console.log();let r=n.status==="running"?A.default.green:n.status==="error"?A.default.red:A.default.yellow;if(console.log(A.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(A.default.bold(" Bots")),console.log(A.default.dim(" No bots detected. Pair bots at https://badgerclaw.ai")),console.log();else{console.log(A.default.bold(` Bots (${n.bots.length})`)),console.log();for(let s of n.bots){let a=s.status==="running"?A.default.green:s.status==="error"?A.default.red:A.default.yellow;if(console.log(` ${A.default.bold(s.botUsername)} ${a(`[${s.status}]`)}`),console.log(` ID: ${s.botId}`),console.log(` Uptime: ${Qr(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: ${A.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(A.default.dim(" Rooms:"));for(let c of s.roomDetails)console.log(A.default.dim(` ${c.roomName} \u2014 ${c.messagesInRoom} msgs, last: ${c.lastActivityInRoom??"N/A"}`))}console.log()}}console.log(A.default.dim(` Last checked: ${new Date().toISOString()}`)),console.log()});function Qr(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 tn=require("commander"),We=d(require("chalk")),ts=d(require("ora"));L();ue();Be();var Ii=new tn.Command("restart").description("Restart the OpenClaw gateway via the plugin probe endpoint").action(async()=>{_()||(console.log(We.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,ts.default)("Restarting gateway...").start(),o=await Le();if(o.success){t.succeed(We.default.green(`Gateway restarted: ${o.message}`));try{await T(),console.log(We.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(We.default.dim(" Could not push heartbeat \u2014 daemon may not be running."))}}else t.fail(We.default.red(`Gateway restart failed: ${o.message}`)),process.exit(1)}),os=new tn.Command("gateway").description("Manage the OpenClaw gateway").addCommand(Ii);var fe=require("commander"),k=d(require("chalk")),Ie=d(require("ora")),ge=d(require("axios"));Ft();L();var Ce="http://localhost:7331",xi=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=>{_()||(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,Ie.default)("Starting Claude Code session...").start();try{await ge.default.post(`${Ce}/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=jo({sessionId:o,port:n,projectDir:r}).pid||0;await new Promise(i=>setTimeout(i,1500)),s.text="MCP server running \u2014 launching Claude Code...",Mo({sessionId:o,port:n,projectDir:r}),Ho(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)}}),Ri=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=>{_()||(console.log(k.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let o=(0,Ie.default)("Stopping Claude Code session...").start();try{e.bot&&e.room&&await ge.default.post(`${Ce}/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(`${Ce}/claude-code/status`,{timeout:5e3})).data?.rooms||[]).find(c=>c.botId===e.bot&&c.roomId===e.room);a&&(n=a.sessionId)}catch{}n?(Uo(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)}}),Ai=new fe.Command("status").description("Show active Claude Code sessions").action(async()=>{_()||(console.log(k.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,Ie.default)("Fetching Claude Code status...").start();try{let o=[];try{o=(await ge.default.get(`${Ce}/claude-code/status`,{timeout:5e3})).data?.rooms||[]}catch{}let n=Fo();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(`
161
- 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(`
162
- 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)}}),Ei=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,Ie.default)("Grouping bot+room into session...").start();try{await ge.default.post(`${Ce}/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)}}),Pi=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,Ie.default)("Adding user to allowlist...").start();try{await ge.default.post(`${Ce}/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)}}),Di=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,Ie.default)("Removing user from allowlist...").start();try{await ge.default.post(`${Ce}/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)}}),ns=new fe.Command("claude-code").description("Manage Claude Code sessions (relay Matrix messages to local Claude Code)").addCommand(xi).addCommand(Ri).addCommand(Ai).addCommand(Ei).addCommand(Pi).addCommand(Di);Ae();async function Oi(){await Cn(process.argv);let e=new rs.Command;e.name("badgerclaw").description("BadgerClaw CLI \u2014 one-click bot provisioning").version("0.3.1"),e.addCommand(hr),e.addCommand(br),e.addCommand(Sr),e.addCommand(Pr),e.addCommand(Fn),e.addCommand(Nr),e.addCommand(Xr),e.addCommand(Vo),e.addCommand(es),e.addCommand(os),e.addCommand(ns),e.parse(process.argv)}Oi().catch(e=>{console.error(e),process.exit(1)});
168
+ `)),console.log(D.default.bold(" Instance")),console.log(` ID: ${ae()}`),console.log(` CLI Version: ${t}`),console.log(` Plugin: ${o.pluginVersion}`),console.log(),console.log(D.default.bold(" Machine")),console.log(` Hostname: ${n.hostname}`),console.log(` OS: ${n.os} / ${n.arch}`),console.log(` Uptime: ${Ys(n.uptimeSeconds)}`),console.log(` Free Memory: ${n.memFreeMb} MB`),console.log();let r=o.status==="running"?D.default.green:o.status==="error"?D.default.red:D.default.yellow;if(console.log(D.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(D.default.bold(" Bots")),console.log(D.default.dim(" No bots detected. Pair bots at https://badgerclaw.ai")),console.log();else{console.log(D.default.bold(` Bots (${o.bots.length})`)),console.log();for(let s of o.bots){let a=s.status==="running"?D.default.green:s.status==="error"?D.default.red:D.default.yellow;if(console.log(` ${D.default.bold(s.botUsername)} ${a(`[${s.status}]`)}`),console.log(` ID: ${s.botId}`),console.log(` Uptime: ${Ys(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: ${D.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(D.default.dim(" Rooms:"));for(let c of s.roomDetails)console.log(D.default.dim(` ${c.roomName} \u2014 ${c.messagesInRoom} msgs, last: ${c.lastActivityInRoom??"N/A"}`))}console.log()}}console.log(D.default.dim(` Last checked: ${new Date().toISOString()}`)),console.log()});function Ys(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 Ao=require("commander"),ot=d(require("chalk")),Xs=d(require("ora"));F();_e();ze();var uc=new Ao.Command("restart").description("Restart the OpenClaw gateway via the plugin probe endpoint").action(async()=>{k()||(console.log(ot.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,Xs.default)("Restarting gateway...").start(),n=await Ye();if(n.success){t.succeed(ot.default.green(`Gateway restarted: ${n.message}`));try{await j(),console.log(ot.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(ot.default.dim(" Could not push heartbeat \u2014 daemon may not be running."))}}else t.fail(ot.default.red(`Gateway restart failed: ${n.message}`)),process.exit(1)}),Zs=new Ao.Command("gateway").description("Manage the OpenClaw gateway").addCommand(uc);var Re=require("commander"),R=d(require("chalk")),Ne=d(require("ora")),ve=d(require("axios"));tn();F();var Me="http://localhost:7331",dc=new Re.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=>{k()||(console.log(R.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,Ne.default)("Starting Claude Code session...").start();try{await ve.default.post(`${Me}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:n},{timeout:1e4}),s.text="Gateway toggled \u2014 launching MCP server...";let c=co({sessionId:n,port:o,projectDir:r}).pid||0;await new Promise(i=>setTimeout(i,1500)),s.text="MCP server running \u2014 launching Claude Code...",uo({sessionId:n,port:o,projectDir:r}),mo(n,0,c,o,r),s.succeed(R.default.green("Claude Code session started")+R.default.dim(` (session: ${n}, port: ${o})`)),console.log(R.default.dim(` Bot: ${e.bot}`)),console.log(R.default.dim(` Room: ${e.room}`)),console.log(R.default.dim(` Project: ${r}`)),console.log(R.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(R.default.red(`Failed to start Claude Code: ${c}`)),process.exit(1)}}),mc=new Re.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=>{k()||(console.log(R.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let n=(0,Ne.default)("Stopping Claude Code session...").start();try{e.bot&&e.room&&await ve.default.post(`${Me}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!1},{timeout:1e4});let o=e.sessionId;if(!o)try{let a=((await ve.default.get(`${Me}/claude-code/status`,{timeout:5e3})).data?.rooms||[]).find(c=>c.botId===e.bot&&c.roomId===e.room);a&&(o=a.sessionId)}catch{}o?(po(o),n.succeed(R.default.green(`Claude Code session stopped (${o})`))):(n.succeed(R.default.green("Claude Code toggled off at gateway")),console.log(R.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(R.default.red(`Failed to stop Claude Code: ${r}`)),process.exit(1)}}),pc=new Re.Command("status").description("Show active Claude Code sessions").action(async()=>{k()||(console.log(R.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,Ne.default)("Fetching Claude Code status...").start();try{let n=[];try{n=(await ve.default.get(`${Me}/claude-code/status`,{timeout:5e3})).data?.rooms||[]}catch{}let o=go();if(t.stop(),n.length===0&&o.length===0){console.log(R.default.dim("No active Claude Code sessions."));return}if(n.length>0){console.log(R.default.bold(`
169
+ Gateway Claude Code Rooms:`)),console.log(R.default.dim(" Bot".padEnd(30)+"Room".padEnd(30)+"Session".padEnd(20)+"Enabled")),console.log(R.default.dim(" "+"-".repeat(88)));for(let r of n){let s=r.enabled?R.default.green("ON"):R.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(R.default.bold(`
170
+ Local Sessions:`)),console.log(R.default.dim(" Session".padEnd(25)+"Port".padEnd(8)+"MCP PID".padEnd(10)+"Project".padEnd(40)+"Started")),console.log(R.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(R.default.red(`Failed to get status: ${n.message}`)),process.exit(1)}}),gc=new Re.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,Ne.default)("Grouping bot+room into session...").start();try{await ve.default.post(`${Me}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:e.session},{timeout:1e4}),t.succeed(R.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(R.default.red(`Failed to group: ${o}`)),process.exit(1)}}),fc=new Re.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,Ne.default)("Adding user to allowlist...").start();try{await ve.default.post(`${Me}/claude-code/allow`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(R.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(R.default.red(`Failed to add user: ${o}`)),process.exit(1)}}),hc=new Re.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,Ne.default)("Removing user from allowlist...").start();try{await ve.default.post(`${Me}/claude-code/revoke`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(R.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(R.default.red(`Failed to revoke user: ${o}`)),process.exit(1)}}),ea=new Re.Command("claude-code").description("Manage Claude Code sessions (relay Matrix messages to local Claude Code)").addCommand(dc).addCommand(mc).addCommand(pc).addCommand(gc).addCommand(fc).addCommand(hc);var Ia=require("commander"),C=d(require("chalk")),Aa=d(require("path"));ie();var ta=require("child_process"),yc="http://127.0.0.1:11434";function Eo(){let e=process.env.OLLAMA_HOST?.trim();return e?/^https?:\/\//.test(e)?e.replace(/\/$/,""):`http://${e}`.replace(/\/$/,""):yc}function je(e,t){return{num_ctx:e,num_predict:t,temperature:0,seed:42,top_p:1,top_k:0}}async function na(e,t,n={}){let o=n.host??Eo(),r=n.fetchImpl??fetch,s=new AbortController,a=setTimeout(()=>s.abort(),n.timeoutMs??3e5);try{let c=await r(`${o}${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),signal:s.signal});if(!c.ok){let i=await c.text().catch(()=>"");throw new Error(`ollama ${e} \u2192 HTTP ${c.status} ${i.slice(0,200)}`)}return await c.json()}finally{clearTimeout(a)}}async function Be(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),na("/api/chat",n,t)}async function oa(e,t={}){return na("/api/show",{model:e},{...t,timeoutMs:15e3})}async function ra(e={}){try{let t=e.host??Eo(),o=await(e.fetchImpl??fetch)(`${t}/api/version`);return o.ok?(await o.json()).version??null:null}catch{return null}}async function sa(e={}){try{let t=e.host??Eo(),o=await(e.fetchImpl??fetch)(`${t}/api/tags`);return o.ok?((await o.json()).models??[]).map(s=>s.name):[]}catch{return[]}}function aa(e){try{(0,ta.spawnSync)("ollama",["stop",e],{encoding:"utf-8",timeout:15e3})}catch{}}function ia(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 ca=require("child_process");function oe(e,t=2){let n=10**t;return Math.round(e*n)/n}function wn(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 Po(e,t){let n=e.filter(c=>Number.isFinite(c)).sort((c,i)=>c-i);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 bc="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)+`
171
+
172
+ Task: In about one hundred words, explain why steady decode throughput and low time-to-first-token both matter for an interactive local assistant.`,Oo=class{constructor(t){this.timer=null;this.peakMb=0;this.sawAny=!1;this.runner=t??((n,o)=>{let r=(0,ca.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(`
173
+ `)){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 wc(e){return e.eval_count&&e.eval_duration?e.eval_count/(e.eval_duration/1e9):null}function _c(e){return e.prompt_eval_count&&e.prompt_eval_duration?e.prompt_eval_count/(e.prompt_eval_duration/1e9):null}function Sc(e){return e.prompt_eval_duration?e.prompt_eval_duration/1e6:null}var la=[{role:"user",content:bc}];async function ua(e){let{model:t,numCtx:n,warmTrials:o}=e,r=e.warmupTrials??2,s=e.perfOpts??{},a=s.log??(()=>{}),c=e.sampler??new Oo;aa(t),a(" cold load trial\u2026");let i=null;try{let f=await Be({model:t,messages:[{role:"user",content:"Reply with: OK"}],options:je(n,8)},s);i=f.load_duration?f.load_duration/1e6:null}catch(f){a(` cold trial failed: ${f.message}`)}for(let f=0;f<r;f++)a(` warmup ${f+1}/${r}\u2026`),await Be({model:t,messages:la,options:je(n,64)},s);let l=[],u=[],p=[],$=null;c.start();try{for(let f=0;f<o;f++){a(` trial ${f+1}/${o}\u2026`);let y=await Be({model:t,messages:la,options:je(n,128)},s),q=wc(y),B=Sc(y),xe=_c(y);q!=null&&l.push(q),B!=null&&u.push(B),xe!=null&&p.push(xe)}}finally{$=c.stop()}let E=wn(l),g=Po(l,.95),w=wn(u),x=Po(u,.95),b=wn(p);return{decode_tps_median:E!=null?oe(E):null,decode_tps_p95:g!=null?oe(g):null,prefill_tps_median:b!=null?oe(b):null,ttft_ms_median:w!=null?oe(w):null,ttft_ms_p95:x!=null?oe(x):null,peak_ram_mb:$,load_ms:i!=null?oe(i):null,max_context:null,num_ctx:n}}async function da(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 c=await Be({model:t,messages:[{role:"user",content:"Reply with: OK"}],options:je(a,8)},o);if(c.eval_count&&c.eval_count>0)s=a;else break}catch{break}return s}var ma=require("child_process");function kc(e){let t=e.match(/```(?:javascript|js)?\s*([\s\S]*?)```/i);return t?t[1].trim():e.trim()}function To(e,t,n,o={}){let s=`${kc(e)}
174
+ const __out = [${t.join(", ")}];
175
+ process.stdout.write(JSON.stringify(__out));`,a=o.exec??(u=>(0,ma.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 c;try{let u=a(s);if(c=JSON.parse(u),!Array.isArray(c))throw new Error("non-array output")}catch{return{score:0,passed:!1,ran:!1}}let i=0;for(let u=0;u<n.length;u++)pa(c[u],n[u])&&i++;return{score:Math.round(i/n.length*100),passed:i===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 Lo={tool_call:.4,instruction:.2,coding:.15,summarization:.15,chat:.1},_n={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"]}}},vc={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"]}}},Rc={type:"function",function:{name:"search_web",description:"Search the web for a query.",parameters:{type:"object",properties:{query:{type:"string"}},required:["query"]}}};function Sn(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 Do(e){return JSON.stringify(e).toLowerCase()}function xc(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 ga(e){return e.split(/[.!?]+/).map(t=>t.trim()).filter(Boolean).length}var Cc=/\b(can'?t|cannot|won'?t|unable|not able|sorry|i'?m sorry)\b/i,fa="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.",ha=["voyager","1977","interstellar","golden record","nasa"],Mo=[{id:"tool_call:single_arg",category:"tool_call",tools:[_n],numPredict:256,messages:[{role:"user",content:"What is the current weather in Paris, France? Use the available tool."}],gradeProgrammatic:e=>{let t=Sn(e),n=!!t&&t.name==="get_weather"&&/paris/.test(Do(t.args));return{score:n?100:t?.name==="get_weather"?50:0,passed:n}}},{id:"tool_call:select_among_many",category:"tool_call",tools:[_n,vc,Rc],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=Sn(e),n=!!t&&t.name==="send_email",o=n&&/bob@example\.com/.test(Do(t.args));return{score:o?100:n?50:0,passed:o}}},{id:"tool_call:no_tool_needed",category:"tool_call",tools:[_n],numPredict:64,messages:[{role:"user",content:"What is 2 + 2? Answer directly with just the number. Do not call any tool."}],gradeProgrammatic:e=>{if(Sn(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:[_n],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=Sn(e),n=!!t&&t.name==="get_weather"&&/tokyo/.test(Do(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=To(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:
176
+
177
+ function isEven(n) { return n % 2 === 1; }
178
+
179
+ Return a corrected version named isEven. Output ONLY the function definition as code, no explanation, no markdown fences.`}],gradeProgrammatic:e=>{let t=To(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":
180
+
181
+ "Please reach out to Jane Doe at jane.doe@example.com regarding the invoice."`}],gradeProgrammatic:e=>{let t=xc(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.
182
+
183
+ `+fa}],gradeProgrammatic:e=>{let t=Q(e).toLowerCase(),o=ha.filter(c=>t.includes(c)).length/ha.length*100,r=ga(Q(e)),s=r>=1&&r<=3;return{score:Math.round(s?o:o*.7),passed:o>=60&&s}},judge:{dimension:"faithfulness",source:fa,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&&!Cc.test(t)&&ga(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 $t=class extends Error{constructor(t){super(t),this.name="JudgeUnavailableError"}};function jo(){return process.env.BENCHMARK_JUDGE_MODEL?.trim()||"claude-opus-4-8"}function kn(){return!!(process.env.ANTHROPIC_API_KEY||process.env.ANTHROPIC_AUTH_TOKEN)}var No=null;function $c(){if(!kn())throw new $t("LLM-judge needs ANTHROPIC_API_KEY (set it for official runs, or pass --no-judge).");if(!No){let e=require("@anthropic-ai/sdk"),t=e.default??e;No=new t}return No}var Ic={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 Ac(e){return Number.isFinite(e)?Math.max(0,Math.min(100,Math.round(e))):0}function Ec(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:Ac(Number(t.score)),passed:!!t.passed,reason:String(t.reason??"").slice(0,300)}}async function ya(e){if(e.impl)return e.impl(e);let t=$c(),n=[`You are an impartial grader. Dimension: ${e.dimension}.`,e.instruction,e.source?`
184
+ SOURCE:
185
+ ${e.source}`:"",`
186
+ OUTPUT TO GRADE:
187
+ ${e.output}`,`
188
+ 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:jo(),max_tokens:1024,messages:[{role:"user",content:n.join(`
189
+ `)}],output_config:{effort:"low",format:{type:"json_schema",schema:Ic}}})).content.find(s=>s.type==="text");if(!r?.text)throw new Error("judge returned no text block");return Ec(r.text)}var Bo="badgerclaw.benchmark.v1";function Pc(){let e={tool_call:0,instruction:0,coding:0,summarization:0,chat:0};for(let t of Mo)e[t.category]++;return e}async function Oc(e,t,n){let o=t.log??(()=>{}),r=t.chatImpl??(u=>Be(u,{host:t.host,fetchImpl:t.fetchImpl})),s;try{o(` task ${e.id}\u2026`),s=await r({model:t.model,messages:e.messages,options:je(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),c=a.score,i=!1,l=a.passed;if(t.useJudge&&e.judge){let u=a.score===null&&a.passed===!1;try{let p=await ya({dimension:e.judge.dimension,instruction:e.judge.instruction,source:e.judge.source,output:e.judge.getOutput(s),impl:t.judgeImpl});i=!0;let $=e.judge.combine??((E,g)=>g);c=u?0:$(a.score,p.score),l=c>=60}catch(p){p instanceof $t?o(` judge unavailable for ${e.id} \u2014 using programmatic score only`):o(` judge error for ${e.id}: ${p.message}`),c=u?0:a.score}}return{id:e.id,category:e.category,score:c,weight:n,passed:l,judged:i}}async function ba(e){let t=Pc(),n=[];for(let l of Mo){let u=oe(Lo[l.category]/t[l.category],4);n.push(await Oc(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]=oe(u.reduce((p,$)=>p+$,0)/u.length,1);let s=0,a=0;for(let l of Object.keys(o)){let u=Lo[l];s+=o[l]*u,a+=u}let c=a>0?oe(s/a,1):null,i={categories:o,tasks:n,suite_version:"v1",judged:n.some(l=>l.judged)};return{overall_score:c,quality_json:i}}var vn=require("fs"),Sa=d(require("path")),ka=d(require("axios"));function Tc(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 Dc(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 wa(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":Dc(Tc(e.decodeTps,e.qualityScore),e.ttftMs)}function _a(e,t){return!t||e.decode_tps_median==null?"error":e.decode_tps_median<4?"too_slow":"ok"}function va(e){let{specs:t,perf:n,quality:o,model:r}=e,s=n.decode_tps_median!=null,a=e.statusOverride??_a(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:Bo,cli_version:e.cliVersion,harness_version:Bo,started_at:e.startedAt,finished_at:e.finishedAt}}function Ra(e,t){let n=Sa.default.dirname(e);return n&&(0,vn.mkdirSync)(n,{recursive:!0}),(0,vn.writeFileSync)(e,JSON.stringify(t,null,2)+`
190
+ `),e}async function xa(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 ka.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 Ca(e){return`${e.replace(/\/$/,"")}/api/v1/admin/benchmark-runs`}var $a=8;function Lc(e,t){return t.push(e),t}function Mc(){try{return he().version}catch{return"0.0.0"}}var Ea=new Ia.Command("benchmark").description("Benchmark local Ollama models (perf + quality) and optionally publish results").option("-m, --model <tag>","Ollama model tag to benchmark (repeatable)",Lc,[]).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("--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||M,n=Number.parseInt(e.numCtx,10)||8192,o=Number.parseInt(e.trials,10)||7,r=e.runtime==="openclaw"?"openclaw":"hermes",s=!!e.official,a=y=>console.log(C.default.gray(y)),c=gn();if(!c.installed||!c.serving){console.error(C.default.red(fn(c))),process.exitCode=1;return}let i=Us();console.log(C.default.bold("Machine: ")+`${i.cpu_model??"unknown CPU"} \xB7 ${i.ram_total_gb} GB (${i.ram_tier}) \xB7 ${i.accelerator??"no accelerator"} \xB7 ${i.os}/${i.arch}`),console.log(C.default.gray(`fingerprint: ${i.machine_fingerprint}`));let l=!i.accelerator;l&&console.log(C.default.gray("no accelerator detected \u2014 treating this as a CPU-only machine."));let u=e.model;if(u.length===0)if(e.all){let y=await $o(yn(),r,{apiBase:t,accelerator:i.accelerator});if(u=y?.recommended.map(q=>q.ollama_tag)??[],u.length===0){console.error(C.default.red(`No recommended models for this machine (${y?.note??"endpoint unreachable"}). Pass --model <tag>.`)),process.exitCode=1;return}console.log(C.default.gray(`--all: benchmarking the ${u.length} recommended models: ${u.join(", ")}`))}else{let y=await bn({runtime:r,interactive:!1,ramGb:yn(),apiBase:t,accelerator:i.accelerator});if(y.tag)u=[y.tag],console.log(C.default.gray(`no --model given; benchmarking the recommended pick: ${y.tag}`));else{console.error(C.default.red(`No model to benchmark (recommendation: ${y.note??"none"}). Pass --model <tag>.`)),process.exitCode=1;return}}let p=process.env.BENCHMARK_WEBHOOK_SECRET?.trim(),$=process.env.BENCHMARK_OFFICIAL_TOKEN?.trim(),E=process.env.BENCHMARK_WEBHOOK_URL?.trim()||Ca(t),g=s&&!!$,w=e.post!==!1&&(s||e.shareResults);w&&!p&&(console.log(C.default.yellow("BENCHMARK_WEBHOOK_SECRET not set \u2014 writing report.json locally but NOT posting.")),w=!1),s&&!$&&console.log(C.default.yellow("BENCHMARK_OFFICIAL_TOKEN not set \u2014 the server will record these as community runs."));let x=g&&e.judge!==!1&&kn();g&&e.judge!==!1&&!kn()&&console.log(C.default.yellow("ANTHROPIC_API_KEY not set \u2014 skipping the LLM-judge; chat + summarization scored programmatically only.")),x&&console.log(C.default.gray(`LLM-judge: ${jo()}`)),w&&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 b=await ra(),f=await sa();for(let y of u){if(console.log(`
191
+ `+C.default.bold.cyan(`\u25B6 ${y}`)),!f.includes(y)){console.log(C.default.gray(`pulling ${y}\u2026`));let U=hn(y);if(!U.ok){console.error(C.default.red(`pull failed: ${U.error}`));continue}}let q="Q4_K_M",B=null;try{let U=await oa(y);U.details?.quantization_level&&(q=U.details.quantization_level),B=ia(U.details?.parameter_size)}catch(U){console.log(C.default.gray(`ollama show failed (${U.message}); using defaults`))}if(l&&B!=null&&B>$a&&!e.force){console.log(C.default.yellow(` skip: ${y} is ${B}B \u2014 too slow to be usable on CPU-only hardware (>${$a}B). Pass --force to benchmark it anyway.`));continue}let xe=new Date().toISOString();console.log(C.default.gray("perf suite\u2026"));let re=await ua({model:y,numCtx:n,warmTrials:o,perfOpts:{log:a}});e.maxContext&&(console.log(C.default.gray("max-context staircase\u2026")),re.max_context=await da({model:y,perfOpts:{log:a}})),console.log(C.default.gray("quality suite\u2026"));let Rn=await ba({model:y,numCtx:n,useJudge:x,log:a}),Oa=new Date().toISOString(),It=va({specs:i,perf:re,quality:Rn,model:{model_name:y,quant:q,model_size_total:B,model_size_active:B,engine_version:b},runtime:r,official:g,submittedBy:e.submittedBy,cliVersion:Mc(),startedAt:xe,finishedAt:Oa}),Ta=wa({status:It.status,decodeTps:re.decode_tps_median,qualityScore:Rn.overall_score,ttftMs:re.ttft_ms_median,peakRamMb:re.peak_ram_mb,ramTotalGb:i.ram_total_gb,maxContext:re.max_context});console.log(C.default.bold(` ${y}: `)+`decode ${re.decode_tps_median??"\u2014"} tok/s (p95 ${re.decode_tps_p95??"\u2014"}), ttft ${re.ttft_ms_median??"\u2014"} ms, peak ${re.peak_ram_mb??"\u2014"} MB, quality ${Rn.overall_score??"\u2014"}, `+C.default.bold(`verdict ${Ta}`)+` (status ${It.status})`);let Da=y.replace(/[^a-z0-9.]+/gi,"_"),La=xe.replace(/[:.]/g,"-"),Fo=Aa.default.join(e.output,`${Da}-${La}.json`);if(Ra(Fo,It),console.log(C.default.gray(`report: ${Fo}`)),w&&p){let U=await xa({webhookUrl:E,secret:p,officialToken:g?$:null,report:It});if(U.ok){let Ma=g;console.log(C.default.green(` posted \u2192 id=${U.body?.id} (${U.body?.created?"created":"updated"}), source=${Ma?"official":"community"}`))}else console.error(C.default.red(` webhook failed: ${U.status??""} ${U.error??""}`.trim()))}else console.log(C.default.gray(" (not posted \u2014 pass --official or --share-results to publish)"))}});Fe();async function Nc(){await ur(process.argv);let e=new Pa.Command;e.name("badgerclaw").description("BadgerClaw CLI \u2014 one-click bot provisioning").version("0.3.3"),e.addCommand(ns),e.addCommand(ss),e.addCommand(is),e.addCommand(ys),e.addCommand(Ir),e.addCommand(_s),e.addCommand(Js),e.addCommand(bo),e.addCommand(Qs),e.addCommand(Zs),e.addCommand(ea),e.addCommand(Ea),e.parse(process.argv)}Nc().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.1",
3
+ "version": "0.3.3",
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",