badgerclaw 0.2.66 → 0.2.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var Wr=Object.create;var it=Object.defineProperty;var Vr=Object.getOwnPropertyDescriptor;var qr=Object.getOwnPropertyNames;var Kr=Object.getPrototypeOf,Jr=Object.prototype.hasOwnProperty;var B=(e,t)=>()=>(e&&(t=e(e=0)),t);var Yr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Kt=(e,t)=>{for(var o in t)it(e,o,{get:t[o],enumerable:!0})},qo=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of qr(t))!Jr.call(e,r)&&r!==o&&it(e,r,{get:()=>t[r],enumerable:!(n=Vr(t,r))||n.enumerable});return e};var d=(e,t,o)=>(o=e!=null?Wr(Kr(e)):{},qo(t||!e||!e.__esModule?it(o,"default",{value:e,enumerable:!0}):o,e)),Ko=e=>qo(it({},"__esModule",{value:!0}),e);function S(){try{let e=Be.default.readFileSync(zt,"utf-8");return JSON.parse(e)}catch{return null}}function ct(e){Be.default.mkdirSync(Xo,{recursive:!0}),Be.default.writeFileSync(zt,JSON.stringify(e,null,2),{mode:384})}function Me(){try{Be.default.unlinkSync(zt)}catch{}}function lt(){let e=S();return e?new Date(e.expires_at)>new Date:!1}function dt(e){let t=e.match(/^@?([^:]+)/);return t?t[1]:e}var Be,Yt,zo,Xo,zt,M=B(()=>{"use strict";Be=d(require("fs")),Yt=d(require("path")),zo=d(require("os")),Xo=Yt.default.join(zo.default.homedir(),".badgerclaw"),zt=Yt.default.join(Xo,"auth.json")});function Xt(){return Qo.default.createHash("sha256").update(`${Y.default.hostname()}-${Y.default.platform()}-${Y.default.arch()}`).digest("hex").slice(0,16)}function z(){let e=S();if(e?.instance_id)return e.instance_id;let t=Xt();return`openclaw-${Y.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${t}`}function ut(){return{hostname:Y.default.hostname(),os:Y.default.platform(),arch:Y.default.arch(),uptimeSeconds:Math.floor(Y.default.uptime()),memFreeMb:Math.floor(Y.default.freemem()/1024/1024)}}var Y,Qo,Ce=B(()=>{"use strict";Y=d(require("os")),Qo=d(require("crypto"));M()});var Zo,U,en,se=B(()=>{"use strict";Zo=process.env.BADGERCLAW_ENV==="local",U=process.env.BADGERCLAW_API_URL??(Zo?"http://localhost:8000":"https://api.badger.signout.io"),en=process.env.BADGERCLAW_AUTH_URL??(Zo?"http://localhost:5500":"https://badgerclaw.ai")});function on(){return Ue}function zr(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 Qt(){let e=S();if(!e?.refresh_token||!e?.email)return Ue=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=zr(e.access_token);try{let o=await He.default.post(`${pt}/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 Ue="server returned no access_token",null;let s=n.expires_in||3600,a=new Date(Date.now()+s*1e3).toISOString();return ct({...e,access_token:r,expires_at:a}),Ue=null,r}catch(o){let n=o?.response?.status,r=o?.response?.data?.errors?.[0]||o?.response?.data?.detail||o?.message||"unknown error";Ue=n?`HTTP ${n}: ${r}`:`network error: ${r}`;let s=o?.response?.data?.errors?.[0]||o?.response?.data?.detail||o?.message||"";if(n===403&&tn.test(s))throw Me(),new Ie(s);return null}}function Zt(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 nn(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(tn.test(n))return Me(),Promise.reject(new Ie(n))}return Promise.reject(t)}),e}function rn(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,mt||(mt=Qt().finally(()=>{mt=null}));let n=await mt;return n?(o.headers.Authorization=`Bearer ${n}`,e.request(o)):Promise.reject(t)}),e}function O(){let e=S(),t={"Content-Type":"application/json"};e&&(t.Authorization=`Bearer ${e.access_token}`);let o=He.default.create({baseURL:pt,headers:t});return Zt(o),rn(o),nn(o),o}function sn(){return Zt(He.default.create({baseURL:pt,headers:{"Content-Type":"application/json"}}))}function Fe(e){let t=He.default.create({baseURL:pt,headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});return Zt(t),rn(t),nn(t),t}var He,pt,Ie,tn,mt,Ue,fe=B(()=>{"use strict";He=d(require("axios"));M();se();pt=U,Ie=class extends Error{constructor(o){super(o);this.code="DEACTIVATED";this.name="DeactivatedError"}},tn=/account\s+has\s+been\s+(deleted|deactivated)/i,mt=null,Ue=null});function dn(){try{let e=ae.default.statSync(he);return Date.now()-e.mtimeMs>cn}catch{return!0}}function eo(){try{return ae.default.mkdirSync(to.default.dirname(he),{recursive:!0}),ae.default.writeFileSync(he,String(process.pid),{flag:"wx"}),!0}catch{if(dn())try{return ae.default.unlinkSync(he),ae.default.writeFileSync(he,String(process.pid),{flag:"wx"}),!0}catch{return!1}return!1}}function un(){try{ae.default.unlinkSync(he)}catch{}}async function mn(e){let t=!1;for(let o=0;o<Xr;o++){if(eo()){t=!0;break}await new Promise(n=>setTimeout(n,ln))}t||console.warn("[config-lock] Could not acquire lock after timeout \u2014 proceeding without lock");try{return await e()}finally{t&&un()}}function ye(e){let t=eo();if(!t&&dn()){try{ae.default.unlinkSync(he)}catch{}t=eo()}try{return e()}finally{t&&un()}}var ae,an,to,he,cn,ln,Xr,Ge=B(()=>{"use strict";ae=d(require("fs")),an=d(require("os")),to=d(require("path")),he=to.default.join(an.default.homedir(),".openclaw","openclaw.json.lock"),cn=1e4,ln=50,Xr=Math.ceil(cn/ln)});var we=Yr((bi,Qr)=>{Qr.exports={name:"badgerclaw",version:"0.2.66",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 ft(e=ns){try{return no.default.readdirSync(e,{withFileTypes:!0}).filter(t=>t.isDirectory()&&t.name.startsWith("badgerclaw-connect-")).map(t=>ee.default.join(e,t.name))}catch{return[]}}function rs(){return[...ft().map(t=>ee.default.join(t,"node_modules/@badgerclaw/connect/package.json")),ee.default.join(os,"package.json"),ee.default.join(pn,"node_modules/@badgerclaw/connect/package.json"),ee.default.join(pn,"package.json")]}function ro(){return"0.2.66"}function ht(){for(let e of rs())try{let t=no.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 ss(e){let t=e.trim(),o=t.match(/\d+(?:\.\d+){1,3}/);return o?o[0]:t}function V(){if((0,oo.spawnSync)("which",["openclaw"],{encoding:"utf-8"}).status!==0)return null;let t=(0,oo.spawnSync)("openclaw",["--version"],{encoding:"utf-8",timeout:3e3});return t.status!==0||!t.stdout?null:ss(t.stdout)||null}async function as(){let e=new AbortController,t=setTimeout(()=>e.abort(),es);try{let o=await fetch(Zr,{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 is(e){let t=[];if(e.cli&&e.cli!=="unknown"){let n=ro();n!==e.cli&&t.push({component:"cli",current:n,approved:e.cli})}if(!(V()!==null))return t;if(e.plugin&&e.plugin!=="unknown"){let n=ht();(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=V();(n===null||n!==e.supported_openclaw)&&t.push({component:"openclaw",current:n??"not installed",approved:e.supported_openclaw})}return t}function cs(e){return e[2]}function ls(e){return!e||e.startsWith("-")?!0:ts.has(e)}function ds(e){let t=[];t.push(""),t.push(ie.default.red.bold("\u2717 Unsupported versions detected")),t.push("");for(let o of e){let n=o.component.padEnd(8);t.push(` ${n} ${ie.default.yellow(o.current)} \u2192 ${ie.default.green(o.approved)} ${ie.default.dim("(supported)")}`)}return t.push(""),t.push("This command is blocked until your installation matches the supported versions."),t.push(""),t.push(ie.default.green(" To fix, run:")),t.push(ie.default.green.bold(" badgerclaw setup")),t.push(""),t.push(ie.default.dim(" (bypass temporarily: BADGERCLAW_NO_VERSION_CHECK=1 badgerclaw <cmd>)")),t.push(""),t.join(`
3
- `)}async function gn(e){if(process.env.BADGERCLAW_NO_VERSION_CHECK)return;let t=cs(e);if(ls(t))return;let o=await as();if(!o)return;let n=is(o);n.length!==0&&(process.stderr.write(ds(n)),process.exit(1))}var no,gt,ee,oo,ie,Zr,es,ts,pn,os,ns,Re=B(()=>{"use strict";no=d(require("fs")),gt=d(require("os")),ee=d(require("path")),oo=require("child_process"),ie=d(require("chalk"));se();Zr=`${U}/api/v1/dashboard/versions/latest`,es=2500,ts=new Set(["setup","logout","help","--version","-V","--help","-h","heartbeat","watch","autopair"]),pn=ee.default.join(gt.default.homedir(),".openclaw/extensions/badgerclaw"),os=ee.default.join(gt.default.homedir(),".openclaw/npm/node_modules/@badgerclaw/connect"),ns=ee.default.join(gt.default.homedir(),".openclaw/npm/projects")});var bn={};Kt(bn,{HERMES_IMAGE_DEFAULT:()=>xe,detectCapabilities:()=>ce,detectDiskFreeGb:()=>wn,detectDocker:()=>yt,detectHermes:()=>wt,detectOpenClaw:()=>yn});function yt(){if((0,We.spawnSync)("which",["docker"],{encoding:"utf-8"}).status!==0)return{installed:!1};let t=(0,We.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 yn(){let e=V();return e?{installed:!0,version:e}:{installed:!1}}function wt(e){if(!e.installed)return{installed:!1};let t=process.env.HERMES_IMAGE||xe;return(0,We.spawnSync)("docker",["image","inspect","--format","{{.RepoDigests}}",t],{encoding:"utf-8",timeout:3e3}).status!==0?{installed:!1}:{installed:!0,image:t}}function wn(){let e=hn.default.join(so.default.homedir(),".badgerclaw"),t=fn.default.existsSync(e)?e:so.default.homedir();if(process.platform==="win32")return null;let o=(0,We.spawnSync)("df",["-Pk",t],{encoding:"utf-8",timeout:3e3});if(o.status!==0||!o.stdout)return null;let n=o.stdout.trim().split(`
4
- `);if(n.length<2)return null;let r=n[1].split(/\s+/),s=parseInt(r[3]||"",10);return Number.isFinite(s)?Math.floor(s/1024/1024):null}function ce(){let e=yt();return{openclaw:yn(),hermes:wt(e),docker:e,disk_free_gb:wn(),ports_in_use:[]}}var We,fn,so,hn,xe,be=B(()=>{"use strict";We=require("child_process"),fn=d(require("fs")),so=d(require("os")),hn=d(require("path"));Re();xe="hermes-agent-bc:bundled"});function _t(e){return X.default.join(us,`bot-${e}`)}function io(e){return`badgerclaw-hermes-bot-${e}`}function co(){if(!N.default.existsSync(ao))return{hermes_bots:{}};try{let e=N.default.readFileSync(ao,"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 ps(e){N.default.existsSync(bt)||N.default.mkdirSync(bt,{recursive:!0,mode:448}),N.default.writeFileSync(ao,JSON.stringify(e,null,2)+`
5
- `,{mode:384})}function gs(e,t=ms){let o=new Set(Object.values(e.hermes_bots).map(r=>r.port)),n=t;for(;o.has(n)||!fs(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 fs(e){let t=kn.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 $n(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 hs(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 ys(e){switch(e){case"gemini":return"GOOGLE_API_KEY";case"anthropic":return"ANTHROPIC_API_KEY";case"openrouter":return"OPENROUTER_API_KEY"}}function ws(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(`${ys(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,Sn.randomBytes)(24).toString("hex")}`),o.join(`
2
+ "use strict";var Qr=Object.create;var pt=Object.defineProperty;var Zr=Object.getOwnPropertyDescriptor;var es=Object.getOwnPropertyNames;var ts=Object.getPrototypeOf,os=Object.prototype.hasOwnProperty;var M=(e,t)=>()=>(e&&(t=e(e=0)),t);var ns=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Xt=(e,t)=>{for(var o in t)pt(e,o,{get:t[o],enumerable:!0})},Xo=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of es(t))!os.call(e,r)&&r!==o&&pt(e,r,{get:()=>t[r],enumerable:!(n=Zr(t,r))||n.enumerable});return e};var d=(e,t,o)=>(o=e!=null?Qr(ts(e)):{},Xo(t||!e||!e.__esModule?pt(o,"default",{value:e,enumerable:!0}):o,e)),Qo=e=>Xo(pt({},"__esModule",{value:!0}),e);function w(){try{let e=We.default.readFileSync(eo,"utf-8");return JSON.parse(e)}catch{return null}}function gt(e){We.default.mkdirSync(on,{recursive:!0}),We.default.writeFileSync(eo,JSON.stringify(e,null,2),{mode:384})}function qe(){try{We.default.unlinkSync(eo)}catch{}}function ft(){let e=w();return e?new Date(e.expires_at)>new Date:!1}function ht(e){let t=e.match(/^@?([^:]+)/);return t?t[1]:e}var We,Zt,tn,on,eo,L=M(()=>{"use strict";We=d(require("fs")),Zt=d(require("path")),tn=d(require("os")),on=Zt.default.join(tn.default.homedir(),".badgerclaw"),eo=Zt.default.join(on,"auth.json")});function to(){return nn.default.createHash("sha256").update(`${X.default.hostname()}-${X.default.platform()}-${X.default.arch()}`).digest("hex").slice(0,16)}function Q(){let e=w();if(e?.instance_id)return e.instance_id;let t=to();return`openclaw-${X.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${t}`}function yt(){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,nn,Re=M(()=>{"use strict";X=d(require("os")),nn=d(require("crypto"));L()});var rn,H,sn,ae=M(()=>{"use strict";rn=process.env.BADGERCLAW_ENV==="local",H=process.env.BADGERCLAW_API_URL??(rn?"http://localhost:8000":"https://api.badger.signout.io"),sn=process.env.BADGERCLAW_AUTH_URL??(rn?"http://localhost:5500":"https://badgerclaw.ai")});function cn(){return Ke}function rs(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 oo(){let e=w();if(!e?.refresh_token||!e?.email)return Ke=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=rs(e.access_token);try{let o=await Je.default.post(`${bt}/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 Ke="server returned no access_token",null;let s=n.expires_in||3600,a=new Date(Date.now()+s*1e3).toISOString();return gt({...e,access_token:r,expires_at:a}),Ke=null,r}catch(o){let n=o?.response?.status,r=o?.response?.data?.errors?.[0]||o?.response?.data?.detail||o?.message||"unknown error";Ke=n?`HTTP ${n}: ${r}`:`network error: ${r}`;let s=o?.response?.data?.errors?.[0]||o?.response?.data?.detail||o?.message||"";if(n===403&&an.test(s))throw qe(),new xe(s);return null}}function no(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 ln(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(an.test(n))return qe(),Promise.reject(new xe(n))}return Promise.reject(t)}),e}function dn(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,wt||(wt=oo().finally(()=>{wt=null}));let n=await wt;return n?(o.headers.Authorization=`Bearer ${n}`,e.request(o)):Promise.reject(t)}),e}function O(){let e=w(),t={"Content-Type":"application/json"};e&&(t.Authorization=`Bearer ${e.access_token}`);let o=Je.default.create({baseURL:bt,headers:t});return no(o),dn(o),ln(o),o}function un(){return no(Je.default.create({baseURL:bt,headers:{"Content-Type":"application/json"}}))}function Ye(e){let t=Je.default.create({baseURL:bt,headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});return no(t),dn(t),ln(t),t}var Je,bt,xe,an,wt,Ke,he=M(()=>{"use strict";Je=d(require("axios"));L();ae();bt=H,xe=class extends Error{constructor(o){super(o);this.code="DEACTIVATED";this.name="DeactivatedError"}},an=/account\s+has\s+been\s+(deleted|deactivated)/i,wt=null,Ke=null});function fn(){try{let e=ie.default.statSync(ye);return Date.now()-e.mtimeMs>pn}catch{return!0}}function ro(){try{return ie.default.mkdirSync(so.default.dirname(ye),{recursive:!0}),ie.default.writeFileSync(ye,String(process.pid),{flag:"wx"}),!0}catch{if(fn())try{return ie.default.unlinkSync(ye),ie.default.writeFileSync(ye,String(process.pid),{flag:"wx"}),!0}catch{return!1}return!1}}function hn(){try{ie.default.unlinkSync(ye)}catch{}}async function yn(e){let t=!1;for(let o=0;o<ss;o++){if(ro()){t=!0;break}await new Promise(n=>setTimeout(n,gn))}t||console.warn("[config-lock] Could not acquire lock after timeout \u2014 proceeding without lock");try{return await e()}finally{t&&hn()}}function we(e){let t=ro();if(!t&&fn()){try{ie.default.unlinkSync(ye)}catch{}t=ro()}try{return e()}finally{t&&hn()}}var ie,mn,so,ye,pn,gn,ss,ze=M(()=>{"use strict";ie=d(require("fs")),mn=d(require("os")),so=d(require("path")),ye=so.default.join(mn.default.homedir(),".openclaw","openclaw.json.lock"),pn=1e4,gn=50,ss=Math.ceil(pn/gn)});var be=ns((Oi,as)=>{as.exports={name:"badgerclaw",version:"0.2.67",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 St(e=us){try{return io.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 ms(){return[...St().map(t=>oe.default.join(t,"node_modules/@badgerclaw/connect/package.json")),oe.default.join(ds,"package.json"),oe.default.join(wn,"node_modules/@badgerclaw/connect/package.json"),oe.default.join(wn,"package.json")]}function co(){return"0.2.67"}function kt(){for(let e of ms())try{let t=io.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 ps(e){let t=e.trim(),o=t.match(/\d+(?:\.\d+){1,3}/);return o?o[0]:t}function W(){if((0,ao.spawnSync)("which",["openclaw"],{encoding:"utf-8"}).status!==0)return null;let t=(0,ao.spawnSync)("openclaw",["--version"],{encoding:"utf-8",timeout:3e3});return t.status!==0||!t.stdout?null:ps(t.stdout)||null}async function gs(){let e=new AbortController,t=setTimeout(()=>e.abort(),cs);try{let o=await fetch(is,{signal:e.signal});if(!o.ok)return null;let n=await o.json(),r=n.result&&typeof n.result=="object"?n.result:n;return{cli:r.cli??"unknown",plugin:r.plugin??"unknown",supported_openclaw:r.supported_openclaw??"unknown"}}catch{return null}finally{clearTimeout(t)}}function fs(e){let t=[];if(e.cli&&e.cli!=="unknown"){let n=co();n!==e.cli&&t.push({component:"cli",current:n,approved:e.cli})}if(!(W()!==null))return t;if(e.plugin&&e.plugin!=="unknown"){let n=kt();(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=W();(n===null||n!==e.supported_openclaw)&&t.push({component:"openclaw",current:n??"not installed",approved:e.supported_openclaw})}return t}function hs(e){return e[2]}function ys(e){return!e||e.startsWith("-")?!0:ls.has(e)}function ws(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 bn(e){if(process.env.BADGERCLAW_NO_VERSION_CHECK)return;let t=hs(e);if(ys(t))return;let o=await gs();if(!o)return;let n=fs(o);n.length!==0&&(process.stderr.write(ws(n)),process.exit(1))}var io,_t,oe,ao,ce,is,cs,ls,wn,ds,us,Ae=M(()=>{"use strict";io=d(require("fs")),_t=d(require("os")),oe=d(require("path")),ao=require("child_process"),ce=d(require("chalk"));ae();is=`${H}/api/v1/dashboard/versions/latest`,cs=2500,ls=new Set(["setup","logout","help","--version","-V","--help","-h","heartbeat","watch","autopair"]),wn=oe.default.join(_t.default.homedir(),".openclaw/extensions/badgerclaw"),ds=oe.default.join(_t.default.homedir(),".openclaw/npm/node_modules/@badgerclaw/connect"),us=oe.default.join(_t.default.homedir(),".openclaw/npm/projects")});var $n={};Xt($n,{HERMES_IMAGE_DEFAULT:()=>Ee,detectCapabilities:()=>le,detectDiskFreeGb:()=>vn,detectDocker:()=>vt,detectHermes:()=>$t,detectOpenClaw:()=>kn});function vt(){if((0,Xe.spawnSync)("which",["docker"],{encoding:"utf-8"}).status!==0)return{installed:!1};let t=(0,Xe.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 kn(){let e=W();return e?{installed:!0,version:e}:{installed:!1}}function $t(e){if(!e.installed)return{installed:!1};let t=process.env.HERMES_IMAGE||Ee;return(0,Xe.spawnSync)("docker",["image","inspect","--format","{{.RepoDigests}}",t],{encoding:"utf-8",timeout:3e3}).status!==0?{installed:!1}:{installed:!0,image:t}}function vn(){let e=Sn.default.join(lo.default.homedir(),".badgerclaw"),t=_n.default.existsSync(e)?e:lo.default.homedir();if(process.platform==="win32")return null;let o=(0,Xe.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=vt();return{openclaw:kn(),hermes:$t(e),docker:e,disk_free_gb:vn(),ports_in_use:[]}}var Xe,_n,lo,Sn,Ee,_e=M(()=>{"use strict";Xe=require("child_process"),_n=d(require("fs")),lo=d(require("os")),Sn=d(require("path"));Ae();Ee="hermes-agent-bc:bundled"});function It(e){return Z.default.join(bs,`bot-${e}`)}function mo(e){return`badgerclaw-hermes-bot-${e}`}function po(){if(!N.default.existsSync(uo))return{hermes_bots:{}};try{let e=N.default.readFileSync(uo,"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 Ss(e){N.default.existsSync(Ct)||N.default.mkdirSync(Ct,{recursive:!0,mode:448}),N.default.writeFileSync(uo,JSON.stringify(e,null,2)+`
5
+ `,{mode:384})}function ks(e,t=_s){let o=new Set(Object.values(e.hermes_bots).map(r=>r.port)),n=t;for(;o.has(n)||!vs(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 vs(e){let t=Rn.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 An(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 $s(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 Cs(e){switch(e){case"gemini":return"GOOGLE_API_KEY";case"anthropic":return"ANTHROPIC_API_KEY";case"openrouter":return"OPENROUTER_API_KEY"}}function Is(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(`${Cs(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,In.randomBytes)(24).toString("hex")}`),o.join(`
6
6
  `)+`
7
- `}function bs(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: ${hs(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 _s(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 Ss(e,t){let o=_t(e.botId);N.default.mkdirSync(o,{recursive:!0,mode:448});let n=X.default.join(o,".env"),r=X.default.join(o,"config.yaml"),s=X.default.join(o,"SOUL.md");return N.default.writeFileSync(n,ws(e,t),{mode:384}),N.default.writeFileSync(r,bs(e),{mode:384}),N.default.existsSync(s)||N.default.writeFileSync(s,_s(e),{mode:384}),{dataDir:o,envPath:n,configPath:r,soulPath:s}}function kt(e){let t=e.run(["network","inspect","bridge","--format","{{range .IPAM.Config}}{{.Subnet}} {{end}}"]);return t.status===0&&!!(t.stdout||"").trim()}function lo(e={}){let t=e.env??process.env;return t.BADGERCLAW_HERMES_NETWORK==="host"?!0:t.BADGERCLAW_HERMES_NETWORK==="bridge"?!1:!(e.bridgeUsable??(()=>kt(St)))()}function ks(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 Cn(e,t={}){let o=t.docker??St,n=e.image||process.env.HERMES_IMAGE||xe;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=co(),s=r.hermes_bots[e.botId],a=s?.port??gs(r,t.portBase),l=s?.container_name??io(e.botId);if(Ss(e,a),!t.skipDocker){o.run(["rm","-f",l]);let i=lo({bridgeUsable:()=>kt(o)}),m=ks({containerName:l,dataDir:_t(e.botId),port:a,image:n,hostNetwork:i}),p=o.run(m);if(p.status!==0)throw new Error(`docker run failed (exit ${p.status}): ${p.stderr||p.stdout}`)}let c={bot_id:e.botId,runtime:"hermes",container_name:l,port:a,data_dir:_t(e.botId),image:n,started_at:new Date().toISOString()};return r.hermes_bots[e.botId]=c,ps(r),c}function In(e={}){let t=e.docker??St,o=co(),n=[];for(let[r,s]of Object.entries(o.hermes_bots)){let a=t.run(["inspect","--format","{{.State.Status}}",s.container_name]),l,c=a.stdout.trim()||null;a.status!==0?(l="missing",c=(a.stderr||a.stdout).trim()||null):c==="running"?l="running":c==="exited"||c==="dead"||c==="created"?l="stopped":l="unknown",n.push({bot_id:r,container_name:s.container_name,status:l,raw:c})}return n}function $s(e){let t=e.match(vs);return t?t[1].trim():null}async function uo(e,t,o,n={}){let r={recoveryKey:null,posted:!1,envUpdated:!1};if(!e.backendBotId)return r;let a=(n.docker??St).run(["logs",t]),l=`${a.stdout}
10
- ${a.stderr}`,c=$s(l);if(!c)return r;if(r.recoveryKey=c,n.api)try{let m=await n.api.post(`/api/v1/hermes/bots/${e.backendBotId}/runtime-bootstrap`,{recovery_key:c,image_ref:o});r.posted=m.status>=200&&m.status<300}catch(m){console.warn(`[hermes] failed to POST recovery key for ${e.botId}: ${m.message}. Daemon will retry next beat.`)}let i=n.envPath??X.default.join(_t(e.botId),".env");return N.default.existsSync(i)&&(N.default.readFileSync(i,"utf-8").includes("MATRIX_RECOVERY_KEY=")||(N.default.appendFileSync(i,`
7
+ `}function Rs(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: ${$s(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 xs(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 As(e,t){let o=It(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,Is(e,t),{mode:384}),N.default.writeFileSync(r,Rs(e),{mode:384}),N.default.existsSync(s)||N.default.writeFileSync(s,xs(e),{mode:384}),{dataDir:o,envPath:n,configPath:r,soulPath:s}}function xt(e){let t=e.run(["network","inspect","bridge","--format","{{range .IPAM.Config}}{{.Subnet}} {{end}}"]);return t.status===0&&!!(t.stdout||"").trim()}function go(e={}){let t=e.env??process.env;return t.BADGERCLAW_HERMES_NETWORK==="host"?!0:t.BADGERCLAW_HERMES_NETWORK==="bridge"?!1:!(e.bridgeUsable??(()=>xt(Rt)))()}function Es(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 En(e,t={}){let o=t.docker??Rt,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=po(),s=r.hermes_bots[e.botId],a=s?.port??ks(r,t.portBase),l=s?.container_name??mo(e.botId);if(As(e,a),!t.skipDocker){o.run(["rm","-f",l]);let i=go({bridgeUsable:()=>xt(o)}),m=Es({containerName:l,dataDir:It(e.botId),port:a,image:n,hostNetwork:i}),p=o.run(m);if(p.status!==0)throw new Error(`docker run failed (exit ${p.status}): ${p.stderr||p.stdout}`)}let c={bot_id:e.botId,runtime:"hermes",container_name:l,port:a,data_dir:It(e.botId),image:n,started_at:new Date().toISOString()};return r.hermes_bots[e.botId]=c,Ss(r),c}function Pn(e={}){let t=e.docker??Rt,o=po(),n=[];for(let[r,s]of Object.entries(o.hermes_bots)){let a=t.run(["inspect","--format","{{.State.Status}}",s.container_name]),l,c=a.stdout.trim()||null;a.status!==0?(l="missing",c=(a.stderr||a.stdout).trim()||null):c==="running"?l="running":c==="exited"||c==="dead"||c==="created"?l="stopped":l="unknown",n.push({bot_id:r,container_name:s.container_name,status:l,raw:c})}return n}function Ds(e){let t=e.match(Ps);return t?t[1].trim():null}async function fo(e,t,o,n={}){let r={recoveryKey:null,posted:!1,envUpdated:!1};if(!e.backendBotId)return r;let a=(n.docker??Rt).run(["logs",t]),l=`${a.stdout}
10
+ ${a.stderr}`,c=Ds(l);if(!c)return r;if(r.recoveryKey=c,n.api)try{let m=await n.api.post(`/api/v1/hermes/bots/${e.backendBotId}/runtime-bootstrap`,{recovery_key:c,image_ref:o});r.posted=m.status>=200&&m.status<300}catch(m){console.warn(`[hermes] failed to POST recovery key for ${e.botId}: ${m.message}. Daemon will retry next beat.`)}let i=n.envPath??Z.default.join(It(e.botId),".env");return N.default.existsSync(i)&&(N.default.readFileSync(i,"utf-8").includes("MATRIX_RECOVERY_KEY=")||(N.default.appendFileSync(i,`
11
11
  # Cross-signing recovery key captured from first-boot logs.
12
12
  # Hermes re-uses this on restart to re-sign the device after
13
13
  # Synapse rotates server keys.
14
14
  MATRIX_RECOVERY_KEY=${c}
15
- `),r.envUpdated=!0)),r}async function Rn(e={}){let t=co(),o=[];for(let[n,r]of Object.entries(t.hermes_bots)){let s=X.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 l=await uo({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:l.recoveryKey!==null,posted:l.posted,envUpdated:l.envUpdated})}catch(l){console.warn(`[hermes] recovery-key retry failed for ${n}: ${l.message}`),o.push({bot_id:n,attempted:!0,recoveryKeyFound:!1,posted:!1,envUpdated:!1})}}return o}var _n,Sn,N,kn,vn,X,bt,us,ao,ms,St,vs,vt=B(()=>{"use strict";_n=require("child_process"),Sn=require("crypto"),N=d(require("fs")),kn=d(require("net")),vn=d(require("os")),X=d(require("path"));be();bt=X.default.join(vn.default.homedir(),".badgerclaw"),us=X.default.join(bt,"hermes"),ao=X.default.join(bt,"state.json"),ms=8642,St={run:e=>{let t=(0,_n.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};vs=/SAVE THIS RECOVERY KEY[\s\S]*?key rotation:\s+((?:[A-Za-z0-9]{4}\s+){7,}[A-Za-z0-9]{4})/});function $t(e){return`'${e.replace(/'/g,"'\\''")}'`}function Cs(){if(le!==null)return le;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(Ve.default.existsSync(t))return le=`${$t(process.execPath)} ${$t(t)}`,le;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=go.default.join(o,"openclaw","openclaw.mjs");if(Ve.default.existsSync(n))return le=`${$t(process.execPath)} ${$t(n)}`,le}}catch{}return le="openclaw",le}function mo(e,t,o){t?t.fail(q.default.red(o)):e&&console.error(`[autopair] ${o}`)}async function Is(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:$n()},n=Cn(o);if(o.backendBotId){let r=S();if(r){let s=Fe(r.access_token);try{await uo(o,io(o.botId),n.image,{api:{post:async(a,l)=>{let c=await s.post(a,l);return{status:c.status,data:c.data}}}})}catch(a){console.warn(`[hermes] recovery key capture failed for ${o.botId}: ${a.message}. Daemon will retry next beat.`)}}}}async function qe(e,t,o,n){let r=S();if(!r)return;let s=n?null:(0,po.default)(`Pairing bot: ${t}...`).start();try{let a=await fetch(`${U}/api/v1/pairing/redeem`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e,instance_id:z()})});if(!a.ok){if(a.status===410){s?.info(q.default.dim(`${t} already paired (race-loss; another channel redeemed first).`));return}let m=await a.json().catch(()=>({errors:[a.statusText]}));mo(n,s,`Failed to redeem ${t}: ${m.errors?.[0]||a.status}`);return}let l=await a.json(),c=l.result??l;if((c.runtime??"openclaw")==="hermes"){try{await Is(c),s?.succeed(q.default.green(`\u2705 ${c.bot_name} (${c.user_id}) running on Hermes \u2014 bot is live!`))}catch(m){mo(n,s,`Failed to start Hermes container for ${t}: ${m.message}`)}return}await mn(async()=>{let m=c.user_id.split(":")[0].replace("@","").replace(/_bot$/,""),p;try{p=JSON.parse(Ve.default.readFileSync(xn,"utf-8"))}catch{p={}}p.channels||(p.channels={}),p.channels.badgerclaw||(p.channels.badgerclaw={}),p.channels.badgerclaw.accounts||(p.channels.badgerclaw.accounts={});let P={userId:c.user_id,accessToken:c.access_token,homeserver:c.homeserver,encryption:!0,groupPolicy:"open",allowlistOnly:!1,dm:{policy:"open"}};c.device_id&&(P.deviceId=c.device_id),p.channels.badgerclaw.accounts[m]=P,Ve.default.writeFileSync(xn,JSON.stringify(p,null,2),{mode:384})}),await fetch(`${U}/api/v1/openclaw/pending-pairs/${e}/claim`,{method:"POST",headers:{Authorization:`Bearer ${r.access_token}`}}).catch(()=>{}),s?.succeed(q.default.green(`\u2705 ${c.bot_name} (${c.user_id}) paired \u2014 bot is live!`))}catch(a){mo(n,s,`Failed to pair ${t}: ${a.message}`)}}async function Ke(e=!1){let t=S();if(!t)return 0;let o=Fe(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 l=e?null:(0,po.default)(`Pairing bot: ${a.bot_name} (${a.bot_user_id})`).start();try{await qe(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(c){l?.fail(q.default.red(`Error pairing ${a.bot_name}: ${c}`))}}if(s>0)try{let{execSync:a}=await import("child_process");a(`${Cs()} gateway restart`,{stdio:"ignore"}),e||console.log(q.default.green(`
15
+ `),r.envUpdated=!0)),r}async function Dn(e={}){let t=po(),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 l=await fo({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:l.recoveryKey!==null,posted:l.posted,envUpdated:l.envUpdated})}catch(l){console.warn(`[hermes] recovery-key retry failed for ${n}: ${l.message}`),o.push({bot_id:n,attempted:!0,recoveryKeyFound:!1,posted:!1,envUpdated:!1})}}return o}var Cn,In,N,Rn,xn,Z,Ct,bs,uo,_s,Rt,Ps,At=M(()=>{"use strict";Cn=require("child_process"),In=require("crypto"),N=d(require("fs")),Rn=d(require("net")),xn=d(require("os")),Z=d(require("path"));_e();Ct=Z.default.join(xn.default.homedir(),".badgerclaw"),bs=Z.default.join(Ct,"hermes"),uo=Z.default.join(Ct,"state.json"),_s=8642,Rt={run:e=>{let t=(0,Cn.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};Ps=/SAVE THIS RECOVERY KEY[\s\S]*?key rotation:\s+((?:[A-Za-z0-9]{4}\s+){7,}[A-Za-z0-9]{4})/});function Et(e){return`'${e.replace(/'/g,"'\\''")}'`}function Os(){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(Qe.default.existsSync(t))return de=`${Et(process.execPath)} ${Et(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=wo.default.join(o,"openclaw","openclaw.mjs");if(Qe.default.existsSync(n))return de=`${Et(process.execPath)} ${Et(n)}`,de}}catch{}return de="openclaw",de}function ho(e,t,o){t?t.fail(q.default.red(o)):e&&console.error(`[autopair] ${o}`)}async function Ns(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:An()},n=En(o);if(o.backendBotId){let r=w();if(r){let s=Ye(r.access_token);try{await fo(o,mo(o.botId),n.image,{api:{post:async(a,l)=>{let c=await s.post(a,l);return{status:c.status,data:c.data}}}})}catch(a){console.warn(`[hermes] recovery key capture failed for ${o.botId}: ${a.message}. Daemon will retry next beat.`)}}}}async function Ze(e,t,o,n){let r=w();if(!r)return;let s=n?null:(0,yo.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(q.default.dim(`${t} already paired (race-loss; another channel redeemed first).`));return}let m=await a.json().catch(()=>({errors:[a.statusText]}));ho(n,s,`Failed to redeem ${t}: ${m.errors?.[0]||a.status}`);return}let l=await a.json(),c=l.result??l;if((c.runtime??"openclaw")==="hermes"){try{await Ns(c),s?.succeed(q.default.green(`\u2705 ${c.bot_name} (${c.user_id}) running on Hermes \u2014 bot is live!`))}catch(m){ho(n,s,`Failed to start Hermes container for ${t}: ${m.message}`)}return}await yn(async()=>{let m=c.user_id.split(":")[0].replace("@","").replace(/_bot$/,""),p;try{p=JSON.parse(Qe.default.readFileSync(On,"utf-8"))}catch{p={}}p.channels||(p.channels={}),p.channels.badgerclaw||(p.channels.badgerclaw={}),p.channels.badgerclaw.accounts||(p.channels.badgerclaw.accounts={});let P={userId:c.user_id,accessToken:c.access_token,homeserver:c.homeserver,encryption:!0,groupPolicy:"open",allowlistOnly:!1,dm:{policy:"open"}};c.device_id&&(P.deviceId=c.device_id),p.channels.badgerclaw.accounts[m]=P,Qe.default.writeFileSync(On,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(q.default.green(`\u2705 ${c.bot_name} (${c.user_id}) paired \u2014 bot is live!`))}catch(a){ho(n,s,`Failed to pair ${t}: ${a.message}`)}}async function et(e=!1){let t=w();if(!t)return 0;let o=Ye(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 l=e?null:(0,yo.default)(`Pairing bot: ${a.bot_name} (${a.bot_user_id})`).start();try{await Ze(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(c){l?.fail(q.default.red(`Error pairing ${a.bot_name}: ${c}`))}}if(s>0)try{let{execSync:a}=await import("child_process");a(`${Os()} gateway restart`,{stdio:"ignore"}),e||console.log(q.default.green(`
16
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(q.default.yellow(`
17
- \u26A1 ${s} bot(s) paired. Run: openclaw gateway restart`))}return s}catch{return 0}}var An,q,po,En,go,Ve,xn,le,Pn,Je=B(()=>{"use strict";An=require("commander"),q=d(require("chalk")),po=d(require("ora")),En=d(require("os")),go=d(require("path")),Ve=d(require("fs"));M();fe();se();Ce();Ge();vt();xn=go.default.join(En.default.homedir(),".openclaw","openclaw.json");le=null;Pn=new An.Command("autopair").description("Check for pending bot pairs and connect them to OpenClaw automatically").action(async()=>{if(!S()){console.log(q.default.yellow("Not logged in. Run `badgerclaw login` first."));return}console.log(q.default.dim("Checking for pending bot pairs...")),await Ke(!1)===0&&console.log(q.default.dim("No pending pairs found."))})});async function _o(){try{return await Et.default.get(Ms,{timeout:2e3,validateStatus:()=>!0}),!0}catch{return!1}}async function Ze(){try{let t=(await Et.default.get(`${Un}/health`,{timeout:5e3})).data;return t.pluginVersion&&t.pluginVersion!=="unknown"&&(bo=t.pluginVersion),t}catch{return{status:await _o()?"running":"stopped",pid:null,lastRestart:null,pluginVersion:bo,bots:[]}}}function So(e){e&&e!=="unknown"&&(bo=e)}async function Ae(){try{return{success:!0,message:(await Et.default.post(`${Un}/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 Et,js,Un,Bs,Ms,bo,de=B(()=>{"use strict";Et=d(require("axios")),js=7331,Un=`http://localhost:${js}`,Bs=parseInt(process.env.OPENCLAW_GATEWAY_PORT||"",10)||18789,Ms=`http://127.0.0.1:${Bs}`,bo="unknown"});var Oo={};Kt(Oo,{getActiveSessions:()=>Do,launchClaudeCode:()=>Ao,launchMCPServer:()=>xo,recordSession:()=>Eo,stopSession:()=>Po});function $o(){try{if(L.default.existsSync(vo))return JSON.parse(L.default.readFileSync(vo,"utf-8"))}catch{}return[]}function Co(e){L.default.mkdirSync(Se,{recursive:!0}),L.default.writeFileSync(vo,JSON.stringify(e,null,2))}function Nt(e){try{return process.kill(e,0),!0}catch{return!1}}function Gs(){if(process.env.TMUX)return"tmux";try{if((0,oe.execSync)(`osascript -e 'tell application "System Events" to (name of processes) contains "iTerm2"'`,{stdio:"pipe",timeout:3e3}),L.default.existsSync("/Applications/iTerm.app"))return"iterm2"}catch{}return process.platform==="darwin"?"terminal":"direct"}function Io(e,t){let o=G.default.join(Se,`claude-launcher-${t}.exp`),n=G.default.join(Se,`pending-input-${t}.txt`);L.default.writeFileSync(n,"","utf-8");let r=`#!/usr/bin/expect -f
17
+ \u26A1 ${s} bot(s) paired. Run: openclaw gateway restart`))}return s}catch{return 0}}var Nn,q,yo,Tn,wo,Qe,On,de,Ln,tt=M(()=>{"use strict";Nn=require("commander"),q=d(require("chalk")),yo=d(require("ora")),Tn=d(require("os")),wo=d(require("path")),Qe=d(require("fs"));L();he();ae();Re();ze();At();On=wo.default.join(Tn.default.homedir(),".openclaw","openclaw.json");de=null;Ln=new Nn.Command("autopair").description("Check for pending bot pairs and connect them to OpenClaw automatically").action(async()=>{if(!w()){console.log(q.default.yellow("Not logged in. Run `badgerclaw login` first."));return}console.log(q.default.dim("Checking for pending bot pairs...")),await et(!1)===0&&console.log(q.default.dim("No pending pairs found."))})});async function Co(){try{return await Nt.default.get(Zs,{timeout:2e3,validateStatus:()=>!0}),!0}catch{return!1}}async function st(){try{let t=(await Nt.default.get(`${Jn}/health`,{timeout:5e3})).data;return t.pluginVersion&&t.pluginVersion!=="unknown"&&($o=t.pluginVersion),t}catch{return{status:await Co()?"running":"stopped",pid:null,lastRestart:null,pluginVersion:$o,bots:[]}}}function Io(e){e&&e!=="unknown"&&($o=e)}async function Le(){try{return{success:!0,message:(await Nt.default.post(`${Jn}/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 Nt,Xs,Jn,Qs,Zs,$o,ue=M(()=>{"use strict";Nt=d(require("axios")),Xs=7331,Jn=`http://localhost:${Xs}`,Qs=parseInt(process.env.OPENCLAW_GATEWAY_PORT||"",10)||18789,Zs=`http://127.0.0.1:${Qs}`,$o="unknown"});var jo={};Xt(jo,{getActiveSessions:()=>Bo,launchClaudeCode:()=>No,launchMCPServer:()=>Oo,recordSession:()=>To,stopSession:()=>Lo});function Ao(){try{if(B.default.existsSync(xo))return JSON.parse(B.default.readFileSync(xo,"utf-8"))}catch{}return[]}function Eo(e){B.default.mkdirSync(ve,{recursive:!0}),B.default.writeFileSync(xo,JSON.stringify(e,null,2))}function jt(e){try{return process.kill(e,0),!0}catch{return!1}}function na(){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 Po(e,t){let o=G.default.join(ve,`claude-launcher-${t}.exp`),n=G.default.join(ve,`pending-input-${t}.txt`);B.default.writeFileSync(n,"","utf-8");let r=`#!/usr/bin/expect -f
18
18
  set timeout -1
19
19
  set msgfile "${n}"
20
20
 
@@ -51,21 +51,21 @@ send "\\r"
51
51
  interact timeout 2 {
52
52
  check_and_send_messages
53
53
  }
54
- `;return L.default.mkdirSync(Se,{recursive:!0}),L.default.writeFileSync(o,r,{mode:493}),o}function Ro(e){return Object.entries(e).map(([t,o])=>`export ${t}="${o}"`).join("; ")}function Ws(e,t,o){let n=Io(e,o.BADGERCLAW_SESSION_ID||"default"),r=Ro(o),s=`
54
+ `;return B.default.mkdirSync(ve,{recursive:!0}),B.default.writeFileSync(o,r,{mode:493}),o}function Do(e){return Object.entries(e).map(([t,o])=>`export ${t}="${o}"`).join("; ")}function ra(e,t,o){let n=Po(e,o.BADGERCLAW_SESSION_ID||"default"),r=Do(o),s=`
55
55
  tell application "iTerm"
56
56
  activate
57
57
  set newWindow to (create window with default profile)
58
58
  tell current session of newWindow
59
- write text "cd ${Tt(t)} && ${r} && ${Tt(n)}"
59
+ write text "cd ${Mt(t)} && ${r} && ${Mt(n)}"
60
60
  end tell
61
61
  end tell
62
- `;(0,oe.execSync)(`osascript -e '${s.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function Vs(e,t,o){let n=Io(e,o.BADGERCLAW_SESSION_ID||"default"),r=Ro(o),a=`
62
+ `;(0,ne.execSync)(`osascript -e '${s.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function sa(e,t,o){let n=Po(e,o.BADGERCLAW_SESSION_ID||"default"),r=Do(o),a=`
63
63
  tell application "Terminal"
64
64
  activate
65
- do script "${`cd ${Tt(t)} && ${r} && ${Tt(n)}`.replace(/"/g,'\\"')}"
65
+ do script "${`cd ${Mt(t)} && ${r} && ${Mt(n)}`.replace(/"/g,'\\"')}"
66
66
  end tell
67
- `;(0,oe.execSync)(`osascript -e '${a.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function qs(e,t,o){let n=Io(e,o.BADGERCLAW_SESSION_ID||"default"),r=Ro(o),s=`badgerclaw-${o.BADGERCLAW_SESSION_ID||"default"}`,a=`cd ${t} && ${r} && ${n}`;(0,oe.execSync)(`tmux new-session -d -s ${s} "${a}"`,{stdio:"pipe",timeout:1e4})}function Tt(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function xo(e){let t=G.default.join(__dirname,"..","claude-code","mcp-server.js"),o=L.default.existsSync(t)?t:G.default.join(__dirname,"mcp-server.js"),n=(0,oe.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 Ao(e){let t=G.default.join(G.default.dirname(process.argv[1]||""),"..","lib","node_modules","badgerclaw","dist","claude-code","mcp-server.js"),o=G.default.join(__dirname,"..","claude-code","mcp-server.js"),n=G.default.join(__dirname,"mcp-server.js"),r=L.default.existsSync(t)?t:L.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}}}),l=G.default.join(Se,`mcp-config-${e.sessionId}.json`);L.default.mkdirSync(Se,{recursive:!0}),L.default.writeFileSync(l,a,"utf-8");let c=`claude --dangerously-skip-permissions --mcp-config ${l}`;switch(Gs()){case"iterm2":Ws(c,e.projectDir,s);break;case"terminal":Vs(c,e.projectDir,s);break;case"tmux":qs(c,e.projectDir,s);break;case"direct":(0,oe.spawn)(c,[],{shell:!0,cwd:e.projectDir,env:{...process.env,...s},stdio:"ignore",detached:!0}).unref();break}}function Eo(e,t,o,n,r){let s=$o().filter(a=>a.sessionId!==e);s.push({sessionId:e,pid:t,mcpPid:o,port:n,projectDir:r,startedAt:new Date().toISOString()}),Co(s)}function Po(e){let t=$o(),o=t.find(r=>r.sessionId===e);if(!o)return!1;if(o.mcpPid&&Nt(o.mcpPid))try{process.kill(o.mcpPid,"SIGTERM")}catch{}if(o.pid&&Nt(o.pid))try{process.kill(o.pid,"SIGTERM")}catch{}try{(0,oe.execSync)(`tmux kill-session -t badgerclaw-${e} 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let n=t.filter(r=>r.sessionId!==e);return Co(n),!0}function Do(){let e=$o(),t=e.filter(o=>Nt(o.mcpPid)||Nt(o.pid));return t.length!==e.length&&Co(t),t}var oe,L,G,Gn,Se,vo,Lt=B(()=>{"use strict";oe=require("child_process"),L=d(require("fs")),G=d(require("path")),Gn=d(require("os")),Se=G.default.join(Gn.default.homedir(),".badgerclaw"),vo=G.default.join(Se,"claude-sessions.json")});async function ne(e){return e.command_type==="update_cli"?Js(e.payload?.target_version):e.command_type==="update_plugin"?Ys(e.payload?.target_version):e.command_type==="restart_gateway"?Ks():e.command_type==="leave_room"?la(e.payload):e.command_type==="start_claude_code"?ea(e.payload):e.command_type==="stop_claude_code"?ta(e.payload):e.command_type==="start_claude_control"?oa(e.payload):e.command_type==="stop_claude_control"?na(e.payload):e.command_type==="update_claude_tools"?ra(e.payload):e.command_type==="bot_share_notify"?sa(e.payload):e.command_type==="bot_share_revoked"?aa(e.payload):e.command_type==="bot_share_expired"?ia(e.payload):e.command_type==="bot_refresh"?ca(e.payload):{success:!1,message:`Unknown command: ${e.command_type}`}}function Ks(){try{return(0,E.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:15e3}),{success:!0,message:"Gateway restarted"}}catch{try{return{success:!0,message:`Gateway restarted via probe: ${(0,E.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 Js(e){let t=e?`badgerclaw@${e}`:"badgerclaw@latest";try{(0,E.execSync)(`npm install -g ${t}`,{stdio:"pipe",timeout:12e4});let o=(0,E.execSync)("npm list -g badgerclaw --json",{stdio:"pipe"}).toString(),r=JSON.parse(o)?.dependencies?.badgerclaw?.version||"unknown";return Xs(),{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 Ys(e){let t=v.default.join(ke.default.homedir(),".openclaw","extensions","badgerclaw"),o=v.default.join(ke.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=v.default.dirname(v.default.dirname(v.default.dirname(o)));(0,E.execSync)(`npm install ${r}`,{cwd:m,stdio:"pipe",timeout:12e4});let p=v.default.join(o,"package.json"),P="unknown";h.default.existsSync(p)&&(P=JSON.parse(h.default.readFileSync(p,"utf-8")).version||"unknown"),So(P);try{(0,E.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await Wn(P)}let s=t;(0,E.execSync)(`npm install ${r}`,{cwd:s,stdio:"pipe",timeout:12e4});let a=v.default.join(s,"node_modules","@badgerclaw","connect"),l=v.default.join(a,"package.json"),c="unknown";h.default.existsSync(l)&&(c=JSON.parse(h.default.readFileSync(l,"utf-8")).version||"unknown"),So(c),zs(a,s);let i=v.default.join(s,"package.json");if(h.default.existsSync(i)&&h.default.existsSync(l))try{let m=JSON.parse(h.default.readFileSync(i,"utf-8")),p=JSON.parse(h.default.readFileSync(l,"utf-8"));m.version=c,p.openclaw&&(m.openclaw={...m.openclaw,...p.openclaw}),h.default.writeFileSync(i,JSON.stringify(m,null,2)+`
68
- `)}catch{}try{(0,E.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await Wn(c)}catch(s){return{success:!1,message:`Plugin update failed: ${(s.stderr?.toString()||s.message||"").slice(0,500)}`}}}async function Wn(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 zs(e,t){let o=v.default.join(e,"dist"),n=v.default.join(t,"dist");h.default.existsSync(o)&&(h.default.mkdirSync(n,{recursive:!0}),No(o,n));let r=v.default.join(e,"openclaw.plugin.json");h.default.existsSync(r)&&h.default.copyFileSync(r,v.default.join(t,"openclaw.plugin.json"));let s=v.default.join(e,"scripts"),a=v.default.join(t,"scripts");h.default.existsSync(s)&&(h.default.mkdirSync(a,{recursive:!0}),No(s,a));for(let l of["index.ts","src","STREAMING.md","SETUP.md","CHANGELOG.md"]){let c=v.default.join(t,l);h.default.existsSync(c)&&(h.default.statSync(c).isDirectory()?h.default.rmSync(c,{recursive:!0,force:!0}):h.default.unlinkSync(c))}}function No(e,t){for(let o of h.default.readdirSync(e,{withFileTypes:!0})){let n=v.default.join(e,o.name),r=v.default.join(t,o.name);o.isDirectory()?(h.default.mkdirSync(r,{recursive:!0}),No(n,r)):h.default.copyFileSync(n,r)}}function Xs(){try{try{(0,E.execSync)('pkill -f "badgerclaw heartbeat"',{stdio:"pipe",timeout:5e3})}catch{}try{(0,E.execSync)('pkill -f "badgerclaw watch"',{stdio:"pipe",timeout:5e3})}catch{}(0,E.execSync)("sleep 1",{stdio:"pipe"});let e=(0,E.execSync)("which badgerclaw",{stdio:"pipe"}).toString().trim();(0,E.execSync)(`nohup ${e} heartbeat > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"}),(0,E.execSync)(`nohup ${e} watch > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"})}catch{}}function Qs(){let e=v.default.join(ke.default.homedir(),".badgerclaw","workspace");h.default.mkdirSync(e,{recursive:!0});let t=v.default.join(e,".git");return h.default.existsSync(t)||(0,E.execSync)("git init",{cwd:e,stdio:"pipe",timeout:5e3}),h.default.writeFileSync(v.default.join(e,"CLAUDE.md"),`You are a chat assistant connected to Matrix rooms via BadgerClaw.
67
+ `;(0,ne.execSync)(`osascript -e '${a.replace(/'/g,`'"'"'`)}'`,{stdio:"pipe",timeout:1e4})}function aa(e,t,o){let n=Po(e,o.BADGERCLAW_SESSION_ID||"default"),r=Do(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 Mt(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Oo(e){let t=G.default.join(__dirname,"..","claude-code","mcp-server.js"),o=B.default.existsSync(t)?t:G.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 No(e){let t=G.default.join(G.default.dirname(process.argv[1]||""),"..","lib","node_modules","badgerclaw","dist","claude-code","mcp-server.js"),o=G.default.join(__dirname,"..","claude-code","mcp-server.js"),n=G.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}}}),l=G.default.join(ve,`mcp-config-${e.sessionId}.json`);B.default.mkdirSync(ve,{recursive:!0}),B.default.writeFileSync(l,a,"utf-8");let c=`claude --dangerously-skip-permissions --mcp-config ${l}`;switch(na()){case"iterm2":ra(c,e.projectDir,s);break;case"terminal":sa(c,e.projectDir,s);break;case"tmux":aa(c,e.projectDir,s);break;case"direct":(0,ne.spawn)(c,[],{shell:!0,cwd:e.projectDir,env:{...process.env,...s},stdio:"ignore",detached:!0}).unref();break}}function To(e,t,o,n,r){let s=Ao().filter(a=>a.sessionId!==e);s.push({sessionId:e,pid:t,mcpPid:o,port:n,projectDir:r,startedAt:new Date().toISOString()}),Eo(s)}function Lo(e){let t=Ao(),o=t.find(r=>r.sessionId===e);if(!o)return!1;if(o.mcpPid&&jt(o.mcpPid))try{process.kill(o.mcpPid,"SIGTERM")}catch{}if(o.pid&&jt(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 Eo(n),!0}function Bo(){let e=Ao(),t=e.filter(o=>jt(o.mcpPid)||jt(o.pid));return t.length!==e.length&&Eo(t),t}var ne,B,G,Xn,ve,xo,Ht=M(()=>{"use strict";ne=require("child_process"),B=d(require("fs")),G=d(require("path")),Xn=d(require("os")),ve=G.default.join(Xn.default.homedir(),".badgerclaw"),xo=G.default.join(ve,"claude-sessions.json")});async function re(e){return e.command_type==="update_cli"?ca(e.payload?.target_version):e.command_type==="update_plugin"?la(e.payload?.target_version):e.command_type==="restart_gateway"?ia():e.command_type==="leave_room"?va(e.payload):e.command_type==="start_claude_code"?ga(e.payload):e.command_type==="stop_claude_code"?fa(e.payload):e.command_type==="start_claude_control"?ha(e.payload):e.command_type==="stop_claude_control"?ya(e.payload):e.command_type==="update_claude_tools"?wa(e.payload):e.command_type==="bot_share_notify"?ba(e.payload):e.command_type==="bot_share_revoked"?_a(e.payload):e.command_type==="bot_share_expired"?Sa(e.payload):e.command_type==="bot_refresh"?ka(e.payload):{success:!1,message:`Unknown command: ${e.command_type}`}}function ia(){try{return(0,E.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:15e3}),{success:!0,message:"Gateway restarted"}}catch{try{return{success:!0,message:`Gateway restarted via probe: ${(0,E.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 ca(e){let t=e?`badgerclaw@${e}`:"badgerclaw@latest";try{(0,E.execSync)(`npm install -g ${t}`,{stdio:"pipe",timeout:12e4});let o=(0,E.execSync)("npm list -g badgerclaw --json",{stdio:"pipe"}).toString(),r=JSON.parse(o)?.dependencies?.badgerclaw?.version||"unknown";return ua(),{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 la(e){let t=v.default.join($e.default.homedir(),".openclaw","extensions","badgerclaw"),o=v.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=v.default.dirname(v.default.dirname(v.default.dirname(o)));(0,E.execSync)(`npm install ${r}`,{cwd:m,stdio:"pipe",timeout:12e4});let p=v.default.join(o,"package.json"),P="unknown";h.default.existsSync(p)&&(P=JSON.parse(h.default.readFileSync(p,"utf-8")).version||"unknown"),Io(P);try{(0,E.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await Qn(P)}let s=t;(0,E.execSync)(`npm install ${r}`,{cwd:s,stdio:"pipe",timeout:12e4});let a=v.default.join(s,"node_modules","@badgerclaw","connect"),l=v.default.join(a,"package.json"),c="unknown";h.default.existsSync(l)&&(c=JSON.parse(h.default.readFileSync(l,"utf-8")).version||"unknown"),Io(c),da(a,s);let i=v.default.join(s,"package.json");if(h.default.existsSync(i)&&h.default.existsSync(l))try{let m=JSON.parse(h.default.readFileSync(i,"utf-8")),p=JSON.parse(h.default.readFileSync(l,"utf-8"));m.version=c,p.openclaw&&(m.openclaw={...m.openclaw,...p.openclaw}),h.default.writeFileSync(i,JSON.stringify(m,null,2)+`
68
+ `)}catch{}try{(0,E.execSync)("openclaw gateway restart",{stdio:"pipe",timeout:1e4})}catch{}return await Qn(c)}catch(s){return{success:!1,message:`Plugin update failed: ${(s.stderr?.toString()||s.message||"").slice(0,500)}`}}}async function Qn(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 da(e,t){let o=v.default.join(e,"dist"),n=v.default.join(t,"dist");h.default.existsSync(o)&&(h.default.mkdirSync(n,{recursive:!0}),Mo(o,n));let r=v.default.join(e,"openclaw.plugin.json");h.default.existsSync(r)&&h.default.copyFileSync(r,v.default.join(t,"openclaw.plugin.json"));let s=v.default.join(e,"scripts"),a=v.default.join(t,"scripts");h.default.existsSync(s)&&(h.default.mkdirSync(a,{recursive:!0}),Mo(s,a));for(let l of["index.ts","src","STREAMING.md","SETUP.md","CHANGELOG.md"]){let c=v.default.join(t,l);h.default.existsSync(c)&&(h.default.statSync(c).isDirectory()?h.default.rmSync(c,{recursive:!0,force:!0}):h.default.unlinkSync(c))}}function Mo(e,t){for(let o of h.default.readdirSync(e,{withFileTypes:!0})){let n=v.default.join(e,o.name),r=v.default.join(t,o.name);o.isDirectory()?(h.default.mkdirSync(r,{recursive:!0}),Mo(n,r)):h.default.copyFileSync(n,r)}}function ua(){try{try{(0,E.execSync)('pkill -f "badgerclaw heartbeat"',{stdio:"pipe",timeout:5e3})}catch{}try{(0,E.execSync)('pkill -f "badgerclaw watch"',{stdio:"pipe",timeout:5e3})}catch{}(0,E.execSync)("sleep 1",{stdio:"pipe"});let e=(0,E.execSync)("which badgerclaw",{stdio:"pipe"}).toString().trim();(0,E.execSync)(`nohup ${e} heartbeat > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"}),(0,E.execSync)(`nohup ${e} watch > /dev/null 2>&1 &`,{stdio:"pipe",shell:"/bin/zsh"})}catch{}}function ma(){let e=v.default.join($e.default.homedir(),".badgerclaw","workspace");h.default.mkdirSync(e,{recursive:!0});let t=v.default.join(e,".git");return h.default.existsSync(t)||(0,E.execSync)("git init",{cwd:e,stdio:"pipe",timeout:5e3}),h.default.writeFileSync(v.default.join(e,"CLAUDE.md"),`You are a chat assistant connected to Matrix rooms via BadgerClaw.
69
69
 
70
70
  When you receive a message, it will be formatted like:
71
71
  [Room: RoomName] Sender: message text
@@ -74,14 +74,14 @@ Reply using the reply tool with botId="..." and roomId="..."
74
74
  ALWAYS use the \`reply\` MCP tool to send your response back to the chat room.
75
75
  Use the exact botId and roomId provided in the message \u2014 do not modify them.
76
76
  Keep responses concise and helpful.
77
- `),e}function Zs(){try{h.default.mkdirSync(v.default.dirname(jt),{recursive:!0});try{let e=h.default.statSync(jt);if(Date.now()-e.mtimeMs<6e4)return!1;h.default.unlinkSync(jt)}catch{}return h.default.writeFileSync(jt,String(process.pid),{flag:"wx"}),!0}catch{return!1}}async function ea(e){if(!e?.bot_id)return{success:!1,message:"Missing bot_id in payload"};if(!Zs())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 et(e.bot_id),{launchClaudeCode:o,recordSession:n,getActiveSessions:r,stopSession:s}=(Lt(),Ko(Oo)),a=new Set;try{let P=(await j.default.get("http://localhost:7331/claude-code/status",{timeout:5e3})).data?.bots||[];for(let f of P)if(f.botId!==t&&f.enabled!==!1){let w=f.port;typeof w=="number"&&w>=7332&&a.add(w)}}catch{}for(let p=7332;p<=7340;p++)try{(0,E.execSync)(`lsof -ti :${p} >/dev/null 2>&1`,{stdio:"pipe",timeout:2e3}),a.add(p)}catch{}let l=7332;for(;a.has(l);)l++;let c=r();for(let p of c)p.port===l&&(console.log(`[command-executor] Stopping existing session ${p.sessionId} on port ${l}`),s(p.sessionId));try{(0,E.execSync)(`lsof -ti :${l} | xargs kill -9 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let i=e.session_id||`session-${Date.now()}`;await j.default.post("http://localhost:7331/claude-code/toggle",{botId:t,enabled:!0,sessionId:i,port:l},{timeout:1e4});let m=Qs();return o({sessionId:i,port:l,projectDir:m}),n(i,0,0,l,m),{success:!0,message:`Claude Code started globally for bot ${t} (session: ${i}, port: ${l})`}}catch(t){return{success:!1,message:`Failed to start Claude Code: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function et(e){if(e.startsWith("@"))return e;try{let o=(await j.default.get("http://localhost:7331/health",{timeout:1e4})).data?.bots||[],n=v.default.join(ke.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 ta(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 et(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}=(Lt(),Ko(Oo));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 oa(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 et(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 na(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 et(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 ra(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 et(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 sa(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 ia(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 ca(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=v.default.join(ke.default.homedir(),".openclaw","badgerclaw","quarantine",`${o}.json`);try{h.default.rmSync(n,{force:!0})}catch{}try{return(0,E.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 la(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 E,h,v,ke,j,jt,To=B(()=>{"use strict";E=require("child_process"),h=d(require("fs")),v=d(require("path")),ke=d(require("os")),j=d(require("axios"));de();jt=v.default.join(ke.default.homedir(),".badgerclaw","claude-code.lock")});var jo={};Kt(jo,{heartbeatCommand:()=>Lo,pushHeartbeat:()=>T});function Mt(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 Bt)n-s>ga&&Bt.delete(r);return Bt.has(o)?!0:(Bt.set(o,n),!1)}function Xn(e,t){let o=ut();return{instance_id:z(),timestamp:new Date().toISOString(),cli_version:t,plugin_version:e.pluginVersion||"unknown",hostname:o.hostname,os:o.os,arch:o.arch,uptime_seconds:o.uptimeSeconds,mem_free_mb:o.memFreeMb,gateway_status:e.status,gateway_pid:e.pid,last_gateway_restart:e.lastRestart,capabilities:ce(),hermes_containers:In(),bots:e.bots.map(n=>({bot_id:n.botId,bot_username:n.botUsername,status:n.status,activity_state:n.activityState||"idle",active_task:n.activeTask||null,last_activity_at:n.lastActivity,messages_received:n.messagesReceived,messages_sent:n.messagesSent,chunked_messages:n.chunkedMessages,total_chunks_sent:n.totalChunksSent,errors:n.errors,last_error:n.lastError,last_error_at:n.lastErrorAt,uptime_seconds:n.uptimeSeconds,rooms_active:n.roomsActive,room_details:(n.roomDetails||[]).map(r=>({roomId:r.roomId,roomName:r.roomName,workspaceName:r.workspaceName||null,messagesInRoom:r.messagesInRoom,lastActivityInRoom:r.lastActivityInRoom})),claude_code_enabled:n.claudeCodeEnabled??!1,claude_code_session_id:n.claudeCodeSessionId??null,quarantined:n.quarantined??!1}))}}async function T(){let{version:e}=we(),t=await Ze(),o=Xn(t,e);await O().post(zn,o)}function fa(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 Kn(){try{let o=(await O().get(ma)).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 Yn.default.post("http://localhost:7331/bot-share/sync",n,{timeout:1e4}),console.log(g.default.dim(` [${$()}] Share sync: ${o.length} active share(s) pushed to plugin`))}catch(e){console.log(g.default.dim(` [${$()}] Share sync failed (non-fatal): ${e.message}`))}}async function ha(){if(!qn){qn=!0;try{await O().post(ua,{instance_id:z()},{timeout:pa}),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 Qn(){let e=S();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(` [${$()}] Token expires soon \u2014 refreshing proactively...`)),await Qt())console.log(g.default.green(` [${$()}] Token refreshed successfully`));else{let s=on()||"unknown reason";console.log(g.default.yellow(` [${$()}] Token refresh failed: ${s}`))}}function wa(e,t){let o=3e3,n=3e4,r=null;async function s(){try{await Qn();let l=S()?.access_token||e,c=require("eventsource"),i=new c(`${U}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${l}`}});i.onopen=()=>{o=3e3,console.log(g.default.dim(` [${$()}] SSE connected \u2014 listening for real-time events`)),r&&clearTimeout(r),r=setTimeout(()=>{console.log(g.default.dim(` [${$()}] SSE proactive reconnect \u2014 refreshing token before expiry`)),i.close(),s()},ya)},i.onmessage=async m=>{try{let p=JSON.parse(m.data);await ba(p)}catch{}},i.onerror=async()=>{i.close(),r&&(clearTimeout(r),r=null),console.log(g.default.dim(` [${$()}] 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(` [${$()}] SSE connection failed: ${a.message}`)),setTimeout(s,o),o=Math.min(o*1.5,n)}}s()}function $(){return new Date().toISOString()}async function ba(e){if(e.type==="pair"){console.log(g.default.cyan(` [${$()}] Pair event: ${e.bot_name}`)),await qe(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(` [${$()}] 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(` [${$()}] 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(ye(()=>{let c=JSON.parse(n.readFileSync(a,"utf-8")),i=!1;if(c.channels?.badgerclaw?.accounts?.[o]&&(delete c.channels.badgerclaw.accounts[o],i=!0),c.agents?.list){let m=c.agents.list.length;c.agents.list=c.agents.list.filter(p=>p.id!==o),c.agents.list.length!==m&&(i=!0)}return i&&n.writeFileSync(a,JSON.stringify(c,null,2)),i})){console.log(g.default.green(` [${$()}] Removed "${o}" from openclaw.json`));let{execSync:c}=await import("child_process");try{c("openclaw gateway restart",{stdio:"ignore"}),console.log(g.default.green(` [${$()}] Gateway restarted`))}catch{}}}catch(n){console.log(g.default.red(` [${$()}] Failed to clean up bot: ${n}`))}try{await T()}catch{}}else if(e.type==="gateway-restart"){console.log(g.default.cyan(` [${$()}] Remote gateway-restart received`));let t=await Ae();console.log(t.success?g.default.green(` [${$()}] Gateway restarted`):g.default.red(` [${$()}] 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(` [${$()}] Claude Code START: bot=${e.bot_id}`)),Mt("start_claude_code",e.bot_id)){console.log(g.default.dim(` [${$()}] Skipping duplicate start_claude_code (already processed)`));return}try{let t=await ne({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(` [${$()}] Claude Code STOP: bot=${e.bot_id}`)),Mt("stop_claude_code",e.bot_id)){console.log(g.default.dim(` [${$()}] Skipping duplicate stop_claude_code (already processed)`));return}try{let t=await ne({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(` [${$()}] Command: ${e.command_type} (${e.command_id})`)),Mt(e.command_type,e.payload?.bot_id)){console.log(g.default.dim(` [${$()}] 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 ne({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(` [${$()}] CLI updated \u2014 restarting in 2s...`)),setTimeout(()=>process.exit(0),2e3))}catch{}try{await T()}catch{}}}var Jn,g,Yn,Vn,da,zn,ua,ma,pa,qn,Bt,ga,Lo,ya,Ee=B(()=>{"use strict";Jn=require("commander"),g=d(require("chalk")),Yn=d(require("axios"));M();fe();Ce();be();vt();de();To();se();Je();de();Ge();Re();Vn=3e4,da=15e4,zn="/api/v1/dashboard/heartbeat",ua="/api/v1/dashboard/disconnect",ma="/api/v1/me/active-shares",pa=3e3,qn=!1,Bt=new Map,ga=3e4;Lo=new Jn.Command("heartbeat").description("Run heartbeat daemon \u2014 reports telemetry to the BadgerClaw dashboard every 30s").action(async()=>{let e=S();e||(console.log(g.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=we();console.log(g.default.green(`Heartbeat daemon started (v${t})`)),console.log(g.default.dim(` Instance: ${z()}`)),console.log(g.default.dim(` Interval: ${Vn/1e3}s`)),console.log(g.default.dim(` Press Ctrl+C to stop.
78
- `));let o=null,n=10,r=0,s=async()=>{try{await Qn();let c=await Ze(),i=Xn(c,t);fa(o,c)&&o!==null&&console.log(g.default.cyan(` [${new Date().toISOString()}] State change detected \u2014 pushing immediately`));let p=O(),P=await p.post(zn,i);r=0;let f=c.bots.length,w=c.bots.filter(C=>C.status==="running").length;console.log(g.default.dim(` [${new Date().toISOString()}] gateway=${c.status} bots=${w}/${f} running mem=${i.mem_free_mb}MB free`)),o=c;try{let R=await Rn({api:{post:async(J,je)=>{let at=await p.post(J,je);return{status:at.status,data:at.data}}}});for(let J of R)J.attempted&&(J.posted||J.envUpdated)&&console.log(g.default.cyan(` [${new Date().toISOString()}] Hermes recovery key captured for ${J.bot_id} (posted=${J.posted}, env_updated=${J.envUpdated})`))}catch(C){console.log(g.default.dim(` [${new Date().toISOString()}] Hermes recovery-key retry skipped: ${C.message}`))}let A=P.data?.pending_commands||[],k=!1;for(let C of A)try{if(console.log(g.default.cyan(` [${new Date().toISOString()}] Received command: ${C.command_type} (${C.id})`)),await p.post(`/api/v1/dashboard/commands/${C.id}/ack`),Mt(C.command_type,C.payload?.bot_id)){console.log(g.default.dim(` [${new Date().toISOString()}] Skipping duplicate ${C.command_type}`));continue}let R=await ne(C);console.log(R.success?g.default.green(` [${new Date().toISOString()}] ${R.message}`):g.default.red(` [${new Date().toISOString()}] ${R.message}`)),await p.post(`/api/v1/dashboard/commands/${C.id}/result`,{status:R.success?"success":"failed",result:R.message,new_version:R.newVersion||null}),C.command_type==="update_cli"&&R.success&&(k=!0)}catch(R){console.log(g.default.dim(` [${new Date().toISOString()}] Command ${C.id} error: ${R.message}`))}if(k){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(c){c instanceof Ie&&(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}): ${c.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=V()!==null;a?await Kn():console.log(g.default.dim(` [${$()}] Hermes-only host \u2014 share-sync disabled (no plugin to push to).`)),setInterval(s,Vn),a&&setInterval(Kn,da),wa(e.access_token,t);let l=c=>{console.log(g.default.yellow(`
79
- [${new Date().toISOString()}] Received ${c} \u2014 posting disconnect and exiting.`)),ha().finally(()=>{process.exit(0)})};process.on("SIGTERM",l),process.on("SIGINT",l),await new Promise(()=>{})});ya=2700*1e3});var Fr=require("commander");var Zn=require("commander"),W=d(require("chalk")),er=d(require("ora")),tr=d(require("open")),Bo=d(require("os"));var Jt=d(require("crypto"));function Jo(){return Jt.default.randomBytes(32).toString("base64url")}function Yo(e){return Jt.default.createHash("sha256").update(e).digest("base64url")}M();Ce();fe();se();Je();var yo=d(require("os")),Qe=d(require("fs")),xt=d(require("path")),At=require("child_process");var Ct=d(require("fs")),_e=d(require("path")),Ye=d(require("os")),ze=require("child_process"),Dn="ai.badgerclaw.watch",On=_e.default.join(Ye.default.homedir(),"Library","LaunchAgents"),fo=_e.default.join(On,`${Dn}.plist`);function Rs(){try{return(0,ze.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/badgerclaw"}}function xs(){try{return(0,ze.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/node"}}function As(e){let t=_e.default.join(Ye.default.homedir(),".badgerclaw"),o=xs(),n=_e.default.dirname(o),r=_e.default.dirname(e),s=[n,r,"/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"],a=new Set,l=s.filter(c=>!c||a.has(c)?!1:(a.add(c),!0)).join(":");return`<?xml version="1.0" encoding="UTF-8"?>
77
+ `),e}function pa(){try{h.default.mkdirSync(v.default.dirname(Ut),{recursive:!0});try{let e=h.default.statSync(Ut);if(Date.now()-e.mtimeMs<6e4)return!1;h.default.unlinkSync(Ut)}catch{}return h.default.writeFileSync(Ut,String(process.pid),{flag:"wx"}),!0}catch{return!1}}async function ga(e){if(!e?.bot_id)return{success:!1,message:"Missing bot_id in payload"};if(!pa())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 at(e.bot_id),{launchClaudeCode:o,recordSession:n,getActiveSessions:r,stopSession:s}=(Ht(),Qo(jo)),a=new Set;try{let P=(await j.default.get("http://localhost:7331/claude-code/status",{timeout:5e3})).data?.bots||[];for(let f of P)if(f.botId!==t&&f.enabled!==!1){let b=f.port;typeof b=="number"&&b>=7332&&a.add(b)}}catch{}for(let p=7332;p<=7340;p++)try{(0,E.execSync)(`lsof -ti :${p} >/dev/null 2>&1`,{stdio:"pipe",timeout:2e3}),a.add(p)}catch{}let l=7332;for(;a.has(l);)l++;let c=r();for(let p of c)p.port===l&&(console.log(`[command-executor] Stopping existing session ${p.sessionId} on port ${l}`),s(p.sessionId));try{(0,E.execSync)(`lsof -ti :${l} | xargs kill -9 2>/dev/null`,{stdio:"pipe",timeout:3e3})}catch{}let i=e.session_id||`session-${Date.now()}`;await j.default.post("http://localhost:7331/claude-code/toggle",{botId:t,enabled:!0,sessionId:i,port:l},{timeout:1e4});let m=ma();return o({sessionId:i,port:l,projectDir:m}),n(i,0,0,l,m),{success:!0,message:`Claude Code started globally for bot ${t} (session: ${i}, port: ${l})`}}catch(t){return{success:!1,message:`Failed to start Claude Code: ${t.response?.data?.message||t.message||"Unknown error"}`}}}async function at(e){if(e.startsWith("@"))return e;try{let o=(await j.default.get("http://localhost:7331/health",{timeout:1e4})).data?.bots||[],n=v.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 fa(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 at(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}=(Ht(),Qo(jo));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 ha(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 at(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 ya(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 at(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 wa(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 at(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 ba(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 _a(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 Sa(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 ka(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=v.default.join($e.default.homedir(),".openclaw","badgerclaw","quarantine",`${o}.json`);try{h.default.rmSync(n,{force:!0})}catch{}try{return(0,E.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 va(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 E,h,v,$e,j,Ut,Ho=M(()=>{"use strict";E=require("child_process"),h=d(require("fs")),v=d(require("path")),$e=d(require("os")),j=d(require("axios"));ue();Ut=v.default.join($e.default.homedir(),".badgerclaw","claude-code.lock")});var Fo={};Xt(Fo,{heartbeatCommand:()=>Uo,pushHeartbeat:()=>T});function Gt(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 Ft)n-s>xa&&Ft.delete(r);return Ft.has(o)?!0:(Ft.set(o,n),!1)}function sr(e,t){let o=yt();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:Pn(),bots:e.bots.map(n=>({bot_id:n.botId,bot_username:n.botUsername,status:n.status,activity_state:n.activityState||"idle",active_task:n.activeTask||null,last_activity_at:n.lastActivity,messages_received:n.messagesReceived,messages_sent:n.messagesSent,chunked_messages:n.chunkedMessages,total_chunks_sent:n.totalChunksSent,errors:n.errors,last_error:n.lastError,last_error_at:n.lastErrorAt,uptime_seconds:n.uptimeSeconds,rooms_active:n.roomsActive,room_details:(n.roomDetails||[]).map(r=>({roomId:r.roomId,roomName:r.roomName,workspaceName:r.workspaceName||null,messagesInRoom:r.messagesInRoom,lastActivityInRoom:r.lastActivityInRoom})),claude_code_enabled:n.claudeCodeEnabled??!1,claude_code_session_id:n.claudeCodeSessionId??null,quarantined:n.quarantined??!1}))}}async function T(){let{version:e}=be(),t=await st(),o=sr(t,e);await O().post(rr,o)}function Aa(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 tr(){try{let o=(await O().get(Ia)).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 nr.default.post("http://localhost:7331/bot-share/sync",n,{timeout:1e4}),console.log(g.default.dim(` [${$()}] Share sync: ${o.length} active share(s) pushed to plugin`))}catch(e){console.log(g.default.dim(` [${$()}] Share sync failed (non-fatal): ${e.message}`))}}async function Ea(){if(!er){er=!0;try{await O().post(Ca,{instance_id:Q()},{timeout:Ra}),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 ar(){let e=w();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(` [${$()}] Token expires soon \u2014 refreshing proactively...`)),await oo())console.log(g.default.green(` [${$()}] Token refreshed successfully`));else{let s=cn()||"unknown reason";console.log(g.default.yellow(` [${$()}] Token refresh failed: ${s}`))}}function Da(e,t){let o=3e3,n=3e4,r=null;async function s(){try{await ar();let l=w()?.access_token||e,c=require("eventsource"),i=new c(`${H}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${l}`}});i.onopen=()=>{o=3e3,console.log(g.default.dim(` [${$()}] SSE connected \u2014 listening for real-time events`)),r&&clearTimeout(r),r=setTimeout(()=>{console.log(g.default.dim(` [${$()}] SSE proactive reconnect \u2014 refreshing token before expiry`)),i.close(),s()},Pa)},i.onmessage=async m=>{try{let p=JSON.parse(m.data);await Oa(p)}catch{}},i.onerror=async()=>{i.close(),r&&(clearTimeout(r),r=null),console.log(g.default.dim(` [${$()}] 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(` [${$()}] SSE connection failed: ${a.message}`)),setTimeout(s,o),o=Math.min(o*1.5,n)}}s()}function $(){return new Date().toISOString()}async function Oa(e){if(e.type==="pair"){console.log(g.default.cyan(` [${$()}] Pair event: ${e.bot_name}`)),await Ze(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(` [${$()}] 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(` [${$()}] 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 c=JSON.parse(n.readFileSync(a,"utf-8")),i=!1;if(c.channels?.badgerclaw?.accounts?.[o]&&(delete c.channels.badgerclaw.accounts[o],i=!0),c.agents?.list){let m=c.agents.list.length;c.agents.list=c.agents.list.filter(p=>p.id!==o),c.agents.list.length!==m&&(i=!0)}return i&&n.writeFileSync(a,JSON.stringify(c,null,2)),i})){console.log(g.default.green(` [${$()}] Removed "${o}" from openclaw.json`));let{execSync:c}=await import("child_process");try{c("openclaw gateway restart",{stdio:"ignore"}),console.log(g.default.green(` [${$()}] Gateway restarted`))}catch{}}}catch(n){console.log(g.default.red(` [${$()}] Failed to clean up bot: ${n}`))}try{await T()}catch{}}else if(e.type==="gateway-restart"){console.log(g.default.cyan(` [${$()}] Remote gateway-restart received`));let t=await Le();console.log(t.success?g.default.green(` [${$()}] Gateway restarted`):g.default.red(` [${$()}] 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(` [${$()}] Claude Code START: bot=${e.bot_id}`)),Gt("start_claude_code",e.bot_id)){console.log(g.default.dim(` [${$()}] 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(` [${$()}] Claude Code STOP: bot=${e.bot_id}`)),Gt("stop_claude_code",e.bot_id)){console.log(g.default.dim(` [${$()}] 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(` [${$()}] Command: ${e.command_type} (${e.command_id})`)),Gt(e.command_type,e.payload?.bot_id)){console.log(g.default.dim(` [${$()}] 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(` [${$()}] CLI updated \u2014 restarting in 2s...`)),setTimeout(()=>process.exit(0),2e3))}catch{}try{await T()}catch{}}}var or,g,nr,Zn,$a,rr,Ca,Ia,Ra,er,Ft,xa,Uo,Pa,Be=M(()=>{"use strict";or=require("commander"),g=d(require("chalk")),nr=d(require("axios"));L();he();Re();_e();At();ue();Ho();ae();tt();ue();ze();Ae();Zn=3e4,$a=15e4,rr="/api/v1/dashboard/heartbeat",Ca="/api/v1/dashboard/disconnect",Ia="/api/v1/me/active-shares",Ra=3e3,er=!1,Ft=new Map,xa=3e4;Uo=new or.Command("heartbeat").description("Run heartbeat daemon \u2014 reports telemetry to the BadgerClaw dashboard every 30s").action(async()=>{let e=w();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: ${Zn/1e3}s`)),console.log(g.default.dim(` Press Ctrl+C to stop.
78
+ `));let o=null,n=10,r=0,s=async()=>{try{await ar();let c=await st(),i=sr(c,t);Aa(o,c)&&o!==null&&console.log(g.default.cyan(` [${new Date().toISOString()}] State change detected \u2014 pushing immediately`));let p=O(),P=await p.post(rr,i);r=0;let f=c.bots.length,b=c.bots.filter(C=>C.status==="running").length;console.log(g.default.dim(` [${new Date().toISOString()}] gateway=${c.status} bots=${b}/${f} running mem=${i.mem_free_mb}MB free`)),o=c;try{let x=await Dn({api:{post:async(z,Ve)=>{let mt=await p.post(z,Ve);return{status:mt.status,data:mt.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(C){console.log(g.default.dim(` [${new Date().toISOString()}] Hermes recovery-key retry skipped: ${C.message}`))}let R=P.data?.pending_commands||[],k=!1;for(let C of R)try{if(console.log(g.default.cyan(` [${new Date().toISOString()}] Received command: ${C.command_type} (${C.id})`)),await p.post(`/api/v1/dashboard/commands/${C.id}/ack`),Gt(C.command_type,C.payload?.bot_id)){console.log(g.default.dim(` [${new Date().toISOString()}] Skipping duplicate ${C.command_type}`));continue}let x=await re(C);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/${C.id}/result`,{status:x.success?"success":"failed",result:x.message,new_version:x.newVersion||null}),C.command_type==="update_cli"&&x.success&&(k=!0)}catch(x){console.log(g.default.dim(` [${new Date().toISOString()}] Command ${C.id} error: ${x.message}`))}if(k){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(c){c instanceof xe&&(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}): ${c.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=W()!==null;a?await tr():console.log(g.default.dim(` [${$()}] Hermes-only host \u2014 share-sync disabled (no plugin to push to).`)),setInterval(s,Zn),a&&setInterval(tr,$a),Da(e.access_token,t);let l=c=>{console.log(g.default.yellow(`
79
+ [${new Date().toISOString()}] Received ${c} \u2014 posting disconnect and exiting.`)),Ea().finally(()=>{process.exit(0)})};process.on("SIGTERM",l),process.on("SIGINT",l),await new Promise(()=>{})});Pa=2700*1e3});var zr=require("commander");var ir=require("commander"),V=d(require("chalk")),cr=d(require("ora")),lr=d(require("open")),Go=d(require("os"));var Qt=d(require("crypto"));function Zo(){return Qt.default.randomBytes(32).toString("base64url")}function en(e){return Qt.default.createHash("sha256").update(e).digest("base64url")}L();Re();he();ae();tt();var Dt=d(require("os")),J=d(require("fs")),Ot=d(require("path")),ke=require("child_process");var Pe=d(require("fs")),Se=d(require("path")),Oe=d(require("os")),Ne=require("child_process"),Bn="ai.badgerclaw.watch",jn=Se.default.join(Oe.default.homedir(),"Library","LaunchAgents"),De=Se.default.join(jn,`${Bn}.plist`);function Ts(){try{return(0,Ne.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/badgerclaw"}}function Ls(){try{return(0,Ne.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/opt/homebrew/bin/node"}}function Bs(e){let t=Se.default.join(Oe.default.homedir(),".badgerclaw"),o=Ls(),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,l=s.filter(c=>!c||a.has(c)?!1:(a.add(c),!0)).join(":");return`<?xml version="1.0" encoding="UTF-8"?>
80
80
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
81
81
  <plist version="1.0">
82
82
  <dict>
83
83
  <key>Label</key>
84
- <string>${Dn}</string>
84
+ <string>${Bn}</string>
85
85
  <key>ProgramArguments</key>
86
86
  <array>
87
87
  <string>${o}</string>
@@ -104,7 +104,7 @@ Keep responses concise and helpful.
104
104
  <key>ThrottleInterval</key>
105
105
  <integer>30</integer>
106
106
  </dict>
107
- </plist>`}function Nn(){if(Ye.default.platform()==="darwin")try{let e=Rs();Ct.default.mkdirSync(On,{recursive:!0}),Ct.default.mkdirSync(_e.default.join(Ye.default.homedir(),".badgerclaw"),{recursive:!0}),Ct.default.writeFileSync(fo,As(e));try{(0,ze.execSync)(`launchctl unload "${fo}" 2>/dev/null`)}catch{}(0,ze.execSync)(`launchctl load "${fo}"`),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")}}var It=d(require("fs")),Xe=d(require("path")),Rt=d(require("os")),te=require("child_process"),ho="badgerclaw-watch.service",Tn=Xe.default.join(Rt.default.homedir(),".config","systemd","user"),Es=Xe.default.join(Tn,ho);function Ps(){try{return(0,te.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/usr/local/bin/badgerclaw"}}function Ds(){try{return(0,te.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/usr/bin/node"}}function Os(e){let t=Ds(),o=Xe.default.dirname(t);return`[Unit]
107
+ </plist>`}function Mn(){if(Oe.default.platform()==="darwin")try{let e=Ts();Pe.default.mkdirSync(jn,{recursive:!0}),Pe.default.mkdirSync(Se.default.join(Oe.default.homedir(),".badgerclaw"),{recursive:!0}),Pe.default.writeFileSync(De,Bs(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 Hn(){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")),nt=d(require("path")),ot=d(require("os")),K=require("child_process"),Pt="badgerclaw-watch.service",Un=nt.default.join(ot.default.homedir(),".config","systemd","user"),bo=nt.default.join(Un,Pt);function js(){try{return(0,K.execSync)("which badgerclaw",{encoding:"utf-8"}).trim()}catch{return"/usr/local/bin/badgerclaw"}}function Ms(){try{return(0,K.execSync)("which node",{encoding:"utf-8"}).trim()}catch{return"/usr/bin/node"}}function Hs(e){let t=Ms(),o=nt.default.dirname(t);return`[Unit]
108
108
  Description=BadgerClaw background watcher (heartbeat + pair events)
109
109
  After=network-online.target
110
110
  Wants=network-online.target
@@ -120,40 +120,41 @@ StandardError=append:%h/.badgerclaw/heartbeat.log
120
120
 
121
121
  [Install]
122
122
  WantedBy=default.target
123
- `}function Ns(){try{return(0,te.execSync)("systemctl --user --version",{stdio:"ignore"}),!0}catch{return!1}}function Ln(){if(Rt.default.platform()!=="linux"||!Ns())return!1;try{let e=Ps();It.default.mkdirSync(Tn,{recursive:!0}),It.default.mkdirSync(Xe.default.join(Rt.default.homedir(),".badgerclaw"),{recursive:!0}),It.default.writeFileSync(Es,Os(e)),(0,te.execSync)("systemctl --user daemon-reload",{stdio:"ignore"});try{(0,te.execSync)(`systemctl --user restart ${ho}`,{stdio:"ignore"})}catch{}(0,te.execSync)(`systemctl --user enable --now ${ho}`,{stdio:"ignore"});try{let t=(0,te.execSync)("whoami",{encoding:"utf-8"}).trim();(0,te.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}}var wo=xt.default.join(yo.default.homedir(),".badgerclaw"),Bn=xt.default.join(wo,"heartbeat.pid"),Ts=xt.default.join(wo,"heartbeat.log");function Ls(){try{let e=parseInt(Qe.default.readFileSync(Bn,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0)return process.kill(e,0),!0}catch{}try{return(0,At.execSync)("pgrep -f 'badgerclaw heartbeat'",{stdio:"ignore"}),!0}catch{return!1}}function jn(){if(Ls())return console.log("\x1B[2mHeartbeat already running.\x1B[0m"),!0;try{Qe.default.mkdirSync(wo,{recursive:!0});let e=Qe.default.openSync(Ts,"a"),t=(0,At.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{Qe.default.writeFileSync(Bn,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 Mn(){let e=yo.default.platform();if(e==="darwin"){Nn();return}if(e==="linux"){if(Ln())return;jn();return}jn()}var ue=d(require("fs")),ko=d(require("os")),Pt=d(require("path")),Q=require("child_process"),H=d(require("chalk"));Ge();de();var Hn=Pt.default.join(ko.default.homedir(),".openclaw","openclaw.json");function Us(){return process.platform!=="linux"?!1:!!(ue.default.existsSync("/.dockerenv")||(0,Q.spawnSync)("which",["systemctl"],{encoding:"utf-8"}).status!==0)}function Fn(e=!1){let t=null;try{ue.default.existsSync(Hn)&&(t=JSON.parse(ue.default.readFileSync(Hn,"utf-8"))?.gateway?.mode??null)}catch{}if(typeof t=="string"&&t.length>0)return!0;e||console.log(H.default.dim(" Setting gateway.mode=local..."));try{return ye(()=>((0,Q.execSync)("openclaw config set gateway.mode local",{encoding:"utf-8",timeout:1e4,stdio:"pipe"}),!0))}catch(o){return e||(console.log(H.default.yellow(` \u26A0\uFE0F Could not set gateway.mode automatically: ${o.message}`)),console.log(H.default.yellow(" Run `openclaw config set gateway.mode local` manually."))),!1}}async function Dt(e={}){let t=e.verbose!==!1,o=l=>{t&&console.log(l)};if(Us())return Fs(t);o(H.default.dim(" Installing OpenClaw gateway service (if not present)...")),(0,Q.spawnSync)("openclaw",["gateway","install"],{stdio:t?"inherit":"pipe",shell:!0}).status!==0&&o(H.default.yellow(" \u26A0\uFE0F `openclaw gateway install` returned non-zero \u2014 continuing.")),Fn(!t),o(H.default.dim(" Starting OpenClaw gateway..."));let r=(0,Q.spawnSync)("openclaw",["gateway","start"],{stdio:t?"inherit":"pipe",shell:!0}),s="started";if(r.status!==0&&(r=(0,Q.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(H.default.dim(" Waiting for the gateway to start answering..."));let a=await Hs(2e4);return a||o(H.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 Hs(e,t=_o,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 Fs(e){let t=i=>{e&&console.log(i)};t(H.default.dim(" Container mode (no systemd) \u2014 running gateway in foreground via nohup.")),Fn(!e);let o=Pt.default.join(ko.default.homedir(),".openclaw","logs");try{ue.default.mkdirSync(o,{recursive:!0})}catch{}let n=Pt.default.join(o,"gateway-foreground.log"),r,s;try{r=ue.default.openSync(n,"a"),s=ue.default.openSync(n,"a")}catch(i){return{ok:!1,error:`cannot open gateway log at ${n}: ${i.message}`}}let a=(0,Q.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(H.default.dim(` Gateway PID: ${a.pid}, log: ${n}`));let l=Date.now()+2e4,c=!1;for(;Date.now()<l;){try{let i=ue.default.readFileSync(n,"utf-8");if(i.includes("[gateway] ready")){c=!0;break}if(/EADDRINUSE|FATAL|Error:|gateway start blocked/.test(i))return{ok:!1,error:`gateway aborted on startup \u2014 see ${n}`}}catch{}await new Promise(i=>setTimeout(i,200))}return c?{ok:!0,state:"started",ready:!0}:{ok:!1,error:`gateway did not report ready within 20s \u2014 see ${n}`}}function Ot(){if(process.platform!=="linux"||process.getuid?.()!==0)return;let e=(0,Q.spawnSync)("loginctl",["show-user","root","--property=Linger"],{encoding:"utf-8"});e.status===0&&/Linger=no/.test(e.stdout||"")&&(console.log(H.default.yellow(`
124
- \u26A0\uFE0F systemd lingering is OFF for root. The gateway will stop on SSH disconnect.`)),console.log(H.default.dim(" Enable persistence: loginctl enable-linger root")))}Re();var _a=2e3,Sa=12e4,or=new Zn.Command("login").description("Log in to BadgerClaw via browser").action(async()=>{let e=Jo(),t=Yo(e),o=`${en}/cli-auth?code=${t}`;console.log(W.default.yellow("Opening browser for authentication...")),console.log(W.default.dim(`If the browser doesn't open, visit: ${o}`)),await(0,tr.default)(o);let n=(0,er.default)("Waiting for authentication...").start(),r=sn(),s=Date.now();for(;Date.now()-s<Sa;){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(l=>setTimeout(l,5e3));continue}if(a.data?.access_token){let{access_token:l,user_id:c,expires_at:i,refresh_token:m,email:p}=a.data,P=Xt(),f=`openclaw-${Bo.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${P}`,w=f;try{let{version:k}=we(),C=await r.post("/api/v1/openclaw/register",{instance_id:f,label:Bo.default.hostname(),version:k,machine_fingerprint:P},{headers:{Authorization:`Bearer ${l}`}}),R=C.data?.result||C.data;R&&typeof R.instance_id=="string"&&R.instance_id.length>0&&(w=R.instance_id)}catch(k){let C=k?.response?.status;if(C===403||C===409){let R=k?.response?.data,J=Array.isArray(R?.errors)&&typeof R.errors[0]=="string"?R.errors[0]:null,je=R?.detail,at=typeof je=="string"?je:je?.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,Gr=J||at||`Login refused (status ${C}). Open the BadgerClaw app to check your subscription state.`;n.fail(W.default.red(Gr)),process.exit(1)}}if(ct({access_token:l,user_id:c,instance_id:w,expires_at:i,refresh_token:m,email:p}),n.succeed(W.default.green(`Logged in as ${dt(c)}`)),V()!==null){let k=await Dt({verbose:!0});k.ok?k.ready===!1&&console.log(W.default.dim(" Gateway is still coming up \u2014 it should be online shortly.")):console.log(W.default.yellow("\n \u26A0\uFE0F Logged in, but gateway failed to start. Re-run `badgerclaw setup` to repair."))}else console.log(W.default.dim(" Hermes-only host \u2014 skipping OpenClaw gateway bring-up."));let A=await Ke(!0);A>0&&console.log(W.default.green(`\u2705 ${A} bot(s) automatically paired to OpenClaw.`)),Mn(),Ot();try{let{pushHeartbeat:k}=await Promise.resolve().then(()=>(Ee(),jo));await k(),console.log(W.default.dim(" Capabilities pushed \u2014 the machine should show online shortly."))}catch(k){console.log(W.default.dim(` Capability push will retry via the heartbeat (${k?.message||k}).`))}return}}catch{}await new Promise(a=>setTimeout(a,_a))}n.fail(W.default.red("Authentication timed out. Please try again.")),process.exit(1)});var rr=require("commander"),tt=d(require("chalk")),Ut=d(require("fs")),Pe=d(require("os")),nt=d(require("path")),ot=require("child_process");M();fe();function ka(){let e=process.platform;if(e==="darwin"){let t=nt.default.join(Pe.default.homedir(),"Library","LaunchAgents","ai.badgerclaw.watch.plist");(0,ot.spawnSync)("launchctl",["unload",t],{stdio:"ignore"});try{Ut.default.unlinkSync(t)}catch{}}else if(e==="linux"){(0,ot.spawnSync)("systemctl",["--user","disable","--now","badgerclaw-watch.service"],{stdio:"ignore"});let t=nt.default.join(Pe.default.homedir(),".config","systemd","user","badgerclaw-watch.service");try{Ut.default.unlinkSync(t)}catch{}(0,ot.spawnSync)("systemctl",["--user","daemon-reload"],{stdio:"ignore"})}(0,ot.spawnSync)("pkill",["-f","badgerclaw heartbeat"],{stdio:"ignore"})}function nr(e){try{return Ut.default.rmSync(e,{recursive:!0,force:!0}),!0}catch{return!1}}var sr=new rr.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=S();if(t)try{let a=Fe(t.access_token),{version:l}=we();await a.post("/api/v1/openclaw/register",{instance_id:t.instance_id,label:Pe.default.hostname(),version:l,online:!1})}catch{}if(ka(),e.keepState){Me(),console.log(tt.default.green("Logged out \u2014 auth cleared. (state preserved with --keep-state)"));return}let o=nt.default.join(Pe.default.homedir(),".badgerclaw"),n=nr(o),r=nt.default.join(Pe.default.homedir(),".openclaw","badgerclaw"),s=nr(r);n||s?(console.log(tt.default.green("Logged out \u2014 local state cleared.")),console.log(tt.default.dim(` Removed: ${o}${s?`, ${r}`:""}`))):console.log(tt.default.green("Logged out."))});var ar=require("commander"),Mo=d(require("chalk"));M();var ir=new ar.Command("status").description("Show connected instance info").action(async()=>{let e=S();(!e||!lt())&&(console.log(Mo.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1)),console.log(Mo.default.green("Authenticated")),console.log(` User: ${dt(e.user_id)}`),console.log(` Instance: ${e.instance_id}`),console.log(` Expires: ${new Date(e.expires_at).toLocaleDateString()}`)});var Oe=require("commander"),b=d(require("chalk")),Wt=d(require("ora")),Gt=d(require("fs")),pr=d(require("os")),gr=d(require("path")),fr=require("child_process");M();fe();var De=d(require("fs")),cr=d(require("os")),lr=d(require("path")),dr=require("child_process");Ge();function Ht(e){let t=e.split(":")[0].replace(/^@/,"").replace(/_bot$/,""),o=lr.join(cr.homedir(),".openclaw","openclaw.json");return De.existsSync(o)?{changed:ye(()=>{let r=JSON.parse(De.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(l=>l.id!==t),r.agents.list.length!==a&&(s=!0)}return s&&De.writeFileSync(o,JSON.stringify(r,null,2)),s})}:{changed:!1}}function Ft(){try{return(0,dr.execSync)("openclaw gateway restart",{stdio:"ignore"}),!0}catch{return!1}}be();function ur(e){return e.hermes?"hermes":"openclaw"}function mr(e){return e.openclaw.installed?"openclaw":e.hermes.installed?"hermes":"openclaw"}function Ho(){lt()||(console.log(b.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 hr(e){return e.replace(/_bot$/,"")}var Uo=["openclaw","hermes"],$a=new Oe.Command("create").description("Create a new bot").argument("<name>","Bot name (4-20 chars, lowercase alphanumeric + underscores)").option("-r, --runtime <runtime>",`Bot runtime: ${Uo.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)=>{Ho(),va(e)||(console.log(b.default.red("Invalid bot name. Must be 4-20 characters, lowercase alphanumeric and underscores only.")),process.exit(1));let o=t.runtime??mr(ce());Uo.includes(o)||(console.log(b.default.red(`Invalid --runtime "${t.runtime}". Must be one of: ${Uo.join(", ")}.`)),process.exit(1));let n=(0,Wt.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(b.default.green(`Bot "${e}" (${o}) created successfully!`)),o==="hermes"&&console.log(b.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(b.default.red(`Failed to create bot: ${s}`)),process.exit(1)}}),Ca=new Oe.Command("list").description("List your bots").action(async()=>{Ho();let e=(0,Wt.default)("Fetching bots...").start();try{let n=(await O().get("/api/v1/openclaw/bots")).data?.bots||[];if(e.stop(),n.length===0){console.log(b.default.yellow("No bots found. Create one with `badgerclaw bot create <name>`."));return}console.log(b.default.green(`Your bots (${n.length}):
125
- `));for(let r of n){let s=hr(r.username||r.name),a=r.active===!1?b.default.dim("deactivated"):r.openclaw_connected?b.default.green("connected"):b.default.gray("disconnected");console.log(` ${b.default.bold(s)} ${a}`)}}catch(t){let o=t.response?.data?.errors?.[0]||t.message;e.fail(b.default.red(`Failed to list bots: ${o}`)),process.exit(1)}}),Ia=new Oe.Command("delete").description("Deactivate a bot").argument("<name>","Bot name to deactivate").action(async e=>{Ho();let t=(0,Wt.default)(`Deactivating bot "${e}"...`).start();try{await O().delete(`/api/v1/openclaw/bots/${e}`),t.succeed(b.default.green(`Bot "${e}" deactivated.`));let{changed:n}=Ht(e);n&&(console.log(b.default.dim(" Removed from openclaw.json")),Ft()&&console.log(b.default.dim(" Gateway restarted")))}catch(o){let n=o.response?.data?.errors?.[0]||o.message;t.fail(b.default.red(`Failed to deactivate bot: ${n}`)),process.exit(1)}});function Ra(e){let t=e.trim();return t.startsWith("@")&&(t=t.slice(1)),t.includes(":")&&(t=t.split(":")[0]),hr(t)}function xa(e){let t=e.replace(/[^a-zA-Z0-9_.-]/g,"_")||"default";return gr.default.join(pr.default.homedir(),".openclaw","badgerclaw","quarantine",`${t}.json`)}var Aa=new Oe.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=Ra(e);t||(console.log(b.default.red(`Couldn't parse bot name "${e}".`)),process.exit(1));let o=xa(t),n=!1;if(Gt.default.existsSync(o))try{let r=JSON.parse(Gt.default.readFileSync(o,"utf-8")),s=r.failureCount??"?",a=r.quarantinedAt??"?";console.log(b.default.dim(` Quarantine for "${t}" \u2014 ${s} failures, since ${a}`)),Gt.default.unlinkSync(o),n=!0}catch(r){console.log(b.default.red(`Failed to clear quarantine ledger at ${o}: ${r.message}`)),process.exit(1)}console.log(n?b.default.green(`\u2705 Cleared quarantine for "${t}"`):b.default.dim(` No quarantine file for "${t}" \u2014 already healthy or never quarantined.`)),console.log(b.default.dim(" Restarting OpenClaw gateway so the refresh chain runs..."));try{(0,fr.execSync)("openclaw gateway restart",{stdio:"inherit"})}catch(r){console.log(b.default.yellow(` Gateway restart command failed: ${r.message}`)),console.log(b.default.yellow(" Run `openclaw gateway restart` manually.")),process.exit(1)}console.log(b.default.green(`
126
- \u2705 Refresh triggered. Watch the gateway logs for token refresh progress:`)),console.log(b.default.dim(" tail -f ~/.openclaw/logs/*.log")),console.log(b.default.dim(" If the bot fails to recover, the plugin's 4 refresh strategies all hit")),console.log(b.default.dim(" dead ends. Verify SYNAPSE_REGISTRATION_SHARED_SECRET is set on this gateway,")),console.log(b.default.dim(" or re-pair the bot from the BadgerClaw iOS app."))}),yr=new Oe.Command("bot").description("Manage bots").addCommand($a).addCommand(Ca).addCommand(Ia).addCommand(Aa);Je();var br=require("commander"),y=d(require("chalk"));M();se();Je();de();Ee();To();fe();Ce();var wr=3e3,Ea=6e4,Pa=2700*1e3,_r=new br.Command("watch").description("Watch for bot pair events in real-time (no polling)").action(async()=>{S()||(console.log(y.default.yellow("Not logged in.")),process.exit(1)),await Ke(!1),console.log(y.default.green("\u{1F534} Listening for pair events... (Ctrl+C to stop)"));let t=require("eventsource"),o=wr,n=null,r=null,s=()=>{let a=S();a||(console.log(y.default.red(" Auth missing \u2014 run `badgerclaw login` and re-start `badgerclaw watch`.")),process.exit(1));let l=new t(`${U}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${a.access_token}`}});r=l,l.onopen=()=>{o=wr,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")),l.close(),s()},Pa)},l.onerror=()=>{l.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,Ea)},l.onmessage=async c=>{try{let i=JSON.parse(c.data);if(i.type==="pair"){let m=i.target_instance_id;if(m&&m!==z()){console.log(y.default.dim(`
123
+ `}function Fn(){try{return(0,K.execSync)("systemctl --user --version",{stdio:"ignore"}),!0}catch{return!1}}function Gn(){if(ot.default.platform()!=="linux"||!Fn())return!1;try{let e=js();Te.default.mkdirSync(Un,{recursive:!0}),Te.default.mkdirSync(nt.default.join(ot.default.homedir(),".badgerclaw"),{recursive:!0}),Te.default.writeFileSync(bo,Hs(e)),(0,K.execSync)("systemctl --user daemon-reload",{stdio:"ignore"});try{(0,K.execSync)(`systemctl --user restart ${Pt}`,{stdio:"ignore"})}catch{}(0,K.execSync)(`systemctl --user enable --now ${Pt}`,{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 Vn(){if(ot.default.platform()==="linux"&&Fn()){try{(0,K.execSync)(`systemctl --user disable --now ${Pt}`,{stdio:"ignore"})}catch{}try{Te.default.existsSync(bo)&&Te.default.unlinkSync(bo),(0,K.execSync)("systemctl --user daemon-reload",{stdio:"ignore"})}catch{}}}var _o=Ot.default.join(Dt.default.homedir(),".badgerclaw"),rt=Ot.default.join(_o,"heartbeat.pid"),Us=Ot.default.join(_o,"heartbeat.log");function Fs(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 Gs(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 So(e){if(!Number.isFinite(e)||e<=0||e===process.pid||e===process.ppid)return!1;let t=Gs(e);return t?Fs(t):!1}function ko(){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=>So(t))}function Vs(e){try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,Math.max(0,e))}catch{}}function Ws(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 qs=/(systemd|supervisord|launchd|runsv|runit|s6-supervise|openrc)/i;function Ks(){for(let e of ko()){let t=Ws(e);if(t&&qs.test(t.comm))return e}return null}function Js(){try{let e=parseInt(J.default.readFileSync(rt,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&So(e))return!0}catch{}return qn(),ko().length>0}function qn(){try{let e=parseInt(J.default.readFileSync(rt,"utf-8").trim(),10);if(Number.isFinite(e)&&e>0&&So(e))return}catch{}try{J.default.rmSync(rt,{force:!0})}catch{}}function Ys(e="SIGTERM"){let t=ko(),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;)Vs(120),s=s.filter(n);for(let a of s)try{process.kill(a,"SIGKILL")}catch{}return o}function Wn(){if(Js())return console.log("\x1B[2mHeartbeat already running.\x1B[0m"),!0;try{J.default.mkdirSync(_o,{recursive:!0});let e=J.default.openSync(Us,"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(rt,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 vo(){let e=Dt.default.platform();if(e==="darwin"){Mn();return}if(e==="linux"){if(Gn())return;Wn();return}Wn()}function zs(){let e=Dt.default.platform();e==="darwin"?Hn():e==="linux"&&Vn(),Ys();try{J.default.rmSync(rt,{force:!0})}catch{}}function Kn(e){let t=e.log||(()=>{}),o=Ks();if(o!==null){qn(),t(`heartbeat already supervised (pid ${o}) \u2014 left in place; cleared any stale pid file.`);return}zs(),t("removed stale heartbeat hooks from previous installs."),e.loggedIn?(vo(),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")),Ro=d(require("os")),Tt=d(require("path")),ee=require("child_process"),U=d(require("chalk"));ze();ue();var Yn=Tt.default.join(Ro.default.homedir(),".openclaw","openclaw.json");function ea(){return process.platform!=="linux"?!1:!!(me.default.existsSync("/.dockerenv")||(0,ee.spawnSync)("which",["systemctl"],{encoding:"utf-8"}).status!==0)}function zn(e=!1){let t=null;try{me.default.existsSync(Yn)&&(t=JSON.parse(me.default.readFileSync(Yn,"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 Lt(e={}){let t=e.verbose!==!1,o=l=>{t&&console.log(l)};if(ea())return oa(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.")),zn(!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 ta(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 ta(e,t=Co,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 oa(e){let t=i=>{e&&console.log(i)};t(U.default.dim(" Container mode (no systemd) \u2014 running gateway in foreground via nohup.")),zn(!e);let o=Tt.default.join(Ro.default.homedir(),".openclaw","logs");try{me.default.mkdirSync(o,{recursive:!0})}catch{}let n=Tt.default.join(o,"gateway-foreground.log"),r,s;try{r=me.default.openSync(n,"a"),s=me.default.openSync(n,"a")}catch(i){return{ok:!1,error:`cannot open gateway log at ${n}: ${i.message}`}}let a=(0,ee.spawn)("openclaw",["gateway"],{detached:!0,stdio:["ignore",r,s]});if(a.pid==null)return{ok:!1,error:"failed to spawn `openclaw gateway`"};a.unref(),t(U.default.dim(` Gateway PID: ${a.pid}, log: ${n}`));let l=Date.now()+2e4,c=!1;for(;Date.now()<l;){try{let i=me.default.readFileSync(n,"utf-8");if(i.includes("[gateway] ready")){c=!0;break}if(/EADDRINUSE|FATAL|Error:|gateway start blocked/.test(i))return{ok:!1,error:`gateway aborted on startup \u2014 see ${n}`}}catch{}await new Promise(i=>setTimeout(i,200))}return c?{ok:!0,state:"started",ready:!0}:{ok:!1,error:`gateway did not report ready within 20s \u2014 see ${n}`}}function Bt(){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 Na=2e3,Ta=12e4,dr=new ir.Command("login").description("Log in to BadgerClaw via browser").action(async()=>{let e=Zo(),t=en(e),o=`${sn}/cli-auth?code=${t}`;console.log(V.default.yellow("Opening browser for authentication...")),console.log(V.default.dim(`If the browser doesn't open, visit: ${o}`)),await(0,lr.default)(o);let n=(0,cr.default)("Waiting for authentication...").start(),r=un(),s=Date.now();for(;Date.now()-s<Ta;){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(l=>setTimeout(l,5e3));continue}if(a.data?.access_token){let{access_token:l,user_id:c,expires_at:i,refresh_token:m,email:p}=a.data,P=to(),f=`openclaw-${Go.default.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${P}`,b=f;try{let{version:k}=be(),C=await r.post("/api/v1/openclaw/register",{instance_id:f,label:Go.default.hostname(),version:k,machine_fingerprint:P},{headers:{Authorization:`Bearer ${l}`}}),x=C.data?.result||C.data;x&&typeof x.instance_id=="string"&&x.instance_id.length>0&&(b=x.instance_id)}catch(k){let C=k?.response?.status;if(C===403||C===409){let x=k?.response?.data,z=Array.isArray(x?.errors)&&typeof x.errors[0]=="string"?x.errors[0]:null,Ve=x?.detail,mt=typeof Ve=="string"?Ve:Ve?.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,Xr=z||mt||`Login refused (status ${C}). Open the BadgerClaw app to check your subscription state.`;n.fail(V.default.red(Xr)),process.exit(1)}}if(gt({access_token:l,user_id:c,instance_id:b,expires_at:i,refresh_token:m,email:p}),n.succeed(V.default.green(`Logged in as ${ht(c)}`)),W()!==null){let k=await Lt({verbose:!0});k.ok?k.ready===!1&&console.log(V.default.dim(" Gateway is still coming up \u2014 it should be online shortly.")):console.log(V.default.yellow("\n \u26A0\uFE0F Logged in, but gateway failed to start. Re-run `badgerclaw setup` to repair."))}else console.log(V.default.dim(" Hermes-only host \u2014 skipping OpenClaw gateway bring-up."));let R=await et(!0);R>0&&console.log(V.default.green(`\u2705 ${R} bot(s) automatically paired to OpenClaw.`)),vo(),Bt();try{let{pushHeartbeat:k}=await Promise.resolve().then(()=>(Be(),Fo));await k(),console.log(V.default.dim(" Capabilities pushed \u2014 the machine should show online shortly."))}catch(k){console.log(V.default.dim(` Capability push will retry via the heartbeat (${k?.message||k}).`))}return}}catch{}await new Promise(a=>setTimeout(a,Na))}n.fail(V.default.red("Authentication timed out. Please try again.")),process.exit(1)});var mr=require("commander"),it=d(require("chalk")),Vt=d(require("fs")),je=d(require("os")),lt=d(require("path")),ct=require("child_process");L();he();function La(){let e=process.platform;if(e==="darwin"){let t=lt.default.join(je.default.homedir(),"Library","LaunchAgents","ai.badgerclaw.watch.plist");(0,ct.spawnSync)("launchctl",["unload",t],{stdio:"ignore"});try{Vt.default.unlinkSync(t)}catch{}}else if(e==="linux"){(0,ct.spawnSync)("systemctl",["--user","disable","--now","badgerclaw-watch.service"],{stdio:"ignore"});let t=lt.default.join(je.default.homedir(),".config","systemd","user","badgerclaw-watch.service");try{Vt.default.unlinkSync(t)}catch{}(0,ct.spawnSync)("systemctl",["--user","daemon-reload"],{stdio:"ignore"})}(0,ct.spawnSync)("pkill",["-f","badgerclaw heartbeat"],{stdio:"ignore"})}function ur(e){try{return Vt.default.rmSync(e,{recursive:!0,force:!0}),!0}catch{return!1}}var pr=new mr.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=w();if(t)try{let a=Ye(t.access_token),{version:l}=be();await a.post("/api/v1/openclaw/register",{instance_id:t.instance_id,label:je.default.hostname(),version:l,online:!1})}catch{}if(La(),e.keepState){qe(),console.log(it.default.green("Logged out \u2014 auth cleared. (state preserved with --keep-state)"));return}let o=lt.default.join(je.default.homedir(),".badgerclaw"),n=ur(o),r=lt.default.join(je.default.homedir(),".openclaw","badgerclaw"),s=ur(r);n||s?(console.log(it.default.green("Logged out \u2014 local state cleared.")),console.log(it.default.dim(` Removed: ${o}${s?`, ${r}`:""}`))):console.log(it.default.green("Logged out."))});var gr=require("commander"),Vo=d(require("chalk"));L();var fr=new gr.Command("status").description("Show connected instance info").action(async()=>{let e=w();(!e||!ft())&&(console.log(Vo.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1)),console.log(Vo.default.green("Authenticated")),console.log(` User: ${ht(e.user_id)}`),console.log(` Instance: ${e.instance_id}`),console.log(` Expires: ${new Date(e.expires_at).toLocaleDateString()}`)});var He=require("commander"),_=d(require("chalk")),Jt=d(require("ora")),Kt=d(require("fs")),Sr=d(require("os")),kr=d(require("path")),vr=require("child_process");L();he();var Me=d(require("fs")),hr=d(require("os")),yr=d(require("path")),wr=require("child_process");ze();function Wt(e){let t=e.split(":")[0].replace(/^@/,"").replace(/_bot$/,""),o=yr.join(hr.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(l=>l.id!==t),r.agents.list.length!==a&&(s=!0)}return s&&Me.writeFileSync(o,JSON.stringify(r,null,2)),s})}:{changed:!1}}function qt(){try{return(0,wr.execSync)("openclaw gateway restart",{stdio:"ignore"}),!0}catch{return!1}}_e();function br(e){return e.hermes?"hermes":"openclaw"}function _r(e){return e.openclaw.installed?"openclaw":e.hermes.installed?"hermes":"openclaw"}function qo(){ft()||(console.log(_.default.red("Not logged in. Run `badgerclaw login` to authenticate.")),process.exit(1))}function Ba(e){return/^[a-z0-9_]{4,20}$/.test(e)}function $r(e){return e.replace(/_bot$/,"")}var Wo=["openclaw","hermes"],ja=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: ${Wo.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)=>{qo(),Ba(e)||(console.log(_.default.red("Invalid bot name. Must be 4-20 characters, lowercase alphanumeric and underscores only.")),process.exit(1));let o=t.runtime??_r(le());Wo.includes(o)||(console.log(_.default.red(`Invalid --runtime "${t.runtime}". Must be one of: ${Wo.join(", ")}.`)),process.exit(1));let n=(0,Jt.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(_.default.green(`Bot "${e}" (${o}) created successfully!`)),o==="hermes"&&console.log(_.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(_.default.red(`Failed to create bot: ${s}`)),process.exit(1)}}),Ma=new He.Command("list").description("List your bots").action(async()=>{qo();let e=(0,Jt.default)("Fetching bots...").start();try{let n=(await O().get("/api/v1/openclaw/bots")).data?.bots||[];if(e.stop(),n.length===0){console.log(_.default.yellow("No bots found. Create one with `badgerclaw bot create <name>`."));return}console.log(_.default.green(`Your bots (${n.length}):
125
+ `));for(let r of n){let s=$r(r.username||r.name),a=r.active===!1?_.default.dim("deactivated"):r.openclaw_connected?_.default.green("connected"):_.default.gray("disconnected");console.log(` ${_.default.bold(s)} ${a}`)}}catch(t){let o=t.response?.data?.errors?.[0]||t.message;e.fail(_.default.red(`Failed to list bots: ${o}`)),process.exit(1)}}),Ha=new He.Command("delete").description("Deactivate a bot").argument("<name>","Bot name to deactivate").action(async e=>{qo();let t=(0,Jt.default)(`Deactivating bot "${e}"...`).start();try{await O().delete(`/api/v1/openclaw/bots/${e}`),t.succeed(_.default.green(`Bot "${e}" deactivated.`));let{changed:n}=Wt(e);n&&(console.log(_.default.dim(" Removed from openclaw.json")),qt()&&console.log(_.default.dim(" Gateway restarted")))}catch(o){let n=o.response?.data?.errors?.[0]||o.message;t.fail(_.default.red(`Failed to deactivate bot: ${n}`)),process.exit(1)}});function Ua(e){let t=e.trim();return t.startsWith("@")&&(t=t.slice(1)),t.includes(":")&&(t=t.split(":")[0]),$r(t)}function Fa(e){let t=e.replace(/[^a-zA-Z0-9_.-]/g,"_")||"default";return kr.default.join(Sr.default.homedir(),".openclaw","badgerclaw","quarantine",`${t}.json`)}var Ga=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=Ua(e);t||(console.log(_.default.red(`Couldn't parse bot name "${e}".`)),process.exit(1));let o=Fa(t),n=!1;if(Kt.default.existsSync(o))try{let r=JSON.parse(Kt.default.readFileSync(o,"utf-8")),s=r.failureCount??"?",a=r.quarantinedAt??"?";console.log(_.default.dim(` Quarantine for "${t}" \u2014 ${s} failures, since ${a}`)),Kt.default.unlinkSync(o),n=!0}catch(r){console.log(_.default.red(`Failed to clear quarantine ledger at ${o}: ${r.message}`)),process.exit(1)}console.log(n?_.default.green(`\u2705 Cleared quarantine for "${t}"`):_.default.dim(` No quarantine file for "${t}" \u2014 already healthy or never quarantined.`)),console.log(_.default.dim(" Restarting OpenClaw gateway so the refresh chain runs..."));try{(0,vr.execSync)("openclaw gateway restart",{stdio:"inherit"})}catch(r){console.log(_.default.yellow(` Gateway restart command failed: ${r.message}`)),console.log(_.default.yellow(" Run `openclaw gateway restart` manually.")),process.exit(1)}console.log(_.default.green(`
126
+ \u2705 Refresh triggered. Watch the gateway logs for token refresh progress:`)),console.log(_.default.dim(" tail -f ~/.openclaw/logs/*.log")),console.log(_.default.dim(" If the bot fails to recover, the plugin's 4 refresh strategies all hit")),console.log(_.default.dim(" dead ends. Verify SYNAPSE_REGISTRATION_SHARED_SECRET is set on this gateway,")),console.log(_.default.dim(" or re-pair the bot from the BadgerClaw iOS app."))}),Cr=new He.Command("bot").description("Manage bots").addCommand(ja).addCommand(Ma).addCommand(Ha).addCommand(Ga);tt();var Rr=require("commander"),y=d(require("chalk"));L();ae();tt();ue();Be();Ho();he();Re();var Ir=3e3,Va=6e4,Wa=2700*1e3,xr=new Rr.Command("watch").description("Watch for bot pair events in real-time (no polling)").action(async()=>{w()||(console.log(y.default.yellow("Not logged in.")),process.exit(1)),await et(!1),console.log(y.default.green("\u{1F534} Listening for pair events... (Ctrl+C to stop)"));let t=require("eventsource"),o=Ir,n=null,r=null,s=()=>{let a=w();a||(console.log(y.default.red(" Auth missing \u2014 run `badgerclaw login` and re-start `badgerclaw watch`.")),process.exit(1));let l=new t(`${H}/api/v1/openclaw/events`,{headers:{Authorization:`Bearer ${a.access_token}`}});r=l,l.onopen=()=>{o=Ir,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")),l.close(),s()},Wa)},l.onerror=()=>{l.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,Va)},l.onmessage=async c=>{try{let i=JSON.parse(c.data);if(i.type==="pair"){let m=i.target_instance_id;if(m&&m!==Q()){console.log(y.default.dim(`
127
127
  \u{1F4F1} Pair event for ${i.bot_name} targets ${m} \u2014 not us, skipping`));return}console.log(y.default.cyan(`
128
- \u{1F4F1} Pair event received: ${i.bot_name}`)),await qe(i.pair_code,i.bot_name,i.bot_user_id,!1);try{let{execSync:p}=await import("child_process");p("openclaw gateway restart",{stdio:"ignore"}),console.log(y.default.green(" \u2705 Gateway restarted \u2014 bot is live!"))}catch{console.log(y.default.dim(" Gateway restart failed \u2014 run: openclaw gateway restart"))}}else if(i.type==="gateway-restart"){console.log(y.default.cyan(`
129
- \u{1F504} Remote gateway-restart command received`));let m=await Ae();m.success?console.log(y.default.green(` \u2705 Gateway restarted: ${m.message}`)):console.log(y.default.red(` \u274C Gateway restart failed: ${m.message}`));try{await T(),console.log(y.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(y.default.dim(" Could not push heartbeat."))}}else if((i.type==="bot.delete"||i.type==="bot.disconnect")&&i.bot_user_id){let m=i.bot_user_id,p=i.type==="bot.delete"?"deleted":"disconnected",P=i.type==="bot.delete"?"\u{1F5D1}\uFE0F ":"\u{1F50C}";console.log(y.default.yellow(`
130
- ${P} Bot ${p}: ${m} \u2014 removing from OpenClaw config...`));try{let{changed:f}=Ht(m);f?(console.log(y.default.green(" \u2705 Removed from openclaw.json")),Ft()?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(f){console.log(y.default.red(` Failed to update openclaw.json: ${f}`))}}else if(i.type==="claude_code.start"&&i.bot_id&&i.room_id){console.log(y.default.cyan(`
131
- \u{1F916} Claude Code START received: bot=${i.bot_id} room=${i.room_id}`));try{let m=await ne({id:i.command_id||`cc-start-${Date.now()}`,command_type:"start_claude_code",payload:{bot_id:i.bot_id,room_id:i.room_id,session_id:i.session_id}});if(console.log(m.success?y.default.green(` \u2705 ${m.message}`):y.default.red(` \u274C ${m.message}`)),i.command_id)try{await O().post(`/api/v1/dashboard/commands/${i.command_id}/result`,{status:m.success?"success":"failed",result:m.message})}catch{}try{await T()}catch{}}catch(m){console.log(y.default.red(` Claude Code start error: ${m.message}`))}}else if(i.type==="claude_code.stop"&&i.bot_id&&i.room_id){console.log(y.default.cyan(`
132
- \u{1F916} Claude Code STOP received: bot=${i.bot_id} room=${i.room_id}`));try{let m=await ne({id:i.command_id||`cc-stop-${Date.now()}`,command_type:"stop_claude_code",payload:{bot_id:i.bot_id,room_id:i.room_id,session_id:i.session_id}});if(console.log(m.success?y.default.green(` \u2705 ${m.message}`):y.default.red(` \u274C ${m.message}`)),i.command_id)try{await O().post(`/api/v1/dashboard/commands/${i.command_id}/result`,{status:m.success?"success":"failed",result:m.message})}catch{}try{await T()}catch{}}catch(m){console.log(y.default.red(` Claude Code stop error: ${m.message}`))}}else if(i.type==="command.execute"&&i.command_id){console.log(y.default.cyan(`
133
- \u26A1 SSE command received: ${i.command_type} (${i.command_id})`));try{let m=O();await m.post(`/api/v1/dashboard/commands/${i.command_id}/ack`);let p=await ne({id:i.command_id,command_type:i.command_type,payload:i.payload});console.log(p.success?y.default.green(` \u2705 ${p.message}`):y.default.red(` \u274C ${p.message}`)),await m.post(`/api/v1/dashboard/commands/${i.command_id}/result`,{status:p.success?"success":"failed",result:p.message,new_version:p.newVersion||null});try{await T()}catch{}i.command_type==="update_cli"&&p.success&&(console.log(y.default.cyan(" CLI updated \u2014 restarting in 2s...")),setTimeout(()=>process.exit(0),2e3))}catch(m){console.log(y.default.red(` Command ${i.command_id} error: ${m.message}`))}}}catch{}}};s(),await new Promise(()=>{})});var Or=require("commander"),u=d(require("chalk")),Z=require("child_process"),I=d(require("fs")),st=d(require("os")),re=d(require("path"));se();Re();be();var Te=require("child_process"),kr=d(require("fs")),D=d(require("chalk")),F={alreadyUp:!1,install:null,start:null,requiresRoot:!1,networkHostRequired:!1,guidance:null},Sr='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 Da(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?Sr:"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?Sr:"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 vr(e,t,o=8e3){return(0,Te.spawnSync)(e,t,{encoding:"utf-8",timeout:o})}function Fo(){let e=vr("docker",["version","--format","{{.Server.Version}}"],4e3);return e.status===0&&!!(e.stdout||"").trim()}function Oa(){return vr("docker",["--version"],4e3).status===0}function Ne(e){return(0,Te.spawnSync)("sh",["-c",`command -v ${e}`],{encoding:"utf-8"}).status===0}function Na(){return Ne("apt-get")?"apt":Ne("dnf")?"dnf":Ne("yum")?"yum":null}function Ta(){let e=(0,Te.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 La(){return process.platform==="darwin"?"darwin":process.platform==="linux"?Ta()?"linux-systemd":"linux-nosystemd":"unsupported"}function ja(){return typeof process.getuid=="function"?process.getuid()===0:!1}function me(e,t){return t(D.default.dim(` $ ${e}`)),(0,Te.spawnSync)("sh",["-c",e],{stdio:"inherit"}).status===0}function Ba(e,t,o){let n=t?"sudo ":"";switch(e.via){case"brew":return o(D.default.dim(" Installing colima + docker CLI via Homebrew...")),me("brew install colima docker",o);case"apt":return o(D.default.dim(" Installing Docker via apt...")),me(`${n}apt-get update`,o),me(`${n}apt-get install -y docker.io`,o);default:return!1}}function Ma(e,t,o){let n=t?"sudo ":"";switch(e){case"docker-app":return me("open -a Docker",o);case"colima":return me("colima start",o);case"systemctl":return me(`${n}systemctl enable --now docker`,o);case"dockerd-restricted":{if(!Ne("dockerd"))return o(D.default.red(" \u274C `dockerd` is not installed (the docker CLI alone is not enough on a no-systemd host).")),!1;if(t&&!me("sudo -v",o))return o(D.default.red(" \u274C root is required to start dockerd here, but sudo is unavailable.")),!1;me(`${n}sh -c 'mount -t cgroup2 none /sys/fs/cgroup 2>/dev/null || true'`,o);let r="/tmp/badgerclaw-dockerd.log";o(D.default.dim(` Starting dockerd (restricted: --bridge=none --iptables=false) \u2192 ${r}`));let s=`nohup dockerd --storage-driver=overlay2 --iptables=false --bridge=none > ${r} 2>&1 &`,a=t?`sudo sh -c ${JSON.stringify(s)}`:`sh -c ${JSON.stringify(s)}`;return(0,Te.spawnSync)("sh",["-c",a],{stdio:"ignore"}).status===0}}}async function Ua(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 $r(e={}){let t=e.log??(a=>console.log(a));if(process.env.BADGERCLAW_NO_AUTO_DEPS==="1"){let a=Fo();return a||(t(D.default.yellow(" BADGERCLAW_NO_AUTO_DEPS=1 \u2014 skipping automatic Docker setup.")),t(D.default.dim(" Start the Docker daemon yourself, then re-run `badgerclaw setup --hermes`."))),{ok:a,daemonUp:a,networkHostRequired:!1}}let o={daemonUp:Fo(),binaryPresent:Oa(),host:La(),hasBrew:Ne("brew"),hasDockerApp:kr.default.existsSync("/Applications/Docker.app"),hasColima:Ne("colima"),pkgManager:Na(),isRoot:ja()},n=Da(o);if(n.alreadyUp)return{ok:!0,daemonUp:!0,networkHostRequired:!1};if(n.guidance)return t(D.default.red(` \u274C ${n.guidance}`)),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired};let r=n.requiresRoot&&!o.isRoot;return r&&t(D.default.dim(" (some steps need root \u2014 using sudo; you may be prompted for your password)")),n.install&&!Ba(n.install,r,t)?(t(D.default.red(" \u274C Docker install failed (see output above). Install it manually, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired}):Ma(n.start,r,t)?(t(D.default.dim(" Waiting for the Docker daemon to answer...")),await Ua(Fo,12e4,1500)?(t(D.default.green(" \u2705 Docker daemon is up.")),{ok:!0,daemonUp:!0,networkHostRequired:n.networkHostRequired}):(t(D.default.red(" \u274C Docker did not become ready in time.")),n.start==="dockerd-restricted"?t(D.default.dim(" Check /tmp/badgerclaw-dockerd.log for the daemon output.")):n.start==="docker-app"&&t(D.default.dim(" Docker Desktop can take a minute to boot \u2014 re-run once its menu-bar icon is steady.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired})):(t(D.default.red(" \u274C Could not start Docker (see output above). Resolve it, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired})}function Cr(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 Ir(e=process.versions.node){return parseInt(String(e).split(".")[0],10)}var Go=require("child_process"),Vt=d(require("fs")),Rr=d(require("os")),qt=d(require("path"));be();vt();function Ha(){let e=xr();for(let t of e)if(Vt.default.existsSync(t))return t;return null}function xr(){return[qt.default.resolve(__dirname,"..","assets","hermes-agent-bc.Dockerfile"),qt.default.resolve(__dirname,"..","..","assets","hermes-agent-bc.Dockerfile")]}var Fa="nousresearch/hermes-agent";function Ga(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`${Fa}:${o}`}var Wa={run:e=>{let t=(0,Go.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};function Va(e){return["build",...e.hostNetwork?["--network","host"]:[],...e.upstreamRef?["--build-arg",`UPSTREAM=${e.upstreamRef}`]:[],"-t",e.image,"-f",e.dockerfile,e.ctxDir]}function Ar(e){let t=yt();if(!t.installed)return{status:"no-docker"};let o=process.env.HERMES_IMAGE||xe;if(wt(t).installed)return{status:"already-present",image:o};let r=Ha();if(!r)return{status:"no-dockerfile",expectedPaths:xr()};let s=Ga(e),a=lo({bridgeUsable:()=>kt(Wa)}),l=Vt.default.mkdtempSync(qt.default.join(Rr.default.tmpdir(),"bc-hermes-build-"));try{let c=(0,Go.spawnSync)("docker",Va({hostNetwork:a,upstreamRef:s,image:o,dockerfile:r,ctxDir:l}),{stdio:"inherit",timeout:6e5});return c.status===0?{status:"built",image:o}:{status:"build-failed",image:o,stderr:`docker build exited ${c.status??"<no-status>"}`}}finally{try{Vt.default.rmSync(l,{recursive:!0,force:!0})}catch{}}}var K=re.default.join(st.default.homedir(),".openclaw","openclaw.json"),rt=K+".badgerclaw-stash",Nr=re.default.join(st.default.homedir(),".openclaw","npm"),qa=re.default.join(Nr,"package.json");async function Er(){try{let e=await fetch(`${U}/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 Ka(){if(!I.default.existsSync(K))return null;try{let e=JSON.parse(I.default.readFileSync(K,"utf-8")),t=e.channels?.badgerclaw;return t?(delete e.channels.badgerclaw,e.plugins?.entries?.badgerclaw&&delete e.plugins.entries.badgerclaw,I.default.writeFileSync(K,JSON.stringify(e,null,2)),I.default.writeFileSync(rt,JSON.stringify(t,null,2)),t):null}catch{return null}}function Ja(){if(!I.default.existsSync(K))return null;try{let e=JSON.parse(I.default.readFileSync(K,"utf-8"));return!e.gateway||typeof e.gateway!="object"?null:JSON.parse(JSON.stringify(e.gateway))}catch{return null}}function Ya(e){if(e&&I.default.existsSync(K))try{let t=JSON.parse(I.default.readFileSync(K,"utf-8"));t.gateway={...e,...t.gateway||{}},I.default.writeFileSync(K,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 za(){if(I.default.existsSync(rt))try{let e=JSON.parse(I.default.readFileSync(rt,"utf-8")),t=JSON.parse(I.default.readFileSync(K,"utf-8"));t.channels=t.channels||{},t.channels.badgerclaw=e,I.default.writeFileSync(K,JSON.stringify(t,null,2)),I.default.unlinkSync(rt)}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: ${rt}`))}}async function Pr(e){return new Promise(t=>{let o=(0,Z.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/,l=()=>{r||s||(r=!0,setTimeout(()=>{if(!s){try{o.kill("SIGTERM")}catch{}setTimeout(()=>{if(!s)try{o.kill("SIGKILL")}catch{}},1e3)}},3e3))},c=(i,m)=>{m.write(i),n+=i.toString("utf-8"),a.test(n)&&l()};o.stdout.on("data",i=>c(i,process.stdout)),o.stderr.on("data",i=>c(i,process.stderr)),o.on("exit",i=>{s=!0,t({status:r?0:i??1})}),o.on("error",i=>{s||(s=!0,console.error(u.default.red(` openclaw spawn error: ${i.message}`)),t({status:1}))})})}function Dr(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)+`
134
- `),!0):!1}function Xa(){let e=[];Dr(qa)&&e.push(Nr);for(let t of ft())Dr(re.default.join(t,"package.json"))&&e.push(t);return e}async function Qa(){let{detectCapabilities:e}=await Promise.resolve().then(()=>(be(),bn)),{pushHeartbeat:t}=await Promise.resolve().then(()=>(Ee(),jo));console.log(u.default.green(`
128
+ \u{1F4F1} Pair event received: ${i.bot_name}`)),await Ze(i.pair_code,i.bot_name,i.bot_user_id,!1);try{let{execSync:p}=await import("child_process");p("openclaw gateway restart",{stdio:"ignore"}),console.log(y.default.green(" \u2705 Gateway restarted \u2014 bot is live!"))}catch{console.log(y.default.dim(" Gateway restart failed \u2014 run: openclaw gateway restart"))}}else if(i.type==="gateway-restart"){console.log(y.default.cyan(`
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((i.type==="bot.delete"||i.type==="bot.disconnect")&&i.bot_user_id){let m=i.bot_user_id,p=i.type==="bot.delete"?"deleted":"disconnected",P=i.type==="bot.delete"?"\u{1F5D1}\uFE0F ":"\u{1F50C}";console.log(y.default.yellow(`
130
+ ${P} Bot ${p}: ${m} \u2014 removing from OpenClaw config...`));try{let{changed:f}=Wt(m);f?(console.log(y.default.green(" \u2705 Removed from openclaw.json")),qt()?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(f){console.log(y.default.red(` Failed to update openclaw.json: ${f}`))}}else if(i.type==="claude_code.start"&&i.bot_id&&i.room_id){console.log(y.default.cyan(`
131
+ \u{1F916} Claude Code START received: bot=${i.bot_id} room=${i.room_id}`));try{let m=await re({id:i.command_id||`cc-start-${Date.now()}`,command_type:"start_claude_code",payload:{bot_id:i.bot_id,room_id:i.room_id,session_id:i.session_id}});if(console.log(m.success?y.default.green(` \u2705 ${m.message}`):y.default.red(` \u274C ${m.message}`)),i.command_id)try{await O().post(`/api/v1/dashboard/commands/${i.command_id}/result`,{status:m.success?"success":"failed",result:m.message})}catch{}try{await T()}catch{}}catch(m){console.log(y.default.red(` Claude Code start error: ${m.message}`))}}else if(i.type==="claude_code.stop"&&i.bot_id&&i.room_id){console.log(y.default.cyan(`
132
+ \u{1F916} Claude Code STOP received: bot=${i.bot_id} room=${i.room_id}`));try{let m=await re({id:i.command_id||`cc-stop-${Date.now()}`,command_type:"stop_claude_code",payload:{bot_id:i.bot_id,room_id:i.room_id,session_id:i.session_id}});if(console.log(m.success?y.default.green(` \u2705 ${m.message}`):y.default.red(` \u274C ${m.message}`)),i.command_id)try{await O().post(`/api/v1/dashboard/commands/${i.command_id}/result`,{status:m.success?"success":"failed",result:m.message})}catch{}try{await T()}catch{}}catch(m){console.log(y.default.red(` Claude Code stop error: ${m.message}`))}}else if(i.type==="command.execute"&&i.command_id){console.log(y.default.cyan(`
133
+ \u26A1 SSE command received: ${i.command_type} (${i.command_id})`));try{let m=O();await m.post(`/api/v1/dashboard/commands/${i.command_id}/ack`);let p=await re({id:i.command_id,command_type:i.command_type,payload:i.payload});console.log(p.success?y.default.green(` \u2705 ${p.message}`):y.default.red(` \u274C ${p.message}`)),await m.post(`/api/v1/dashboard/commands/${i.command_id}/result`,{status:p.success?"success":"failed",result:p.message,new_version:p.newVersion||null});try{await T()}catch{}i.command_type==="update_cli"&&p.success&&(console.log(y.default.cyan(" CLI updated \u2014 restarting in 2s...")),setTimeout(()=>process.exit(0),2e3))}catch(m){console.log(y.default.red(` Command ${i.command_id} error: ${m.message}`))}}}catch{}}};s(),await new Promise(()=>{})});var Ur=require("commander"),u=d(require("chalk")),te=require("child_process"),I=d(require("fs")),ut=d(require("os")),se=d(require("path"));ae();Ae();_e();var Fe=require("child_process"),Er=d(require("fs")),D=d(require("chalk")),F={alreadyUp:!1,install:null,start:null,requiresRoot:!1,networkHostRequired:!1,guidance:null},Ar='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 qa(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?Ar:"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?Ar:"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 Pr(e,t,o=8e3){return(0,Fe.spawnSync)(e,t,{encoding:"utf-8",timeout:o})}function Ko(){let e=Pr("docker",["version","--format","{{.Server.Version}}"],4e3);return e.status===0&&!!(e.stdout||"").trim()}function Ka(){return Pr("docker",["--version"],4e3).status===0}function Ue(e){return(0,Fe.spawnSync)("sh",["-c",`command -v ${e}`],{encoding:"utf-8"}).status===0}function Ja(){return Ue("apt-get")?"apt":Ue("dnf")?"dnf":Ue("yum")?"yum":null}function Ya(){let e=(0,Fe.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 za(){return process.platform==="darwin"?"darwin":process.platform==="linux"?Ya()?"linux-systemd":"linux-nosystemd":"unsupported"}function Xa(){return typeof process.getuid=="function"?process.getuid()===0:!1}function pe(e,t){return t(D.default.dim(` $ ${e}`)),(0,Fe.spawnSync)("sh",["-c",e],{stdio:"inherit"}).status===0}function Qa(e,t,o){let n=t?"sudo ":"";switch(e.via){case"brew":return o(D.default.dim(" Installing colima + docker CLI via Homebrew...")),pe("brew install colima docker",o);case"apt":return o(D.default.dim(" Installing Docker via apt...")),pe(`${n}apt-get update`,o),pe(`${n}apt-get install -y docker.io`,o);default:return!1}}function Za(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(!Ue("dockerd"))return o(D.default.red(" \u274C `dockerd` is not installed (the docker CLI alone is not enough on a no-systemd host).")),!1;if(t&&!pe("sudo -v",o))return o(D.default.red(" \u274C root is required to start dockerd here, but sudo is unavailable.")),!1;pe(`${n}sh -c 'mount -t cgroup2 none /sys/fs/cgroup 2>/dev/null || true'`,o);let r="/tmp/badgerclaw-dockerd.log";o(D.default.dim(` Starting dockerd (restricted: --bridge=none --iptables=false) \u2192 ${r}`));let s=`nohup dockerd --storage-driver=overlay2 --iptables=false --bridge=none > ${r} 2>&1 &`,a=t?`sudo sh -c ${JSON.stringify(s)}`:`sh -c ${JSON.stringify(s)}`;return(0,Fe.spawnSync)("sh",["-c",a],{stdio:"ignore"}).status===0}}}async function ei(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 Dr(e={}){let t=e.log??(a=>console.log(a));if(process.env.BADGERCLAW_NO_AUTO_DEPS==="1"){let a=Ko();return a||(t(D.default.yellow(" BADGERCLAW_NO_AUTO_DEPS=1 \u2014 skipping automatic Docker setup.")),t(D.default.dim(" Start the Docker daemon yourself, then re-run `badgerclaw setup --hermes`."))),{ok:a,daemonUp:a,networkHostRequired:!1}}let o={daemonUp:Ko(),binaryPresent:Ka(),host:za(),hasBrew:Ue("brew"),hasDockerApp:Er.default.existsSync("/Applications/Docker.app"),hasColima:Ue("colima"),pkgManager:Ja(),isRoot:Xa()},n=qa(o);if(n.alreadyUp)return{ok:!0,daemonUp:!0,networkHostRequired:!1};if(n.guidance)return t(D.default.red(` \u274C ${n.guidance}`)),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired};let r=n.requiresRoot&&!o.isRoot;return r&&t(D.default.dim(" (some steps need root \u2014 using sudo; you may be prompted for your password)")),n.install&&!Qa(n.install,r,t)?(t(D.default.red(" \u274C Docker install failed (see output above). Install it manually, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired}):Za(n.start,r,t)?(t(D.default.dim(" Waiting for the Docker daemon to answer...")),await ei(Ko,12e4,1500)?(t(D.default.green(" \u2705 Docker daemon is up.")),{ok:!0,daemonUp:!0,networkHostRequired:n.networkHostRequired}):(t(D.default.red(" \u274C Docker did not become ready in time.")),n.start==="dockerd-restricted"?t(D.default.dim(" Check /tmp/badgerclaw-dockerd.log for the daemon output.")):n.start==="docker-app"&&t(D.default.dim(" Docker Desktop can take a minute to boot \u2014 re-run once its menu-bar icon is steady.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired})):(t(D.default.red(" \u274C Could not start Docker (see output above). Resolve it, then re-run.")),{ok:!1,daemonUp:!1,networkHostRequired:n.networkHostRequired})}function Or(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 Nr(e=process.versions.node){return parseInt(String(e).split(".")[0],10)}var Jo=require("child_process"),Yt=d(require("fs")),Tr=d(require("os")),zt=d(require("path"));_e();At();function ti(){let e=Lr();for(let t of e)if(Yt.default.existsSync(t))return t;return null}function Lr(){return[zt.default.resolve(__dirname,"..","assets","hermes-agent-bc.Dockerfile"),zt.default.resolve(__dirname,"..","..","assets","hermes-agent-bc.Dockerfile")]}var oi="nousresearch/hermes-agent";function ni(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`${oi}:${o}`}var ri={run:e=>{let t=(0,Jo.spawnSync)("docker",e,{encoding:"utf-8"});return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||""}}};function si(e){return["build",...e.hostNetwork?["--network","host"]:[],...e.upstreamRef?["--build-arg",`UPSTREAM=${e.upstreamRef}`]:[],"-t",e.image,"-f",e.dockerfile,e.ctxDir]}function Br(e){let t=vt();if(!t.installed)return{status:"no-docker"};let o=process.env.HERMES_IMAGE||Ee;if($t(t).installed)return{status:"already-present",image:o};let r=ti();if(!r)return{status:"no-dockerfile",expectedPaths:Lr()};let s=ni(e),a=go({bridgeUsable:()=>xt(ri)}),l=Yt.default.mkdtempSync(zt.default.join(Tr.default.tmpdir(),"bc-hermes-build-"));try{let c=(0,Jo.spawnSync)("docker",si({hostNetwork:a,upstreamRef:s,image:o,dockerfile:r,ctxDir:l}),{stdio:"inherit",timeout:6e5});return c.status===0?{status:"built",image:o}:{status:"build-failed",image:o,stderr:`docker build exited ${c.status??"<no-status>"}`}}finally{try{Yt.default.rmSync(l,{recursive:!0,force:!0})}catch{}}}L();var Y=se.default.join(ut.default.homedir(),".openclaw","openclaw.json"),dt=Y+".badgerclaw-stash",Fr=se.default.join(ut.default.homedir(),".openclaw","npm"),ai=se.default.join(Fr,"package.json");async function jr(){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 ii(){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(dt,JSON.stringify(t,null,2)),t):null}catch{return null}}function ci(){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 li(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 di(){if(I.default.existsSync(dt))try{let e=JSON.parse(I.default.readFileSync(dt,"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(dt)}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: ${dt}`))}}async function Mr(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/,l=()=>{r||s||(r=!0,setTimeout(()=>{if(!s){try{o.kill("SIGTERM")}catch{}setTimeout(()=>{if(!s)try{o.kill("SIGKILL")}catch{}},1e3)}},3e3))},c=(i,m)=>{m.write(i),n+=i.toString("utf-8"),a.test(n)&&l()};o.stdout.on("data",i=>c(i,process.stdout)),o.stderr.on("data",i=>c(i,process.stderr)),o.on("exit",i=>{s=!0,t({status:r?0:i??1})}),o.on("error",i=>{s||(s=!0,console.error(u.default.red(` openclaw spawn error: ${i.message}`)),t({status:1}))})})}function Hr(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)+`
134
+ `),!0):!1}function ui(){let e=[];Hr(ai)&&e.push(Fr);for(let t of St())Hr(se.default.join(t,"package.json"))&&e.push(t);return e}async function mi(){let{detectCapabilities:e}=await Promise.resolve().then(()=>(_e(),$n)),{pushHeartbeat:t}=await Promise.resolve().then(()=>(Be(),Fo));console.log(u.default.green(`
135
135
  \u{1F9A1} BadgerClaw \u2014 capability refresh
136
- `));let o=e();console.log(u.default.dim(" Detected on this host:")),console.log(u.default.dim(` OpenClaw : ${Wo(o.openclaw)}`)),console.log(u.default.dim(` Hermes : ${Wo(o.hermes)}`)),console.log(u.default.dim(` Docker : ${Wo(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(`
136
+ `));let o=e();console.log(u.default.dim(" Detected on this host:")),console.log(u.default.dim(` OpenClaw : ${Yo(o.openclaw)}`)),console.log(u.default.dim(` Hermes : ${Yo(o.hermes)}`)),console.log(u.default.dim(` Docker : ${Yo(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(`
137
137
  \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(`
138
138
  \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(`
139
- \u274C Failed to push capabilities: ${r}`)),process.exit(1)}}function Wo(e){return e.installed?e.version?`installed (${e.version})`:e.image?`installed (${e.image})`:"installed":"not installed"}var Tr=new Or.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 Qa();return}if(console.log(u.default.green(`
139
+ \u274C Failed to push capabilities: ${r}`)),process.exit(1)}}function Yo(e){return e.installed?e.version?`installed (${e.version})`:e.image?`installed (${e.image})`:"installed":"not installed"}var Gr=new Ur.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 mi();return}if(console.log(u.default.green(`
140
140
  \u{1F9A1} BadgerClaw Setup
141
- `)),ur({hermes:e.hermes})==="hermes"){let f=Cr({nodeMajor:Ir(),npmPresent:(0,Z.spawnSync)("sh",["-c","command -v npm"],{encoding:"utf-8"}).status===0});f&&(console.log(u.default.red(`
142
- \u274C ${f}`)),process.exit(1));let w=ce();if(console.log(u.default.dim(` Detected: Docker ${w.docker.installed?"running":"not running"}, Hermes image ${w.hermes.installed?"present":"absent"}.`)),console.log(u.default.dim(` Selected runtime: ${u.default.cyan("hermes")} (via --hermes flag)
143
- `)),!w.docker.installed){console.log(u.default.dim(" Docker is not ready \u2014 bootstrapping it for the Hermes runtime..."));let A=await $r({log:k=>console.log(k)});A.ok||(console.log(u.default.red(`
144
- \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)),A.networkHostRequired&&console.log(u.default.dim(" \u24D8 No Docker bridge on this host \u2014 Hermes bots will use host networking automatically at pair time.")),w=ce()}if(w.disk_free_gb!==null&&w.disk_free_gb<6&&console.log(u.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(u.default.dim(` Hermes image already present: ${w.hermes.image}`));else{let A=(await Er()).hermes;A&&console.log(u.default.dim(` Pinned Hermes upstream: ${A}`)),console.log(u.default.dim(" Building Hermes image (one-time, ~2 min)..."));let k=Ar({upstream:A});k.status==="built"?console.log(u.default.green(` \u2705 Hermes image built: ${k.image}`)):k.status==="already-present"?console.log(u.default.dim(` Hermes image already present: ${k.image}`)):k.status==="no-dockerfile"?(console.log(u.default.red(`
141
+ `)),br({hermes:e.hermes})==="hermes"){let f=Or({nodeMajor:Nr(),npmPresent:(0,te.spawnSync)("sh",["-c","command -v npm"],{encoding:"utf-8"}).status===0});f&&(console.log(u.default.red(`
142
+ \u274C ${f}`)),process.exit(1));let b=le();if(console.log(u.default.dim(` Detected: Docker ${b.docker.installed?"running":"not running"}, Hermes image ${b.hermes.installed?"present":"absent"}.`)),console.log(u.default.dim(` Selected runtime: ${u.default.cyan("hermes")} (via --hermes flag)
143
+ `)),!b.docker.installed){console.log(u.default.dim(" Docker is not ready \u2014 bootstrapping it for the Hermes runtime..."));let R=await Dr({log:k=>console.log(k)});R.ok||(console.log(u.default.red(`
144
+ \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)),R.networkHostRequired&&console.log(u.default.dim(" \u24D8 No Docker bridge on this host \u2014 Hermes bots will use host networking automatically at pair time.")),b=le()}if(b.disk_free_gb!==null&&b.disk_free_gb<6&&console.log(u.default.yellow(` \u26A0\uFE0F Low disk: ${b.disk_free_gb} GB free \u2014 the Hermes image build needs ~5 GB and may fail if it runs out.`)),b.hermes.installed)console.log(u.default.dim(` Hermes image already present: ${b.hermes.image}`));else{let R=(await jr()).hermes;R&&console.log(u.default.dim(` Pinned Hermes upstream: ${R}`)),console.log(u.default.dim(" Building Hermes image (one-time, ~2 min)..."));let k=Br({upstream:R});k.status==="built"?console.log(u.default.green(` \u2705 Hermes image built: ${k.image}`)):k.status==="already-present"?console.log(u.default.dim(` Hermes image already present: ${k.image}`)):k.status==="no-dockerfile"?(console.log(u.default.red(`
145
145
  \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: ${k.expectedPaths.join(", ")}`)),process.exit(1)):k.status==="build-failed"?(console.log(u.default.red(`
146
146
  \u274C Hermes image build failed: ${k.stderr}`)),console.log(u.default.dim(" See the docker output above for details.")),process.exit(1)):k.status==="no-docker"&&(console.log(u.default.red(`
147
147
  \u274C Docker is not running.`)),process.exit(1))}console.log(u.default.dim(`
148
+ Cleaning up heartbeat hooks from previous installs...`)),Kn({loggedIn:w()!==null,log:R=>console.log(u.default.dim(` ${R}`))}),console.log(u.default.dim(`
148
149
  Hermes-only mode \u2014 skipping OpenClaw plugin + gateway install.
149
150
  To enable OC bots later, drop the --hermes flag: \`badgerclaw setup\`.
150
- `)),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 Er();if(o.cli){let f=ro();f!==o.cli?(console.log(u.default.dim(` Updating CLI: ${f} \u2192 ${o.cli} (supported)...`)),(0,Z.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=V();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,Z.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 V()===null&&(console.log(u.default.yellow(" \u26A0\uFE0F No approved OpenClaw version and none installed \u2014 installing latest from npm.")),(0,Z.spawnSync)("npm",["install","-g","openclaw"],{stdio:"inherit",shell:!0}).status!==0&&(console.log(u.default.red(`
151
- \u274C OpenClaw install failed.`)),process.exit(1)));let n=Ka();n&&console.log(u.default.dim(" Existing bot config stashed temporarily..."));let r=Ja();(0,Z.spawnSync)("openclaw",["gateway","stop"],{stdio:"pipe",shell:!0,timeout:1e4});let s=[re.default.join(st.default.homedir(),".openclaw","extensions","badgerclaw"),re.default.join(st.default.homedir(),".openclaw","npm","node_modules","@badgerclaw","connect"),...ft()],a=[],l=[],c=f=>{let w=`${f}.bc-setup-stash-${Date.now()}-${Math.floor(Math.random()*1e6)}`,A=(0,Z.spawnSync)("mv",["-f",f,w],{encoding:"utf-8"});return A.status===0?{ok:!0,stash:w}:{ok:!1,error:(A.stderr||"").trim()||`exit ${A.status}`}};for(let f of s)if(I.default.existsSync(f))try{I.default.rmSync(f,{recursive:!0,force:!0}),a.push(f)}catch(w){let A=c(f);A.ok?(l.push(`${f} \u2192 ${A.stash}`),console.log(u.default.yellow(` \u26A0\uFE0F Could not delete ${f} (${w.message}); renamed it aside instead.`))):(console.log(u.default.red(` \u274C Could not delete ${f} (${w.message})`)),console.log(u.default.red(` Could not rename ${f} aside either (${A.error}). Plugin install will likely fail.`)))}a.length>0&&console.log(u.default.dim(` Cleared existing plugin director${a.length>1?"ies":"y"}.`)),l.length>0&&console.log(u.default.dim(` Renamed busy install${l.length>1?"s":""} aside: ${l.join(", ")}`));let i=o.plugin?`@badgerclaw/connect@${o.plugin}`:"@badgerclaw/connect";o.plugin?console.log(u.default.dim(` Installing ${i} (supported)...`)):console.log(u.default.yellow(" \u26A0\uFE0F Allow-list unavailable \u2014 installing @badgerclaw/connect unpinned."));let m=await Pr(i);if(m.status===0&&o.plugin&&o.plugin!=="unknown"){for(let w=1;w<=2&&!(ht()===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 ${w}/2)...`)),m=await Pr(i),m.status!==0));w++);m.status===0&&ht()!==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&&(za(),console.log(u.default.dim(" Bot config restored."))),r&&(Ya(r),console.log(u.default.dim(" Gateway config restored."))),m.status!==0&&(console.log(u.default.red(`
151
+ `)),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 jr();if(o.cli){let f=co();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=W();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 W()===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(`
152
+ \u274C OpenClaw install failed.`)),process.exit(1)));let n=ii();n&&console.log(u.default.dim(" Existing bot config stashed temporarily..."));let r=ci();(0,te.spawnSync)("openclaw",["gateway","stop"],{stdio:"pipe",shell:!0,timeout:1e4});let s=[se.default.join(ut.default.homedir(),".openclaw","extensions","badgerclaw"),se.default.join(ut.default.homedir(),".openclaw","npm","node_modules","@badgerclaw","connect"),...St()],a=[],l=[],c=f=>{let b=`${f}.bc-setup-stash-${Date.now()}-${Math.floor(Math.random()*1e6)}`,R=(0,te.spawnSync)("mv",["-f",f,b],{encoding:"utf-8"});return R.status===0?{ok:!0,stash:b}:{ok:!1,error:(R.stderr||"").trim()||`exit ${R.status}`}};for(let f of s)if(I.default.existsSync(f))try{I.default.rmSync(f,{recursive:!0,force:!0}),a.push(f)}catch(b){let R=c(f);R.ok?(l.push(`${f} \u2192 ${R.stash}`),console.log(u.default.yellow(` \u26A0\uFE0F Could not delete ${f} (${b.message}); renamed it aside instead.`))):(console.log(u.default.red(` \u274C Could not delete ${f} (${b.message})`)),console.log(u.default.red(` Could not rename ${f} aside either (${R.error}). Plugin install will likely fail.`)))}a.length>0&&console.log(u.default.dim(` Cleared existing plugin director${a.length>1?"ies":"y"}.`)),l.length>0&&console.log(u.default.dim(` Renamed busy install${l.length>1?"s":""} aside: ${l.join(", ")}`));let i=o.plugin?`@badgerclaw/connect@${o.plugin}`:"@badgerclaw/connect";o.plugin?console.log(u.default.dim(` Installing ${i} (supported)...`)):console.log(u.default.yellow(" \u26A0\uFE0F Allow-list unavailable \u2014 installing @badgerclaw/connect unpinned."));let m=await Mr(i);if(m.status===0&&o.plugin&&o.plugin!=="unknown"){for(let b=1;b<=2&&!(kt()===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 ${b}/2)...`)),m=await Mr(i),m.status!==0));b++);m.status===0&&kt()!==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&&(di(),console.log(u.default.dim(" Bot config restored."))),r&&(li(r),console.log(u.default.dim(" Gateway config restored."))),m.status!==0&&(console.log(u.default.red(`
152
153
  \u274C Plugin install failed. Your bot config has been restored.`)),process.exit(1)),console.log(u.default.green(`
153
- \u2705 BadgerClaw plugin installed successfully!`));let p=Xa();for(let f of p){console.log(u.default.dim(` Stripping OpenClaw uuid:14 override in ${f} (breaks request@2.88 in matrix-bot-sdk)...`));try{I.default.rmSync(re.default.join(f,"node_modules","uuid"),{recursive:!0,force:!0})}catch{}try{I.default.rmSync(re.default.join(f,"package-lock.json"),{force:!0})}catch{}(0,Z.spawnSync)("npm",["install"],{cwd:f,stdio:"inherit",shell:!0}).status!==0&&(console.log(u.default.red(`
154
- \u274C npm install failed after removing uuid override. Bot will not reply correctly until this is resolved.`)),process.exit(1))}p.length>0&&console.log(u.default.green(" \u2705 uuid override stripped + npm tree re-resolved.")),console.log("");let P=await Dt({verbose:!0});P.ok||(console.log(u.default.red(`
155
- \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)),P.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.")),Ot()});Ee();var jr=require("commander"),x=d(require("chalk"));M();Ce();de();var Br=new jr.Command("dashboard").description("Show local diagnostic dashboard \u2014 machine health, gateway status, bot telemetry").action(async()=>{S()||(console.log(x.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=we(),o=ut(),n=await Ze();console.log(x.default.bold.green(`
154
+ \u2705 BadgerClaw plugin installed successfully!`));let p=ui();for(let f of p){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(`
155
+ \u274C npm install failed after removing uuid override. Bot will not reply correctly until this is resolved.`)),process.exit(1))}p.length>0&&console.log(u.default.green(" \u2705 uuid override stripped + npm tree re-resolved.")),console.log("");let P=await Lt({verbose:!0});P.ok||(console.log(u.default.red(`
156
+ \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)),P.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.")),Bt()});Be();var Wr=require("commander"),A=d(require("chalk"));L();Re();ue();var qr=new Wr.Command("dashboard").description("Show local diagnostic dashboard \u2014 machine health, gateway status, bot telemetry").action(async()=>{w()||(console.log(A.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let{version:t}=be(),o=yt(),n=await st();console.log(A.default.bold.green(`
156
157
  BadgerClaw Dashboard
157
- `)),console.log(x.default.bold(" Instance")),console.log(` ID: ${z()}`),console.log(` CLI Version: ${t}`),console.log(` Plugin: ${n.pluginVersion}`),console.log(),console.log(x.default.bold(" Machine")),console.log(` Hostname: ${o.hostname}`),console.log(` OS: ${o.os} / ${o.arch}`),console.log(` Uptime: ${Lr(o.uptimeSeconds)}`),console.log(` Free Memory: ${o.memFreeMb} MB`),console.log();let r=n.status==="running"?x.default.green:n.status==="error"?x.default.red:x.default.yellow;if(console.log(x.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(x.default.bold(" Bots")),console.log(x.default.dim(" No bots detected. Pair bots at https://badgerclaw.ai")),console.log();else{console.log(x.default.bold(` Bots (${n.bots.length})`)),console.log();for(let s of n.bots){let a=s.status==="running"?x.default.green:s.status==="error"?x.default.red:x.default.yellow;if(console.log(` ${x.default.bold(s.botUsername)} ${a(`[${s.status}]`)}`),console.log(` ID: ${s.botId}`),console.log(` Uptime: ${Lr(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: ${x.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(x.default.dim(" Rooms:"));for(let l of s.roomDetails)console.log(x.default.dim(` ${l.roomName} \u2014 ${l.messagesInRoom} msgs, last: ${l.lastActivityInRoom??"N/A"}`))}console.log()}}console.log(x.default.dim(` Last checked: ${new Date().toISOString()}`)),console.log()});function Lr(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 Vo=require("commander"),Le=d(require("chalk")),Mr=d(require("ora"));M();de();Ee();var Za=new Vo.Command("restart").description("Restart the OpenClaw gateway via the plugin probe endpoint").action(async()=>{S()||(console.log(Le.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,Mr.default)("Restarting gateway...").start(),o=await Ae();if(o.success){t.succeed(Le.default.green(`Gateway restarted: ${o.message}`));try{await T(),console.log(Le.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(Le.default.dim(" Could not push heartbeat \u2014 daemon may not be running."))}}else t.fail(Le.default.red(`Gateway restart failed: ${o.message}`)),process.exit(1)}),Ur=new Vo.Command("gateway").description("Manage the OpenClaw gateway").addCommand(Za);var ge=require("commander"),_=d(require("chalk")),$e=d(require("ora")),pe=d(require("axios"));Lt();M();var ve="http://localhost:7331",ei=new ge.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=>{S()||(console.log(_.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,$e.default)("Starting Claude Code session...").start();try{await pe.default.post(`${ve}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:o},{timeout:1e4}),s.text="Gateway toggled \u2014 launching MCP server...";let l=xo({sessionId:o,port:n,projectDir:r}).pid||0;await new Promise(c=>setTimeout(c,1500)),s.text="MCP server running \u2014 launching Claude Code...",Ao({sessionId:o,port:n,projectDir:r}),Eo(o,0,l,n,r),s.succeed(_.default.green("Claude Code session started")+_.default.dim(` (session: ${o}, port: ${n})`)),console.log(_.default.dim(` Bot: ${e.bot}`)),console.log(_.default.dim(` Room: ${e.room}`)),console.log(_.default.dim(` Project: ${r}`)),console.log(_.default.dim(" Claude Code should open in a new terminal window."))}catch(a){let l=a.response?.data?.message||a.message||"Unknown error";s.fail(_.default.red(`Failed to start Claude Code: ${l}`)),process.exit(1)}}),ti=new ge.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=>{S()||(console.log(_.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let o=(0,$e.default)("Stopping Claude Code session...").start();try{e.bot&&e.room&&await pe.default.post(`${ve}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!1},{timeout:1e4});let n=e.sessionId;if(!n)try{let a=((await pe.default.get(`${ve}/claude-code/status`,{timeout:5e3})).data?.rooms||[]).find(l=>l.botId===e.bot&&l.roomId===e.room);a&&(n=a.sessionId)}catch{}n?(Po(n),o.succeed(_.default.green(`Claude Code session stopped (${n})`))):(o.succeed(_.default.green("Claude Code toggled off at gateway")),console.log(_.default.dim(" No local session found to kill \u2014 may need to close Claude Code manually.")))}catch(n){let r=n.response?.data?.message||n.message||"Unknown error";o.fail(_.default.red(`Failed to stop Claude Code: ${r}`)),process.exit(1)}}),oi=new ge.Command("status").description("Show active Claude Code sessions").action(async()=>{S()||(console.log(_.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,$e.default)("Fetching Claude Code status...").start();try{let o=[];try{o=(await pe.default.get(`${ve}/claude-code/status`,{timeout:5e3})).data?.rooms||[]}catch{}let n=Do();if(t.stop(),o.length===0&&n.length===0){console.log(_.default.dim("No active Claude Code sessions."));return}if(o.length>0){console.log(_.default.bold(`
158
- Gateway Claude Code Rooms:`)),console.log(_.default.dim(" Bot".padEnd(30)+"Room".padEnd(30)+"Session".padEnd(20)+"Enabled")),console.log(_.default.dim(" "+"-".repeat(88)));for(let r of o){let s=r.enabled?_.default.green("ON"):_.default.dim("OFF");console.log(` ${(r.botId||"").padEnd(30)}${(r.roomName||r.roomId||"").padEnd(30)}${(r.sessionId||"-").padEnd(20)}${s}`)}}if(n.length>0){console.log(_.default.bold(`
159
- Local Sessions:`)),console.log(_.default.dim(" Session".padEnd(25)+"Port".padEnd(8)+"MCP PID".padEnd(10)+"Project".padEnd(40)+"Started")),console.log(_.default.dim(" "+"-".repeat(90)));for(let r of 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(_.default.red(`Failed to get status: ${o.message}`)),process.exit(1)}}),ni=new ge.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,$e.default)("Grouping bot+room into session...").start();try{await pe.default.post(`${ve}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:e.session},{timeout:1e4}),t.succeed(_.default.green(`Grouped ${e.bot} + ${e.room} into session "${e.session}"`))}catch(o){let n=o.response?.data?.message||o.message||"Unknown error";t.fail(_.default.red(`Failed to group: ${n}`)),process.exit(1)}}),ri=new ge.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,$e.default)("Adding user to allowlist...").start();try{await pe.default.post(`${ve}/claude-code/allow`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(_.default.green(`Added ${e.user} to allowlist for ${e.bot} in ${e.room}`))}catch(o){let n=o.response?.data?.message||o.message||"Unknown error";t.fail(_.default.red(`Failed to add user: ${n}`)),process.exit(1)}}),si=new ge.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,$e.default)("Removing user from allowlist...").start();try{await pe.default.post(`${ve}/claude-code/revoke`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(_.default.green(`Removed ${e.user} from allowlist for ${e.bot} in ${e.room}`))}catch(o){let n=o.response?.data?.message||o.message||"Unknown error";t.fail(_.default.red(`Failed to revoke user: ${n}`)),process.exit(1)}}),Hr=new ge.Command("claude-code").description("Manage Claude Code sessions (relay Matrix messages to local Claude Code)").addCommand(ei).addCommand(ti).addCommand(oi).addCommand(ni).addCommand(ri).addCommand(si);Re();async function ai(){await gn(process.argv);let e=new Fr.Command;e.name("badgerclaw").description("BadgerClaw CLI \u2014 one-click bot provisioning").version("0.2.66"),e.addCommand(or),e.addCommand(sr),e.addCommand(ir),e.addCommand(yr),e.addCommand(Pn),e.addCommand(_r),e.addCommand(Tr),e.addCommand(Lo),e.addCommand(Br),e.addCommand(Ur),e.addCommand(Hr),e.parse(process.argv)}ai().catch(e=>{console.error(e),process.exit(1)});
158
+ `)),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: ${Vr(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: ${Vr(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 l of s.roomDetails)console.log(A.default.dim(` ${l.roomName} \u2014 ${l.messagesInRoom} msgs, last: ${l.lastActivityInRoom??"N/A"}`))}console.log()}}console.log(A.default.dim(` Last checked: ${new Date().toISOString()}`)),console.log()});function Vr(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 zo=require("commander"),Ge=d(require("chalk")),Kr=d(require("ora"));L();ue();Be();var pi=new zo.Command("restart").description("Restart the OpenClaw gateway via the plugin probe endpoint").action(async()=>{w()||(console.log(Ge.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,Kr.default)("Restarting gateway...").start(),o=await Le();if(o.success){t.succeed(Ge.default.green(`Gateway restarted: ${o.message}`));try{await T(),console.log(Ge.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(Ge.default.dim(" Could not push heartbeat \u2014 daemon may not be running."))}}else t.fail(Ge.default.red(`Gateway restart failed: ${o.message}`)),process.exit(1)}),Jr=new zo.Command("gateway").description("Manage the OpenClaw gateway").addCommand(pi);var fe=require("commander"),S=d(require("chalk")),Ie=d(require("ora")),ge=d(require("axios"));Ht();L();var Ce="http://localhost:7331",gi=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=>{w()||(console.log(S.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 l=Oo({sessionId:o,port:n,projectDir:r}).pid||0;await new Promise(c=>setTimeout(c,1500)),s.text="MCP server running \u2014 launching Claude Code...",No({sessionId:o,port:n,projectDir:r}),To(o,0,l,n,r),s.succeed(S.default.green("Claude Code session started")+S.default.dim(` (session: ${o}, port: ${n})`)),console.log(S.default.dim(` Bot: ${e.bot}`)),console.log(S.default.dim(` Room: ${e.room}`)),console.log(S.default.dim(` Project: ${r}`)),console.log(S.default.dim(" Claude Code should open in a new terminal window."))}catch(a){let l=a.response?.data?.message||a.message||"Unknown error";s.fail(S.default.red(`Failed to start Claude Code: ${l}`)),process.exit(1)}}),fi=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=>{w()||(console.log(S.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(l=>l.botId===e.bot&&l.roomId===e.room);a&&(n=a.sessionId)}catch{}n?(Lo(n),o.succeed(S.default.green(`Claude Code session stopped (${n})`))):(o.succeed(S.default.green("Claude Code toggled off at gateway")),console.log(S.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(S.default.red(`Failed to stop Claude Code: ${r}`)),process.exit(1)}}),hi=new fe.Command("status").description("Show active Claude Code sessions").action(async()=>{w()||(console.log(S.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=Bo();if(t.stop(),o.length===0&&n.length===0){console.log(S.default.dim("No active Claude Code sessions."));return}if(o.length>0){console.log(S.default.bold(`
159
+ Gateway Claude Code Rooms:`)),console.log(S.default.dim(" Bot".padEnd(30)+"Room".padEnd(30)+"Session".padEnd(20)+"Enabled")),console.log(S.default.dim(" "+"-".repeat(88)));for(let r of o){let s=r.enabled?S.default.green("ON"):S.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(S.default.bold(`
160
+ Local Sessions:`)),console.log(S.default.dim(" Session".padEnd(25)+"Port".padEnd(8)+"MCP PID".padEnd(10)+"Project".padEnd(40)+"Started")),console.log(S.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(S.default.red(`Failed to get status: ${o.message}`)),process.exit(1)}}),yi=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(S.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(S.default.red(`Failed to group: ${n}`)),process.exit(1)}}),wi=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(S.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(S.default.red(`Failed to add user: ${n}`)),process.exit(1)}}),bi=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(S.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(S.default.red(`Failed to revoke user: ${n}`)),process.exit(1)}}),Yr=new fe.Command("claude-code").description("Manage Claude Code sessions (relay Matrix messages to local Claude Code)").addCommand(gi).addCommand(fi).addCommand(hi).addCommand(yi).addCommand(wi).addCommand(bi);Ae();async function _i(){await bn(process.argv);let e=new zr.Command;e.name("badgerclaw").description("BadgerClaw CLI \u2014 one-click bot provisioning").version("0.2.67"),e.addCommand(dr),e.addCommand(pr),e.addCommand(fr),e.addCommand(Cr),e.addCommand(Ln),e.addCommand(xr),e.addCommand(Gr),e.addCommand(Uo),e.addCommand(qr),e.addCommand(Jr),e.addCommand(Yr),e.parse(process.argv)}_i().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.2.66",
3
+ "version": "0.2.67",
4
4
  "engines": {
5
5
  "node": ">=18"
6
6
  },
@@ -7,6 +7,27 @@
7
7
  // `gateway=running` every 30s using cached config — iOS continues to show
8
8
  // the user's machine as online for hours after their explicit uninstall.
9
9
  //
10
+ // IMPORTANT — npm lifecycle reality, by major version:
11
+ // * npm <= 6: fires `preuninstall` on a genuine `npm uninstall -g`, AND on an
12
+ // `npm install -g badgerclaw@<ver>` UPGRADE (it removes the old copy first,
13
+ // firing its preuninstall). The old version of this script ran its full
14
+ // teardown — including `rm -rf ~/.badgerclaw` — in BOTH, so on npm 6 every
15
+ // routine CLI upgrade silently deleted the user's login token + instance
16
+ // mapping and logged the host out ("machine went offline after a CLI
17
+ // update"). detectNpmAction() below now classifies the npm verb so the
18
+ // destructive cleanup runs ONLY on a genuine uninstall.
19
+ // * npm >= 7 (every runtime in our `engines.node >= 18` matrix — Node 18→npm
20
+ // 9, Node 20+→npm 10): npm does NOT run this hook AT ALL — not on upgrade
21
+ // and not even on `npm uninstall -g` (removal runs no lifecycle scripts).
22
+ // So on supported npm this script is effectively a no-op; it is kept only
23
+ // as a best-effort safety net for legacy npm 6 environments.
24
+ //
25
+ // Because `preuninstall` is dead on supported npm, the REAL, supported teardown
26
+ // (stop the heartbeat + clear local state so the host stops reporting online
27
+ // and a fresh login can't inherit a previous user's bot mapping) is the
28
+ // explicit `badgerclaw logout` command — see src/commands/logout.ts. Point
29
+ // users there for a clean removal.
30
+ //
10
31
  // CommonJS + plain Node (no dependencies on the package's dist/) so it
11
32
  // works even mid-uninstall, when half the package is gone.
12
33
 
@@ -19,56 +40,117 @@ function quiet(cmd) {
19
40
  try { execSync(cmd, { stdio: 'ignore' }); } catch { /* best-effort */ }
20
41
  }
21
42
 
22
- console.log('[badgerclaw] preuninstall: stopping heartbeat daemon...');
43
+ // Classify the npm command that triggered this lifecycle script.
44
+ // 'uninstall' → genuine removal; do the full teardown + state wipe.
45
+ // 'upgrade' → install/reinstall/update; PRESERVE credentials + heartbeat.
46
+ // 'unknown' → can't tell; default to PRESERVE (wrongly wiping a user's
47
+ // login on an upgrade is far worse than leaving a stale daemon
48
+ // running for a few seconds on an undetectable uninstall).
49
+ function detectNpmAction(env) {
50
+ env = env || process.env;
51
+ const UNINSTALL = new Set(['uninstall', 'remove', 'rm', 'r', 'un', 'unlink']);
52
+ const INSTALL = new Set(['install', 'i', 'in', 'ins', 'add', 'ci', 'isntall', 'update', 'up', 'upgrade']);
53
+
54
+ // npm v7+ exposes the top-level verb directly.
55
+ const cmd = String(env.npm_command || '').toLowerCase();
56
+ if (UNINSTALL.has(cmd)) return 'uninstall';
57
+ if (INSTALL.has(cmd)) return 'upgrade';
58
+
59
+ // npm v6 (and some CI wrappers) expose the raw argv instead. Scan ALL tokens
60
+ // for a known verb rather than taking the first non-dash token — a
61
+ // value-bearing flag before the verb (`npm --loglevel warn uninstall -g …`,
62
+ // `npm --prefix /usr/local uninstall …`) would otherwise make the flag's
63
+ // VALUE ('warn', '/usr/local') look like the verb and misclassify a real
64
+ // uninstall as 'unknown'. Verb keywords never appear as flag values, so a
65
+ // full-token scan is safe. Prefer npm's normalized `cooked` argv when present.
66
+ try {
67
+ const argv = JSON.parse(env.npm_config_argv || '{}');
68
+ const tokens = []
69
+ .concat(Array.isArray(argv.cooked) ? argv.cooked.map(String) : [])
70
+ .concat(Array.isArray(argv.original) ? argv.original.map(String) : [])
71
+ .map((t) => t.toLowerCase());
72
+ if (tokens.some((t) => UNINSTALL.has(t))) return 'uninstall';
73
+ if (tokens.some((t) => INSTALL.has(t))) return 'upgrade';
74
+ } catch { /* malformed / absent argv */ }
75
+
76
+ return 'unknown';
77
+ }
78
+
79
+ // Full teardown — only safe on a genuine uninstall.
80
+ function fullUninstallCleanup() {
81
+ if (process.platform === 'darwin') {
82
+ // macOS LaunchAgent — label from src/lib/launchagent.ts.
83
+ const plist = path.join(
84
+ os.homedir(),
85
+ 'Library',
86
+ 'LaunchAgents',
87
+ 'ai.badgerclaw.watch.plist',
88
+ );
89
+ if (fs.existsSync(plist)) {
90
+ quiet(`launchctl unload "${plist}"`);
91
+ try { fs.unlinkSync(plist); } catch { /* best-effort */ }
92
+ }
93
+ } else if (process.platform === 'linux') {
94
+ // Linux systemd user unit — name from src/lib/systemdunit.ts.
95
+ // disable --now is stop+disable in one shot; safe if the unit doesn't exist.
96
+ quiet('systemctl --user disable --now badgerclaw-watch.service');
97
+ const unitFile = path.join(
98
+ os.homedir(),
99
+ '.config',
100
+ 'systemd',
101
+ 'user',
102
+ 'badgerclaw-watch.service',
103
+ );
104
+ if (fs.existsSync(unitFile)) {
105
+ try { fs.unlinkSync(unitFile); } catch { /* best-effort */ }
106
+ quiet('systemctl --user daemon-reload');
107
+ }
108
+ }
23
109
 
24
- if (process.platform === 'darwin') {
25
- // macOS LaunchAgent label from src/lib/launchagent.ts.
26
- const plist = path.join(
27
- os.homedir(),
28
- 'Library',
29
- 'LaunchAgents',
30
- 'ai.badgerclaw.watch.plist',
31
- );
32
- if (fs.existsSync(plist)) {
33
- quiet(`launchctl unload "${plist}"`);
34
- try { fs.unlinkSync(plist); } catch { /* best-effort */ }
110
+ // Catch-all for detached heartbeat processes not managed by the service
111
+ // manager (e.g. the user ran `badgerclaw heartbeat` directly in a
112
+ // terminal, or older installs before the unit existed).
113
+ if (process.platform !== 'win32') {
114
+ quiet("pkill -f 'badgerclaw heartbeat'");
35
115
  }
36
- } else if (process.platform === 'linux') {
37
- // Linux systemd user unit name from src/lib/systemdunit.ts.
38
- // disable --now is stop+disable in one shot; safe if the unit doesn't exist.
39
- quiet('systemctl --user disable --now badgerclaw-watch.service');
40
- const unitFile = path.join(
41
- os.homedir(),
42
- '.config',
43
- 'systemd',
44
- 'user',
45
- 'badgerclaw-watch.service',
46
- );
47
- if (fs.existsSync(unitFile)) {
48
- try { fs.unlinkSync(unitFile); } catch { /* best-effort */ }
49
- quiet('systemctl --user daemon-reload');
116
+
117
+ // Wipe local user state so a subsequent `npm install -g badgerclaw` +
118
+ // fresh `badgerclaw login` doesn't inherit the previous user's bot
119
+ // mapping, claude-sessions, heartbeat logs, or plugin quarantine ledger.
120
+ // Reproduced 2026-04-30 on srv1554824: `bot list` after a fresh install
121
+ // returned a previous user's bots because bot-mapping.json survived the
122
+ // uninstall. Scope is strictly user state: ~/.badgerclaw and
123
+ // ~/.openclaw/badgerclaw — we don't touch ~/.openclaw itself (gateway
124
+ // config + other plugins are managed by openclaw, not badgerclaw).
125
+ function rmrfSafe(target) {
126
+ try { fs.rmSync(target, { recursive: true, force: true }); } catch { /* best-effort */ }
50
127
  }
128
+ rmrfSafe(path.join(os.homedir(), '.badgerclaw'));
129
+ rmrfSafe(path.join(os.homedir(), '.openclaw', 'badgerclaw'));
51
130
  }
52
131
 
53
- // Catch-all for detached heartbeat processes not managed by the service
54
- // manager (e.g. the user ran `badgerclaw heartbeat` directly in a
55
- // terminal, or older installs before the unit existed).
56
- if (process.platform !== 'win32') {
57
- quiet("pkill -f 'badgerclaw heartbeat'");
132
+ function main() {
133
+ const action = detectNpmAction();
134
+
135
+ // Preserve everything unless this is unambiguously a genuine uninstall.
136
+ // Escape hatch: BADGERCLAW_FORCE_UNINSTALL_CLEANUP=1 forces the full
137
+ // teardown (e.g. an automated reset script that really does want it).
138
+ if (action !== 'uninstall' && process.env.BADGERCLAW_FORCE_UNINSTALL_CLEANUP !== '1') {
139
+ console.log(
140
+ `[badgerclaw] preuninstall: ${action === 'upgrade' ? 'upgrade/reinstall' : 'non-uninstall'} ` +
141
+ 'detected — preserving login + heartbeat (no state wipe).',
142
+ );
143
+ return;
144
+ }
145
+
146
+ console.log('[badgerclaw] preuninstall: stopping heartbeat daemon + clearing local state...');
147
+ fullUninstallCleanup();
148
+ console.log('[badgerclaw] preuninstall: done.');
58
149
  }
59
150
 
60
- // Wipe local user state so a subsequent `npm install -g badgerclaw` +
61
- // fresh `badgerclaw login` doesn't inherit the previous user's bot
62
- // mapping, claude-sessions, heartbeat logs, or plugin quarantine ledger.
63
- // Reproduced 2026-04-30 on srv1554824: `bot list` after a fresh install
64
- // returned a previous user's bots because bot-mapping.json survived the
65
- // uninstall. Scope is strictly user state: ~/.badgerclaw and
66
- // ~/.openclaw/badgerclaw — we don't touch ~/.openclaw itself (gateway
67
- // config + other plugins are managed by openclaw, not badgerclaw).
68
- function rmrfSafe(target) {
69
- try { fs.rmSync(target, { recursive: true, force: true }); } catch { /* best-effort */ }
151
+ // Run when invoked by npm; stay side-effect-free when require()'d by tests.
152
+ if (require.main === module) {
153
+ main();
70
154
  }
71
- rmrfSafe(path.join(os.homedir(), '.badgerclaw'));
72
- rmrfSafe(path.join(os.homedir(), '.openclaw', 'badgerclaw'));
73
155
 
74
- console.log('[badgerclaw] preuninstall: done.');
156
+ module.exports = { detectNpmAction, fullUninstallCleanup };