badgerclaw 0.2.35 → 0.2.36
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 +3 -3
- package/package.json +3 -1
- package/scripts/preuninstall.cjs +60 -0
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var Eo=Object.create;var ye=Object.defineProperty;var Do=Object.getOwnPropertyDescriptor;var Oo=Object.getOwnPropertyNames;var No=Object.getPrototypeOf,To=Object.prototype.hasOwnProperty;var jo=(e,t)=>()=>(e&&(t=e(e=0)),t);var Bo=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Lo=(e,t)=>{for(var o in t)ye(e,o,{get:t[o],enumerable:!0})},wt=(e,t,o,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Oo(t))!To.call(e,n)&&n!==o&&ye(e,n,{get:()=>t[n],enumerable:!(s=Do(t,n))||s.enumerable});return e};var c=(e,t,o)=>(o=e!=null?Eo(No(e)):{},wt(t||!e||!e.__esModule?ye(o,"default",{value:e,enumerable:!0}):o,e)),yt=e=>wt(ye({},"__esModule",{value:!0}),e);var z=Bo((Ps,Yo)=>{Yo.exports={name:"badgerclaw",version:"0.2.
|
|
2
|
+
"use strict";var Eo=Object.create;var ye=Object.defineProperty;var Do=Object.getOwnPropertyDescriptor;var Oo=Object.getOwnPropertyNames;var No=Object.getPrototypeOf,To=Object.prototype.hasOwnProperty;var jo=(e,t)=>()=>(e&&(t=e(e=0)),t);var Bo=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Lo=(e,t)=>{for(var o in t)ye(e,o,{get:t[o],enumerable:!0})},wt=(e,t,o,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Oo(t))!To.call(e,n)&&n!==o&&ye(e,n,{get:()=>t[n],enumerable:!(s=Do(t,n))||s.enumerable});return e};var c=(e,t,o)=>(o=e!=null?Eo(No(e)):{},wt(t||!e||!e.__esModule?ye(o,"default",{value:e,enumerable:!0}):o,e)),yt=e=>wt(ye({},"__esModule",{value:!0}),e);var z=Bo((Ps,Yo)=>{Yo.exports={name:"badgerclaw",version:"0.2.36",description:"BadgerClaw CLI \u2014 one-click bot provisioning",main:"dist/index.js",bin:{badgerclaw:"./dist/index.js"},files:["dist/","scripts/","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:'echo "Error: no test specified" && exit 1'},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",typescript:"^5.3.0"}}});var dt={};Lo(dt,{getActiveSessions:()=>lt,launchClaudeCode:()=>at,launchMCPServer:()=>rt,recordSession:()=>it,stopSession:()=>ct});function tt(){try{if(E.default.existsSync(et))return JSON.parse(E.default.readFileSync(et,"utf-8"))}catch{}return[]}function ot(e){E.default.mkdirSync(Y,{recursive:!0}),E.default.writeFileSync(et,JSON.stringify(e,null,2))}function De(e){try{return process.kill(e,0),!0}catch{return!1}}function dn(){if(process.env.TMUX)return"tmux";try{if((0,F.execSync)(`osascript -e 'tell application "System Events" to (name of processes) contains "iTerm2"'`,{stdio:"pipe",timeout:3e3}),E.default.existsSync("/Applications/iTerm.app"))return"iterm2"}catch{}return process.platform==="darwin"?"terminal":"direct"}function nt(e,t){let o=T.default.join(Y,`claude-launcher-${t}.exp`),s=T.default.join(Y,`pending-input-${t}.txt`);E.default.writeFileSync(s,"","utf-8");let n=`#!/usr/bin/expect -f
|
|
3
3
|
set timeout -1
|
|
4
4
|
set msgfile "${s}"
|
|
5
5
|
|
|
@@ -114,7 +114,7 @@ Keep responses concise and helpful.
|
|
|
114
114
|
\u{1F5D1}\uFE0F Bot deleted: ${r} \u2014 removing from OpenClaw config...`));try{let i=await import("fs"),l=await import("path"),f=await import("os"),b=l.join(f.homedir(),".openclaw","openclaw.json"),y=JSON.parse(i.readFileSync(b,"utf-8")),v=!1;if(y.channels?.badgerclaw?.accounts?.[a]&&(delete y.channels.badgerclaw.accounts[a],v=!0),y.agents?.list){let I=y.agents.list.length;y.agents.list=y.agents.list.filter(A=>A.id!==a),y.agents.list.length!==I&&(v=!0)}if(v){i.writeFileSync(b,JSON.stringify(y,null,2)),console.log(m.default.green(` \u2705 Removed "${a}" from openclaw.json`));let{execSync:I}=await import("child_process");try{I("openclaw gateway restart",{stdio:"ignore"}),console.log(m.default.green(" \u2705 Gateway restarted"))}catch{console.log(m.default.dim(" Gateway restart failed \u2014 restart manually"))}}else console.log(m.default.dim(` "${a}" not found in openclaw.json \u2014 nothing to remove`))}catch(i){console.log(m.default.red(` Failed to update openclaw.json: ${i}`))}}else if(n.type==="claude_code.start"&&n.bot_id&&n.room_id){console.log(m.default.cyan(`
|
|
115
115
|
\u{1F916} Claude Code START received: bot=${n.bot_id} room=${n.room_id}`));try{let r=await M({id:n.command_id||`cc-start-${Date.now()}`,command_type:"start_claude_code",payload:{bot_id:n.bot_id,room_id:n.room_id,session_id:n.session_id}});if(console.log(r.success?m.default.green(` \u2705 ${r.message}`):m.default.red(` \u274C ${r.message}`)),n.command_id)try{await R().post(`/api/v1/dashboard/commands/${n.command_id}/result`,{status:r.success?"success":"failed",result:r.message})}catch{}try{await O()}catch{}}catch(r){console.log(m.default.red(` Claude Code start error: ${r.message}`))}}else if(n.type==="claude_code.stop"&&n.bot_id&&n.room_id){console.log(m.default.cyan(`
|
|
116
116
|
\u{1F916} Claude Code STOP received: bot=${n.bot_id} room=${n.room_id}`));try{let r=await M({id:n.command_id||`cc-stop-${Date.now()}`,command_type:"stop_claude_code",payload:{bot_id:n.bot_id,room_id:n.room_id,session_id:n.session_id}});if(console.log(r.success?m.default.green(` \u2705 ${r.message}`):m.default.red(` \u274C ${r.message}`)),n.command_id)try{await R().post(`/api/v1/dashboard/commands/${n.command_id}/result`,{status:r.success?"success":"failed",result:r.message})}catch{}try{await O()}catch{}}catch(r){console.log(m.default.red(` Claude Code stop error: ${r.message}`))}}else if(n.type==="command.execute"&&n.command_id){console.log(m.default.cyan(`
|
|
117
|
-
\u26A1 SSE command received: ${n.command_type} (${n.command_id})`));try{let r=R();await r.post(`/api/v1/dashboard/commands/${n.command_id}/ack`);let a=await M({id:n.command_id,command_type:n.command_type,payload:n.payload});console.log(a.success?m.default.green(` \u2705 ${a.message}`):m.default.red(` \u274C ${a.message}`)),await r.post(`/api/v1/dashboard/commands/${n.command_id}/result`,{status:a.success?"success":"failed",result:a.message,new_version:a.newVersion||null});try{await O()}catch{}n.command_type==="update_cli"&&a.success&&(console.log(m.default.cyan(" CLI updated \u2014 restarting in 2s...")),setTimeout(()=>process.exit(0),2e3))}catch(r){console.log(m.default.red(` Command ${n.command_id} error: ${r.message}`))}}}catch{}},o.onerror=()=>{console.log(m.default.dim(" Reconnecting..."))},await new Promise(()=>{})});var $o=require("commander"),g=c(require("chalk")),oe=require("child_process"),C=c(require("fs")),gt=c(require("os")),ft=c(require("path"));var yo=c(require("fs")),_o=c(require("os")),Le=c(require("path")),mt=require("child_process"),V=c(require("chalk"));var Bn=`${N}/api/v1/dashboard/versions/latest`,Ln=2500,Un=new Set(["setup","logout","help","--version","-V","--help","-h","heartbeat","watch","autopair"]),wo=Le.default.join(_o.default.homedir(),".openclaw/extensions/badgerclaw"),Fn=[Le.default.join(wo,"node_modules/@badgerclaw/connect/package.json"),Le.default.join(wo,"package.json")];function pt(){return"0.2.
|
|
117
|
+
\u26A1 SSE command received: ${n.command_type} (${n.command_id})`));try{let r=R();await r.post(`/api/v1/dashboard/commands/${n.command_id}/ack`);let a=await M({id:n.command_id,command_type:n.command_type,payload:n.payload});console.log(a.success?m.default.green(` \u2705 ${a.message}`):m.default.red(` \u274C ${a.message}`)),await r.post(`/api/v1/dashboard/commands/${n.command_id}/result`,{status:a.success?"success":"failed",result:a.message,new_version:a.newVersion||null});try{await O()}catch{}n.command_type==="update_cli"&&a.success&&(console.log(m.default.cyan(" CLI updated \u2014 restarting in 2s...")),setTimeout(()=>process.exit(0),2e3))}catch(r){console.log(m.default.red(` Command ${n.command_id} error: ${r.message}`))}}}catch{}},o.onerror=()=>{console.log(m.default.dim(" Reconnecting..."))},await new Promise(()=>{})});var $o=require("commander"),g=c(require("chalk")),oe=require("child_process"),C=c(require("fs")),gt=c(require("os")),ft=c(require("path"));var yo=c(require("fs")),_o=c(require("os")),Le=c(require("path")),mt=require("child_process"),V=c(require("chalk"));var Bn=`${N}/api/v1/dashboard/versions/latest`,Ln=2500,Un=new Set(["setup","logout","help","--version","-V","--help","-h","heartbeat","watch","autopair"]),wo=Le.default.join(_o.default.homedir(),".openclaw/extensions/badgerclaw"),Fn=[Le.default.join(wo,"node_modules/@badgerclaw/connect/package.json"),Le.default.join(wo,"package.json")];function pt(){return"0.2.36"}function Mn(){for(let e of Fn)try{let t=yo.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 Gn(e){let t=e.trim(),o=t.match(/\d+(?:\.\d+){1,3}/);return o?o[0]:t}function Ue(){if((0,mt.spawnSync)("which",["openclaw"],{encoding:"utf-8"}).status!==0)return null;let t=(0,mt.spawnSync)("openclaw",["--version"],{encoding:"utf-8",timeout:3e3});return t.status!==0||!t.stdout?null:Gn(t.stdout)||null}async function Vn(){let e=new AbortController,t=setTimeout(()=>e.abort(),Ln);try{let o=await fetch(Bn,{signal:e.signal});if(!o.ok)return null;let s=await o.json(),n=s.result&&typeof s.result=="object"?s.result:s;return{cli:n.cli??"unknown",plugin:n.plugin??"unknown",supported_openclaw:n.supported_openclaw??"unknown"}}catch{return null}finally{clearTimeout(t)}}function Wn(e){let t=[];if(e.cli&&e.cli!=="unknown"){let o=pt();o!==e.cli&&t.push({component:"cli",current:o,approved:e.cli})}if(e.plugin&&e.plugin!=="unknown"){let o=Mn();(o===null||o!==e.plugin)&&t.push({component:"plugin",current:o??"not installed",approved:e.plugin})}if(e.supported_openclaw&&e.supported_openclaw!=="unknown"){let o=Ue();(o===null||o!==e.supported_openclaw)&&t.push({component:"openclaw",current:o??"not installed",approved:e.supported_openclaw})}return t}function qn(e){return e[2]}function Hn(e){return!e||e.startsWith("-")?!0:Un.has(e)}function Jn(e){let t=[];t.push(""),t.push(V.default.red.bold("\u2717 Unsupported versions detected")),t.push("");for(let o of e){let s=o.component.padEnd(8);t.push(` ${s} ${V.default.yellow(o.current)} \u2192 ${V.default.green(o.approved)} ${V.default.dim("(supported)")}`)}return t.push(""),t.push("This command is blocked until your installation matches the supported versions."),t.push(""),t.push(V.default.green(" To fix, run:")),t.push(V.default.green.bold(" badgerclaw setup")),t.push(""),t.push(V.default.dim(" (bypass temporarily: BADGERCLAW_NO_VERSION_CHECK=1 badgerclaw <cmd>)")),t.push(""),t.join(`
|
|
118
118
|
`)}async function bo(e){if(process.env.BADGERCLAW_NO_VERSION_CHECK)return;let t=qn(e);if(Hn(t))return;let o=await Vn();if(!o)return;let s=Wn(o);s.length!==0&&(process.stderr.write(Jn(s)),process.exit(1))}var B=ft.default.join(gt.default.homedir(),".openclaw","openclaw.json"),we=B+".badgerclaw-stash";async function zn(){try{let e=await fetch(`${N}/api/v1/dashboard/versions/latest`,{headers:{Accept:"application/json"}});if(!e.ok)return{cli:null,plugin:null,openclaw:null};let t=await e.json(),o=t.result&&typeof t.result=="object"?t.result:t,s=n=>typeof n!="string"||!n||n==="unknown"?null:n;return{cli:s(o.cli),plugin:s(o.plugin),openclaw:s(o.supported_openclaw)}}catch{return{cli:null,plugin:null,openclaw:null}}}function Yn(){if(!C.default.existsSync(B))return null;try{let e=JSON.parse(C.default.readFileSync(B,"utf-8")),t=e.channels?.badgerclaw;return t?(delete e.channels.badgerclaw,e.plugins?.entries?.badgerclaw&&delete e.plugins.entries.badgerclaw,C.default.writeFileSync(B,JSON.stringify(e,null,2)),C.default.writeFileSync(we,JSON.stringify(t,null,2)),t):null}catch{return null}}function Kn(){if(!C.default.existsSync(B))return null;try{let e=JSON.parse(C.default.readFileSync(B,"utf-8"));return!e.gateway||typeof e.gateway!="object"?null:JSON.parse(JSON.stringify(e.gateway))}catch{return null}}function Xn(e){if(e&&C.default.existsSync(B))try{let t=JSON.parse(C.default.readFileSync(B,"utf-8"));t.gateway={...e,...t.gateway||{}},C.default.writeFileSync(B,JSON.stringify(t,null,2))}catch(t){console.log(g.default.yellow(` \u26A0\uFE0F Could not restore gateway block: ${t.message}`)),console.log(g.default.yellow(" Run `openclaw config set gateway.mode local` manually if the gateway fails to start."))}}function Qn(){if(C.default.existsSync(we))try{let e=JSON.parse(C.default.readFileSync(we,"utf-8")),t=JSON.parse(C.default.readFileSync(B,"utf-8"));t.channels=t.channels||{},t.channels.badgerclaw=e,C.default.writeFileSync(B,JSON.stringify(t,null,2)),C.default.unlinkSync(we)}catch(e){console.log(g.default.yellow(` \u26A0\uFE0F Could not restore config: ${e.message}`)),console.log(g.default.yellow(` Your bot credentials are backed up at: ${we}`))}}var So=new $o.Command("setup").description("Install or update the OpenClaw BadgerClaw plugin safely (handles config automatically)").action(async()=>{console.log(g.default.green(`
|
|
119
119
|
\u{1F9A1} BadgerClaw Setup
|
|
120
120
|
`));let e=await zn();if(e.cli){let i=pt();i!==e.cli?(console.log(g.default.dim(` Updating CLI: ${i} \u2192 ${e.cli} (supported)...`)),(0,oe.spawnSync)("npm",["install","-g",`badgerclaw@${e.cli}`],{stdio:"inherit",shell:!0}).status!==0&&(console.log(g.default.red("\n\u274C CLI update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(g.default.green(` \u2705 CLI updated to ${e.cli}`))):console.log(g.default.dim(` CLI already at approved version ${i}.`))}if(e.openclaw){let i=Ue();i!==e.openclaw?(console.log(i===null?g.default.dim(` Installing OpenClaw ${e.openclaw} (supported)...`):g.default.dim(` Updating OpenClaw: ${i} \u2192 ${e.openclaw} (supported)...`)),(0,oe.spawnSync)("npm",["install","-g",`openclaw@${e.openclaw}`],{stdio:"inherit",shell:!0}).status!==0&&(console.log(g.default.red("\n\u274C OpenClaw install/update failed. Fix the npm error above, then re-run `badgerclaw setup`.")),process.exit(1)),console.log(g.default.green(` \u2705 OpenClaw at ${e.openclaw}`))):console.log(g.default.dim(` OpenClaw already at approved version ${i}.`))}else Ue()===null&&(console.log(g.default.yellow(" \u26A0\uFE0F No approved OpenClaw version and none installed \u2014 installing latest from npm.")),(0,oe.spawnSync)("npm",["install","-g","openclaw"],{stdio:"inherit",shell:!0}).status!==0&&(console.log(g.default.red(`
|
|
@@ -125,4 +125,4 @@ Keep responses concise and helpful.
|
|
|
125
125
|
BadgerClaw Dashboard
|
|
126
126
|
`)),console.log(S.default.bold(" Instance")),console.log(` ID: ${J()}`),console.log(` CLI Version: ${t}`),console.log(` Plugin: ${s.pluginVersion}`),console.log(),console.log(S.default.bold(" Machine")),console.log(` Hostname: ${o.hostname}`),console.log(` OS: ${o.os} / ${o.arch}`),console.log(` Uptime: ${Co(o.uptimeSeconds)}`),console.log(` Free Memory: ${o.memFreeMb} MB`),console.log();let n=s.status==="running"?S.default.green:s.status==="error"?S.default.red:S.default.yellow;if(console.log(S.default.bold(" Gateway")),console.log(` Status: ${n(s.status)}`),console.log(` PID: ${s.pid??"N/A"}`),console.log(` Last Restart: ${s.lastRestart??"N/A"}`),console.log(),s.bots.length===0)console.log(S.default.bold(" Bots")),console.log(S.default.dim(" No bots detected. Pair bots at https://badgerclaw.ai")),console.log();else{console.log(S.default.bold(` Bots (${s.bots.length})`)),console.log();for(let r of s.bots){let a=r.status==="running"?S.default.green:r.status==="error"?S.default.red:S.default.yellow;if(console.log(` ${S.default.bold(r.botUsername)} ${a(`[${r.status}]`)}`),console.log(` ID: ${r.botId}`),console.log(` Uptime: ${Co(r.uptimeSeconds)}`),console.log(` Messages: ${r.messagesReceived} in / ${r.messagesSent} out`),r.chunkedMessages>0&&console.log(` Chunked: ${r.chunkedMessages} messages, ${r.totalChunksSent} chunks`),console.log(` Rooms: ${r.roomsActive} active`),console.log(` Errors: ${r.errors}`),r.lastError&&(console.log(` Last Error: ${S.default.red(r.lastError)}`),console.log(` Error At: ${r.lastErrorAt}`)),console.log(` Last Active: ${r.lastActivity??"N/A"}`),r.roomDetails&&r.roomDetails.length>0){console.log(S.default.dim(" Rooms:"));for(let i of r.roomDetails)console.log(S.default.dim(` ${i.roomName} \u2014 ${i.messagesInRoom} msgs, last: ${i.lastActivityInRoom??"N/A"}`))}console.log()}}console.log(S.default.dim(` Last checked: ${new Date().toISOString()}`)),console.log()});function Co(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 ht=require("commander"),ne=c(require("chalk")),xo=c(require("ora"));var Zn=new ht.Command("restart").description("Restart the OpenClaw gateway via the plugin probe endpoint").action(async()=>{h()||(console.log(ne.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,xo.default)("Restarting gateway...").start(),o=await te();if(o.success){t.succeed(ne.default.green(`Gateway restarted: ${o.message}`));try{await O(),console.log(ne.default.dim(" Heartbeat pushed with updated status."))}catch{console.log(ne.default.dim(" Could not push heartbeat \u2014 daemon may not be running."))}}else t.fail(ne.default.red(`Gateway restart failed: ${o.message}`)),process.exit(1)}),Ao=new ht.Command("gateway").description("Manage the OpenClaw gateway").addCommand(Zn);var q=require("commander"),p=c(require("chalk")),X=c(require("ora")),W=c(require("axios"));Ne();var K="http://localhost:7331",es=new q.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=>{h()||(console.log(p.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let o=e.sessionId||`session-${Date.now()}`,s=parseInt(e.port,10),n=e.project.replace(/^~/,process.env.HOME||""),r=(0,X.default)("Starting Claude Code session...").start();try{await W.default.post(`${K}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:o},{timeout:1e4}),r.text="Gateway toggled \u2014 launching MCP server...";let i=rt({sessionId:o,port:s,projectDir:n}).pid||0;await new Promise(l=>setTimeout(l,1500)),r.text="MCP server running \u2014 launching Claude Code...",at({sessionId:o,port:s,projectDir:n}),it(o,0,i,s,n),r.succeed(p.default.green("Claude Code session started")+p.default.dim(` (session: ${o}, port: ${s})`)),console.log(p.default.dim(` Bot: ${e.bot}`)),console.log(p.default.dim(` Room: ${e.room}`)),console.log(p.default.dim(` Project: ${n}`)),console.log(p.default.dim(" Claude Code should open in a new terminal window."))}catch(a){let i=a.response?.data?.message||a.message||"Unknown error";r.fail(p.default.red(`Failed to start Claude Code: ${i}`)),process.exit(1)}}),ts=new q.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=>{h()||(console.log(p.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let o=(0,X.default)("Stopping Claude Code session...").start();try{e.bot&&e.room&&await W.default.post(`${K}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!1},{timeout:1e4});let s=e.sessionId;if(!s)try{let a=((await W.default.get(`${K}/claude-code/status`,{timeout:5e3})).data?.rooms||[]).find(i=>i.botId===e.bot&&i.roomId===e.room);a&&(s=a.sessionId)}catch{}s?(ct(s),o.succeed(p.default.green(`Claude Code session stopped (${s})`))):(o.succeed(p.default.green("Claude Code toggled off at gateway")),console.log(p.default.dim(" No local session found to kill \u2014 may need to close Claude Code manually.")))}catch(s){let n=s.response?.data?.message||s.message||"Unknown error";o.fail(p.default.red(`Failed to stop Claude Code: ${n}`)),process.exit(1)}}),os=new q.Command("status").description("Show active Claude Code sessions").action(async()=>{h()||(console.log(p.default.yellow("Not logged in. Run `badgerclaw login` first.")),process.exit(1));let t=(0,X.default)("Fetching Claude Code status...").start();try{let o=[];try{o=(await W.default.get(`${K}/claude-code/status`,{timeout:5e3})).data?.rooms||[]}catch{}let s=lt();if(t.stop(),o.length===0&&s.length===0){console.log(p.default.dim("No active Claude Code sessions."));return}if(o.length>0){console.log(p.default.bold(`
|
|
127
127
|
Gateway Claude Code Rooms:`)),console.log(p.default.dim(" Bot".padEnd(30)+"Room".padEnd(30)+"Session".padEnd(20)+"Enabled")),console.log(p.default.dim(" "+"-".repeat(88)));for(let n of o){let r=n.enabled?p.default.green("ON"):p.default.dim("OFF");console.log(` ${(n.botId||"").padEnd(30)}${(n.roomName||n.roomId||"").padEnd(30)}${(n.sessionId||"-").padEnd(20)}${r}`)}}if(s.length>0){console.log(p.default.bold(`
|
|
128
|
-
Local Sessions:`)),console.log(p.default.dim(" Session".padEnd(25)+"Port".padEnd(8)+"MCP PID".padEnd(10)+"Project".padEnd(40)+"Started")),console.log(p.default.dim(" "+"-".repeat(90)));for(let n of s)console.log(` ${n.sessionId.padEnd(25)}${String(n.port).padEnd(8)}${String(n.mcpPid).padEnd(10)}${n.projectDir.padEnd(40)}${n.startedAt}`)}console.log("")}catch(o){t.fail(p.default.red(`Failed to get status: ${o.message}`)),process.exit(1)}}),ns=new q.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,X.default)("Grouping bot+room into session...").start();try{await W.default.post(`${K}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:e.session},{timeout:1e4}),t.succeed(p.default.green(`Grouped ${e.bot} + ${e.room} into session "${e.session}"`))}catch(o){let s=o.response?.data?.message||o.message||"Unknown error";t.fail(p.default.red(`Failed to group: ${s}`)),process.exit(1)}}),ss=new q.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,X.default)("Adding user to allowlist...").start();try{await W.default.post(`${K}/claude-code/allow`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(p.default.green(`Added ${e.user} to allowlist for ${e.bot} in ${e.room}`))}catch(o){let s=o.response?.data?.message||o.message||"Unknown error";t.fail(p.default.red(`Failed to add user: ${s}`)),process.exit(1)}}),rs=new q.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,X.default)("Removing user from allowlist...").start();try{await W.default.post(`${K}/claude-code/revoke`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(p.default.green(`Removed ${e.user} from allowlist for ${e.bot} in ${e.room}`))}catch(o){let s=o.response?.data?.message||o.message||"Unknown error";t.fail(p.default.red(`Failed to revoke user: ${s}`)),process.exit(1)}}),ko=new q.Command("claude-code").description("Manage Claude Code sessions (relay Matrix messages to local Claude Code)").addCommand(es).addCommand(ts).addCommand(os).addCommand(ns).addCommand(ss).addCommand(rs);async function as(){await bo(process.argv);let e=new Ro.Command;e.name("badgerclaw").description("BadgerClaw CLI \u2014 one-click bot provisioning").version("0.2.
|
|
128
|
+
Local Sessions:`)),console.log(p.default.dim(" Session".padEnd(25)+"Port".padEnd(8)+"MCP PID".padEnd(10)+"Project".padEnd(40)+"Started")),console.log(p.default.dim(" "+"-".repeat(90)));for(let n of s)console.log(` ${n.sessionId.padEnd(25)}${String(n.port).padEnd(8)}${String(n.mcpPid).padEnd(10)}${n.projectDir.padEnd(40)}${n.startedAt}`)}console.log("")}catch(o){t.fail(p.default.red(`Failed to get status: ${o.message}`)),process.exit(1)}}),ns=new q.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,X.default)("Grouping bot+room into session...").start();try{await W.default.post(`${K}/claude-code/toggle`,{botId:e.bot,roomId:e.room,enabled:!0,sessionId:e.session},{timeout:1e4}),t.succeed(p.default.green(`Grouped ${e.bot} + ${e.room} into session "${e.session}"`))}catch(o){let s=o.response?.data?.message||o.message||"Unknown error";t.fail(p.default.red(`Failed to group: ${s}`)),process.exit(1)}}),ss=new q.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,X.default)("Adding user to allowlist...").start();try{await W.default.post(`${K}/claude-code/allow`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(p.default.green(`Added ${e.user} to allowlist for ${e.bot} in ${e.room}`))}catch(o){let s=o.response?.data?.message||o.message||"Unknown error";t.fail(p.default.red(`Failed to add user: ${s}`)),process.exit(1)}}),rs=new q.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,X.default)("Removing user from allowlist...").start();try{await W.default.post(`${K}/claude-code/revoke`,{botId:e.bot,roomId:e.room,userId:e.user},{timeout:1e4}),t.succeed(p.default.green(`Removed ${e.user} from allowlist for ${e.bot} in ${e.room}`))}catch(o){let s=o.response?.data?.message||o.message||"Unknown error";t.fail(p.default.red(`Failed to revoke user: ${s}`)),process.exit(1)}}),ko=new q.Command("claude-code").description("Manage Claude Code sessions (relay Matrix messages to local Claude Code)").addCommand(es).addCommand(ts).addCommand(os).addCommand(ns).addCommand(ss).addCommand(rs);async function as(){await bo(process.argv);let e=new Ro.Command;e.name("badgerclaw").description("BadgerClaw CLI \u2014 one-click bot provisioning").version("0.2.36"),e.addCommand(Jt),e.addCommand(Yt),e.addCommand(Xt),e.addCommand(oo),e.addCommand(jt),e.addCommand(ho),e.addCommand(So),e.addCommand(po),e.addCommand(Io),e.addCommand(Ao),e.addCommand(ko),e.parse(process.argv)}as().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.
|
|
3
|
+
"version": "0.2.36",
|
|
4
4
|
"description": "BadgerClaw CLI — one-click bot provisioning",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist/",
|
|
11
|
+
"scripts/",
|
|
11
12
|
"README.md"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"build": "node build.mjs",
|
|
15
16
|
"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 — rebuild before publish (package.json='+v+')'); process.exit(1);} console.log('dist/index.js OK — version '+v);\"",
|
|
16
17
|
"prepublishOnly": "rm -rf dist && npm run build && npm run verify-dist-version",
|
|
18
|
+
"preuninstall": "node scripts/preuninstall.cjs",
|
|
17
19
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
18
20
|
},
|
|
19
21
|
"keywords": [],
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// preuninstall.cjs — runs automatically on `npm uninstall -g badgerclaw`.
|
|
3
|
+
//
|
|
4
|
+
// Stops the heartbeat daemon (LaunchAgent on macOS, systemd user unit on
|
|
5
|
+
// Linux) before npm unlinks the binary. Without this, Linux holds the
|
|
6
|
+
// unlinked binary's inode open and the running heartbeat keeps sending
|
|
7
|
+
// `gateway=running` every 30s using cached config — iOS continues to show
|
|
8
|
+
// the user's machine as online for hours after their explicit uninstall.
|
|
9
|
+
//
|
|
10
|
+
// CommonJS + plain Node (no dependencies on the package's dist/) so it
|
|
11
|
+
// works even mid-uninstall, when half the package is gone.
|
|
12
|
+
|
|
13
|
+
const { execSync } = require('child_process');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const os = require('os');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
|
|
18
|
+
function quiet(cmd) {
|
|
19
|
+
try { execSync(cmd, { stdio: 'ignore' }); } catch { /* best-effort */ }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log('[badgerclaw] preuninstall: stopping heartbeat daemon...');
|
|
23
|
+
|
|
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 */ }
|
|
35
|
+
}
|
|
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');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
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'");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log('[badgerclaw] preuninstall: done.');
|