@snelusha/noto 1.3.4-beta.1 → 1.3.4-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +19 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import{createCli as Et}from"trpc-cli";var ue="@snelusha/noto",T="1.3.4-beta.1";import ft from"node:fs/promises";import{initTRPC as ht}from"@trpc/server";import*as O from"@clack/prompts";import b from"picocolors";import ie from"dedent";import Je from"simple-git";var P=Je(),W=async()=>{return P.checkIsRepo()},_=async()=>{try{return await P.revparse(["--show-toplevel"])}catch{return null}};var ge=async(e=20,t=!1)=>{try{let a=t?{maxCount:e,"--no-merges":null}:{maxCount:e};return(await P.log(a)).all.map((o)=>o.message)}catch{return null}};var fe=async()=>{try{return P.diff(["--cached","--",":!*.lock"])}catch{return null}},j=async(e,t)=>{try{let a=t?{"--amend":null}:void 0,{summary:{changes:r}}=await P.commit(e,void 0,a);return Boolean(r)}catch{return!1}},he=async()=>{try{let e=await P.push();return e.update||e.pushed&&e.pushed.length>0}catch{return!1}},ye=async()=>{try{return(await P.branch()).current}catch{return null}},we=async(e)=>{try{let t=await P.branch();return e?t.all:Object.keys(t.branches).filter((a)=>!a.startsWith("remotes/"))}catch{return null}},ae=async(e)=>{try{return await P.checkout(e,{}),!0}catch{return!1}},oe=async(e)=>{try{return await P.checkoutLocalBranch(e),!0}catch{return!1}};import et from"os";import{join as tt,resolve as at}from"path";import{z as L}from"zod";import{promises as K}from"fs";import{dirname as Qe}from"path";function Y(e){let{schema:t,path:a}=e;return class{static storagePath=a;static storage={};static async load(){try{await K.access(this.storagePath);let o=await K.readFile(this.storagePath,"utf-8"),n=o?JSON.parse(o):{},s=t.safeParse(n);this.storage=s.success?s.data:{}}catch{this.storage={}}return this.storage}static async save(){try{let o=Qe(this.storagePath);await K.mkdir(o,{recursive:!0});let n=JSON.stringify(this.storage,null,2);await K.writeFile(this.storagePath,n,"utf-8")}catch{}}static async update(o){try{await this.load();let n=await o(this.storage),s=t.safeParse(n);if(s.success)this.storage=s.data,await this.save()}catch{}return this.storage}static async get(){return await this.load(),JSON.parse(JSON.stringify(this.storage))}static async clear(){this.storage={},await this.save()}static get path(){return this.storagePath}static set path(o){this.storagePath=o}static get raw(){return this.storage}}}import{z as Ze}from"zod";var be=Ze.enum(["gemini-1.5-flash","gemini-1.5-flash-latest","gemini-1.5-flash-8b","gemini-1.5-flash-8b-latest","gemini-1.5-pro","gemini-1.5-pro-latest","gemini-2.0-flash-001","gemini-2.0-flash","gemini-2.0-flash-lite-preview-02-05","gemini-2.5-flash-preview-04-17","gemini-2.5-pro-preview-05-06"]);var ot=L.object({llm:L.object({apiKey:L.string().optional(),model:be.optional().or(L.string())}).optional(),lastGeneratedMessage:L.string().optional()}),p=Y({path:at(tt(et.homedir(),".config","noto"),".notorc"),schema:ot});async function ve(){try{let e=await p.get();await p.update(()=>e)}catch{}}import rt from"node:fs/promises";import E from"node:path";import{fileURLToPath as it}from"node:url";var xe=(e)=>e instanceof URL?it(e):e;async function Me(e,t={}){let a=E.resolve(xe(t.cwd??"")),{root:r}=E.parse(a);t.stopAt=E.resolve(xe(t.stopAt??r));let o=E.isAbsolute(e);while(a){let n=o?e:E.join(a,e);try{let s=await rt.stat(n);if(t.type===void 0||t.type==="file"&&s.isFile()||t.type==="directory"&&s.isDirectory())return n}catch{}if(a===t.stopAt||a===r)break;a=E.dirname(a)}}var H=async()=>{let e=await _();return await Me(".noto/commit-prompt.md",{stopAt:e||process.cwd(),type:"file"})};import*as Ce from"@clack/prompts";import ke from"picocolors";import ut from"dedent";import v from"semver";import mt from"latest-version";import st from"os";import{join as nt,resolve as ct}from"path";import{z as R}from"zod";var lt=R.object({commitGenerationCache:R.record(R.string(),R.string()).optional(),update:R.object({timestamp:R.number(),current:R.string(),latest:R.string()}).optional()}),U=Y({path:ct(nt(st.homedir(),".cache","noto"),"cache"),schema:lt});var pt=43200000;async function re(e=!1,t=!1){let a=(await U.get()).update;if(!t&&a){if(v.valid(a.current)&&v.valid(a.latest)){let o=v.gte(a.current,a.latest),n=Date.now()-a.timestamp<pt;if(o||n)return{latest:a.latest,current:a.current,timestamp:a.timestamp}}}try{let o={latest:await mt(ue),current:T,timestamp:Date.now()};if(e)await dt(o);return o}catch{if(a)return{latest:a.latest,current:a.current,timestamp:a.timestamp};return{latest:T,current:T,timestamp:Date.now()}}}async function dt(e){if(!e)return;await U.update((t)=>({...t,update:e&&{timestamp:e.timestamp,latest:e.latest,current:e.current}}))}async function X(e=!1,t=!1){let a=await re(e,t);if(v.valid(a.current)&&v.valid(a.latest)){if(!v.gte(a.current,a.latest))return a}return null}async function gt(){let e=await X();if(e)Ce.log.warn(ut`A new version of noto is available: ${ke.dim(e.current)} → ${ke.green(e.latest)}
3
- Please run \`noto upgrade\` to update`.trim())}var i=async(e,t=!0)=>{if(t)await gt();await new Promise((a)=>setTimeout(a,1)),console.log(),process.exit(e)};var I=ht.meta().create({defaultMeta:{intro:!0,authRequired:!0,repoRequired:!0,diffRequired:!1,promptRequired:!1}}),Pe=I.middleware(async(e)=>{let{meta:t,next:a}=e,r=await p.get(),o=process.env.NOTO_API_KEY||r.llm?.apiKey;if(t?.authRequired&&!o)return O.log.error(ie`${b.red("noto api key is missing.")}
4
- ${b.dim(`run ${b.cyan("`noto config key`")} to set it up.`)}`),await i(1);return a()}),Se=I.middleware(async(e)=>{let{meta:t,next:a}=e,r=await W();if(t?.repoRequired&&!r)return O.log.error(ie`${b.red("no git repository found in cwd.")}
5
- ${b.dim(`run ${b.cyan("`git init`")} to initialize a new repository.`)}`),await i(1);let o=r&&await fe();if(t?.diffRequired&&!o)return O.log.error(ie`${b.red("no staged changes found.")}
6
- ${b.dim(`run ${b.cyan("`git add <file>`")} or ${b.cyan("`git add .`")} to stage changes.`)}`),await i(1);let n=null;if(t?.promptRequired){let s=await H();if(s)try{n=await ft.readFile(s,"utf-8")}catch{}}return a({ctx:{noto:{prompt:n},git:{isRepository:r,diff:o}}})}),x=I.procedure.use((e)=>{let{meta:t,next:a}=e;if(t?.intro)console.log(),O.intro(`${b.bgCyan(b.black(" @snelusha/noto "))}`);return a()}),Ca=x.use(Pe),J=x.use(Se),Q=x.use(Pe).use(Se);import{z as D}from"zod";import*as c from"@clack/prompts";import u from"picocolors";import yt from"clipboardy";var Re=J.meta({description:"checkout a branch"}).input(D.object({copy:D.boolean().meta({description:"copy the selected branch to clipboard",alias:"c"}),create:D.union([D.boolean(),D.string()]).optional().meta({description:"create a new branch",alias:"b"}),branch:D.string().optional().meta({positional:!0})})).mutation(async(e)=>{let{input:t}=e,a=await we();if(!a)return c.log.error("failed to fetch branches"),await i(1);let r=await ye(),o=typeof t.create==="string"?t.create:t.branch;if((t.create===!0||typeof t.create==="string")&&o){if(a.includes(o))return c.log.error(`branch ${u.red(o)} already exists in the repository`),await i(1);if(!await oe(o))return c.log.error(`failed to create and checkout ${u.bold(o)}`),await i(1);return c.log.success(`created and checked out ${u.green(o)}`),await i(0)}if(o){if(!a.includes(o)){c.log.error(`branch ${u.red(o)} does not exist in the repository`);let $=await c.confirm({message:`do you want to create branch ${u.green(o)}?`});if(c.isCancel($))return c.log.error("aborted"),await i(1);if($){if(!await oe(o))return c.log.error(`failed to create and checkout ${u.bold(o)}`),await i(1);return c.log.success(`created and checked out ${u.green(o)}`),await i(0)}return await i(1)}if(o===r)return c.log.error(`${u.red("already on branch")} ${u.green(o)}`),await i(1);if(!await ae(o))return c.log.error(`failed to checkout ${u.bold(o)}`),await i(1);return c.log.success(`checked out ${u.green(o)}`),await i(0)}if(a.length===0)return c.log.error("no branches found in the repository"),await i(1);let s=await c.select({message:"select a branch to checkout",options:a.map((l)=>({value:l,label:u.bold(l===r?u.green(l):l),hint:l===r?"current branch":void 0})),initialValue:r});if(c.isCancel(s))return c.log.error("nothing selected!"),await i(1);if(!s)return c.log.error("no branch selected"),await i(1);if(t.copy)return yt.writeSync(s),c.log.success(`copied ${u.green(s)} to clipboard`),await i(0);if(s===r)return c.log.error(`${u.red("already on branch")}`),await i(1);if(!await ae(s))return c.log.error(`failed to checkout ${u.bold(s)}`),await i(1);c.log.success(`checked out ${u.green(s)}`),await i(0)});import{z as wt}from"zod";import*as M from"@clack/prompts";import se from"picocolors";var Ae=x.meta({description:"configure noto api key"}).input(wt.string().optional().describe("apiKey")).mutation(async(e)=>{let{input:t}=e,a=t;if((await p.get()).llm?.apiKey){let r=await M.confirm({message:"noto api key already configured, do you want to update it?"});if(M.isCancel(r)||!r)return M.log.error(se.red("nothing changed!")),await i(1)}if(!a){let r=await M.text({message:"enter your noto api key"});if(M.isCancel(r))return M.log.error(se.red("nothing changed!")),await i(1);a=r}await p.update((r)=>({...r,llm:{...r.llm,apiKey:a}})),M.log.success(se.green("noto api key configured!")),await i(0)});import*as C from"@clack/prompts";import ce from"picocolors";import{createGoogleGenerativeAI as bt}from"@ai-sdk/google";var k=bt({apiKey:process.env.NOTO_API_KEY||(await p.get()).llm?.apiKey||"api-key"}),Ie="gemini-2.0-flash",Z={"gemini-1.5-flash":k("gemini-1.5-flash"),"gemini-1.5-flash-latest":k("gemini-1.5-flash-latest"),"gemini-1.5-flash-8b":k("gemini-1.5-flash-8b"),"gemini-1.5-flash-8b-latest":k("gemini-1.5-flash-8b-latest"),"gemini-1.5-pro":k("gemini-1.5-pro"),"gemini-1.5-pro-latest":k("gemini-1.5-pro-latest"),"gemini-2.0-flash-001":k("gemini-2.0-flash-001"),"gemini-2.0-flash":k("gemini-2.0-flash"),"gemini-2.0-flash-lite-preview-02-05":k("gemini-2.0-flash-lite-preview-02-05"),"gemini-2.5-flash-preview-04-17":k("gemini-2.5-flash-preview-04-17"),"gemini-2.5-pro-preview-05-06":k("gemini-2.5-pro-preview-05-06")},vt=Object.keys(Z),ne=async()=>{let e=(await p.get()).llm?.model;if(!e||!vt.includes(e))e=Ie,await p.update((t)=>({...t,llm:{...t.llm,model:Ie}}));return Z[e]};var Ge=x.meta({description:"configure model"}).mutation(async()=>{let e=await C.select({message:"select a model",initialValue:(await p.get()).llm?.model,options:Object.keys(Z).map((t)=>({label:t,value:t}))});if(C.isCancel(e))return C.log.error(ce.red("nothing changed!")),await i(1);if(e==="gemini-2.5-pro-preview-05-06"){let t=await C.confirm({message:"this model does not have free quota tier, do you want to continue?"});if(C.isCancel(t)||!t)return C.log.error(ce.red("nothing changed!")),await i(1)}await p.update((t)=>({...t,llm:{...t.llm,model:e}})),C.log.success(ce.green("model configured!")),await i(0)});import*as G from"@clack/prompts";import Ne from"picocolors";var $e=x.meta({description:"reset the configuration"}).mutation(async()=>{let e=await G.confirm({message:"are you sure you want to reset the configuration?"});if(G.isCancel(e)||!e)return G.log.error(Ne.red("nothing changed!")),await i(1);await p.clear(),G.log.success(Ne.green("configuration reset!")),await i(0)});var Te=I.router({key:Ae,model:Ge,reset:$e});import{z}from"zod";import*as f from"@clack/prompts";import g from"picocolors";import Ee from"dedent";import xt from"clipboardy";var Ue=J.meta({description:"access the last generated commit",repoRequired:!1}).input(z.object({copy:z.boolean().meta({description:"copy the last commit to clipboard",alias:"c"}),apply:z.boolean().meta({description:"commit the last generated message",alias:"a"}),edit:z.boolean().meta({description:"edit the last generated commit message",alias:"e"}),amend:z.boolean().meta({description:"amend the last commit with the last message"})})).mutation(async(e)=>{let{input:t,ctx:a}=e,r=(await p.get()).lastGeneratedMessage;if(!r)return f.log.error(g.red("no previous commit message found")),await i(1);let{edit:o,amend:n}=t;if(n&&!o)return f.log.error(g.red("the --amend option requires the --edit option")),await i(1);if(f.log.step(o?g.white(r):g.green(r)),o){let s=await f.text({message:"edit the last generated commit message",initialValue:r,placeholder:r});if(f.isCancel(s))return f.log.error(g.red("nothing changed!")),await i(1);r=s,await p.update((w)=>({...w,lastGeneratedMessage:s})),f.log.step(g.green(r))}if(t.copy)xt.writeSync(r),f.log.step(g.dim("copied last generated commit message to clipboard"));if(t.apply||n){if(!a.git.isRepository)return f.log.error(Ee`${g.red("no git repository found in cwd.")}
7
- ${g.dim(`run ${g.cyan("`git init`")} to initialize a new repository.`)}`),await i(1);if(!a.git.diff&&!n)return f.log.error(Ee`${g.red("no staged changes found.")}
8
- ${g.dim(`run ${g.cyan("`git add <file>`")} or ${g.cyan("`git add .`")} to stage changes.`)}`),await i(1);if(await j(r,n))f.log.step(g.dim("commit successful"));else f.log.error(g.red("failed to commit changes"))}return await i(0)});import ze from"node:fs/promises";import{z as le}from"zod";import*as d from"@clack/prompts";import S from"picocolors";import q from"dedent";import{generateObject as Fe,wrapLanguageModel as kt}from"ai";import ee from"zod";import B from"dedent";import De from"superjson";import{createHash as Mt}from"crypto";function Oe(e){let t=Buffer.from(e,"utf-8"),a=Buffer.from(`blob ${t.length}\x00`,"utf-8");return Mt("sha1").update(a).update(t).digest("hex")}var Ct=B`
2
+ import{createCli as Ot}from"trpc-cli";var W="@snelusha/noto",R="1.3.4-beta.3";import yt from"node:fs/promises";import{initTRPC as wt}from"@trpc/server";import*as N from"@clack/prompts";import w from"picocolors";import le from"dedent";import Ze from"simple-git";var P=Ze(),_=async()=>{return P.checkIsRepo()},K=async()=>{try{return await P.revparse(["--show-toplevel"])}catch{return null}};var he=async(e=20,t=!1)=>{try{let a=t?{maxCount:e,"--no-merges":null}:{maxCount:e};return(await P.log(a)).all.map((r)=>r.message)}catch{return null}};var ye=async()=>{try{return P.diff(["--cached","--",":!*.lock"])}catch{return null}},j=async(e,t)=>{try{let a=t?{"--amend":null}:void 0,{summary:{changes:o}}=await P.commit(e,void 0,a);return Boolean(o)}catch{return!1}},we=async()=>{try{let e=await P.push();return e.update||e.pushed&&e.pushed.length>0}catch{return!1}},be=async()=>{try{return(await P.branch()).current}catch{return null}},ve=async(e)=>{try{let t=await P.branch();return e?t.all:Object.keys(t.branches).filter((a)=>!a.startsWith("remotes/"))}catch{return null}},re=async(e)=>{try{return await P.checkout(e,{}),!0}catch{return!1}},ie=async(e)=>{try{return await P.checkoutLocalBranch(e),!0}catch{return!1}};import*as G from"node:fs";import*as L from"node:path";import*as xe from"node:child_process";import se from"node:process";var Y=R.includes("beta");async function Me(){let e=se.argv[1];if(!e)return{packageManager:"unknown",isGlobal:!1};let t=se.cwd();try{let a=G.realpathSync(e).replace(/\\/g,"/"),o=t.replace(/\\/g,"/");if(await _()&&o&&a.startsWith(o)&&!a.includes("/node_modules/"))return{packageManager:"unknown",isGlobal:!1,updateMessage:'Running from a local git clone. Please update with "git pull".'};if(a.includes("/.npm/_npx")||a.includes("/npm/_npx"))return{packageManager:"npx",isGlobal:!1,updateMessage:"Running via npx, update not applicable."};if(se.platform==="darwin")try{return xe.execSync('brew list -1 | grep -q "^noto$"',{stdio:"ignore"}),{packageManager:"homebrew",isGlobal:!0,updateMessage:'Installed via Homebrew. Please update with "brew upgrade".'}}catch{}if(a.includes("/pnpm/dlx")||a.includes("/pnpm-cache/dlx"))return{packageManager:"pnpx",isGlobal:!1,updateMessage:"Running via pnpx, update not applicable."};if(a.includes("/pnpm/global"))return{packageManager:"pnpm",isGlobal:!0,updateCommand:"pnpm add -g @snelusha/noto@latest",updateMessage:"Please run pnpm add -g @snelusha/noto@latest to update"};if(a.includes("/.yarn/global"))return{packageManager:"yarn",isGlobal:!0,updateCommand:"yarn global add @snelusha/noto@latest",updateMessage:"Please run yarn global add @snelusha/noto@latest to update"};if(a.includes("/bunx"))return{packageManager:"bunx",isGlobal:!1,updateMessage:"Running via bunx, update not applicable."};if(a.includes("/.bun/install/global"))return{packageManager:"bun",isGlobal:!0,updateCommand:"bun add -g @snelusha/noto@latest",updateMessage:"Please run bun add -g @snelusha/noto@latest to update"};if(o&&a.startsWith(`${o}/node_modules`)){let s="npm";if(G.existsSync(L.join(t,"yarn.lock")))s="yarn";else if(G.existsSync(L.join(t,"pnpm-lock.yaml")))s="pnpm";else if(G.existsSync(L.join(t,"bun.lockb"))||G.existsSync(L.join(t,"bun.lock")))s="bun";return{packageManager:s,isGlobal:!1,updateMessage:"Locally installed. Please update via your project's package.json."}}let n="npm install -g @snelusha/noto@latest";return{packageManager:"npm",isGlobal:!0,updateCommand:n,updateMessage:`Please run ${n} to update`}}catch{return{packageManager:"unknown",isGlobal:!1}}}import at from"os";import{join as ot,resolve as rt}from"path";import{z}from"zod";import{promises as H}from"fs";import{dirname as et}from"path";function X(e){let{schema:t,path:a}=e;return class{static storagePath=a;static storage={};static async load(){try{await H.access(this.storagePath);let r=await H.readFile(this.storagePath,"utf-8"),n=r?JSON.parse(r):{},s=t.safeParse(n);this.storage=s.success?s.data:{}}catch{this.storage={}}return this.storage}static async save(){try{let r=et(this.storagePath);await H.mkdir(r,{recursive:!0});let n=JSON.stringify(this.storage,null,2);await H.writeFile(this.storagePath,n,"utf-8")}catch{}}static async update(r){try{await this.load();let n=await r(this.storage),s=t.safeParse(n);if(s.success)this.storage=s.data,await this.save()}catch{}return this.storage}static async get(){return await this.load(),JSON.parse(JSON.stringify(this.storage))}static async clear(){this.storage={},await this.save()}static get path(){return this.storagePath}static set path(r){this.storagePath=r}static get raw(){return this.storage}}}import{z as tt}from"zod";var ke=tt.enum(["gemini-1.5-flash","gemini-1.5-flash-latest","gemini-1.5-flash-8b","gemini-1.5-flash-8b-latest","gemini-1.5-pro","gemini-1.5-pro-latest","gemini-2.0-flash-001","gemini-2.0-flash","gemini-2.0-flash-lite-preview-02-05","gemini-2.5-flash-preview-04-17","gemini-2.5-pro-preview-05-06"]);var it=z.object({llm:z.object({apiKey:z.string().optional(),model:ke.optional().or(z.string())}).optional(),lastGeneratedMessage:z.string().optional()}),p=X({path:rt(ot(at.homedir(),".config","noto"),".notorc"),schema:it});async function Ce(){try{let e=await p.get();await p.update(()=>e)}catch{}}import st from"node:fs/promises";import U from"node:path";import{fileURLToPath as nt}from"node:url";var Pe=(e)=>e instanceof URL?nt(e):e;async function Se(e,t={}){let a=U.resolve(Pe(t.cwd??"")),{root:o}=U.parse(a);t.stopAt=U.resolve(Pe(t.stopAt??o));let r=U.isAbsolute(e);while(a){let n=r?e:U.join(a,e);try{let s=await st.stat(n);if(t.type===void 0||t.type==="file"&&s.isFile()||t.type==="directory"&&s.isDirectory())return n}catch{}if(a===t.stopAt||a===o)break;a=U.dirname(a)}}var J=async()=>{let e=await K();return await Se(".noto/commit-prompt.md",{stopAt:e||process.cwd(),type:"file"})};import*as Ae from"@clack/prompts";import Re from"picocolors";import ft from"dedent";import y from"semver";import ne from"latest-version";import ct from"os";import{join as lt,resolve as mt}from"path";import{z as A}from"zod";var pt=A.object({commitGenerationCache:A.record(A.string(),A.string()).optional(),update:A.object({timestamp:A.number(),current:A.string(),latest:A.string()}).optional()}),O=X({path:mt(lt(ct.homedir(),".cache","noto"),"cache"),schema:pt});var dt=43200000;function ut(e,t){if(!e||!t)return e||t||null;let a=y.coerce(t)?.version,o=y.coerce(e)?.version;if(!a||!o)return e||t||null;return a===o||y.gt(o,a)?e:t}async function ce(e=!1,t=!1){let a=(await O.get()).update;if(!t&&a){if(y.valid(a.current)&&y.valid(a.latest)){let r=y.gte(a.current,a.latest),n=Date.now()-a.timestamp<dt;if(r||n)return{latest:a.latest,current:a.current,timestamp:a.timestamp}}}try{let r={latest:Y?ut(...await Promise.all([ne(W,{version:"beta"}),ne(W)])):await ne(W),current:R,timestamp:Date.now()};if(e)await gt(r);return r}catch{if(a)return{latest:a.latest,current:a.current,timestamp:a.timestamp};return{latest:R,current:R,timestamp:Date.now()}}}async function gt(e){if(!e)return;await O.update((t)=>({...t,update:e&&{timestamp:e.timestamp,latest:e.latest,current:e.current}}))}async function Q(e=!1,t=!1){let a=await ce(e,t);if(y.valid(a.current)&&y.valid(a.latest)){if(!y.gte(a.current,a.latest))return a}return null}async function ht(){let e=await Q();if(e)Ae.log.warn(ft`A new version of noto is available: ${Re.dim(e.current)} → ${Re.green(e.latest)}
3
+ Please run \`noto upgrade\` to update`.trim())}var i=async(e,t=!0)=>{if(t)await ht();await new Promise((a)=>setTimeout(a,1)),console.log(),process.exit(e)};var $=wt.meta().create({defaultMeta:{intro:!0,authRequired:!0,repoRequired:!0,diffRequired:!1,promptRequired:!1}}),Ie=$.middleware(async(e)=>{let{meta:t,next:a}=e,o=await p.get(),r=process.env.NOTO_API_KEY||o.llm?.apiKey;if(t?.authRequired&&!r)return N.log.error(le`${w.red("noto api key is missing.")}
4
+ ${w.dim(`run ${w.cyan("`noto config key`")} to set it up.`)}`),await i(1);return a()}),Ge=$.middleware(async(e)=>{let{meta:t,next:a}=e,o=await _();if(t?.repoRequired&&!o)return N.log.error(le`${w.red("no git repository found in cwd.")}
5
+ ${w.dim(`run ${w.cyan("`git init`")} to initialize a new repository.`)}`),await i(1);let r=o&&await ye();if(t?.diffRequired&&!r)return N.log.error(le`${w.red("no staged changes found.")}
6
+ ${w.dim(`run ${w.cyan("`git add <file>`")} or ${w.cyan("`git add .`")} to stage changes.`)}`),await i(1);let n=null;if(t?.promptRequired){let s=await J();if(s)try{n=await yt.readFile(s,"utf-8")}catch{}}return a({ctx:{noto:{prompt:n},git:{isRepository:o,diff:r}}})}),x=$.procedure.use((e)=>{let{meta:t,next:a}=e;if(t?.intro)if(console.log(),Y)N.intro(`${w.bgGreen(w.black(" @snelusha/noto [Prerelease] "))}`);else N.intro(`${w.bgCyan(w.black(" @snelusha/noto "))}`);return a()}),$a=x.use(Ie),Z=x.use(Ge),ee=x.use(Ie).use(Ge);import{z as D}from"zod";import*as c from"@clack/prompts";import u from"picocolors";import bt from"clipboardy";var Ne=Z.meta({description:"checkout a branch"}).input(D.object({copy:D.boolean().meta({description:"copy the selected branch to clipboard",alias:"c"}),create:D.union([D.boolean(),D.string()]).optional().meta({description:"create a new branch",alias:"b"}),branch:D.string().optional().meta({positional:!0})})).mutation(async(e)=>{let{input:t}=e,a=await ve();if(!a)return c.log.error("failed to fetch branches"),await i(1);let o=await be(),r=typeof t.create==="string"?t.create:t.branch;if((t.create===!0||typeof t.create==="string")&&r){if(a.includes(r))return c.log.error(`branch ${u.red(r)} already exists in the repository`),await i(1);if(!await ie(r))return c.log.error(`failed to create and checkout ${u.bold(r)}`),await i(1);return c.log.success(`created and checked out ${u.green(r)}`),await i(0)}if(r){if(!a.includes(r)){c.log.error(`branch ${u.red(r)} does not exist in the repository`);let E=await c.confirm({message:`do you want to create branch ${u.green(r)}?`});if(c.isCancel(E))return c.log.error("aborted"),await i(1);if(E){if(!await ie(r))return c.log.error(`failed to create and checkout ${u.bold(r)}`),await i(1);return c.log.success(`created and checked out ${u.green(r)}`),await i(0)}return await i(1)}if(r===o)return c.log.error(`${u.red("already on branch")} ${u.green(r)}`),await i(1);if(!await re(r))return c.log.error(`failed to checkout ${u.bold(r)}`),await i(1);return c.log.success(`checked out ${u.green(r)}`),await i(0)}if(a.length===0)return c.log.error("no branches found in the repository"),await i(1);let s=await c.select({message:"select a branch to checkout",options:a.map((l)=>({value:l,label:u.bold(l===o?u.green(l):l),hint:l===o?"current branch":void 0})),initialValue:o});if(c.isCancel(s))return c.log.error("nothing selected!"),await i(1);if(!s)return c.log.error("no branch selected"),await i(1);if(t.copy)return bt.writeSync(s),c.log.success(`copied ${u.green(s)} to clipboard`),await i(0);if(s===o)return c.log.error(`${u.red("already on branch")}`),await i(1);if(!await re(s))return c.log.error(`failed to checkout ${u.bold(s)}`),await i(1);c.log.success(`checked out ${u.green(s)}`),await i(0)});import{z as vt}from"zod";import*as M from"@clack/prompts";import me from"picocolors";var $e=x.meta({description:"configure noto api key"}).input(vt.string().optional().describe("apiKey")).mutation(async(e)=>{let{input:t}=e,a=t;if((await p.get()).llm?.apiKey){let o=await M.confirm({message:"noto api key already configured, do you want to update it?"});if(M.isCancel(o)||!o)return M.log.error(me.red("nothing changed!")),await i(1)}if(!a){let o=await M.text({message:"enter your noto api key"});if(M.isCancel(o))return M.log.error(me.red("nothing changed!")),await i(1);a=o}await p.update((o)=>({...o,llm:{...o.llm,apiKey:a}})),M.log.success(me.green("noto api key configured!")),await i(0)});import*as C from"@clack/prompts";import de from"picocolors";import{createGoogleGenerativeAI as xt}from"@ai-sdk/google";var k=xt({apiKey:process.env.NOTO_API_KEY||(await p.get()).llm?.apiKey||"api-key"}),Te="gemini-2.0-flash",te={"gemini-1.5-flash":k("gemini-1.5-flash"),"gemini-1.5-flash-latest":k("gemini-1.5-flash-latest"),"gemini-1.5-flash-8b":k("gemini-1.5-flash-8b"),"gemini-1.5-flash-8b-latest":k("gemini-1.5-flash-8b-latest"),"gemini-1.5-pro":k("gemini-1.5-pro"),"gemini-1.5-pro-latest":k("gemini-1.5-pro-latest"),"gemini-2.0-flash-001":k("gemini-2.0-flash-001"),"gemini-2.0-flash":k("gemini-2.0-flash"),"gemini-2.0-flash-lite-preview-02-05":k("gemini-2.0-flash-lite-preview-02-05"),"gemini-2.5-flash-preview-04-17":k("gemini-2.5-flash-preview-04-17"),"gemini-2.5-pro-preview-05-06":k("gemini-2.5-pro-preview-05-06")},Mt=Object.keys(te),pe=async()=>{let e=(await p.get()).llm?.model;if(!e||!Mt.includes(e))e=Te,await p.update((t)=>({...t,llm:{...t.llm,model:Te}}));return te[e]};var Ee=x.meta({description:"configure model"}).mutation(async()=>{let e=await C.select({message:"select a model",initialValue:(await p.get()).llm?.model,options:Object.keys(te).map((t)=>({label:t,value:t}))});if(C.isCancel(e))return C.log.error(de.red("nothing changed!")),await i(1);if(e==="gemini-2.5-pro-preview-05-06"){let t=await C.confirm({message:"this model does not have free quota tier, do you want to continue?"});if(C.isCancel(t)||!t)return C.log.error(de.red("nothing changed!")),await i(1)}await p.update((t)=>({...t,llm:{...t.llm,model:e}})),C.log.success(de.green("model configured!")),await i(0)});import*as T from"@clack/prompts";import Ue from"picocolors";var Oe=x.meta({description:"reset the configuration"}).mutation(async()=>{let e=await T.confirm({message:"are you sure you want to reset the configuration?"});if(T.isCancel(e)||!e)return T.log.error(Ue.red("nothing changed!")),await i(1);await p.clear(),T.log.success(Ue.green("configuration reset!")),await i(0)});var De=$.router({key:$e,model:Ee,reset:Oe});import{z as B}from"zod";import*as f from"@clack/prompts";import g from"picocolors";import Fe from"dedent";import kt from"clipboardy";var je=Z.meta({description:"access the last generated commit",repoRequired:!1}).input(B.object({copy:B.boolean().meta({description:"copy the last commit to clipboard",alias:"c"}),apply:B.boolean().meta({description:"commit the last generated message",alias:"a"}),edit:B.boolean().meta({description:"edit the last generated commit message",alias:"e"}),amend:B.boolean().meta({description:"amend the last commit with the last message"})})).mutation(async(e)=>{let{input:t,ctx:a}=e,o=(await p.get()).lastGeneratedMessage;if(!o)return f.log.error(g.red("no previous commit message found")),await i(1);let{edit:r,amend:n}=t;if(n&&!r)return f.log.error(g.red("the --amend option requires the --edit option")),await i(1);if(f.log.step(r?g.white(o):g.green(o)),r){let s=await f.text({message:"edit the last generated commit message",initialValue:o,placeholder:o});if(f.isCancel(s))return f.log.error(g.red("nothing changed!")),await i(1);o=s,await p.update((v)=>({...v,lastGeneratedMessage:s})),f.log.step(g.green(o))}if(t.copy)kt.writeSync(o),f.log.step(g.dim("copied last generated commit message to clipboard"));if(t.apply||n){if(!a.git.isRepository)return f.log.error(Fe`${g.red("no git repository found in cwd.")}
7
+ ${g.dim(`run ${g.cyan("`git init`")} to initialize a new repository.`)}`),await i(1);if(!a.git.diff&&!n)return f.log.error(Fe`${g.red("no staged changes found.")}
8
+ ${g.dim(`run ${g.cyan("`git add <file>`")} or ${g.cyan("`git add .`")} to stage changes.`)}`),await i(1);if(await j(o,n))f.log.step(g.dim("commit successful"));else f.log.error(g.red("failed to commit changes"))}return await i(0)});import We from"node:fs/promises";import{z as ue}from"zod";import*as d from"@clack/prompts";import S from"picocolors";import V from"dedent";import{generateObject as Be,wrapLanguageModel as Pt}from"ai";import ae from"zod";import q from"dedent";import ze from"superjson";import{createHash as Ct}from"crypto";function Le(e){let t=Buffer.from(e,"utf-8"),a=Buffer.from(`blob ${t.length}\x00`,"utf-8");return Ct("sha1").update(a).update(t).digest("hex")}var St=q`
9
9
  # System Instruction for Noto
10
10
 
11
11
  You are a Git commit message generator for the \`noto\` CLI tool. Your role is to analyze staged code changes and generate clear, single-line commit messages that follow the user's established style.
@@ -76,7 +76,7 @@ Or whatever format matches the user's guidelines. **Must be single-line only.**
76
76
  - Don't use generic or vague descriptions
77
77
 
78
78
  **Remember:** Your output becomes permanent git history. Generate commit messages that are clear, accurate, and consistent with the user's established patterns.
79
- `,Pt=B`
79
+ `,Rt=q`
80
80
  # Commit Message Guidelines
81
81
 
82
82
  ## Format
@@ -148,7 +148,7 @@ For breaking changes, add \`!\` after the type/scope:
148
148
  ## Additional Notes
149
149
  - If a commit addresses a specific issue, you can reference it in the description (e.g., \`fix: resolve memory leak (fixes #123)\`)
150
150
  - Each commit should represent a single logical change
151
- - Write commits as if completing the sentence: "If applied, this commit will..."`,St=B`
151
+ - Write commits as if completing the sentence: "If applied, this commit will..."`,At=q`
152
152
  You are a commit style analyzer. Analyze the provided commit history and generate a personalized style guide that will be used to generate future commit messages.
153
153
 
154
154
  ## Task
@@ -304,27 +304,27 @@ Start with action verb (add, implement, resolve, update, simplify). Be specific
304
304
  - The output will be stored as \`.noto/commit-prompt.md\` and used by an AI to generate commits
305
305
 
306
306
  Generate the markdown guidelines now based on the commit history provided.
307
- `,Rt={wrapGenerate:async({doGenerate:e,params:t})=>{let a=Oe(JSON.stringify(t)),r=(await U.get()).commitGenerationCache;if(r&&a in r)return De.parse(r[a]);let o=await e();return await U.update((n)=>({...n,commitGenerationCache:{[a]:De.stringify(o)}})),o}},je=async(e,t,a,r=!1)=>{let o=await ne(),{object:n}=await Fe({model:!r?kt({model:o,middleware:Rt}):o,schema:ee.object({message:ee.string()}),messages:[{role:"system",content:Ct},{role:"user",content:B`
307
+ `,It={wrapGenerate:async({doGenerate:e,params:t})=>{let a=Le(JSON.stringify(t)),o=(await O.get()).commitGenerationCache;if(o&&a in o)return ze.parse(o[a]);let r=await e();return await O.update((n)=>({...n,commitGenerationCache:{[a]:ze.stringify(r)}})),r}},qe=async(e,t,a,o=!1)=>{let r=await pe(),{object:n}=await Be({model:!o?Pt({model:r,middleware:It}):r,schema:ae.object({message:ae.string()}),messages:[{role:"system",content:St},{role:"user",content:q`
308
308
  USER GUIDELINES:
309
- ${t??Pt}
309
+ ${t??Rt}
310
310
  ${a?`
311
311
  USER CONTEXT:
312
312
  ${a}`:""}
313
313
 
314
314
  GIT DIFF:
315
315
  ${e}
316
- `}]});return n.message.trim()},Le=async(e)=>{let t=await ne(),{object:a}=await Fe({model:t,schema:ee.object({prompt:ee.string()}),messages:[{role:"system",content:St},{role:"user",content:B`
316
+ `}]});return n.message.trim()},Ve=async(e)=>{let t=await pe(),{object:a}=await Be({model:t,schema:ae.object({prompt:ae.string()}),messages:[{role:"system",content:At},{role:"user",content:q`
317
317
  COMMIT HISTORY:
318
318
  ${e.join(`
319
- `)}`}]});return a.prompt.trim()};var At=q`
319
+ `)}`}]});return a.prompt.trim()};var Gt=V`
320
320
  # Commit Message Guidelines
321
321
 
322
322
  # Add your custom guidelines here.
323
- # When no guidelines are present, noto will use conventional commits format by default.`,Be=Q.meta({description:"initialize noto in the repository"}).input(le.object({root:le.boolean().meta({description:"create the prompt file in the git root"}),generate:le.boolean().meta({description:"generate a prompt file based on existing commits"})})).mutation(async(e)=>{let{input:t}=e,a=await _(),r=a,o=process.cwd(),n=await H(),s=null;if(n)if(!n.startsWith(o)){d.log.warn(q`${S.yellow("a prompt file already exists!")}
324
- ${S.gray(n)}`);let h=await d.confirm({message:"do you want to create in the current directory instead?",initialValue:!0});if(d.isCancel(h)||!h)return d.log.error("aborted"),await i(1);r=o}else return d.log.error(q`${S.red("a prompt file already exists.")}
325
- ${S.gray(n)}`),await i(1);if(a!==o&&!t.root){let h=await d.confirm({message:"do you want to create the prompt file in the git root?",initialValue:!0});if(d.isCancel(h))return d.log.error("aborted"),await i(1);if(!h)r=o}let w=await ge(20,!0),l=t.generate;if(l){if(!w||w.length<5)return d.log.error(q`${S.red("not enough commits to generate a prompt file.")}
326
- ${S.gray("at least 5 commits are required.")}`),await i(1)}else if(w&&w.length>=5){let h=await d.confirm({message:"do you want to generate a prompt file based on existing commits?",initialValue:!0});if(d.isCancel(h))return d.log.error("aborted"),await i(1);l=h}let $=d.spinner();if(w&&l)$.start("generating commit message guidelines"),s=await Le(w),$.stop(S.green("generated commit message guidelines!"));else s=At;try{let h=`${r}/.noto`;await ze.mkdir(h,{recursive:!0});let pe=`${h}/commit-prompt.md`;return await ze.writeFile(pe,s,"utf-8"),d.log.success(q`${S.green("prompt file created!")}
327
- ${S.gray(pe)}`),await i(0)}catch{d.log.error(S.red("failed to create the prompt file!"))}});import{z as A}from"zod";import*as m from"@clack/prompts";import y from"picocolors";import It from"clipboardy";import{APICallError as Gt,RetryError as Nt}from"ai";var qe=Q.meta({description:"generate a commit message",default:!0,diffRequired:!0,promptRequired:!0}).input(A.object({message:A.string().or(A.boolean()).meta({description:"provide context for commit message",alias:"m"}),copy:A.boolean().meta({description:"copy the generated message to clipboard",alias:"c"}),apply:A.boolean().meta({description:"commit the generated message",alias:"a"}),push:A.boolean().meta({description:"commit and push the changes",alias:"p"}),force:A.boolean().meta({description:"bypass cache and force regeneration of commit message",alias:"f"}),manual:A.boolean().meta({description:"custom commit message"})})).mutation(async(e)=>{let{input:t,ctx:a}=e,r=m.spinner();try{if(t.manual){let l=await m.text({message:"edit the generated commit message",placeholder:"chore: init repo"});if(m.isCancel(l))return m.log.error(y.red("nothing changed!")),await i(1);if(m.log.step(y.green(l)),await p.update((h)=>({...h,lastGeneratedMessage:l})),await j(l))m.log.step(y.dim("commit successful"));else m.log.error(y.red("failed to commit changes"));return await i(0)}let n=t.message;if(typeof n==="string")n=n.trim();else if(typeof n==="boolean"&&n===!0){let l=await m.text({message:"provide context for the commit message",placeholder:"describe the changes"});if(m.isCancel(l))return m.log.error(y.red("nothing changed!")),await i(1);n=l}r.start("generating commit message");let s=null;s=await je(a.git.diff,a.noto.prompt,typeof n==="string"?n:void 0,t.force),r.stop(y.white(s));let w=await m.text({message:"edit the generated commit message",initialValue:s,placeholder:s});if(m.isCancel(w))return m.log.error(y.red("nothing changed!")),await i(1);if(s=w,m.log.step(y.green(s)),await p.update((l)=>({...l,lastGeneratedMessage:s})),t.copy)It.writeSync(s),m.log.step(y.dim("copied commit message to clipboard"));if(t.apply)if(await j(s))m.log.step(y.dim("commit successful"));else m.log.error(y.red("failed to commit changes"));if(t.push)if(await he())m.log.step(y.dim("push successful"));else m.log.error(y.red("failed to push changes"));return await i(0)}catch(o){let n;if(Nt.isInstance(o)&&Gt.isInstance(o.lastError))n=$t(o.lastError.responseBody);let s=n?`
328
- ${n}`:"";r.stop(y.red(`failed to generate commit message${s}`),1),await i(1)}});function $t(e){if(typeof e!=="string")return;try{let t=JSON.parse(e);return t?.error?.message??t?.message}catch{return}}import{spawn as Tt}from"node:child_process";import*as F from"@clack/prompts";import te from"picocolors";import*as N from"node:fs";import*as V from"node:path";import*as Ve from"node:child_process";import me from"node:process";async function We(){let e=me.argv[1];if(!e)return{packageManager:"unknown",isGlobal:!1};let t=me.cwd();try{let a=N.realpathSync(e).replace(/\\/g,"/"),r=t.replace(/\\/g,"/");if(await W()&&r&&a.startsWith(r)&&!a.includes("/node_modules/"))return{packageManager:"unknown",isGlobal:!1,updateMessage:'Running from a local git clone. Please update with "git pull".'};if(a.includes("/.npm/_npx")||a.includes("/npm/_npx"))return{packageManager:"npx",isGlobal:!1,updateMessage:"Running via npx, update not applicable."};if(me.platform==="darwin")try{return Ve.execSync('brew list -1 | grep -q "^noto$"',{stdio:"ignore"}),{packageManager:"homebrew",isGlobal:!0,updateMessage:'Installed via Homebrew. Please update with "brew upgrade".'}}catch{}if(a.includes("/pnpm/dlx")||a.includes("/pnpm-cache/dlx"))return{packageManager:"pnpx",isGlobal:!1,updateMessage:"Running via pnpx, update not applicable."};if(a.includes("/pnpm/global"))return{packageManager:"pnpm",isGlobal:!0,updateCommand:"pnpm add -g @snelusha/noto@latest",updateMessage:"Please run pnpm add -g @snelusha/noto@latest to update"};if(a.includes("/.yarn/global"))return{packageManager:"yarn",isGlobal:!0,updateCommand:"yarn global add @snelusha/noto@latest",updateMessage:"Please run yarn global add @snelusha/noto@latest to update"};if(a.includes("/bunx"))return{packageManager:"bunx",isGlobal:!1,updateMessage:"Running via bunx, update not applicable."};if(a.includes("/.bun/install/global"))return{packageManager:"bun",isGlobal:!0,updateCommand:"bun add -g @snelusha/noto@latest",updateMessage:"Please run bun add -g @snelusha/noto@latest to update"};if(r&&a.startsWith(`${r}/node_modules`)){let s="npm";if(N.existsSync(V.join(t,"yarn.lock")))s="yarn";else if(N.existsSync(V.join(t,"pnpm-lock.yaml")))s="pnpm";else if(N.existsSync(V.join(t,"bun.lockb"))||N.existsSync(V.join(t,"bun.lock")))s="bun";return{packageManager:s,isGlobal:!1,updateMessage:"Locally installed. Please update via your project's package.json."}}let n="npm install -g @snelusha/noto@latest";return{packageManager:"npm",isGlobal:!0,updateCommand:n,updateMessage:`Please run ${n} to update`}}catch{return{packageManager:"unknown",isGlobal:!1}}}var _e=x.meta({description:"upgrade noto"}).mutation(async()=>{let e=F.spinner();e.start("fetching latest version");let t=await X(!0,!0);if(!t)return e.stop(`You're already on the latest version of noto (${te.dim(`which is ${T}`)})`),await i(0,!1);e.stop(`noto ${te.green(t.latest)} is out! You are on ${te.dim(t.current)}.`);let a=await We();if(!a.updateCommand){if(a.updateMessage)return F.log.warn(a.updateMessage),await i(0,!1);return F.log.error("unable to determine update command for your installation."),await i(1,!1)}let r=Tt(a.updateCommand,{stdio:"pipe",shell:!0});e.start("upgrading noto");try{await new Promise((o,n)=>{r.on("close",(s)=>{if(s===0)o();else n()})}),e.stop(te.green("noto has been updated successfully!"))}catch{return F.log.error(`automatic update failed. please try updating manually by running: ${a.updateCommand}`),await i(1,!1)}return await i(0,!1)});var Ke={checkout:Re,config:Te,prev:Ue,init:Be,noto:qe,upgrade:_e};var Ye=I.router(Ke);var He=process.argv.slice(2),Xe="1.3.4-beta.1";if(He.includes("--version")||He.includes("-v"))console.log(Xe),process.exit(0);ve();re(!0);Et({name:"noto",router:Ye,version:Xe}).run();
323
+ # When no guidelines are present, noto will use conventional commits format by default.`,_e=ee.meta({description:"initialize noto in the repository"}).input(ue.object({root:ue.boolean().meta({description:"create the prompt file in the git root"}),generate:ue.boolean().meta({description:"generate a prompt file based on existing commits"})})).mutation(async(e)=>{let{input:t}=e,a=await K(),o=a,r=process.cwd(),n=await J(),s=null;if(n)if(!n.startsWith(r)){d.log.warn(V`${S.yellow("a prompt file already exists!")}
324
+ ${S.gray(n)}`);let h=await d.confirm({message:"do you want to create in the current directory instead?",initialValue:!0});if(d.isCancel(h)||!h)return d.log.error("aborted"),await i(1);o=r}else return d.log.error(V`${S.red("a prompt file already exists.")}
325
+ ${S.gray(n)}`),await i(1);if(a!==r&&!t.root){let h=await d.confirm({message:"do you want to create the prompt file in the git root?",initialValue:!0});if(d.isCancel(h))return d.log.error("aborted"),await i(1);if(!h)o=r}let v=await he(20,!0),l=t.generate;if(l){if(!v||v.length<5)return d.log.error(V`${S.red("not enough commits to generate a prompt file.")}
326
+ ${S.gray("at least 5 commits are required.")}`),await i(1)}else if(v&&v.length>=5){let h=await d.confirm({message:"do you want to generate a prompt file based on existing commits?",initialValue:!0});if(d.isCancel(h))return d.log.error("aborted"),await i(1);l=h}let E=d.spinner();if(v&&l)E.start("generating commit message guidelines"),s=await Ve(v),E.stop(S.green("generated commit message guidelines!"));else s=Gt;try{let h=`${o}/.noto`;await We.mkdir(h,{recursive:!0});let ge=`${h}/commit-prompt.md`;return await We.writeFile(ge,s,"utf-8"),d.log.success(V`${S.green("prompt file created!")}
327
+ ${S.gray(ge)}`),await i(0)}catch{d.log.error(S.red("failed to create the prompt file!"))}});import{z as I}from"zod";import*as m from"@clack/prompts";import b from"picocolors";import Nt from"clipboardy";import{APICallError as $t,RetryError as Tt}from"ai";var Ke=ee.meta({description:"generate a commit message",default:!0,diffRequired:!0,promptRequired:!0}).input(I.object({message:I.string().or(I.boolean()).meta({description:"provide context for commit message",alias:"m"}),copy:I.boolean().meta({description:"copy the generated message to clipboard",alias:"c"}),apply:I.boolean().meta({description:"commit the generated message",alias:"a"}),push:I.boolean().meta({description:"commit and push the changes",alias:"p"}),force:I.boolean().meta({description:"bypass cache and force regeneration of commit message",alias:"f"}),manual:I.boolean().meta({description:"custom commit message"})})).mutation(async(e)=>{let{input:t,ctx:a}=e,o=m.spinner();try{if(t.manual){let l=await m.text({message:"edit the generated commit message",placeholder:"chore: init repo"});if(m.isCancel(l))return m.log.error(b.red("nothing changed!")),await i(1);if(m.log.step(b.green(l)),await p.update((h)=>({...h,lastGeneratedMessage:l})),await j(l))m.log.step(b.dim("commit successful"));else m.log.error(b.red("failed to commit changes"));return await i(0)}let n=t.message;if(typeof n==="string")n=n.trim();else if(typeof n==="boolean"&&n===!0){let l=await m.text({message:"provide context for the commit message",placeholder:"describe the changes"});if(m.isCancel(l))return m.log.error(b.red("nothing changed!")),await i(1);n=l}o.start("generating commit message");let s=null;s=await qe(a.git.diff,a.noto.prompt,typeof n==="string"?n:void 0,t.force),o.stop(b.white(s));let v=await m.text({message:"edit the generated commit message",initialValue:s,placeholder:s});if(m.isCancel(v))return m.log.error(b.red("nothing changed!")),await i(1);if(s=v,m.log.step(b.green(s)),await p.update((l)=>({...l,lastGeneratedMessage:s})),t.copy)Nt.writeSync(s),m.log.step(b.dim("copied commit message to clipboard"));if(t.apply)if(await j(s))m.log.step(b.dim("commit successful"));else m.log.error(b.red("failed to commit changes"));if(t.push)if(await we())m.log.step(b.dim("push successful"));else m.log.error(b.red("failed to push changes"));return await i(0)}catch(r){let n;if(Tt.isInstance(r)&&$t.isInstance(r.lastError))n=Et(r.lastError.responseBody);let s=n?`
328
+ ${n}`:"";o.stop(b.red(`failed to generate commit message${s}`),1),await i(1)}});function Et(e){if(typeof e!=="string")return;try{let t=JSON.parse(e);return t?.error?.message??t?.message}catch{return}}import{spawn as Ut}from"node:child_process";import*as F from"@clack/prompts";import oe from"picocolors";var Ye=x.meta({description:"upgrade noto"}).mutation(async()=>{let e=F.spinner();e.start("fetching latest version");let t=await Q(!0,!0);if(!t)return e.stop(`You're already on the latest version of noto (${oe.dim(`which is ${R}`)})`),await i(0,!1);e.stop(`noto ${oe.green(t.latest)} is out! You are on ${oe.dim(t.current)}.`);let a=await Me();if(!a.updateCommand){if(a.updateMessage)return F.log.warn(a.updateMessage),await i(0,!1);return F.log.error("unable to determine update command for your installation."),await i(1,!1)}let o=Ut(a.updateCommand,{stdio:"pipe",shell:!0});e.start("upgrading noto");try{await new Promise((r,n)=>{o.on("close",(s)=>{if(s===0)r();else n()})}),e.stop(oe.green("noto has been updated successfully!"))}catch{return F.log.error(`automatic update failed. please try updating manually by running: ${a.updateCommand}`),await i(1,!1)}return await i(0,!1)});var He={checkout:Ne,config:De,prev:je,init:_e,noto:Ke,upgrade:Ye};var Xe=$.router(He);var Je=process.argv.slice(2),Qe="1.3.4-beta.3";if(Je.includes("--version")||Je.includes("-v"))console.log(Qe),process.exit(0);Ce();ce(!0);Ot({name:"noto",router:Xe,version:Qe}).run();
329
329
 
330
330
  // Made by a human on earth!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snelusha/noto",
3
- "version": "1.3.4-beta.1",
3
+ "version": "1.3.4-beta.3",
4
4
  "description": "Generate clean commit messages in a snap! ✨",
5
5
  "license": "MIT",
6
6
  "type": "module",