UNPKG

bwc-cli

Version:

CLI tool for installing Claude Code subagents and commands

10 lines (9 loc) 16 kB
#!/usr/bin/env node import{Command as wt}from"commander";import yt from"update-notifier";import{readFileSync as bt}from"fs";import{fileURLToPath as Ct}from"url";import{dirname as Pt,join as $t}from"path";import{Command as rt}from"commander";import v from"fs-extra";import P from"path";import at from"os";var M=at.homedir(),A=P.join(M,".bwc"),C=P.join(A,"config.json"),D=P.join(M,".claude"),T=P.join(D,"agents"),k=P.join(D,"commands");async function R(a){await v.ensureDir(a)}async function x(a){try{return await v.access(a),!0}catch{return!1}}async function it(a){return v.readFile(a,"utf-8")}async function $(a,n){await v.ensureDir(P.dirname(a)),await v.writeFile(a,n,"utf-8")}async function U(a){let n=await it(a);return JSON.parse(n)}async function L(a,n){await $(a,JSON.stringify(n,null,2))}function N(a){return a.startsWith("~/")?P.join(M,a.slice(2)):a}import u from"path";import _ from"process";var O={version:"1.0",registry:"https://buildwithclaude.com/registry.json",paths:{subagents:T,commands:k},installed:{subagents:[],commands:[]}},B={version:"1.0",registry:"https://buildwithclaude.com/registry.json",paths:{subagents:".claude/agents/",commands:".claude/commands/"},installed:{subagents:[],commands:[]}},f=class{config=null;configPath=null;isProjectLevel=!1;async findProjectConfig(){let n=["bwc.config.json",".bwc/config.json"],t=_.cwd();for(;t!==u.dirname(t);){for(let o of n){let e=u.join(t,o);if(await x(e))return e}t=u.dirname(t)}return null}async init(n){if(n!=null&&n.project){let t=u.join(_.cwd(),"bwc.config.json");if(await x(t)&&!n.force)throw new Error("Project configuration already exists. Use --force to overwrite.");await L(t,B),this.config=B,this.configPath=t,this.isProjectLevel=!0}else{if(await R(A),await x(C)&&!(n!=null&&n.force))throw new Error("Configuration already exists. Use --force to overwrite.");await L(C,O),this.config=O,this.configPath=C,this.isProjectLevel=!1}}async load(){if(this.config)return this.config;let n=await this.findProjectConfig();if(n)return this.config=await U(n),this.configPath=n,this.isProjectLevel=!0,this.config;if(!await x(C))throw new Error('Configuration not found. Run "bwc init" first.');return this.config=await U(C),this.configPath=C,this.isProjectLevel=!1,this.config}async save(){if(!this.config||!this.configPath)throw new Error("No configuration loaded");await L(this.configPath,this.config)}async getSubagentsPath(){let t=(await this.load()).paths.subagents;if(this.isProjectLevel&&!u.isAbsolute(t)){let o=u.dirname(this.configPath);t=u.join(o,t)}else t=N(t);return await R(t),t}async getCommandsPath(){let t=(await this.load()).paths.commands;if(this.isProjectLevel&&!u.isAbsolute(t)){let o=u.dirname(this.configPath);t=u.join(o,t)}else t=N(t);return await R(t),t}async addInstalledSubagent(n){let t=await this.load();t.installed.subagents.includes(n)||(t.installed.subagents.push(n),await this.save())}async addInstalledCommand(n){let t=await this.load();t.installed.commands.includes(n)||(t.installed.commands.push(n),await this.save())}async removeInstalledSubagent(n){let t=await this.load();t.installed.subagents=t.installed.subagents.filter(o=>o!==n),await this.save()}async removeInstalledCommand(n){let t=await this.load();t.installed.commands=t.installed.commands.filter(o=>o!==n),await this.save()}async getInstalledSubagents(){return(await this.load()).installed.subagents}async getInstalledCommands(){return(await this.load()).installed.commands}async getRegistryUrl(){return(await this.load()).registry}async isUsingProjectConfig(){return await this.load(),this.isProjectLevel}async getConfigLocation(){return await this.load(),this.configPath||C}async getAllDependencies(){let n=await this.load();return{subagents:n.installed.subagents||[],commands:n.installed.commands||[]}}};import S from"chalk";import st from"ora";var s={info:a=>console.log(S.blue("\u2139"),a),success:a=>console.log(S.green("\u2713"),a),error:a=>console.log(S.red("\u2717"),a),warn:a=>console.log(S.yellow("\u26A0"),a),heading:a=>console.log(` `+S.bold(a)),list:a=>{a.forEach(n=>console.log(` ${S.gray("\u2022")} ${n}`))},code:a=>console.log(S.gray(a)),spinner:a=>st(a).start()};function J(){return new rt("init").description("Initialize bwc configuration").option("-f, --force","overwrite existing configuration").option("-p, --project","create project-level configuration").action(async n=>{try{let t=new f,o=n.project,e=o?"project":"global",c=s.spinner(`Initializing ${e} bwc configuration...`);try{await t.init({project:o,force:n.force}),c.succeed(`${e} configuration initialized successfully!`);let r=await t.getConfigLocation();s.info(`Configuration saved to: ${r}`),o?(s.info("Project-level configuration created."),s.info("Subagents and commands will be installed to this project."),s.info(""),s.info("Consider adding .claude/ to your .gitignore:"),s.code('echo ".claude/" >> .gitignore')):s.info('You can now use "bwc add" to install subagents and commands.')}catch(r){throw c.fail(`Failed to initialize ${e} configuration`),r}}catch(t){s.error(t instanceof Error?t.message:"Unknown error"),process.exit(1)}})}import{Command as lt}from"commander";import I from"inquirer";import W from"path";import G from"got";import{z as g}from"zod";var ct=g.object({name:g.string(),category:g.string(),description:g.string(),version:g.string().default("1.0.0"),file:g.string(),tools:g.array(g.string()),tags:g.array(g.string()).default([]),sha:g.string().optional()}),gt=g.object({name:g.string(),category:g.string(),description:g.string(),version:g.string().default("1.0.0"),file:g.string(),prefix:g.string().default("/"),tags:g.array(g.string()).default([]),sha:g.string().optional()}),z=g.object({version:g.string(),lastUpdated:g.string(),subagents:g.array(ct),commands:g.array(gt)});var h=class{configManager;constructor(n){this.configManager=n}async fetchRegistry(){let n=await this.configManager.getRegistryUrl();try{let t=await G(n).json();return z.parse(t)}catch(t){throw t instanceof Error?new Error(`Failed to fetch registry: ${t.message}`):t}}async getSubagents(){return(await this.fetchRegistry()).subagents}async getCommands(){return(await this.fetchRegistry()).commands}async findSubagent(n){return(await this.getSubagents()).find(o=>o.name===n)}async findCommand(n){return(await this.getCommands()).find(o=>o.name===n)}async searchSubagents(n){let t=await this.getSubagents(),o=n.toLowerCase();return t.filter(e=>e.name.toLowerCase().includes(o)||e.description.toLowerCase().includes(o)||e.tags.some(c=>c.toLowerCase().includes(o)))}async searchCommands(n){let t=await this.getCommands(),o=n.toLowerCase();return t.filter(e=>e.name.toLowerCase().includes(o)||e.description.toLowerCase().includes(o)||e.tags.some(c=>c.toLowerCase().includes(o)))}async fetchFileContent(n){let o="https://raw.githubusercontent.com/davepoon/claude-code-subagents-collection/main/"+n;try{return await G(o).text()}catch(e){throw e instanceof Error?new Error(`Failed to fetch file content: ${e.message}`):e}}};function H(){return new lt("add").description("Add subagents or commands").option("-a, --agent <name>","add a specific subagent").option("-c, --command <name>","add a specific command").option("-g, --global","force global installation").action(async n=>{try{let t=new f,o=new h(t);await t.isUsingProjectConfig()&&!n.global&&s.info("Installing to project configuration"),n.agent?await Y(n.agent,t,o):n.command?await Q(n.command,t,o):await mt(t,o)}catch(t){s.error(t instanceof Error?t.message:"Unknown error"),process.exit(1)}})}async function Y(a,n,t){let o=s.spinner(`Fetching subagent: ${a}`);try{let e=await t.findSubagent(a);if(!e){o.fail(`Subagent "${a}" not found`);return}o.text=`Downloading ${e.name}...`;let c=await t.fetchFileContent(e.file),r=await n.getSubagentsPath(),i=W.join(r,`${e.name}.md`);await $(i,c),await n.addInstalledSubagent(e.name),o.succeed(`Successfully installed subagent: ${e.name}`),s.info(`Location: ${i}`),s.info(`Tools: ${e.tools.join(", ")}`)}catch(e){throw o.fail("Failed to add subagent"),e}}async function Q(a,n,t){let o=s.spinner(`Fetching command: ${a}`);try{let e=await t.findCommand(a);if(!e){o.fail(`Command "${a}" not found`);return}o.text=`Downloading ${e.name}...`;let c=await t.fetchFileContent(e.file),r=await n.getCommandsPath(),i=W.join(r,`${e.name}.md`);await $(i,c),await n.addInstalledCommand(e.name),o.succeed(`Successfully installed command: ${e.prefix}${e.name}`),s.info(`Location: ${i}`)}catch(e){throw o.fail("Failed to add command"),e}}async function mt(a,n){try{let{type:t}=await I.prompt([{type:"list",name:"type",message:"What would you like to add?",choices:[{name:"Subagent",value:"subagent"},{name:"Command",value:"command"}]}]);t==="subagent"?await dt(a,n):await ft(a,n)}catch(t){if(t instanceof Error&&t.message.includes("fetch registry"))s.error("Failed to connect to registry. Please check your internet connection."),s.info("Registry URL: "+await a.getRegistryUrl());else throw t}}async function dt(a,n){let t=await n.getSubagents(),o=[...new Set(t.map(i=>i.category))].sort(),{category:e}=await I.prompt([{type:"list",name:"category",message:"Select a category:",choices:["All",...o]}]),c=e==="All"?t:t.filter(i=>i.category===e);s.info("Use SPACE to select/deselect, ENTER to confirm");let{selected:r}=await I.prompt([{type:"checkbox",name:"selected",message:"Select subagents to install:",choices:c.map(i=>({name:`${i.name} - ${i.description}`,value:i.name,short:i.name})),validate:i=>i.length<1?"You must select at least one subagent!":!0}]);if(!r||r.length===0){s.warn("No subagents selected");return}s.info(`Installing ${r.length} subagent(s)...`);for(let i of r)await Y(i,a,n)}async function ft(a,n){let t=await n.getCommands(),o=[...new Set(t.map(i=>i.category))].sort(),{category:e}=await I.prompt([{type:"list",name:"category",message:"Select a category:",choices:["All",...o]}]),c=e==="All"?t:t.filter(i=>i.category===e);s.info("Use SPACE to select/deselect, ENTER to confirm");let{selected:r}=await I.prompt([{type:"checkbox",name:"selected",message:"Select commands to install:",choices:c.map(i=>({name:`${i.prefix}${i.name} - ${i.description}`,value:i.name,short:i.name})),validate:i=>i.length<1?"You must select at least one command!":!0}]);if(!r||r.length===0){s.warn("No commands selected");return}s.info(`Installing ${r.length} command(s)...`);for(let i of r)await Q(i,a,n)}import{Command as ut}from"commander";import y from"chalk";function X(){return new ut("list").description("List available subagents and commands").option("-a, --agents","list subagents only").option("-c, --commands","list commands only").option("--category <category>","filter by category").option("--installed","show only installed items").action(async n=>{try{let t=new f,o=new h(t),e=await t.isUsingProjectConfig(),c=await t.getConfigLocation(),r=e?"project":"global";s.info(`Using ${r} configuration: ${c}`),console.log(),n.agents?await K(t,o,n):n.commands?await V(t,o,n):(await K(t,o,n),console.log(),await V(t,o,n))}catch(t){s.error(t instanceof Error?t.message:"Unknown error"),process.exit(1)}})}async function K(a,n,t){let o=s.spinner("Fetching subagents...");try{let e=await n.getSubagents(),c=await a.getInstalledSubagents();t.category&&(e=e.filter(i=>i.category===t.category)),t.installed&&(e=e.filter(i=>c.includes(i.name))),o.stop(),s.heading("Available Subagents");let r=[...new Set(e.map(i=>i.category))].sort();for(let i of r){let d=e.filter(l=>l.category===i);console.log(` ${y.cyan(i)}:`);for(let l of d){let m=c.includes(l.name)?y.green(" \u2713"):"";console.log(` ${y.bold(l.name)}${m} - ${l.description}`),console.log(` ${y.gray(`Tools: ${l.tools.join(", ")}`)}`)}}console.log(` ${y.gray(`Total: ${e.length} subagents`)}`)}catch(e){throw o.fail("Failed to fetch subagents"),e}}async function V(a,n,t){let o=s.spinner("Fetching commands...");try{let e=await n.getCommands(),c=await a.getInstalledCommands();t.category&&(e=e.filter(i=>i.category===t.category)),t.installed&&(e=e.filter(i=>c.includes(i.name))),o.stop(),s.heading("Available Commands");let r=[...new Set(e.map(i=>i.category))].sort();for(let i of r){let d=e.filter(l=>l.category===i);console.log(` ${y.cyan(i)}:`);for(let l of d){let m=c.includes(l.name)?y.green(" \u2713"):"";console.log(` ${y.bold(l.prefix+l.name)}${m} - ${l.description}`)}}console.log(` ${y.gray(`Total: ${e.length} commands`)}`)}catch(e){throw o.fail("Failed to fetch commands"),e}}import{Command as ht}from"commander";import b from"chalk";function tt(){return new ht("search").description("Search for subagents and commands").argument("<query>","search query").option("-a, --agents","search subagents only").option("-c, --commands","search commands only").action(async(n,t)=>{try{let o=new f,e=new h(o);t.agents?await Z(n,o,e):t.commands?await q(n,o,e):(await Z(n,o,e),console.log(),await q(n,o,e))}catch(o){s.error(o instanceof Error?o.message:"Unknown error"),process.exit(1)}})}async function Z(a,n,t){let o=s.spinner(`Searching subagents for "${a}"...`);try{let e=await t.searchSubagents(a),c=await n.getInstalledSubagents();if(o.stop(),e.length===0){s.info(`No subagents found matching "${a}"`);return}s.heading(`Subagents matching "${a}" (${e.length} results)`);for(let r of e){let i=c.includes(r.name)?b.green(" \u2713"):"";console.log(` ${b.bold(r.name)}${i}`),console.log(` ${r.description}`),console.log(` ${b.gray(`Category: ${r.category}`)}`),console.log(` ${b.gray(`Tools: ${r.tools.join(", ")}`)}`),r.tags.length>0&&console.log(` ${b.gray(`Tags: ${r.tags.join(", ")}`)}`)}}catch(e){throw o.fail("Search failed"),e}}async function q(a,n,t){let o=s.spinner(`Searching commands for "${a}"...`);try{let e=await t.searchCommands(a),c=await n.getInstalledCommands();if(o.stop(),e.length===0){s.info(`No commands found matching "${a}"`);return}s.heading(`Commands matching "${a}" (${e.length} results)`);for(let r of e){let i=c.includes(r.name)?b.green(" \u2713"):"";console.log(` ${b.bold(r.prefix+r.name)}${i}`),console.log(` ${r.description}`),console.log(` ${b.gray(`Category: ${r.category}`)}`),r.tags.length>0&&console.log(` ${b.gray(`Tags: ${r.tags.join(", ")}`)}`)}}catch(e){throw o.fail("Search failed"),e}}import{Command as pt}from"commander";import nt from"path";function et(){return new pt("install").description("Install all subagents and commands from configuration").action(async()=>{try{let n=new f,t=new h(n),o=await n.isUsingProjectConfig(),e=await n.getConfigLocation();s.info(`Installing from: ${e}`);let{subagents:c,commands:r}=await n.getAllDependencies();if(c.length===0&&r.length===0){s.info("No dependencies to install.");return}if(s.heading(`Installing ${c.length} subagents and ${r.length} commands`),c.length>0){let i=await n.getSubagentsPath();s.info(`Installing subagents to: ${i}`);for(let d of c){let l=s.spinner(`Installing subagent: ${d}`);try{let m=await t.findSubagent(d);if(!m){l.fail(`Subagent "${d}" not found in registry`);continue}let E=await t.fetchFileContent(m.file),F=nt.join(i,`${m.name}.md`);await $(F,E),l.succeed(`Installed subagent: ${d}`)}catch(m){l.fail(`Failed to install subagent: ${d}`),s.error(m.message)}}}if(r.length>0){let i=await n.getCommandsPath();s.info(`Installing commands to: ${i}`);for(let d of r){let l=s.spinner(`Installing command: ${d}`);try{let m=await t.findCommand(d);if(!m){l.fail(`Command "${d}" not found in registry`);continue}let E=await t.fetchFileContent(m.file),F=nt.join(i,`${m.name}.md`);await $(F,E),l.succeed(`Installed command: ${m.prefix}${d}`)}catch(m){l.fail(`Failed to install command: ${d}`),s.error(m.message)}}}s.success("Installation complete!"),o&&s.info("Dependencies installed to project.")}catch(n){s.error(n instanceof Error?n.message:"Unknown error"),process.exit(1)}})}var St=Ct(import.meta.url),jt=Pt(St),ot=JSON.parse(bt($t(jt,"../package.json"),"utf-8"));yt({pkg:ot}).notify();var j=new wt().name("bwc").description("CLI tool for installing Claude Code subagents and commands").version(ot.version);j.addCommand(J());j.addCommand(H());j.addCommand(X());j.addCommand(tt());j.addCommand(et());j.parse();