bunli 0.7.1 → 0.8.0
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/README.md +10 -0
- package/dist/cli.js +3 -3
- package/dist/commands/dev.d.ts +1 -1
- package/dist/commands/release.d.ts +2 -2
- package/dist/commands/test.d.ts +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -258,10 +258,20 @@ export default defineConfig({
|
|
|
258
258
|
dev: {
|
|
259
259
|
watch: true,
|
|
260
260
|
inspect: false
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
tui: {
|
|
264
|
+
renderer: {
|
|
265
|
+
bufferMode: 'alternate' // or 'standard'
|
|
266
|
+
}
|
|
261
267
|
}
|
|
262
268
|
})
|
|
263
269
|
```
|
|
264
270
|
|
|
271
|
+
Default `tui.renderer.bufferMode` policy:
|
|
272
|
+
- `'standard'` by default
|
|
273
|
+
- set `'alternate'` explicitly for fullscreen/blocking terminal flows
|
|
274
|
+
|
|
265
275
|
### Build Behavior
|
|
266
276
|
|
|
267
277
|
The build system works as follows:
|
package/dist/cli.js
CHANGED
|
@@ -143,7 +143,7 @@ declare module '@bunli/core' {
|
|
|
143
143
|
`);return F0.err(new iX({message:`Failed to parse ${G.length} command module(s):
|
|
144
144
|
${z}`,cause:G}))}let Y=XY(Q),H=await this.writeTypes(Y);if(F0.isError(H))return F0.err(new iX({message:`Failed to write generated types to ${this.config.outputFile}`,cause:H.error}));if(this.config.generateReport){let z={commandsParsed:Q.length,filesScanned:Z.length,skipped:Z.filter((V)=>!Q.some((K)=>K.filePath===V)),parseErrors:G.map((V)=>({filePath:V.filePath,message:V.message})),names:Q.map((V)=>V.name).sort()},W=await this.writeReport(z);if(F0.isError(W))return F0.err(new iX({message:`Failed to write generation report for ${this.config.outputFile}`,cause:W.error}))}return console.log(`\u2713 Generated types for ${Q.length} commands`),F0.ok()}async scanCommands(){return await this.scanner.scanCommands(this.config.entry,this.config.directory)}async parseCommands(J){let X=[],Z=[];for(let Q of J){m7(`Parsing file: ${Q}`);let G=this.config.directory?AP(this.config.directory):OP(AP(this.config.entry)),Y=await JY(Q,G,this.config.outputFile);if(F0.isError(Y)){Z.push(Y.error),m7(`\u274C Failed to parse: ${Q}`);continue}let H=Y.value;if(H)m7(`\u2705 Successfully parsed: ${H.name}`),X.push(H);else m7(`\u274C Failed to parse: ${Q}`)}return{commands:X,parseErrors:Z}}async writeTypes(J){return F0.tryPromise({try:async()=>{let X=OP(this.config.outputFile);await a11(X,{recursive:!0}),await Bun.write(this.config.outputFile,J)},catch:(X)=>new Q2({outputFile:this.config.outputFile,message:`Could not write generated types to ${this.config.outputFile}`,cause:X})})}async writeReport(J){let X=this.config.outputFile.replace(/\.ts$/,".report.json");return F0.tryPromise({try:async()=>{await Bun.write(X,JSON.stringify(J,null,2))},catch:(Z)=>new G2({reportFile:X,message:`Could not write generator report to ${X}`,cause:Z})})}getConfig(){return{...this.config}}updateConfig(J){this.config={...this.config,...J}}}import{createLogger as d11}from"@bunli/core/utils";var c7=d11("generator:plugin");function ZY(J={}){let{entry:X="./cli.ts",directory:Z,outputFile:Q="./commands.gen.ts",config:G,generateReport:Y}=J,H=null;return{name:"bunli-codegen",setup(z){H=new s1({entry:X,directory:Z,outputFile:Q,config:G,generateReport:Y}),z.onStart(async()=>{if(H){c7.debug("Generating command types...");let W=await H.run();if(F0.isError(W)){c7.warn("Failed to generate command types: %s",W.error.message);return}c7.debug("Command types generated")}}),z.onEnd(async(W)=>{if(W.success&&H){let V=await H.run();if(F0.isError(V))c7.warn("Failed to regenerate types: %s",V.error.message)}})}}}import{z as MX}from"zod";import{loadConfig as t11}from"@bunli/core";import{existsSync as IP}from"fs";import NP from"path";var s11=["src/cli.ts","src/index.ts","src/main.ts","cli.ts","index.ts","main.ts","src/cli.js","src/index.js","src/main.js","cli.js","index.js","main.js"];async function C9(J=process.cwd()){for(let Z of s11){let Q=NP.join(J,Z);if(IP(Q))return Z}let X=NP.join(J,"package.json");if(IP(X))try{let Z=await Bun.file(X).json();if(Z.bin){if(typeof Z.bin==="string")return Z.bin;else if(typeof Z.bin==="object"){let Q=Object.values(Z.bin)[0];if(typeof Q==="string")return Q}}}catch{}return}var{$:kX}=globalThis.Bun;import m8 from"path";var o11=DJ("BuildCommandError")(),q9=(J,X)=>F0.err(new o11({message:J,cause:X})),SP=n11({name:"build",description:"Build your CLI for production",alias:"b",options:{entry:BX(MX.string().optional(),{short:"e",description:"Entry file (defaults to auto-detect)"}),outdir:BX(MX.string().optional(),{short:"o",description:"Output directory"}),outfile:BX(MX.string().optional(),{description:"Output filename (for single executable)"}),minify:BX(MX.boolean().optional(),{short:"m",description:"Minify output"}),sourcemap:BX(MX.boolean().optional(),{short:"s",description:"Generate sourcemaps"}),bytecode:BX(MX.boolean().default(!1),{description:"Enable bytecode compilation (experimental)"}),runtime:BX(MX.enum(["bun","node"]).optional(),{short:"r",description:"Runtime target (for non-compiled builds)"}),targets:BX(MX.string().optional().transform((J)=>{if(!J)return;return J.split(",").map((X)=>X.trim())}),{short:"t",description:"Target platforms for compilation (e.g., darwin-arm64,linux-x64)"}),watch:BX(MX.boolean().default(!1),{short:"w",description:"Watch for changes"})},handler:async({flags:J,spinner:X,colors:Z})=>{let Q=await e11(J,X,Z);if(Q.isErr())throw Q.error}});async function e11(J,X,Z){let Q=await t11(),G=J,Y=G.entry||Q.build?.entry||await C9();if(!Y)return q9("No entry file found. Please specify with --entry or in bunli.config.ts");let H=Array.isArray(Y)?Y:[Y],z=H[0];if(!z)return q9("Entry file is undefined");let V=Q.commands?.entry||z;{let h=X("Generating types..."),_=await new s1({entry:V,directory:Q.commands?.directory,outputFile:"./.bunli/commands.gen.ts",config:Q,generateReport:Q.commands?.generateReport}).run();if(F0.isError(_))return h.fail("Failed to generate types"),q9(_.error.message,_.error);h.succeed("Types generated")}let K=G.targets||Q.build?.targets,R=Boolean(K&&K.length>0);if(R&&H.length>1)return q9("Compiled builds only support a single entry file");let S=z,T=G.outdir||Q.build?.outdir||"./dist",b=X("Building CLI...");b.start();try{if(await kX`rm -rf ${T}`,await kX`mkdir -p ${T}`,R){b.update("Compiling to standalone executable...");let f=[];if(K?.includes("all"))f=["darwin-arm64","darwin-x64","linux-arm64","linux-x64","windows-x64"];else if(K?.includes("native"))f=[`${process.platform}-${process.arch}`];else f=K??[];for(let _ of f){b.update(`Compiling for ${_}...`);let a=f.length>1?m8.join(T,_):T;await kX`mkdir -p ${a}`;let n=m8.extname(S),V0=n?S.slice(0,-n.length):S,S0=m8.basename(V0),y0=_.includes("windows"),m0=G.outfile||m8.join(a,y0?`${S0}.exe`:S0),s0=["build",S,"--compile","--outfile",m0,"--target",`bun-${_}`];if(G.minify??Q.build?.minify??!0)s0.push("--minify");if(G.sourcemap??Q.build?.sourcemap??!1)s0.push("--sourcemap");if(G.bytecode)s0.push("--bytecode");let LJ=Q.build?.external||[];for(let kJ of LJ)s0.push("--external",kJ);if((await kX`bun ${s0}`.quiet()).exitCode!==0)return q9(`Compilation failed for ${_}`)}if(Q.build?.compress&&f.length>1){b.update("Compressing builds...");for(let _ of f)await kX`cd ${T} && tar -czf ${_}.tar.gz ${_}`,await kX`rm -rf ${T}/${_}`}}else{let f=await Bun.build({entrypoints:H,outdir:T,target:G.runtime||"bun",format:"esm",minify:G.minify??Q.build?.minify??!0,sourcemap:G.sourcemap??Q.build?.sourcemap??!1,external:Q.build?.external||[],plugins:[ZY({entry:V,directory:Q.commands?.directory,outputFile:"./.bunli/commands.gen.ts",config:Q})]});if(!f.success)return q9(`Build failed: ${f.logs.join(`
|
|
145
145
|
`)}`);for(let _ of f.outputs)if(_.path.endsWith(".js")){let c=await _.text(),a=G.runtime==="node"?"node":"bun",n=c.replace(/^#![^\n]*\n/,""),V0=`#!/usr/bin/env ${a}
|
|
146
|
-
${n}`;await Bun.write(_.path,V0),await kX`chmod +x ${_.path}`}}b.succeed("Build complete!");let h=await kX`du -sh ${T}`.text();return console.log(Z.dim(`Output size: ${h.trim()}`)),F0.ok(void 0)}catch(h){return b.fail("Build failed"),q9(h instanceof Error?h.message:String(h),h)}}import{defineCommand as JX1,option as $6}from"@bunli/core";import{z as B6}from"zod";import{loadConfig as XX1}from"@bunli/core";import R6 from"path";import{existsSync as QY,statSync as ZX1}from"fs";import{watch as QX1}from"fs/promises";var GX1=DJ("DevCommandError")(),M6=(J,X)=>F0.err(new GX1({message:J,cause:X}));function GY(J){try{return ZX1(J).isDirectory()}catch{return!1}}function YX1(J,X){if(X)return R6.resolve(X);let Z=process.cwd(),Q=R6.resolve(Z,"commands");if(GY(Q))return Q;let G=R6.resolve(Z,"src/commands");if(GY(G))return G;let Y=R6.dirname(J);if(Y!==Z)return Y;let H=R6.resolve(Z,"src");if(GY(H))return H;return null}var wP=JX1({name:"dev",description:"Run your CLI in development mode with hot reload",alias:"d",options:{entry:$6(B6.string().optional(),{short:"e",description:"Entry file (defaults to auto-detect)"}),generate:$6(B6.boolean().default(!0),{description:"Enable codegen"}),clearScreen:$6(B6.boolean().default(!0),{description:"Clear screen on reload"}),watch:$6(B6.boolean().default(!0),{short:"w",description:"Watch for changes"}),inspect:$6(B6.boolean().default(!1),{short:"i",description:"Enable debugger"}),port:$6(B6.number().int().min(1).max(65535).optional(),{short:"p",description:"Debugger port"})},handler:async({flags:J,positional:X,spinner:Z,colors:Q})=>{let G=await HX1(J,X,Z,Q);if(G.isErr())throw G.error}});async function HX1(J,X,Z,Q){let G=await XX1(),Y=J,H=async()=>{if(!Y.generate)return F0.ok(void 0);let a=G.commands?.entry||G.build?.entry,n=Array.isArray(a)?a[0]:a,V0=await C9(),S0=Y.entry||n||V0;if(!S0)return M6("No entry file found for code generation. Set commands.entry or pass --entry.");let m0=await new s1({entry:S0,directory:G.commands?.directory,outputFile:"./.bunli/commands.gen.ts",config:G,generateReport:G.commands?.generateReport}).run();if(F0.isError(m0))return M6(`Failed to generate types: ${m0.error.message}`,m0.error);return F0.ok(void 0)};if(Y.generate){let a=Z("Generating command types..."),n=await H();if(n.isErr())return a.fail("Failed to generate types"),n;a.succeed("Types generated")}let z=G.commands?.entry||G.build?.entry,W=Array.isArray(z)?z[0]:z,V=Y.entry||W||await C9();if(!V)return M6("No entry file found. Please specify with --entry or in bunli.config.ts");let K=Array.isArray(V)?V[0]:V;if(!K)return M6("Entry file is required");let R=R6.resolve(K);if(!QY(R))return M6(`Entry file not found: ${R}`);let S=[];if(Y.watch??G.dev?.watch??!0)S.push("--hot");if(Y.inspect){if(S.push("--inspect"),Y.port)S.push(`--inspect-port=${Y.port}`)}else if(Y.port)S.push(`--inspect-port=${Y.port}`);if(S.push(R),X.length>0)S.push(...X);if(console.log(Q.cyan(`
|
|
146
|
+
${n}`;await Bun.write(_.path,V0),await kX`chmod +x ${_.path}`}}b.succeed("Build complete!");let h=await kX`du -sh ${T}`.text();return console.log(Z.dim(`Output size: ${h.trim()}`)),F0.ok(void 0)}catch(h){return b.fail("Build failed"),q9(h instanceof Error?h.message:String(h),h)}}import{defineCommand as JX1,option as $6}from"@bunli/core";import{z as B6}from"zod";import{loadConfig as XX1}from"@bunli/core";import R6 from"path";import{existsSync as QY,statSync as ZX1}from"fs";import{watch as QX1}from"fs/promises";var GX1=DJ("DevCommandError")(),M6=(J,X)=>F0.err(new GX1({message:J,cause:X}));function GY(J){try{return ZX1(J).isDirectory()}catch{return!1}}function YX1(J,X){if(X)return R6.resolve(X);let Z=process.cwd(),Q=R6.resolve(Z,"commands");if(GY(Q))return Q;let G=R6.resolve(Z,"src/commands");if(GY(G))return G;let Y=R6.dirname(J);if(Y!==Z)return Y;let H=R6.resolve(Z,"src");if(GY(H))return H;return null}var wP=JX1({name:"dev",description:"Run your CLI in development mode with hot reload",alias:"d",options:{entry:$6(B6.string().optional(),{short:"e",description:"Entry file (defaults to auto-detect)"}),generate:$6(B6.boolean().default(!0),{description:"Enable codegen"}),clearScreen:$6(B6.boolean().default(!0),{description:"Clear screen on reload"}),watch:$6(B6.boolean().default(!0),{short:"w",description:"Watch for changes"}),inspect:$6(B6.boolean().default(!1),{short:"i",description:"Enable debugger"}),port:$6(B6.coerce.number().int().min(1).max(65535).optional(),{short:"p",description:"Debugger port"})},handler:async({flags:J,positional:X,spinner:Z,colors:Q})=>{let G=await HX1(J,X,Z,Q);if(G.isErr())throw G.error}});async function HX1(J,X,Z,Q){let G=await XX1(),Y=J,H=async()=>{if(!Y.generate)return F0.ok(void 0);let a=G.commands?.entry||G.build?.entry,n=Array.isArray(a)?a[0]:a,V0=await C9(),S0=Y.entry||n||V0;if(!S0)return M6("No entry file found for code generation. Set commands.entry or pass --entry.");let m0=await new s1({entry:S0,directory:G.commands?.directory,outputFile:"./.bunli/commands.gen.ts",config:G,generateReport:G.commands?.generateReport}).run();if(F0.isError(m0))return M6(`Failed to generate types: ${m0.error.message}`,m0.error);return F0.ok(void 0)};if(Y.generate){let a=Z("Generating command types..."),n=await H();if(n.isErr())return a.fail("Failed to generate types"),n;a.succeed("Types generated")}let z=G.commands?.entry||G.build?.entry,W=Array.isArray(z)?z[0]:z,V=Y.entry||W||await C9();if(!V)return M6("No entry file found. Please specify with --entry or in bunli.config.ts");let K=Array.isArray(V)?V[0]:V;if(!K)return M6("Entry file is required");let R=R6.resolve(K);if(!QY(R))return M6(`Entry file not found: ${R}`);let S=[];if(Y.watch??G.dev?.watch??!0)S.push("--hot");if(Y.inspect){if(S.push("--inspect"),Y.port)S.push(`--inspect-port=${Y.port}`)}else if(Y.port)S.push(`--inspect-port=${Y.port}`);if(S.push(R),X.length>0)S.push(...X);if(console.log(Q.cyan(`
|
|
147
147
|
\uD83D\uDC40 Starting dev mode...
|
|
148
148
|
`)),Y.watch??G.dev?.watch??!0)console.log(Q.dim(`Running: bun ${S.join(" ")}
|
|
149
149
|
`));let T=null;if(Y.watch??G.dev?.watch??!0){let a=YX1(R,G.commands?.directory);if(Y.generate&&a&&QY(a)){console.log(Q.dim(`Watching command changes in ${a}`)),T=new AbortController;let{signal:n}=T;(async()=>{try{let S0=QX1(a,{recursive:!0,signal:n});for await(let y0 of S0){if(!y0.filename?.match(/\.(ts|tsx|js|jsx)$/))continue;if(y0.filename?.includes("commands.gen.ts"))continue;if(y0.filename?.includes(".bunli/"))continue;console.log(Q.dim(`
|
|
@@ -175,11 +175,11 @@ try {
|
|
|
175
175
|
console.error('Binary not found. Try reinstalling ' + pkg + '.')
|
|
176
176
|
process.exit(1)
|
|
177
177
|
}
|
|
178
|
-
`;var qX1=["darwin-arm64","darwin-x64","linux-arm64","linux-x64","windows-x64"],HY={"darwin-arm64":{os:"darwin",cpu:"arm64"},"darwin-x64":{os:"darwin",cpu:"x64"},"linux-arm64":{os:"linux",cpu:"arm64"},"linux-x64":{os:"linux",cpu:"x64"},"windows-x64":{os:"win32",cpu:"x64"}};function OX1(J){if(J.includes("all"))return qX1;return J.flatMap((X)=>X==="native"?[`${process.platform}-${process.arch}`]:[X]).filter((X)=>(X in HY))}function AX1(J){if(!J.length)throw Error("Binary release requires build.targets to include at least one platform");let X=J.filter((Q)=>Q!=="all"&&Q!=="native"&&!(Q in HY));if(X.length>0)throw Error(`Unsupported build.targets for binary release: ${X.join(", ")}`);let Z=Array.from(new Set(OX1(J)));if(Z.length===0)throw Error("Binary release resolved to zero supported platforms");return Z}function PX1(J,X,Z){return J.replace("{{name}}",X).replace("{{platform}}",Z)}function IX1(J){let X={};for(let Z of J){let Q=Z.platform.startsWith("windows")?Z.platform.replace("windows","win32"):Z.platform;X[Q]=Z.packageName}return X}function NX1(J,X){return X.replaceAll("{{version}}",J).replaceAll("${version}",J)}function kP(J){return["npm","publish","--access","public",...J?["--dry-run"]:[]]}var gP=FX1({name:"release",description:"Create a release of your CLI",alias:"r",options:{version:C6(O9.enum(["patch","minor","major"]).or(O9.string()).optional(),{short:"
|
|
178
|
+
`;var qX1=["darwin-arm64","darwin-x64","linux-arm64","linux-x64","windows-x64"],HY={"darwin-arm64":{os:"darwin",cpu:"arm64"},"darwin-x64":{os:"darwin",cpu:"x64"},"linux-arm64":{os:"linux",cpu:"arm64"},"linux-x64":{os:"linux",cpu:"x64"},"windows-x64":{os:"win32",cpu:"x64"}};function OX1(J){if(J.includes("all"))return qX1;return J.flatMap((X)=>X==="native"?[`${process.platform}-${process.arch}`]:[X]).filter((X)=>(X in HY))}function AX1(J){if(!J.length)throw Error("Binary release requires build.targets to include at least one platform");let X=J.filter((Q)=>Q!=="all"&&Q!=="native"&&!(Q in HY));if(X.length>0)throw Error(`Unsupported build.targets for binary release: ${X.join(", ")}`);let Z=Array.from(new Set(OX1(J)));if(Z.length===0)throw Error("Binary release resolved to zero supported platforms");return Z}function PX1(J,X,Z){return J.replace("{{name}}",X).replace("{{platform}}",Z)}function IX1(J){let X={};for(let Z of J){let Q=Z.platform.startsWith("windows")?Z.platform.replace("windows","win32"):Z.platform;X[Q]=Z.packageName}return X}function NX1(J,X){return X.replaceAll("{{version}}",J).replaceAll("${version}",J)}function kP(J){return["npm","publish","--access","public",...J?["--dry-run"]:[]]}var gP=FX1({name:"release",description:"Create a release of your CLI",alias:"r",options:{version:C6(O9.enum(["patch","minor","major"]).or(O9.string()).optional(),{short:"V",description:"Version to release (patch/minor/major/x.y.z)"}),tag:C6(O9.string().optional(),{short:"t",description:"Git tag format"}),npm:C6(O9.boolean().optional(),{description:"Publish to npm"}),github:C6(O9.boolean().optional(),{description:"Create GitHub release"}),dry:C6(O9.boolean().default(!1),{short:"d",description:"Dry run - show what would be done"}),all:C6(O9.boolean().default(!1),{description:"Release all packages (workspace mode)"})},handler:async({flags:J,prompt:X,spinner:Z,colors:Q,runtime:G})=>{let Y=wX1(G.args);if(Y.length>0)console.error(Q.red(`Unsupported flags: ${Y.join(", ")}. Use --npm=false or --github=false.`)),process.exit(1);let H=await CX1();if(J.all)console.error(Q.red("Workspace release (--all) is not implemented yet.")),process.exit(1);try{if((await wJ`git status --porcelain`.text()).trim()&&!J.dry)console.error(Q.red("Working directory is not clean. Please commit or stash changes first.")),process.exit(1)}catch{console.error(Q.red("Not a git repository")),process.exit(1)}await SX1(J,H,X,Z,Q)}});async function SX1(J,X,Z,Q,G){let Y=await zY(),H=await Bun.file("package.json").text(),z=LX1(Y),W=Y.version??"0.0.0",V=X.release.binary,K=V?.shimPath,R=K?await Bun.file(K).exists():!1,S=K&&R?await Bun.file(K).text():null,T=await TX1(J.version,W,Z);if(T===W)console.error(G.red(`Version unchanged: ${T}. Please choose a different version.`)),process.exit(1);let b=J.npm??X.release.npm,h=J.github??X.release.github,f=null;if(V&&b){if(X.build.compress)console.error(G.red("Binary release is incompatible with build.compress: true - raw binaries are removed after compression.")),process.exit(1);try{f=DX1(X)}catch(a){console.error(G.red(a instanceof Error?a.message:String(a))),process.exit(1)}}let _=NX1(T,J.tag??X.release.tagFormat);if(console.log(G.bold(`Releasing ${Y.name||"CLI"}`)),console.log(G.dim(` Current: ${W}`)),console.log(G.dim(` New: ${T}`)),console.log(G.dim(` Tag: ${_}`)),f)console.log(G.dim(` Mode: binary (${f.platforms.length} platforms)`));if(console.log(),!J.dry){if(!await Z.confirm("Continue with release?",{default:!0})){console.log(G.yellow("Release cancelled"));return}}let c=[{name:"Running tests",cmd:async()=>{let a=await wJ`bun test`.nothrow(),n=a.stderr.toString();if(a.exitCode!==0&&!n.includes("No tests found"))throw Error(`Tests failed with exit code ${a.exitCode}`)}},{name:"Updating version",runInDry:!0,cmd:()=>bX1(T)},{name:"Building project",cmd:()=>wJ`bun run build`.then()},...f?[{name:"Publishing platform packages",runInDry:!0,cmd:async()=>{let a=await gX1({context:f,pkg:Y,cliBinName:z,newVersion:T,binaryConfig:V,dry:J.dry,spinner:Q,colors:G});await vX1(a,V.shimPath,z),await EX1(V.shimPath,a,z)}}]:[],{name:"Creating git tag",cmd:()=>fX1({tag:_,conventionalCommits:X.release.conventionalCommits,shimPath:V?.shimPath})},{name:"Publishing to npm",skip:!b,runInDry:!0,cmd:()=>hX1(Y,J.dry)},{name:"Creating GitHub release",skip:!h,cmd:()=>_X1(_)}];try{for(let a of c){if(a.skip)continue;let n=Q(a.name);n.start();try{if(!J.dry||a.runInDry)await a.cmd();n.succeed(a.name)}catch(V0){n.fail(a.name),console.error(G.red(V0 instanceof Error?V0.message:String(V0))),process.exit(1)}}}finally{if(f)await wJ`rm -rf .bunli/platform-packages`.nothrow();if(J.dry){if(await Bun.write("package.json",H),K)if(R&&S!==null)await Bun.write(K,S);else await wJ`rm -f ${K}`.nothrow()}}if(console.log(),console.log(G.green(`\u2728 Released ${Y.name||"CLI"} ${_}!`)),h)console.log(G.dim(`GitHub: https://github.com/${await xX1()}/releases/tag/${_}`));if(b)console.log(G.dim(`NPM: https://npmjs.com/package/${Y.name}`))}function wX1(J){return J.filter((X)=>X==="--no-npm"||X==="--no-github")}function LX1(J){if(J.bin){let X=Object.keys(J.bin);if(X.length>0&&X[0])return X[0]}if(J.name.includes("/")){let X=J.name.split("/").at(-1);if(X)return X}return J.name}function DX1(J){let X=AX1(J.build.targets),Z=J.build.outdir??"./dist",Q=J.build.entry;if(!Q)throw Error("build.entry must be set for binary release");let G=Array.isArray(Q)?Q[0]:Q;if(!G)throw Error("build.entry must be set for binary release");let Y=n1.basename(G,n1.extname(G));return{platforms:X,outdir:Z,baseName:Y}}async function zY(){return Bun.file("package.json").json()}async function TX1(J,X,Z){if(J){if(["patch","minor","major"].includes(J))return c8(X,J);return J}let Q=await Z.select("Select version bump:",{options:[{label:`patch (${c8(X,"patch")})`,value:"patch"},{label:`minor (${c8(X,"minor")})`,value:"minor"},{label:`major (${c8(X,"major")})`,value:"major"},{label:"custom",value:"custom"}]});if(Q==="custom")return await Z("Enter version:");return c8(X,Q)}function c8(J,X){let Z=J.split(".").map(Number),[Q=0,G=0,Y=0]=Z;switch(X){case"patch":return`${Q}.${G}.${Y+1}`;case"minor":return`${Q}.${G+1}.0`;case"major":return`${Q+1}.0.0`}}async function bX1(J){let X=await zY();X.version=J,await Bun.write("package.json",JSON.stringify(X,null,2)+`
|
|
179
179
|
`)}async function kX1(J,X){let Q=X.startsWith("windows")?".exe":"",G=n1.join(J.outdir,X,`${J.baseName}${Q}`),Y=n1.join(J.outdir,`${J.baseName}${Q}`);if(await Bun.file(G).exists())return G;if(J.platforms.length===1&&await Bun.file(Y).exists())return Y;throw Error(`Binary artifact not found for ${X}. Checked: ${G}${J.platforms.length===1?` and ${Y}`:""}`)}async function gX1(J){let{context:X,pkg:Z,cliBinName:Q,newVersion:G,binaryConfig:Y,dry:H,spinner:z,colors:W}=J,V=[];for(let K of X.platforms){let R=HY[K];if(!R)throw Error(`Unsupported platform metadata: ${K}`);let S=await kX1(X,K),b=K.startsWith("windows")?".exe":"",h=PX1(Y.packageNameFormat,Z.name,K),f=n1.join(".bunli","platform-packages",K),_=n1.join(f,"bin");await wJ`mkdir -p ${_}`,await wJ`cp ${S} ${n1.join(_,`${Q}${b}`)}`;let c={name:h,version:G,description:`${K} binary for ${Z.name}`,os:[R.os],cpu:[R.cpu],bin:{[Q]:`bin/${Q}${b}`},...Z.license?{license:Z.license}:{}};await Bun.write(n1.join(f,"package.json"),JSON.stringify(c,null,2)+`
|
|
180
180
|
`);let a=z(`Publishing ${h}`);a.stop(),console.log(W.dim(`
|
|
181
181
|
Publishing ${h}${H?" (dry-run)":""}...`));let n=kP(H),S0=await Bun.spawn(n,{cwd:n1.resolve(f),stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited;if(S0!==0)throw Error(`Failed to publish ${h} (exit code ${S0})`);a.succeed(`Published ${h}`),V.push({platform:K,packageName:h,version:G})}if(V.length===0)throw Error("Binary release did not publish any platform packages");return V}async function vX1(J,X,Z){let Q=await zY(),G=Object.fromEntries(J.map((Y)=>[Y.packageName,Y.version]));Q.optionalDependencies={...Q.optionalDependencies,...G},Q.bin={...Q.bin,[Z]:X},await Bun.write("package.json",JSON.stringify(Q,null,2)+`
|
|
182
|
-
`)}async function EX1(J,X,Z){let Q=IX1(X),G=bP.replace("__PLATFORM_MAP__",JSON.stringify(Q,null,2)).replaceAll("__CLI_BIN_NAME__",Z),Y=n1.dirname(J);await wJ`mkdir -p ${Y}`,await Bun.write(J,G),await wJ`chmod +x ${J}`}async function fX1(J){let{tag:X,conventionalCommits:Z,shimPath:Q}=J;if(await wJ`git add package.json`,Q)await wJ`git add ${Q}`.nothrow();let G=Z?`chore(release): ${X}`:`chore: release ${X}`;await wJ`git commit -m ${G}`,await wJ`git tag ${X}`,await wJ`git push origin main --tags`}async function hX1(J,X){if(J.private)throw Error("Cannot publish private package to npm");let Z=kP(X),G=await Bun.spawn(Z,{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited;if(G!==0)throw Error(`npm publish failed (exit code ${G})`)}async function _X1(J){try{await wJ`gh --version`.quiet()}catch{console.warn("GitHub CLI not found, skipping GitHub release");return}await wJ`gh release create ${J} --title "Release ${J}" --generate-notes`}async function xX1(){let J=await wJ`git remote get-url origin`.nothrow();if(J.exitCode!==0)return"unknown/repo";return J.stdout.toString().match(/github\.com[:/]([^\s/]+\/[^\s/]+?)(?:\.git)?(?:\s|$)/)?.[1]??"unknown/repo"}import{defineCommand as uX1,option as q6}from"@bunli/core";import{z as gX}from"zod";import{loadConfig as yX1}from"@bunli/core";import{spawn as mX1}from"child_process";import{readdir as cX1}from"fs/promises";import{existsSync as vP}from"fs";import EP from"path";var hP=uX1({name:"test",description:"Run tests for your CLI",alias:"t",options:{pattern:q6(gX.string().or(gX.array(gX.string())).optional(),{short:"p",description:"Test file patterns"}),watch:q6(gX.boolean().default(!1),{short:"w",description:"Watch for changes"}),coverage:q6(gX.boolean().default(!1),{short:"c",description:"Generate coverage report"}),bail:q6(gX.boolean().default(!1),{short:"b",description:"Stop on first failure"}),timeout:q6(gX.number().int().positive().optional(),{description:"Test timeout in milliseconds"}),all:q6(gX.boolean().default(!1),{description:"Run tests in all packages (workspace mode)"})},handler:async({flags:J,positional:X,spinner:Z,colors:Q})=>{let G=await yX1();if(J.all&&G.workspace?.packages){let Y=G.workspace.packages,H=!0;for(let z of Y){let W=await lX1(z);for(let V of W){let K=Z(`Testing ${V}...`);K.start();try{if((await fP(V,J,G)).success)K.succeed(`${V} tests passed`);else if(K.fail(`${V} tests failed`),H=!1,J.bail)break}catch(R){if(K.fail(`${V} tests failed`),console.error(Q.red(R instanceof Error?R.message:String(R))),H=!1,J.bail)break}}if(!H&&J.bail)break}if(!H)process.exit(1)}else{let Y=Z("Running tests...");Y.start();try{let H=await fP(".",J,G);if(H.success){if(Y.succeed("All tests passed!"),console.log(Q.green(`\u2713 ${H.passed} tests passed`)),H.skipped>0)console.log(Q.yellow(`\u229D ${H.skipped} tests skipped`))}else Y.fail("Tests failed"),console.log(Q.red(`\u2717 ${H.failed} tests failed`)),process.exit(1)}catch(H){Y.fail("Tests failed"),console.error(Q.red(H instanceof Error?H.message:String(H))),process.exit(1)}}}});async function fP(J,X,Z){return new Promise((Q,G)=>{let Y=["test"],H=X.pattern||Z.test?.pattern||"**/*.test.ts",z=Array.isArray(H)?H:[H];if(Y.push(...z),X.watch??Z.test?.watch)Y.push("--watch");if(X.coverage??Z.test?.coverage)Y.push("--coverage");if(X.bail)Y.push("--bail");if(X.timeout)Y.push("--timeout",X.timeout.toString());let W=mX1("bun",Y,{cwd:J,stdio:["inherit","pipe","pipe"],env:{...process.env,NODE_ENV:"test"}}),V="",K="";W.stdout?.on("data",(R)=>{V+=R.toString(),process.stdout.write(R)}),W.stderr?.on("data",(R)=>{K+=R.toString(),process.stderr.write(R)}),W.on("exit",(R)=>{let S=(V.match(/\u2713/g)||[]).length,T=(V.match(/\u2717/g)||[]).length,b=(V.match(/\u229D/g)||[]).length;Q({success:R===0,passed:S,failed:T,skipped:b})}),W.on("error",G)})}async function lX1(J){if(J.endsWith("/*")){let X=J.slice(0,-2);if(vP(X))return(await cX1(X,{withFileTypes:!0})).filter((Q)=>Q.isDirectory()&&vP(EP.join(X,Q.name,"package.json"))).map((Q)=>EP.join(X,Q.name))}return[]}import{defineGroup as a91}from"@bunli/core";import{createCLI as y91,defineCommand as m91,option as oP}from"@bunli/core";import{createPlugin as iX1}from"@bunli/core/plugin";import{defineCommand as rX1}from"@bunli/core";import nX1 from"assert";import{resolve as aP}from"path";import{readFile as I91}from"fs/promises";import{pathToFileURL as N91}from"url";import{GLOBAL_FLAGS as D91}from"@bunli/core";function pX1(J,X){return`#compdef ${J}
|
|
182
|
+
`)}async function EX1(J,X,Z){let Q=IX1(X),G=bP.replace("__PLATFORM_MAP__",JSON.stringify(Q,null,2)).replaceAll("__CLI_BIN_NAME__",Z),Y=n1.dirname(J);await wJ`mkdir -p ${Y}`,await Bun.write(J,G),await wJ`chmod +x ${J}`}async function fX1(J){let{tag:X,conventionalCommits:Z,shimPath:Q}=J;if(await wJ`git add package.json`,Q)await wJ`git add ${Q}`.nothrow();let G=Z?`chore(release): ${X}`:`chore: release ${X}`;await wJ`git commit -m ${G}`,await wJ`git tag ${X}`,await wJ`git push origin main --tags`}async function hX1(J,X){if(J.private)throw Error("Cannot publish private package to npm");let Z=kP(X),G=await Bun.spawn(Z,{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited;if(G!==0)throw Error(`npm publish failed (exit code ${G})`)}async function _X1(J){try{await wJ`gh --version`.quiet()}catch{console.warn("GitHub CLI not found, skipping GitHub release");return}await wJ`gh release create ${J} --title "Release ${J}" --generate-notes`}async function xX1(){let J=await wJ`git remote get-url origin`.nothrow();if(J.exitCode!==0)return"unknown/repo";return J.stdout.toString().match(/github\.com[:/]([^\s/]+\/[^\s/]+?)(?:\.git)?(?:\s|$)/)?.[1]??"unknown/repo"}import{defineCommand as uX1,option as q6}from"@bunli/core";import{z as gX}from"zod";import{loadConfig as yX1}from"@bunli/core";import{spawn as mX1}from"child_process";import{readdir as cX1}from"fs/promises";import{existsSync as vP}from"fs";import EP from"path";var hP=uX1({name:"test",description:"Run tests for your CLI",alias:"t",options:{pattern:q6(gX.string().or(gX.array(gX.string())).optional(),{short:"p",description:"Test file patterns"}),watch:q6(gX.boolean().default(!1),{short:"w",description:"Watch for changes"}),coverage:q6(gX.boolean().default(!1),{short:"c",description:"Generate coverage report"}),bail:q6(gX.boolean().default(!1),{short:"b",description:"Stop on first failure"}),timeout:q6(gX.coerce.number().int().positive().optional(),{description:"Test timeout in milliseconds"}),all:q6(gX.boolean().default(!1),{description:"Run tests in all packages (workspace mode)"})},handler:async({flags:J,positional:X,spinner:Z,colors:Q})=>{let G=await yX1();if(J.all&&G.workspace?.packages){let Y=G.workspace.packages,H=!0;for(let z of Y){let W=await lX1(z);for(let V of W){let K=Z(`Testing ${V}...`);K.start();try{if((await fP(V,J,G)).success)K.succeed(`${V} tests passed`);else if(K.fail(`${V} tests failed`),H=!1,J.bail)break}catch(R){if(K.fail(`${V} tests failed`),console.error(Q.red(R instanceof Error?R.message:String(R))),H=!1,J.bail)break}}if(!H&&J.bail)break}if(!H)process.exit(1)}else{let Y=Z("Running tests...");Y.start();try{let H=await fP(".",J,G);if(H.success){if(Y.succeed("All tests passed!"),console.log(Q.green(`\u2713 ${H.passed} tests passed`)),H.skipped>0)console.log(Q.yellow(`\u229D ${H.skipped} tests skipped`))}else Y.fail("Tests failed"),console.log(Q.red(`\u2717 ${H.failed} tests failed`)),process.exit(1)}catch(H){Y.fail("Tests failed"),console.error(Q.red(H instanceof Error?H.message:String(H))),process.exit(1)}}}});async function fP(J,X,Z){return new Promise((Q,G)=>{let Y=["test"],H=X.pattern||Z.test?.pattern||"**/*.test.ts",z=Array.isArray(H)?H:[H];if(Y.push(...z),X.watch??Z.test?.watch)Y.push("--watch");if(X.coverage??Z.test?.coverage)Y.push("--coverage");if(X.bail)Y.push("--bail");if(X.timeout)Y.push("--timeout",X.timeout.toString());let W=mX1("bun",Y,{cwd:J,stdio:["inherit","pipe","pipe"],env:{...process.env,NODE_ENV:"test"}}),V="",K="";W.stdout?.on("data",(R)=>{V+=R.toString(),process.stdout.write(R)}),W.stderr?.on("data",(R)=>{K+=R.toString(),process.stderr.write(R)}),W.on("exit",(R)=>{let S=(V.match(/\u2713/g)||[]).length,T=(V.match(/\u2717/g)||[]).length,b=(V.match(/\u229D/g)||[]).length;Q({success:R===0,passed:S,failed:T,skipped:b})}),W.on("error",G)})}async function lX1(J){if(J.endsWith("/*")){let X=J.slice(0,-2);if(vP(X))return(await cX1(X,{withFileTypes:!0})).filter((Q)=>Q.isDirectory()&&vP(EP.join(X,Q.name,"package.json"))).map((Q)=>EP.join(X,Q.name))}return[]}import{defineGroup as a91}from"@bunli/core";import{createCLI as y91,defineCommand as m91,option as oP}from"@bunli/core";import{createPlugin as iX1}from"@bunli/core/plugin";import{defineCommand as rX1}from"@bunli/core";import nX1 from"assert";import{resolve as aP}from"path";import{readFile as I91}from"fs/promises";import{pathToFileURL as N91}from"url";import{GLOBAL_FLAGS as D91}from"@bunli/core";function pX1(J,X){return`#compdef ${J}
|
|
183
183
|
compdef _${J} ${J}
|
|
184
184
|
|
|
185
185
|
# zsh completion for ${J} -*- shell-script -*-
|
package/dist/commands/dev.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ declare const _default: import("@bunli/core").RunnableCommand<{
|
|
|
6
6
|
clearScreen: import("@bunli/core").CLIOption<z.ZodDefault<z.ZodBoolean>>;
|
|
7
7
|
watch: import("@bunli/core").CLIOption<z.ZodDefault<z.ZodBoolean>>;
|
|
8
8
|
inspect: import("@bunli/core").CLIOption<z.ZodDefault<z.ZodBoolean>>;
|
|
9
|
-
port: import("@bunli/core").CLIOption<z.ZodOptional<z.
|
|
9
|
+
port: import("@bunli/core").CLIOption<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
10
10
|
}, {}, string> & {
|
|
11
11
|
name: "dev";
|
|
12
12
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type {
|
|
2
|
+
import type { PromptApi } from '@bunli/core';
|
|
3
3
|
interface PublishedPlatformPackage {
|
|
4
4
|
platform: string;
|
|
5
5
|
packageName: string;
|
|
@@ -26,6 +26,6 @@ declare const _default: import("@bunli/core").RunnableCommand<{
|
|
|
26
26
|
name: "release";
|
|
27
27
|
};
|
|
28
28
|
export default _default;
|
|
29
|
-
export declare function determineVersion(versionFlag: string | undefined, current: string, prompt:
|
|
29
|
+
export declare function determineVersion(versionFlag: string | undefined, current: string, prompt: PromptApi): Promise<string>;
|
|
30
30
|
export declare function bumpVersion(version: string, type: 'patch' | 'minor' | 'major'): string;
|
|
31
31
|
export declare function updatePackageVersion(version: string): Promise<void>;
|
package/dist/commands/test.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ declare const _default: import("@bunli/core").RunnableCommand<{
|
|
|
4
4
|
watch: import("@bunli/core").CLIOption<z.ZodDefault<z.ZodBoolean>>;
|
|
5
5
|
coverage: import("@bunli/core").CLIOption<z.ZodDefault<z.ZodBoolean>>;
|
|
6
6
|
bail: import("@bunli/core").CLIOption<z.ZodDefault<z.ZodBoolean>>;
|
|
7
|
-
timeout: import("@bunli/core").CLIOption<z.ZodOptional<z.
|
|
7
|
+
timeout: import("@bunli/core").CLIOption<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
8
8
|
all: import("@bunli/core").CLIOption<z.ZodDefault<z.ZodBoolean>>;
|
|
9
9
|
}, {}, string> & {
|
|
10
10
|
name: "test";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Bunli CLI toolchain for developing, building, and distributing CLIs",
|
|
6
6
|
"bin": {
|
|
@@ -47,15 +47,15 @@
|
|
|
47
47
|
"prepublishOnly": "bun run build"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@bunli/core": "^0.
|
|
51
|
-
"@bunli/generator": "^0.6.
|
|
52
|
-
"@bunli/plugin-completions": "^0.3.
|
|
53
|
-
"@bunli/utils": "^0.
|
|
50
|
+
"@bunli/core": "^0.8.0",
|
|
51
|
+
"@bunli/generator": "^0.6.4",
|
|
52
|
+
"@bunli/plugin-completions": "^0.3.4",
|
|
53
|
+
"@bunli/utils": "^0.5.0",
|
|
54
54
|
"better-result": "^2.7.0",
|
|
55
55
|
"zod": "^4.3.6"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@bunli/test": "^0.
|
|
58
|
+
"@bunli/test": "^0.5.0",
|
|
59
59
|
"@types/bun": "1.3.9",
|
|
60
60
|
"typescript": "^5.8.3"
|
|
61
61
|
}
|