@snelusha/noto 0.3.8 → 0.4.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/dist/cli.cjs CHANGED
@@ -1,4 +1,5 @@
1
- "use strict";var L=Object.create;var I=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Q=Object.getPrototypeOf,V=Object.prototype.hasOwnProperty;var Z=(e,t,o,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of X(t))!V.call(e,a)&&a!==o&&I(e,a,{get:()=>t[a],enumerable:!(i=W(t,a))||i.enumerable});return e};var s=(e,t,o)=>(o=e!=null?L(Q(e)):{},Z(t||!e||!e.__esModule?I(o,"default",{value:e,enumerable:!0}):o,e));var q=s(require("yargs"),1),H=require("yargs/helpers");var C=s(require("@posva/prompts"),1),f=s(require("picocolors"),1);var R=require("path"),S=require("fs");var M=s(require("os"),1),g=s(require("process"),1),ee=s(require("which"),1),w=s(require("ora"),1),r=s(require("picocolors"),1),u=require("path"),n=require("fs");var y=s(require("simple-git"),1);async function $(){try{return await(0,y.default)().checkIsRepo()}catch{return!1}}async function K(){try{return await(0,y.default)().diff(["--cached"])}catch{return null}}async function h(e){try{return(await(0,y.default)().commit(e)).summary.changes>0}catch{return!1}}var l=(0,u.join)(M.default.homedir(),"snelusha-noto");var T=0;async function j(){(0,n.existsSync)(l)||await n.promises.mkdir(l,{recursive:!0});let e=(0,u.join)(l,`.${g.default.pid}.${T}`);return T+=1,n.promises.open(e,"wx").then(t=>({fd:t,path:e,cleanup(){t.close().then(()=>{(0,n.existsSync)(e)&&n.promises.unlink(e)})}})).catch(t=>{if(t&&t.code==="EEXIST")return j()})}async function F(e,t=""){let o=await j();if(o)try{await n.promises.writeFile(o.path,t);let i=(0,u.dirname)(e);return(0,n.existsSync)(i)||await n.promises.mkdir(i,{recursive:!0}),await n.promises.rename(o.path,e),!0}catch{return!1}finally{o.cleanup()}return!1}function b(){let e;return{start(t){e=(0,w.default)(t),e.spinner={interval:150,frames:["\u2736","\u2738","\u2739","\u273A","\u2739","\u2737"]},e.start()},fail(t){e||(e=(0,w.default)()),e.fail(t),e=void 0},success(t){e||(e=(0,w.default)()),e.succeed(t),e=void 0},stop(){e&&(e.stop(),e=void 0)}}}async function O(){(await c()).apiKey||(console.log(`Please run ${r.default.cyan(r.default.bold("`noto config`"))} to set your API key.`),g.default.exit(1))}async function x(){await $()||(console.log(r.default.red("Oops! No Git repository found in the current directory.")),console.log(r.default.dim(`You can initialize one by running ${r.default.cyan(r.default.bold("`git init`"))}`)),g.default.exit(1))}async function v(){let e=await K();if(e)return e;console.log(r.default.red("Oops! No staged changes found to commit.")),console.log(r.default.dim(`Stage changes with ${r.default.cyan(r.default.bold("`git add <file>`"))} or ${r.default.cyan(r.default.bold("`git add .`"))} for stage all files.`)),g.default.exit(1)}var m={},P=(0,R.resolve)(l,"storage.json");async function c(e){try{Object.keys(m).length||(m=(0,S.existsSync)(P)?JSON.parse(await S.promises.readFile(P,"utf-8")||"{}")||{}:{}),e&&await e(m)&&await d()}catch(t){console.error("error loading storage:",t),m={}}return m}async function d(){try{m&&await F(P,JSON.stringify(m,null,2))}catch(e){console.error("error saving storage:",e)}}async function z(){let e=await c();e.apiKey&&((await(0,C.default)({type:"confirm",name:"reset",message:"Do you want to reset your API key?"},{onCancel:()=>process.exit(0)})).reset||(console.log(`Use ${f.default.greenBright(f.default.bold("`noto`"))} to generate your commit message!`),process.exit(0)));let t=await(0,C.default)({type:"password",name:"apiKey",message:"Please enter your API key:",validate:o=>o?!0:"API key is required!"});t.apiKey&&(e.apiKey=t.apiKey,await d(),console.log("API key configured successfully!"),console.log(`Use ${f.default.greenBright(f.default.bold("`noto`"))} to generate your commit message!`))}var k=s(require("picocolors"),1),E=s(require("clipboardy"),1);var D=require("ai"),N=require("@ai-sdk/google"),A=s(require("dedent"),1),G=require("zod");async function B(e){let t=await c(),o=(0,N.createGoogleGenerativeAI)({apiKey:t.apiKey}),{object:i}=await(0,D.generateObject)({model:o("gemini-2.0-flash-exp",{structuredOutputs:!1}),schema:G.z.object({message:G.z.string()}),messages:[{role:"system",content:A.default`
1
+ "use strict";var X=Object.create;var F=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var V=Object.getOwnPropertyNames;var Z=Object.getPrototypeOf,ee=Object.prototype.hasOwnProperty;var te=(e,t,o,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of V(t))!ee.call(e,r)&&r!==o&&F(e,r,{get:()=>t[r],enumerable:!(i=Q(t,r))||i.enumerable});return e};var s=(e,t,o)=>(o=e!=null?X(Z(e)):{},te(t||!e||!e.__esModule?F(o,"default",{value:e,enumerable:!0}):o,e));var q=s(require("yargs"),1),L=require("yargs/helpers");var C=s(require("@posva/prompts"),1),y=s(require("picocolors"),1);var E=require("path"),P=require("fs");var M=s(require("os"),1),g=s(require("process"),1),ie=s(require("which"),1),w=s(require("ora"),1),a=s(require("picocolors"),1),d=require("path"),n=require("fs");var l=s(require("simple-git"),1);async function I(){try{return await(0,l.default)().checkIsRepo()}catch{return!1}}async function $(){try{let t=(await(0,l.default)().diff(["--cached","--name-only"])).split(`
2
+ `).filter(Boolean),o=["*.lock","*.lockb","*.yaml.lock","*.hcl.lock","*.resolved"],i=t.filter(r=>!o.some(W=>new RegExp(W.replace("*",".*")).test(r)));return i.length===0?null:await(0,l.default)().diff(["--cached","--",...i])}catch{return null}}async function h(e){try{return(await(0,l.default)().commit(e)).summary.changes>0}catch{return!1}}async function oe(){try{let e=await(0,l.default)().raw(["rev-list","--count","HEAD"]);return Number(e.trim())}catch(e){return/(ambiguous argument.*HEAD|unknown revision or path.*HEAD)/i.test(e.message)?0:null}}async function K(){try{return await oe()===0}catch{return!1}}var u=(0,d.join)(M.default.homedir(),"snelusha-noto");var T=0;async function j(){(0,n.existsSync)(u)||await n.promises.mkdir(u,{recursive:!0});let e=(0,d.join)(u,`.${g.default.pid}.${T}`);return T+=1,n.promises.open(e,"wx").then(t=>({fd:t,path:e,cleanup(){t.close().then(()=>{(0,n.existsSync)(e)&&n.promises.unlink(e)})}})).catch(t=>{if(t&&t.code==="EEXIST")return j()})}async function D(e,t=""){let o=await j();if(o)try{await n.promises.writeFile(o.path,t);let i=(0,d.dirname)(e);return(0,n.existsSync)(i)||await n.promises.mkdir(i,{recursive:!0}),await n.promises.rename(o.path,e),!0}catch{return!1}finally{o.cleanup()}return!1}function b(){let e;return{start(t){e=(0,w.default)(t),e.spinner={interval:150,frames:["\u2736","\u2738","\u2739","\u273A","\u2739","\u2737"]},e.start()},fail(t){e||(e=(0,w.default)()),e.fail(t),e=void 0},success(t){e||(e=(0,w.default)()),e.succeed(t),e=void 0},stop(){e&&(e.stop(),e=void 0)}}}async function O(){(await c()).apiKey||(console.log(`Please run ${a.default.cyan(a.default.bold("`noto config`"))} to set your API key.`),g.default.exit(1))}async function x(){await I()||(console.log(a.default.red("Oops! No Git repository found in the current directory.")),console.log(a.default.dim(`You can initialize one by running ${a.default.cyan(a.default.bold("`git init`"))}`)),g.default.exit(1))}async function v(){let e=await $();if(e)return e;console.log(a.default.red("Oops! No staged changes found to commit.")),console.log(a.default.dim(`Stage changes with ${a.default.cyan(a.default.bold("`git add <file>`"))} or ${a.default.cyan(a.default.bold("`git add .`"))} for stage all files.`)),g.default.exit(1)}var m={},S=(0,E.resolve)(u,"storage.json");async function c(e){try{Object.keys(m).length||(m=(0,P.existsSync)(S)?JSON.parse(await P.promises.readFile(S,"utf-8")||"{}")||{}:{}),e&&await e(m)&&await f()}catch(t){console.error("error loading storage:",t),m={}}return m}async function f(){try{m&&await D(S,JSON.stringify(m,null,2))}catch(e){console.error("error saving storage:",e)}}async function R(){let e=await c();e.apiKey&&((await(0,C.default)({type:"confirm",name:"reset",message:"Do you want to reset your API key?"},{onCancel:()=>process.exit(0)})).reset||(console.log(`Use ${y.default.greenBright(y.default.bold("`noto`"))} to generate your commit message!`),process.exit(0)));let t=await(0,C.default)({type:"password",name:"apiKey",message:"Please enter your API key:",validate:o=>o?!0:"API key is required!"});t.apiKey&&(e.apiKey=t.apiKey,await f(),console.log("API key configured successfully!"),console.log(`Use ${y.default.greenBright(y.default.bold("`noto`"))} to generate your commit message!`))}var G=s(require("picocolors"),1),H=s(require("clipboardy"),1);var N=require("ai"),z=require("@ai-sdk/google"),A=s(require("dedent"),1),k=require("zod");async function B(e){if(await K())return"chore: init repo";let t=await c(),o=(0,z.createGoogleGenerativeAI)({apiKey:t.apiKey}),{object:i}=await(0,N.generateObject)({model:o("gemini-2.0-flash-exp",{structuredOutputs:!1}),schema:k.z.object({message:k.z.string()}),messages:[{role:"system",content:A.default`
2
3
  You are a state-of-the-art AI model tasked with generating a precise Git commit message based on staged changes.
3
4
  Adhere strictly to the following instructions, ranked by priority:
4
5
 
@@ -10,5 +11,5 @@
10
11
  6. Avoid mentioning file names unless a file was renamed or is critical for understanding the changes.
11
12
  7. Prioritize clarity and focus on the most impactful changes for the commit.
12
13
 
13
- You are expected to generate structured outputs that align with the provided guidelines and produce a message optimized for readability and accuracy. Strictly follow all constraints to ensure high-quality results.`},{role:"user",content:A.default`generate a commit message for the following staged changes:\n${e}`}]});return i.message.trim()}async function J(e){let t=await c();await O(),await x();let o=await v(),i=b();try{i.start("Generating commit message...");let a=await B(o);t.lastGeneratedMessage=a,await d(),i.success(`Commit Message: ${k.default.dim(k.default.bold(a))}`),e.copy&&(E.default.writeSync(a),i.success("Message copied to clipboard!")),e.apply&&(await h(a)||(i.fail("Failed to commit staged changes."),process.exit(1)),i.success("Staged changes committed!"))}catch{i.fail("Failed to generate commit message."),process.exit(1)}}var p=s(require("picocolors"),1),U=s(require("clipboardy"),1);async function Y(e){let t=await c();t.lastGeneratedMessage||(console.log(p.default.red("No previous commit message found.")),console.log(p.default.dim(`Generate a new message with ${p.default.cyan(p.default.bold("`noto`"))} command.`)),process.exit(1));let o=b(),i=t.lastGeneratedMessage;o.success(`Previous Commit Message: ${p.default.dim(p.default.bold(i))}`),e.copy&&(U.default.writeSync(i),o.success("Message copied to clipboard!")),e.apply&&(await x(),await v(),await h(i)||(o.fail("Failed to commit staged changes."),process.exit(1)),o.success("Staged changes committed!"))}var _="0.3.8";(0,q.default)((0,H.hideBin)(process.argv)).scriptName("noto").usage("$0 [args]").command("config","setup you API key to enable noto.",()=>{},z).command("prev","access previous commit message",e=>{e.option("copy",{alias:"c",type:"boolean",description:"Copy the previous commit message to the clipboard."}),e.option("apply",{alias:"a",type:"boolean",description:"Commit the staged changes with the previous message."})},Y).command("*","generate commit message",e=>{e.option("copy",{alias:"c",type:"boolean",description:"Copy the generated commit message to the clipboard."}),e.option("apply",{alias:"a",type:"boolean",description:"Commit the staged changes with the generated message."})},J).version("version",_).alias("-v","--version").alias("-h","--help").argv;
14
+ You are expected to generate structured outputs that align with the provided guidelines and produce a message optimized for readability and accuracy. Strictly follow all constraints to ensure high-quality results.`},{role:"user",content:A.default`generate a commit message for the following staged changes:\n${e}`}]});return i.message.trim()}async function J(e){let t=await c();await O(),await x();let o=await v(),i=b();try{i.start("Generating commit message...");let r=await B(o);t.lastGeneratedMessage=r,await f(),i.success(`Commit Message: ${G.default.dim(G.default.bold(r))}`),e.copy&&(H.default.writeSync(r),i.success("Message copied to clipboard!")),e.apply&&(await h(r)||(i.fail("Failed to commit staged changes."),process.exit(1)),i.success("Staged changes committed!"))}catch{i.fail("Failed to generate commit message."),process.exit(1)}}var p=s(require("picocolors"),1),U=s(require("clipboardy"),1);async function Y(e){let t=await c();t.lastGeneratedMessage||(console.log(p.default.red("No previous commit message found.")),console.log(p.default.dim(`Generate a new message with ${p.default.cyan(p.default.bold("`noto`"))} command.`)),process.exit(1));let o=b(),i=t.lastGeneratedMessage;o.success(`Previous Commit Message: ${p.default.dim(p.default.bold(i))}`),e.copy&&(U.default.writeSync(i),o.success("Message copied to clipboard!")),e.apply&&(await x(),await v(),await h(i)||(o.fail("Failed to commit staged changes."),process.exit(1)),o.success("Staged changes committed!"))}var _="0.4.0";(0,q.default)((0,L.hideBin)(process.argv)).scriptName("noto").usage("$0 [args]").command("config","setup you API key to enable noto.",()=>{},R).command("prev","access previous commit message",e=>{e.option("copy",{alias:"c",type:"boolean",description:"Copy the previous commit message to the clipboard."}),e.option("apply",{alias:"a",type:"boolean",description:"Commit the staged changes with the previous message."})},Y).command("*","generate commit message",e=>{e.option("copy",{alias:"c",type:"boolean",description:"Copy the generated commit message to the clipboard."}),e.option("apply",{alias:"a",type:"boolean",description:"Commit the staged changes with the generated message."})},J).version("version",_).alias("-v","--version").alias("-h","--help").argv;
14
15
  //# sourceMappingURL=cli.cjs.map
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../commands/config.ts","../src/storage.ts","../src/utils.ts","../src/git.ts","../commands/generate.ts","../src/ai.ts","../commands/prev.ts","../package.json"],"sourcesContent":["import yargs from \"yargs\";\n\nimport { hideBin } from \"yargs/helpers\";\n\nimport { config } from \"commands/config\";\nimport { generate } from \"commands/generate\";\nimport { prev } from \"commands/prev\";\n\nimport { version } from \"package\";\n\nyargs(hideBin(process.argv))\n .scriptName(\"noto\")\n .usage(\"$0 [args]\")\n .command(\"config\", \"setup you API key to enable noto.\", () => {}, config)\n .command(\n \"prev\",\n \"access previous commit message\",\n (args) => {\n args.option(\"copy\", {\n alias: \"c\",\n type: \"boolean\",\n description: \"Copy the previous commit message to the clipboard.\",\n });\n args.option(\"apply\", {\n alias: \"a\",\n type: \"boolean\",\n description: \"Commit the staged changes with the previous message.\",\n });\n },\n prev\n )\n .command(\n \"*\",\n \"generate commit message\",\n (args) => {\n args.option(\"copy\", {\n alias: \"c\",\n type: \"boolean\",\n description: \"Copy the generated commit message to the clipboard.\",\n });\n args.option(\"apply\", {\n alias: \"a\",\n type: \"boolean\",\n description: \"Commit the staged changes with the generated message.\",\n });\n },\n generate\n )\n .version(\"version\", version)\n .alias(\"-v\", \"--version\")\n .alias(\"-h\", \"--help\").argv;\n","import prompts from \"@posva/prompts\";\nimport c from \"picocolors\";\n\nimport { load, dump } from \"@/storage\";\n\nexport async function config() {\n const storage = await load();\n\n if (storage.apiKey) {\n const response = await prompts(\n {\n type: \"confirm\",\n name: \"reset\",\n message: \"Do you want to reset your API key?\",\n },\n {\n onCancel: () => process.exit(0),\n }\n );\n\n if (!response.reset) {\n console.log(\n `Use ${c.greenBright(\n c.bold(\"`noto`\")\n )} to generate your commit message!`\n );\n process.exit(0);\n }\n }\n\n const response = await prompts({\n type: \"password\",\n name: \"apiKey\",\n message: \"Please enter your API key:\",\n validate: (value) => (value ? true : \"API key is required!\"),\n });\n if (response.apiKey) {\n storage.apiKey = response.apiKey;\n await dump();\n console.log(\"API key configured successfully!\");\n console.log(\n `Use ${c.greenBright(c.bold(\"`noto`\"))} to generate your commit message!`\n );\n }\n}\n","import { resolve } from \"node:path\";\nimport { existsSync, promises as fs } from \"node:fs\";\n\nimport { APP_DIR, writeFileSafe } from \"@/utils\";\n\nexport interface Storage {\n apiKey?: string;\n lastGeneratedMessage?: string;\n}\n\nlet storage: Storage = {};\n\nconst storagePath = resolve(APP_DIR, \"storage.json\");\n\nexport async function load(\n fn?: (storage: Storage) => Promise<boolean> | boolean\n): Promise<Storage> {\n try {\n if (!Object.keys(storage).length) {\n storage = existsSync(storagePath)\n ? JSON.parse((await fs.readFile(storagePath, \"utf-8\")) || \"{}\") || {}\n : {};\n }\n if (fn && (await fn(storage))) {\n await dump();\n }\n } catch (error) {\n console.error(\"error loading storage:\", error);\n storage = {};\n }\n\n return storage;\n}\n\nexport async function dump(): Promise<void> {\n try {\n if (storage) {\n await writeFileSafe(storagePath, JSON.stringify(storage, null, 2));\n }\n } catch (error) {\n console.error(\"error saving storage:\", error);\n }\n}\n","import os from \"node:os\";\nimport process from \"node:process\";\n\nimport which from \"which\";\nimport ora from \"ora\";\nimport c from \"picocolors\";\n\nimport { dirname, join } from \"node:path\";\nimport { existsSync, promises as fs } from \"node:fs\";\n\nimport type { Buffer } from \"node:buffer\";\n\nimport type { Ora } from \"ora\";\n\nimport { load } from \"@/storage\";\nimport { getStagedDiff, isGitRepository } from \"@/git\";\n\nexport const APP_DIR = join(os.homedir(), \"snelusha-noto\");\n\nexport function remove<T>(arr: T[], v: T) {\n const index = arr.indexOf(v);\n if (index >= 0) arr.splice(index, 1);\n return arr;\n}\n\nexport function exclude<T>(arr: T[], ...v: T[]) {\n return arr.slice().filter((item) => !v.includes(item));\n}\n\nexport function cmdExists(cmd: string) {\n return which.sync(cmd, { nothrow: true }) !== null;\n}\n\ninterface TempFile {\n path: string;\n fd: fs.FileHandle;\n cleanup: () => void;\n}\n\nlet counter = 0;\n\nasync function openTemp(): Promise<TempFile | undefined> {\n if (!existsSync(APP_DIR)) await fs.mkdir(APP_DIR, { recursive: true });\n\n const competitivePath = join(APP_DIR, `.${process.pid}.${counter}`);\n counter += 1;\n\n return fs\n .open(competitivePath, \"wx\")\n .then((fd) => ({\n fd,\n path: competitivePath,\n cleanup() {\n fd.close().then(() => {\n if (existsSync(competitivePath)) fs.unlink(competitivePath);\n });\n },\n }))\n .catch((error: any) => {\n if (error && error.code === \"EEXIST\") return openTemp();\n else return undefined;\n });\n}\n\nexport async function writeFileSafe(\n path: string,\n data: string | Buffer = \"\"\n): Promise<boolean> {\n const temp = await openTemp();\n\n if (temp) {\n try {\n // @ts-expect-error eslint-disable-next-line\n await fs.writeFile(temp.path, data);\n const directory = dirname(path);\n if (!existsSync(directory))\n await fs.mkdir(directory, { recursive: true });\n await fs.rename(temp.path, path);\n return true;\n } catch {\n return false;\n } finally {\n temp.cleanup();\n }\n }\n\n return false;\n}\n\nexport function spinner() {\n let s: Ora | undefined;\n\n return {\n start(text: string) {\n s = ora(text);\n s.spinner = {\n interval: 150,\n frames: [\"✶\", \"✸\", \"✹\", \"✺\", \"✹\", \"✷\"],\n };\n s.start();\n },\n fail(text: string) {\n if (!s) {\n s = ora();\n }\n s.fail(text);\n s = undefined;\n },\n success(text: string) {\n if (!s) {\n s = ora();\n }\n s.succeed(text);\n s = undefined;\n },\n stop() {\n if (s) {\n s.stop();\n s = undefined;\n }\n },\n };\n}\n\nexport async function ensureApiKey() {\n const storage = await load();\n if (!storage.apiKey) {\n console.log(\n `Please run ${c.cyan(c.bold(\"`noto config`\"))} to set your API key.`\n );\n process.exit(1);\n }\n}\n\nexport async function ensureGitRepository() {\n if (await isGitRepository()) return;\n console.log(c.red(\"Oops! No Git repository found in the current directory.\"));\n console.log(\n c.dim(`You can initialize one by running ${c.cyan(c.bold(\"`git init`\"))}`)\n );\n process.exit(1);\n}\n\nexport async function ensureStagedChanges() {\n const diff = await getStagedDiff();\n if (diff) return diff;\n console.log(c.red(\"Oops! No staged changes found to commit.\"));\n console.log(\n c.dim(\n `Stage changes with ${c.cyan(c.bold(\"`git add <file>`\"))} or ${c.cyan(\n c.bold(\"`git add .`\")\n )} for stage all files.`\n )\n );\n process.exit(1);\n}\n","import simpleGit from \"simple-git\";\n\nexport async function isGitRepository() {\n try {\n return await simpleGit().checkIsRepo();\n } catch {\n return false;\n }\n}\n\nexport async function getStagedDiff(): Promise<string | null> {\n try {\n return await simpleGit().diff([\"--cached\"]);\n } catch {\n return null;\n }\n}\n\nexport async function commit(message: string): Promise<boolean> {\n try {\n const result = await simpleGit().commit(message);\n return result.summary.changes > 0;\n } catch {\n return false;\n }\n}\n","import c from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { load, dump } from \"@/storage\";\nimport { commit } from \"@/git\";\nimport { generateCommitMessage } from \"@/ai\";\nimport {\n ensureApiKey,\n ensureGitRepository,\n ensureStagedChanges,\n spinner,\n} from \"@/utils\";\n\nimport type { ArgumentsCamelCase } from \"yargs\";\n\nexport async function generate(args: ArgumentsCamelCase) {\n const storage = await load();\n\n await ensureApiKey();\n await ensureGitRepository();\n\n const diff = await ensureStagedChanges();\n\n const spin = spinner();\n\n try {\n spin.start(\"Generating commit message...\");\n\n const message = await generateCommitMessage(diff);\n\n storage.lastGeneratedMessage = message;\n await dump();\n\n spin.success(`Commit Message: ${c.dim(c.bold(message))}`);\n\n if (args.copy) {\n clipboardy.writeSync(message);\n spin.success(\"Message copied to clipboard!\");\n }\n\n if (args.apply) {\n if (!(await commit(message))) {\n spin.fail(\"Failed to commit staged changes.\");\n process.exit(1);\n }\n spin.success(\"Staged changes committed!\");\n }\n } catch (_) {\n spin.fail(\"Failed to generate commit message.\");\n process.exit(1);\n }\n}\n","import { generateObject } from \"ai\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\n\nimport dedent from \"dedent\";\n\nimport { z } from \"zod\";\n\nimport { load } from \"@/storage\";\n\nexport async function generateCommitMessage(diff: string): Promise<string> {\n const storage = await load();\n\n const google = createGoogleGenerativeAI({\n apiKey: storage.apiKey,\n });\n\n const { object } = await generateObject({\n model: google(\"gemini-2.0-flash-exp\", {\n structuredOutputs: false,\n }),\n schema: z.object({\n message: z.string(),\n }),\n messages: [\n {\n role: \"system\",\n content: dedent`\n You are a state-of-the-art AI model tasked with generating a precise Git commit message based on staged changes.\n Adhere strictly to the following instructions, ranked by priority:\n \n 1. Write the commit message in present tense, starting with a present-tense verb such as add, fix, update, remove, improve, or implement. This applies to all repositories, including Java.\n 2. Summarize the key changes only, crafting a concise and clear commit message in the format \"<type>: <description>\".\n 3. Use one of the following standardized types: feat, fix, refactor, docs, test, or chore.\n 4. Ensure the commit message is a single line, fully lowercase, with no scope or body, and omit punctuation such as full stops at the end.\n 5. Limit the length of the commit message to 72 characters.\n 6. Avoid mentioning file names unless a file was renamed or is critical for understanding the changes.\n 7. Prioritize clarity and focus on the most impactful changes for the commit.\n \n You are expected to generate structured outputs that align with the provided guidelines and produce a message optimized for readability and accuracy. Strictly follow all constraints to ensure high-quality results.`,\n },\n {\n role: \"user\",\n content: dedent`generate a commit message for the following staged changes:\\n${diff}`,\n },\n ],\n });\n\n return object.message.trim();\n}\n","import c from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { load } from \"@/storage\";\nimport { commit } from \"@/git\";\n\nimport {\n ensureApiKey,\n ensureGitRepository,\n ensureStagedChanges,\n spinner,\n} from \"@/utils\";\n\nimport type { ArgumentsCamelCase } from \"yargs\";\n\nexport async function prev(args: ArgumentsCamelCase) {\n const storage = await load();\n\n if (!storage.lastGeneratedMessage) {\n console.log(c.red(\"No previous commit message found.\"));\n console.log(\n c.dim(`Generate a new message with ${c.cyan(c.bold(\"`noto`\"))} command.`)\n );\n process.exit(1);\n }\n const spin = spinner();\n\n const message = storage.lastGeneratedMessage;\n\n spin.success(`Previous Commit Message: ${c.dim(c.bold(message))}`);\n\n if (args.copy) {\n clipboardy.writeSync(message);\n spin.success(\"Message copied to clipboard!\");\n }\n\n if (args.apply) {\n await ensureGitRepository();\n\n await ensureStagedChanges();\n\n if (!(await commit(message))) {\n spin.fail(\"Failed to commit staged changes.\");\n process.exit(1);\n }\n\n spin.success(\"Staged changes committed!\");\n }\n}\n","{\n \"name\": \"@snelusha/noto\",\n \"type\": \"module\",\n \"version\": \"0.3.8\",\n \"description\": \"generate clean commit messages in a snap! ✨\",\n \"license\": \"MIT\",\n \"author\": {\n \"name\": \"Sithija Nelusha Silva\",\n \"email\": \"hello@snelusha.dev\",\n \"url\": \"https://snelusha.dev\"\n },\n \"homepage\": \"https://github.com/snelusha/noto\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/snelusha/noto.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/snelusha/noto/issues\"\n },\n \"main\": \"dist/cli.js\",\n \"module\": \"dist/cli.js\",\n \"types\": \"dist/cli.d.ts\",\n \"bin\": {\n \"noto\": \"bin/noto.mjs\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"publish\": \"npm publish --public\"\n },\n \"devDependencies\": {\n \"@types/bun\": \"latest\",\n \"@types/which\": \"^3.0.4\",\n \"@types/yargs\": \"^17.0.33\",\n \"esbuild-plugin-alias\": \"^0.2.1\",\n \"tsup\": \"^8.3.5\"\n },\n \"peerDependencies\": {\n \"typescript\": \"^5.0.0\"\n },\n \"dependencies\": {\n \"@ai-sdk/google\": \"^1.0.16\",\n \"@posva/prompts\": \"^2.4.4\",\n \"ai\": \"^4.0.36\",\n \"clipboardy\": \"^4.0.0\",\n \"dedent\": \"^1.5.3\",\n \"ora\": \"^8.1.1\",\n \"picocolors\": \"^1.1.1\",\n \"simple-git\": \"^3.27.0\",\n \"which\": \"^5.0.0\",\n \"yargs\": \"^17.7.2\",\n \"zod\": \"^3.24.1\"\n }\n}\n"],"mappings":"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","names":["import_yargs","import_helpers","import_prompts","import_picocolors","import_node_path","import_node_fs","import_node_os","import_node_process","import_which","import_ora","import_picocolors","import_node_path","import_node_fs","import_simple_git","isGitRepository","simpleGit","getStagedDiff","commit","message","APP_DIR","os","counter","openTemp","APP_DIR","fs","competitivePath","process","fd","error","writeFileSafe","path","data","temp","directory","spinner","s","text","ora","ensureApiKey","load","c","ensureGitRepository","isGitRepository","ensureStagedChanges","diff","getStagedDiff","storage","storagePath","APP_DIR","load","fn","fs","dump","error","writeFileSafe","config","storage","load","prompts","c","response","value","dump","import_picocolors","import_clipboardy","import_ai","import_google","import_dedent","import_zod","generateCommitMessage","diff","storage","load","google","object","dedent","generate","args","storage","load","ensureApiKey","ensureGitRepository","diff","ensureStagedChanges","spin","spinner","message","generateCommitMessage","dump","c","clipboardy","commit","import_picocolors","import_clipboardy","prev","args","storage","load","c","spin","spinner","message","clipboardy","ensureGitRepository","ensureStagedChanges","commit","version","yargs","config","args","prev","generate","version"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/config.ts","../src/storage.ts","../src/utils.ts","../src/git.ts","../src/commands/generate.ts","../src/ai.ts","../src/commands/prev.ts","../package.json"],"sourcesContent":["import yargs from \"yargs\";\n\nimport { hideBin } from \"yargs/helpers\";\n\nimport { config } from \"@/commands/config\";\nimport { generate } from \"@/commands/generate\";\nimport { prev } from \"@/commands/prev\";\n\nimport { version } from \"package\";\n\nyargs(hideBin(process.argv))\n .scriptName(\"noto\")\n .usage(\"$0 [args]\")\n .command(\"config\", \"setup you API key to enable noto.\", () => {}, config)\n .command(\n \"prev\",\n \"access previous commit message\",\n (args) => {\n args.option(\"copy\", {\n alias: \"c\",\n type: \"boolean\",\n description: \"Copy the previous commit message to the clipboard.\",\n });\n args.option(\"apply\", {\n alias: \"a\",\n type: \"boolean\",\n description: \"Commit the staged changes with the previous message.\",\n });\n },\n prev\n )\n .command(\n \"*\",\n \"generate commit message\",\n (args) => {\n args.option(\"copy\", {\n alias: \"c\",\n type: \"boolean\",\n description: \"Copy the generated commit message to the clipboard.\",\n });\n args.option(\"apply\", {\n alias: \"a\",\n type: \"boolean\",\n description: \"Commit the staged changes with the generated message.\",\n });\n },\n generate\n )\n .version(\"version\", version)\n .alias(\"-v\", \"--version\")\n .alias(\"-h\", \"--help\").argv;\n","import prompts from \"@posva/prompts\";\nimport pc from \"picocolors\";\n\nimport { load, dump } from \"@/storage\";\n\nexport async function config() {\n const storage = await load();\n\n if (storage.apiKey) {\n const response = await prompts(\n {\n type: \"confirm\",\n name: \"reset\",\n message: \"Do you want to reset your API key?\",\n },\n {\n onCancel: () => process.exit(0),\n }\n );\n\n if (!response.reset) {\n console.log(\n `Use ${pc.greenBright(\n pc.bold(\"`noto`\")\n )} to generate your commit message!`\n );\n process.exit(0);\n }\n }\n\n const response = await prompts({\n type: \"password\",\n name: \"apiKey\",\n message: \"Please enter your API key:\",\n validate: (value) => (value ? true : \"API key is required!\"),\n });\n if (response.apiKey) {\n storage.apiKey = response.apiKey;\n await dump();\n console.log(\"API key configured successfully!\");\n console.log(\n `Use ${pc.greenBright(pc.bold(\"`noto`\"))} to generate your commit message!`\n );\n }\n}\n","import { resolve } from \"node:path\";\nimport { existsSync, promises as fs } from \"node:fs\";\n\nimport { APP_DIR, writeFileSafe } from \"@/utils\";\n\nexport interface Storage {\n apiKey?: string;\n lastGeneratedMessage?: string;\n}\n\nlet storage: Storage = {};\n\nconst storagePath = resolve(APP_DIR, \"storage.json\");\n\nexport async function load(\n fn?: (storage: Storage) => Promise<boolean> | boolean\n): Promise<Storage> {\n try {\n if (!Object.keys(storage).length) {\n storage = existsSync(storagePath)\n ? JSON.parse((await fs.readFile(storagePath, \"utf-8\")) || \"{}\") || {}\n : {};\n }\n if (fn && (await fn(storage))) {\n await dump();\n }\n } catch (error) {\n console.error(\"error loading storage:\", error);\n storage = {};\n }\n\n return storage;\n}\n\nexport async function dump(): Promise<void> {\n try {\n if (storage) {\n await writeFileSafe(storagePath, JSON.stringify(storage, null, 2));\n }\n } catch (error) {\n console.error(\"error saving storage:\", error);\n }\n}\n","import os from \"node:os\";\nimport process from \"node:process\";\n\nimport which from \"which\";\nimport ora from \"ora\";\nimport pc from \"picocolors\";\n\nimport { dirname, join } from \"node:path\";\nimport { existsSync, promises as fs } from \"node:fs\";\n\nimport type { Buffer } from \"node:buffer\";\n\nimport type { Ora } from \"ora\";\n\nimport { load } from \"@/storage\";\nimport { getStagedDiff, isGitRepository } from \"@/git\";\n\nexport const APP_DIR = join(os.homedir(), \"snelusha-noto\");\n\nexport function remove<T>(arr: T[], v: T) {\n const index = arr.indexOf(v);\n if (index >= 0) arr.splice(index, 1);\n return arr;\n}\n\nexport function exclude<T>(arr: T[], ...v: T[]) {\n return arr.slice().filter((item) => !v.includes(item));\n}\n\nexport function cmdExists(cmd: string) {\n return which.sync(cmd, { nothrow: true }) !== null;\n}\n\ninterface TempFile {\n path: string;\n fd: fs.FileHandle;\n cleanup: () => void;\n}\n\nlet counter = 0;\n\nasync function openTemp(): Promise<TempFile | undefined> {\n if (!existsSync(APP_DIR)) await fs.mkdir(APP_DIR, { recursive: true });\n\n const competitivePath = join(APP_DIR, `.${process.pid}.${counter}`);\n counter += 1;\n\n return fs\n .open(competitivePath, \"wx\")\n .then((fd) => ({\n fd,\n path: competitivePath,\n cleanup() {\n fd.close().then(() => {\n if (existsSync(competitivePath)) fs.unlink(competitivePath);\n });\n },\n }))\n .catch((error: any) => {\n if (error && error.code === \"EEXIST\") return openTemp();\n else return undefined;\n });\n}\n\nexport async function writeFileSafe(\n path: string,\n data: string | Buffer = \"\"\n): Promise<boolean> {\n const temp = await openTemp();\n\n if (temp) {\n try {\n // @ts-expect-error eslint-disable-next-line\n await fs.writeFile(temp.path, data);\n const directory = dirname(path);\n if (!existsSync(directory))\n await fs.mkdir(directory, { recursive: true });\n await fs.rename(temp.path, path);\n return true;\n } catch {\n return false;\n } finally {\n temp.cleanup();\n }\n }\n\n return false;\n}\n\nexport function spinner() {\n let s: Ora | undefined;\n\n return {\n start(text: string) {\n s = ora(text);\n s.spinner = {\n interval: 150,\n frames: [\"✶\", \"✸\", \"✹\", \"✺\", \"✹\", \"✷\"],\n };\n s.start();\n },\n fail(text: string) {\n if (!s) {\n s = ora();\n }\n s.fail(text);\n s = undefined;\n },\n success(text: string) {\n if (!s) {\n s = ora();\n }\n s.succeed(text);\n s = undefined;\n },\n stop() {\n if (s) {\n s.stop();\n s = undefined;\n }\n },\n };\n}\n\nexport async function ensureApiKey() {\n const storage = await load();\n if (!storage.apiKey) {\n console.log(\n `Please run ${pc.cyan(pc.bold(\"`noto config`\"))} to set your API key.`\n );\n process.exit(1);\n }\n}\n\nexport async function ensureGitRepository() {\n if (await isGitRepository()) return;\n console.log(pc.red(\"Oops! No Git repository found in the current directory.\"));\n console.log(\n pc.dim(`You can initialize one by running ${pc.cyan(pc.bold(\"`git init`\"))}`)\n );\n process.exit(1);\n}\n\nexport async function ensureStagedChanges() {\n const diff = await getStagedDiff();\n if (diff) return diff;\n console.log(pc.red(\"Oops! No staged changes found to commit.\"));\n console.log(\n pc.dim(\n `Stage changes with ${pc.cyan(pc.bold(\"`git add <file>`\"))} or ${pc.cyan(\n pc.bold(\"`git add .`\")\n )} for stage all files.`\n )\n );\n process.exit(1);\n}\n","import simpleGit from \"simple-git\";\n\nexport async function isGitRepository() {\n try {\n return await simpleGit().checkIsRepo();\n } catch {\n return false;\n }\n}\n\nexport async function getStagedDiff(): Promise<string | null> {\n try {\n const stagedFiles = await simpleGit().diff([\"--cached\", \"--name-only\"]);\n\n const files = stagedFiles.split(\"\\n\").filter(Boolean);\n\n const excludedPatterns = [\n \"*.lock\",\n \"*.lockb\",\n \"*.yaml.lock\",\n \"*.hcl.lock\",\n \"*.resolved\",\n ];\n const filteredFiles = files.filter(\n (file) =>\n !excludedPatterns.some((pattern) => {\n const regex = new RegExp(pattern.replace(\"*\", \".*\"));\n return regex.test(file);\n })\n );\n\n if (filteredFiles.length === 0) return null;\n\n return await simpleGit().diff([\"--cached\", \"--\", ...filteredFiles]);\n } catch {\n return null;\n }\n}\n\nexport async function commit(message: string): Promise<boolean> {\n try {\n const result = await simpleGit().commit(message);\n return result.summary.changes > 0;\n } catch {\n return false;\n }\n}\n\nexport async function getCommitCount() {\n try {\n const count = await simpleGit().raw([\"rev-list\", \"--count\", \"HEAD\"]);\n return Number(count.trim());\n } catch (error) {\n if (\n /(ambiguous argument.*HEAD|unknown revision or path.*HEAD)/i.test(\n (error as Error).message\n )\n ) {\n return 0;\n }\n return null;\n }\n}\n\nexport async function isFirstCommit() {\n try {\n const count = await getCommitCount();\n return count === 0;\n } catch {\n return false;\n }\n}\n","import pc from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { load, dump } from \"@/storage\";\nimport { commit } from \"@/git\";\nimport { generateCommitMessage } from \"@/ai\";\nimport {\n ensureApiKey,\n ensureGitRepository,\n ensureStagedChanges,\n spinner,\n} from \"@/utils\";\n\nimport type { ArgumentsCamelCase } from \"yargs\";\n\nexport async function generate(args: ArgumentsCamelCase) {\n const storage = await load();\n\n await ensureApiKey();\n await ensureGitRepository();\n\n const diff = await ensureStagedChanges();\n\n const spin = spinner();\n\n try {\n spin.start(\"Generating commit message...\");\n\n const message = await generateCommitMessage(diff);\n\n storage.lastGeneratedMessage = message;\n await dump();\n\n spin.success(`Commit Message: ${pc.dim(pc.bold(message))}`);\n\n if (args.copy) {\n clipboardy.writeSync(message);\n spin.success(\"Message copied to clipboard!\");\n }\n\n if (args.apply) {\n if (!(await commit(message))) {\n spin.fail(\"Failed to commit staged changes.\");\n process.exit(1);\n }\n spin.success(\"Staged changes committed!\");\n }\n } catch (_) {\n spin.fail(\"Failed to generate commit message.\");\n process.exit(1);\n }\n}\n","import { generateObject } from \"ai\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\n\nimport dedent from \"dedent\";\n\nimport { z } from \"zod\";\n\nimport { load } from \"@/storage\";\nimport { isFirstCommit } from \"@/git\";\n\nexport async function generateCommitMessage(diff: string): Promise<string> {\n if (await isFirstCommit()) return \"chore: init repo\";\n\n const storage = await load();\n\n const google = createGoogleGenerativeAI({\n apiKey: storage.apiKey,\n });\n\n const { object } = await generateObject({\n model: google(\"gemini-2.0-flash-exp\", {\n structuredOutputs: false,\n }),\n schema: z.object({\n message: z.string(),\n }),\n messages: [\n {\n role: \"system\",\n content: dedent`\n You are a state-of-the-art AI model tasked with generating a precise Git commit message based on staged changes.\n Adhere strictly to the following instructions, ranked by priority:\n \n 1. Write the commit message in present tense, starting with a present-tense verb such as add, fix, update, remove, improve, or implement. This applies to all repositories, including Java.\n 2. Summarize the key changes only, crafting a concise and clear commit message in the format \"<type>: <description>\".\n 3. Use one of the following standardized types: feat, fix, refactor, docs, test, or chore.\n 4. Ensure the commit message is a single line, fully lowercase, with no scope or body, and omit punctuation such as full stops at the end.\n 5. Limit the length of the commit message to 72 characters.\n 6. Avoid mentioning file names unless a file was renamed or is critical for understanding the changes.\n 7. Prioritize clarity and focus on the most impactful changes for the commit.\n \n You are expected to generate structured outputs that align with the provided guidelines and produce a message optimized for readability and accuracy. Strictly follow all constraints to ensure high-quality results.`,\n },\n {\n role: \"user\",\n content: dedent`generate a commit message for the following staged changes:\\n${diff}`,\n },\n ],\n });\n\n return object.message.trim();\n}\n","import pc from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { load } from \"@/storage\";\nimport { commit } from \"@/git\";\n\nimport {\n ensureApiKey,\n ensureGitRepository,\n ensureStagedChanges,\n spinner,\n} from \"@/utils\";\n\nimport type { ArgumentsCamelCase } from \"yargs\";\n\nexport async function prev(args: ArgumentsCamelCase) {\n const storage = await load();\n\n if (!storage.lastGeneratedMessage) {\n console.log(pc.red(\"No previous commit message found.\"));\n console.log(\n pc.dim(`Generate a new message with ${pc.cyan(pc.bold(\"`noto`\"))} command.`)\n );\n process.exit(1);\n }\n const spin = spinner();\n\n const message = storage.lastGeneratedMessage;\n\n spin.success(`Previous Commit Message: ${pc.dim(pc.bold(message))}`);\n\n if (args.copy) {\n clipboardy.writeSync(message);\n spin.success(\"Message copied to clipboard!\");\n }\n\n if (args.apply) {\n await ensureGitRepository();\n\n await ensureStagedChanges();\n\n if (!(await commit(message))) {\n spin.fail(\"Failed to commit staged changes.\");\n process.exit(1);\n }\n\n spin.success(\"Staged changes committed!\");\n }\n}\n","{\n \"name\": \"@snelusha/noto\",\n \"type\": \"module\",\n \"version\": \"0.4.0\",\n \"description\": \"generate clean commit messages in a snap! ✨\",\n \"license\": \"MIT\",\n \"author\": {\n \"name\": \"Sithija Nelusha Silva\",\n \"email\": \"hello@snelusha.dev\",\n \"url\": \"https://snelusha.dev\"\n },\n \"homepage\": \"https://github.com/snelusha/noto\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/snelusha/noto.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/snelusha/noto/issues\"\n },\n \"main\": \"dist/cli.js\",\n \"module\": \"dist/cli.js\",\n \"types\": \"dist/cli.d.ts\",\n \"bin\": {\n \"noto\": \"bin/noto.mjs\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"publish\": \"npm publish --public\"\n },\n \"devDependencies\": {\n \"@types/bun\": \"latest\",\n \"@types/which\": \"^3.0.4\",\n \"@types/yargs\": \"^17.0.33\",\n \"esbuild-plugin-alias\": \"^0.2.1\",\n \"tsup\": \"^8.3.5\"\n },\n \"peerDependencies\": {\n \"typescript\": \"^5.0.0\"\n },\n \"dependencies\": {\n \"@ai-sdk/google\": \"^1.0.16\",\n \"@posva/prompts\": \"^2.4.4\",\n \"ai\": \"^4.0.36\",\n \"clipboardy\": \"^4.0.0\",\n \"dedent\": \"^1.5.3\",\n \"ora\": \"^8.1.1\",\n \"picocolors\": \"^1.1.1\",\n \"simple-git\": \"^3.27.0\",\n \"which\": \"^5.0.0\",\n \"yargs\": \"^17.7.2\",\n \"zod\": \"^3.24.1\"\n }\n}\n"],"mappings":"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","names":["import_yargs","import_helpers","import_prompts","import_picocolors","import_node_path","import_node_fs","import_node_os","import_node_process","import_which","import_ora","import_picocolors","import_node_path","import_node_fs","import_simple_git","isGitRepository","simpleGit","getStagedDiff","files","excludedPatterns","filteredFiles","file","pattern","commit","message","getCommitCount","count","error","isFirstCommit","APP_DIR","os","counter","openTemp","APP_DIR","fs","competitivePath","process","fd","error","writeFileSafe","path","data","temp","directory","spinner","s","text","ora","ensureApiKey","load","pc","ensureGitRepository","isGitRepository","ensureStagedChanges","diff","getStagedDiff","storage","storagePath","APP_DIR","load","fn","fs","dump","error","writeFileSafe","config","storage","load","prompts","pc","response","value","dump","import_picocolors","import_clipboardy","import_ai","import_google","import_dedent","import_zod","generateCommitMessage","diff","isFirstCommit","storage","load","google","object","dedent","generate","args","storage","load","ensureApiKey","ensureGitRepository","diff","ensureStagedChanges","spin","spinner","message","generateCommitMessage","dump","pc","clipboardy","commit","import_picocolors","import_clipboardy","prev","args","storage","load","pc","spin","spinner","message","clipboardy","ensureGitRepository","ensureStagedChanges","commit","version","yargs","config","args","prev","generate","version"]}
package/dist/cli.js CHANGED
@@ -1,4 +1,5 @@
1
- import L from"yargs";import{hideBin as W}from"yargs/helpers";import $ from"@posva/prompts";import h from"picocolors";import{resolve as B}from"node:path";import{existsSync as E,promises as J}from"node:fs";import D from"node:os";import u from"node:process";import te from"which";import b from"ora";import s from"picocolors";import{dirname as N,join as A}from"node:path";import{existsSync as x,promises as n}from"node:fs";import w from"simple-git";async function S(){try{return await w().checkIsRepo()}catch{return!1}}async function P(){try{return await w().diff(["--cached"])}catch{return null}}async function g(e){try{return(await w().commit(e)).summary.changes>0}catch{return!1}}var p=A(D.homedir(),"snelusha-noto");var C=0;async function G(){x(p)||await n.mkdir(p,{recursive:!0});let e=A(p,`.${u.pid}.${C}`);return C+=1,n.open(e,"wx").then(t=>({fd:t,path:e,cleanup(){t.close().then(()=>{x(e)&&n.unlink(e)})}})).catch(t=>{if(t&&t.code==="EEXIST")return G()})}async function k(e,t=""){let o=await G();if(o)try{await n.writeFile(o.path,t);let i=N(e);return x(i)||await n.mkdir(i,{recursive:!0}),await n.rename(o.path,e),!0}catch{return!1}finally{o.cleanup()}return!1}function d(){let e;return{start(t){e=b(t),e.spinner={interval:150,frames:["\u2736","\u2738","\u2739","\u273A","\u2739","\u2737"]},e.start()},fail(t){e||(e=b()),e.fail(t),e=void 0},success(t){e||(e=b()),e.succeed(t),e=void 0},stop(){e&&(e.stop(),e=void 0)}}}async function I(){(await r()).apiKey||(console.log(`Please run ${s.cyan(s.bold("`noto config`"))} to set your API key.`),u.exit(1))}async function f(){await S()||(console.log(s.red("Oops! No Git repository found in the current directory.")),console.log(s.dim(`You can initialize one by running ${s.cyan(s.bold("`git init`"))}`)),u.exit(1))}async function y(){let e=await P();if(e)return e;console.log(s.red("Oops! No staged changes found to commit.")),console.log(s.dim(`Stage changes with ${s.cyan(s.bold("`git add <file>`"))} or ${s.cyan(s.bold("`git add .`"))} for stage all files.`)),u.exit(1)}var a={},v=B(p,"storage.json");async function r(e){try{Object.keys(a).length||(a=E(v)?JSON.parse(await J.readFile(v,"utf-8")||"{}")||{}:{}),e&&await e(a)&&await l()}catch(t){console.error("error loading storage:",t),a={}}return a}async function l(){try{a&&await k(v,JSON.stringify(a,null,2))}catch(e){console.error("error saving storage:",e)}}async function K(){let e=await r();e.apiKey&&((await $({type:"confirm",name:"reset",message:"Do you want to reset your API key?"},{onCancel:()=>process.exit(0)})).reset||(console.log(`Use ${h.greenBright(h.bold("`noto`"))} to generate your commit message!`),process.exit(0)));let t=await $({type:"password",name:"apiKey",message:"Please enter your API key:",validate:o=>o?!0:"API key is required!"});t.apiKey&&(e.apiKey=t.apiKey,await l(),console.log("API key configured successfully!"),console.log(`Use ${h.greenBright(h.bold("`noto`"))} to generate your commit message!`))}import F from"picocolors";import _ from"clipboardy";import{generateObject as U}from"ai";import{createGoogleGenerativeAI as Y}from"@ai-sdk/google";import T from"dedent";import{z as M}from"zod";async function j(e){let t=await r(),o=Y({apiKey:t.apiKey}),{object:i}=await U({model:o("gemini-2.0-flash-exp",{structuredOutputs:!1}),schema:M.object({message:M.string()}),messages:[{role:"system",content:T`
1
+ import Q from"yargs";import{hideBin as V}from"yargs/helpers";import $ from"@posva/prompts";import w from"picocolors";import{resolve as J}from"node:path";import{existsSync as U,promises as Y}from"node:fs";import B from"node:os";import d from"node:process";import re from"which";import b from"ora";import s from"picocolors";import{dirname as H,join as k}from"node:path";import{existsSync as x,promises as c}from"node:fs";import p from"simple-git";async function P(){try{return await p().checkIsRepo()}catch{return!1}}async function S(){try{let t=(await p().diff(["--cached","--name-only"])).split(`
2
+ `).filter(Boolean),o=["*.lock","*.lockb","*.yaml.lock","*.hcl.lock","*.resolved"],i=t.filter(a=>!o.some(N=>new RegExp(N.replace("*",".*")).test(a)));return i.length===0?null:await p().diff(["--cached","--",...i])}catch{return null}}async function g(e){try{return(await p().commit(e)).summary.changes>0}catch{return!1}}async function z(){try{let e=await p().raw(["rev-list","--count","HEAD"]);return Number(e.trim())}catch(e){return/(ambiguous argument.*HEAD|unknown revision or path.*HEAD)/i.test(e.message)?0:null}}async function C(){try{return await z()===0}catch{return!1}}var l=k(B.homedir(),"snelusha-noto");var A=0;async function G(){x(l)||await c.mkdir(l,{recursive:!0});let e=k(l,`.${d.pid}.${A}`);return A+=1,c.open(e,"wx").then(t=>({fd:t,path:e,cleanup(){t.close().then(()=>{x(e)&&c.unlink(e)})}})).catch(t=>{if(t&&t.code==="EEXIST")return G()})}async function F(e,t=""){let o=await G();if(o)try{await c.writeFile(o.path,t);let i=H(e);return x(i)||await c.mkdir(i,{recursive:!0}),await c.rename(o.path,e),!0}catch{return!1}finally{o.cleanup()}return!1}function f(){let e;return{start(t){e=b(t),e.spinner={interval:150,frames:["\u2736","\u2738","\u2739","\u273A","\u2739","\u2737"]},e.start()},fail(t){e||(e=b()),e.fail(t),e=void 0},success(t){e||(e=b()),e.succeed(t),e=void 0},stop(){e&&(e.stop(),e=void 0)}}}async function I(){(await r()).apiKey||(console.log(`Please run ${s.cyan(s.bold("`noto config`"))} to set your API key.`),d.exit(1))}async function y(){await P()||(console.log(s.red("Oops! No Git repository found in the current directory.")),console.log(s.dim(`You can initialize one by running ${s.cyan(s.bold("`git init`"))}`)),d.exit(1))}async function h(){let e=await S();if(e)return e;console.log(s.red("Oops! No staged changes found to commit.")),console.log(s.dim(`Stage changes with ${s.cyan(s.bold("`git add <file>`"))} or ${s.cyan(s.bold("`git add .`"))} for stage all files.`)),d.exit(1)}var n={},v=J(l,"storage.json");async function r(e){try{Object.keys(n).length||(n=U(v)?JSON.parse(await Y.readFile(v,"utf-8")||"{}")||{}:{}),e&&await e(n)&&await u()}catch(t){console.error("error loading storage:",t),n={}}return n}async function u(){try{n&&await F(v,JSON.stringify(n,null,2))}catch(e){console.error("error saving storage:",e)}}async function K(){let e=await r();e.apiKey&&((await $({type:"confirm",name:"reset",message:"Do you want to reset your API key?"},{onCancel:()=>process.exit(0)})).reset||(console.log(`Use ${w.greenBright(w.bold("`noto`"))} to generate your commit message!`),process.exit(0)));let t=await $({type:"password",name:"apiKey",message:"Please enter your API key:",validate:o=>o?!0:"API key is required!"});t.apiKey&&(e.apiKey=t.apiKey,await u(),console.log("API key configured successfully!"),console.log(`Use ${w.greenBright(w.bold("`noto`"))} to generate your commit message!`))}import D from"picocolors";import L from"clipboardy";import{generateObject as _}from"ai";import{createGoogleGenerativeAI as q}from"@ai-sdk/google";import T from"dedent";import{z as M}from"zod";async function j(e){if(await C())return"chore: init repo";let t=await r(),o=q({apiKey:t.apiKey}),{object:i}=await _({model:o("gemini-2.0-flash-exp",{structuredOutputs:!1}),schema:M.object({message:M.string()}),messages:[{role:"system",content:T`
2
3
  You are a state-of-the-art AI model tasked with generating a precise Git commit message based on staged changes.
3
4
  Adhere strictly to the following instructions, ranked by priority:
4
5
 
@@ -10,5 +11,5 @@ import L from"yargs";import{hideBin as W}from"yargs/helpers";import $ from"@posv
10
11
  6. Avoid mentioning file names unless a file was renamed or is critical for understanding the changes.
11
12
  7. Prioritize clarity and focus on the most impactful changes for the commit.
12
13
 
13
- You are expected to generate structured outputs that align with the provided guidelines and produce a message optimized for readability and accuracy. Strictly follow all constraints to ensure high-quality results.`},{role:"user",content:T`generate a commit message for the following staged changes:\n${e}`}]});return i.message.trim()}async function O(e){let t=await r();await I(),await f();let o=await y(),i=d();try{i.start("Generating commit message...");let m=await j(o);t.lastGeneratedMessage=m,await l(),i.success(`Commit Message: ${F.dim(F.bold(m))}`),e.copy&&(_.writeSync(m),i.success("Message copied to clipboard!")),e.apply&&(await g(m)||(i.fail("Failed to commit staged changes."),process.exit(1)),i.success("Staged changes committed!"))}catch{i.fail("Failed to generate commit message."),process.exit(1)}}import c from"picocolors";import q from"clipboardy";async function R(e){let t=await r();t.lastGeneratedMessage||(console.log(c.red("No previous commit message found.")),console.log(c.dim(`Generate a new message with ${c.cyan(c.bold("`noto`"))} command.`)),process.exit(1));let o=d(),i=t.lastGeneratedMessage;o.success(`Previous Commit Message: ${c.dim(c.bold(i))}`),e.copy&&(q.writeSync(i),o.success("Message copied to clipboard!")),e.apply&&(await f(),await y(),await g(i)||(o.fail("Failed to commit staged changes."),process.exit(1)),o.success("Staged changes committed!"))}var z="0.3.8";L(W(process.argv)).scriptName("noto").usage("$0 [args]").command("config","setup you API key to enable noto.",()=>{},K).command("prev","access previous commit message",e=>{e.option("copy",{alias:"c",type:"boolean",description:"Copy the previous commit message to the clipboard."}),e.option("apply",{alias:"a",type:"boolean",description:"Commit the staged changes with the previous message."})},R).command("*","generate commit message",e=>{e.option("copy",{alias:"c",type:"boolean",description:"Copy the generated commit message to the clipboard."}),e.option("apply",{alias:"a",type:"boolean",description:"Commit the staged changes with the generated message."})},O).version("version",z).alias("-v","--version").alias("-h","--help").argv;
14
+ You are expected to generate structured outputs that align with the provided guidelines and produce a message optimized for readability and accuracy. Strictly follow all constraints to ensure high-quality results.`},{role:"user",content:T`generate a commit message for the following staged changes:\n${e}`}]});return i.message.trim()}async function O(e){let t=await r();await I(),await y();let o=await h(),i=f();try{i.start("Generating commit message...");let a=await j(o);t.lastGeneratedMessage=a,await u(),i.success(`Commit Message: ${D.dim(D.bold(a))}`),e.copy&&(L.writeSync(a),i.success("Message copied to clipboard!")),e.apply&&(await g(a)||(i.fail("Failed to commit staged changes."),process.exit(1)),i.success("Staged changes committed!"))}catch{i.fail("Failed to generate commit message."),process.exit(1)}}import m from"picocolors";import W from"clipboardy";async function E(e){let t=await r();t.lastGeneratedMessage||(console.log(m.red("No previous commit message found.")),console.log(m.dim(`Generate a new message with ${m.cyan(m.bold("`noto`"))} command.`)),process.exit(1));let o=f(),i=t.lastGeneratedMessage;o.success(`Previous Commit Message: ${m.dim(m.bold(i))}`),e.copy&&(W.writeSync(i),o.success("Message copied to clipboard!")),e.apply&&(await y(),await h(),await g(i)||(o.fail("Failed to commit staged changes."),process.exit(1)),o.success("Staged changes committed!"))}var R="0.4.0";Q(V(process.argv)).scriptName("noto").usage("$0 [args]").command("config","setup you API key to enable noto.",()=>{},K).command("prev","access previous commit message",e=>{e.option("copy",{alias:"c",type:"boolean",description:"Copy the previous commit message to the clipboard."}),e.option("apply",{alias:"a",type:"boolean",description:"Commit the staged changes with the previous message."})},E).command("*","generate commit message",e=>{e.option("copy",{alias:"c",type:"boolean",description:"Copy the generated commit message to the clipboard."}),e.option("apply",{alias:"a",type:"boolean",description:"Commit the staged changes with the generated message."})},O).version("version",R).alias("-v","--version").alias("-h","--help").argv;
14
15
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../commands/config.ts","../src/storage.ts","../src/utils.ts","../src/git.ts","../commands/generate.ts","../src/ai.ts","../commands/prev.ts","../package.json"],"sourcesContent":["import yargs from \"yargs\";\n\nimport { hideBin } from \"yargs/helpers\";\n\nimport { config } from \"commands/config\";\nimport { generate } from \"commands/generate\";\nimport { prev } from \"commands/prev\";\n\nimport { version } from \"package\";\n\nyargs(hideBin(process.argv))\n .scriptName(\"noto\")\n .usage(\"$0 [args]\")\n .command(\"config\", \"setup you API key to enable noto.\", () => {}, config)\n .command(\n \"prev\",\n \"access previous commit message\",\n (args) => {\n args.option(\"copy\", {\n alias: \"c\",\n type: \"boolean\",\n description: \"Copy the previous commit message to the clipboard.\",\n });\n args.option(\"apply\", {\n alias: \"a\",\n type: \"boolean\",\n description: \"Commit the staged changes with the previous message.\",\n });\n },\n prev\n )\n .command(\n \"*\",\n \"generate commit message\",\n (args) => {\n args.option(\"copy\", {\n alias: \"c\",\n type: \"boolean\",\n description: \"Copy the generated commit message to the clipboard.\",\n });\n args.option(\"apply\", {\n alias: \"a\",\n type: \"boolean\",\n description: \"Commit the staged changes with the generated message.\",\n });\n },\n generate\n )\n .version(\"version\", version)\n .alias(\"-v\", \"--version\")\n .alias(\"-h\", \"--help\").argv;\n","import prompts from \"@posva/prompts\";\nimport c from \"picocolors\";\n\nimport { load, dump } from \"@/storage\";\n\nexport async function config() {\n const storage = await load();\n\n if (storage.apiKey) {\n const response = await prompts(\n {\n type: \"confirm\",\n name: \"reset\",\n message: \"Do you want to reset your API key?\",\n },\n {\n onCancel: () => process.exit(0),\n }\n );\n\n if (!response.reset) {\n console.log(\n `Use ${c.greenBright(\n c.bold(\"`noto`\")\n )} to generate your commit message!`\n );\n process.exit(0);\n }\n }\n\n const response = await prompts({\n type: \"password\",\n name: \"apiKey\",\n message: \"Please enter your API key:\",\n validate: (value) => (value ? true : \"API key is required!\"),\n });\n if (response.apiKey) {\n storage.apiKey = response.apiKey;\n await dump();\n console.log(\"API key configured successfully!\");\n console.log(\n `Use ${c.greenBright(c.bold(\"`noto`\"))} to generate your commit message!`\n );\n }\n}\n","import { resolve } from \"node:path\";\nimport { existsSync, promises as fs } from \"node:fs\";\n\nimport { APP_DIR, writeFileSafe } from \"@/utils\";\n\nexport interface Storage {\n apiKey?: string;\n lastGeneratedMessage?: string;\n}\n\nlet storage: Storage = {};\n\nconst storagePath = resolve(APP_DIR, \"storage.json\");\n\nexport async function load(\n fn?: (storage: Storage) => Promise<boolean> | boolean\n): Promise<Storage> {\n try {\n if (!Object.keys(storage).length) {\n storage = existsSync(storagePath)\n ? JSON.parse((await fs.readFile(storagePath, \"utf-8\")) || \"{}\") || {}\n : {};\n }\n if (fn && (await fn(storage))) {\n await dump();\n }\n } catch (error) {\n console.error(\"error loading storage:\", error);\n storage = {};\n }\n\n return storage;\n}\n\nexport async function dump(): Promise<void> {\n try {\n if (storage) {\n await writeFileSafe(storagePath, JSON.stringify(storage, null, 2));\n }\n } catch (error) {\n console.error(\"error saving storage:\", error);\n }\n}\n","import os from \"node:os\";\nimport process from \"node:process\";\n\nimport which from \"which\";\nimport ora from \"ora\";\nimport c from \"picocolors\";\n\nimport { dirname, join } from \"node:path\";\nimport { existsSync, promises as fs } from \"node:fs\";\n\nimport type { Buffer } from \"node:buffer\";\n\nimport type { Ora } from \"ora\";\n\nimport { load } from \"@/storage\";\nimport { getStagedDiff, isGitRepository } from \"@/git\";\n\nexport const APP_DIR = join(os.homedir(), \"snelusha-noto\");\n\nexport function remove<T>(arr: T[], v: T) {\n const index = arr.indexOf(v);\n if (index >= 0) arr.splice(index, 1);\n return arr;\n}\n\nexport function exclude<T>(arr: T[], ...v: T[]) {\n return arr.slice().filter((item) => !v.includes(item));\n}\n\nexport function cmdExists(cmd: string) {\n return which.sync(cmd, { nothrow: true }) !== null;\n}\n\ninterface TempFile {\n path: string;\n fd: fs.FileHandle;\n cleanup: () => void;\n}\n\nlet counter = 0;\n\nasync function openTemp(): Promise<TempFile | undefined> {\n if (!existsSync(APP_DIR)) await fs.mkdir(APP_DIR, { recursive: true });\n\n const competitivePath = join(APP_DIR, `.${process.pid}.${counter}`);\n counter += 1;\n\n return fs\n .open(competitivePath, \"wx\")\n .then((fd) => ({\n fd,\n path: competitivePath,\n cleanup() {\n fd.close().then(() => {\n if (existsSync(competitivePath)) fs.unlink(competitivePath);\n });\n },\n }))\n .catch((error: any) => {\n if (error && error.code === \"EEXIST\") return openTemp();\n else return undefined;\n });\n}\n\nexport async function writeFileSafe(\n path: string,\n data: string | Buffer = \"\"\n): Promise<boolean> {\n const temp = await openTemp();\n\n if (temp) {\n try {\n // @ts-expect-error eslint-disable-next-line\n await fs.writeFile(temp.path, data);\n const directory = dirname(path);\n if (!existsSync(directory))\n await fs.mkdir(directory, { recursive: true });\n await fs.rename(temp.path, path);\n return true;\n } catch {\n return false;\n } finally {\n temp.cleanup();\n }\n }\n\n return false;\n}\n\nexport function spinner() {\n let s: Ora | undefined;\n\n return {\n start(text: string) {\n s = ora(text);\n s.spinner = {\n interval: 150,\n frames: [\"✶\", \"✸\", \"✹\", \"✺\", \"✹\", \"✷\"],\n };\n s.start();\n },\n fail(text: string) {\n if (!s) {\n s = ora();\n }\n s.fail(text);\n s = undefined;\n },\n success(text: string) {\n if (!s) {\n s = ora();\n }\n s.succeed(text);\n s = undefined;\n },\n stop() {\n if (s) {\n s.stop();\n s = undefined;\n }\n },\n };\n}\n\nexport async function ensureApiKey() {\n const storage = await load();\n if (!storage.apiKey) {\n console.log(\n `Please run ${c.cyan(c.bold(\"`noto config`\"))} to set your API key.`\n );\n process.exit(1);\n }\n}\n\nexport async function ensureGitRepository() {\n if (await isGitRepository()) return;\n console.log(c.red(\"Oops! No Git repository found in the current directory.\"));\n console.log(\n c.dim(`You can initialize one by running ${c.cyan(c.bold(\"`git init`\"))}`)\n );\n process.exit(1);\n}\n\nexport async function ensureStagedChanges() {\n const diff = await getStagedDiff();\n if (diff) return diff;\n console.log(c.red(\"Oops! No staged changes found to commit.\"));\n console.log(\n c.dim(\n `Stage changes with ${c.cyan(c.bold(\"`git add <file>`\"))} or ${c.cyan(\n c.bold(\"`git add .`\")\n )} for stage all files.`\n )\n );\n process.exit(1);\n}\n","import simpleGit from \"simple-git\";\n\nexport async function isGitRepository() {\n try {\n return await simpleGit().checkIsRepo();\n } catch {\n return false;\n }\n}\n\nexport async function getStagedDiff(): Promise<string | null> {\n try {\n return await simpleGit().diff([\"--cached\"]);\n } catch {\n return null;\n }\n}\n\nexport async function commit(message: string): Promise<boolean> {\n try {\n const result = await simpleGit().commit(message);\n return result.summary.changes > 0;\n } catch {\n return false;\n }\n}\n","import c from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { load, dump } from \"@/storage\";\nimport { commit } from \"@/git\";\nimport { generateCommitMessage } from \"@/ai\";\nimport {\n ensureApiKey,\n ensureGitRepository,\n ensureStagedChanges,\n spinner,\n} from \"@/utils\";\n\nimport type { ArgumentsCamelCase } from \"yargs\";\n\nexport async function generate(args: ArgumentsCamelCase) {\n const storage = await load();\n\n await ensureApiKey();\n await ensureGitRepository();\n\n const diff = await ensureStagedChanges();\n\n const spin = spinner();\n\n try {\n spin.start(\"Generating commit message...\");\n\n const message = await generateCommitMessage(diff);\n\n storage.lastGeneratedMessage = message;\n await dump();\n\n spin.success(`Commit Message: ${c.dim(c.bold(message))}`);\n\n if (args.copy) {\n clipboardy.writeSync(message);\n spin.success(\"Message copied to clipboard!\");\n }\n\n if (args.apply) {\n if (!(await commit(message))) {\n spin.fail(\"Failed to commit staged changes.\");\n process.exit(1);\n }\n spin.success(\"Staged changes committed!\");\n }\n } catch (_) {\n spin.fail(\"Failed to generate commit message.\");\n process.exit(1);\n }\n}\n","import { generateObject } from \"ai\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\n\nimport dedent from \"dedent\";\n\nimport { z } from \"zod\";\n\nimport { load } from \"@/storage\";\n\nexport async function generateCommitMessage(diff: string): Promise<string> {\n const storage = await load();\n\n const google = createGoogleGenerativeAI({\n apiKey: storage.apiKey,\n });\n\n const { object } = await generateObject({\n model: google(\"gemini-2.0-flash-exp\", {\n structuredOutputs: false,\n }),\n schema: z.object({\n message: z.string(),\n }),\n messages: [\n {\n role: \"system\",\n content: dedent`\n You are a state-of-the-art AI model tasked with generating a precise Git commit message based on staged changes.\n Adhere strictly to the following instructions, ranked by priority:\n \n 1. Write the commit message in present tense, starting with a present-tense verb such as add, fix, update, remove, improve, or implement. This applies to all repositories, including Java.\n 2. Summarize the key changes only, crafting a concise and clear commit message in the format \"<type>: <description>\".\n 3. Use one of the following standardized types: feat, fix, refactor, docs, test, or chore.\n 4. Ensure the commit message is a single line, fully lowercase, with no scope or body, and omit punctuation such as full stops at the end.\n 5. Limit the length of the commit message to 72 characters.\n 6. Avoid mentioning file names unless a file was renamed or is critical for understanding the changes.\n 7. Prioritize clarity and focus on the most impactful changes for the commit.\n \n You are expected to generate structured outputs that align with the provided guidelines and produce a message optimized for readability and accuracy. Strictly follow all constraints to ensure high-quality results.`,\n },\n {\n role: \"user\",\n content: dedent`generate a commit message for the following staged changes:\\n${diff}`,\n },\n ],\n });\n\n return object.message.trim();\n}\n","import c from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { load } from \"@/storage\";\nimport { commit } from \"@/git\";\n\nimport {\n ensureApiKey,\n ensureGitRepository,\n ensureStagedChanges,\n spinner,\n} from \"@/utils\";\n\nimport type { ArgumentsCamelCase } from \"yargs\";\n\nexport async function prev(args: ArgumentsCamelCase) {\n const storage = await load();\n\n if (!storage.lastGeneratedMessage) {\n console.log(c.red(\"No previous commit message found.\"));\n console.log(\n c.dim(`Generate a new message with ${c.cyan(c.bold(\"`noto`\"))} command.`)\n );\n process.exit(1);\n }\n const spin = spinner();\n\n const message = storage.lastGeneratedMessage;\n\n spin.success(`Previous Commit Message: ${c.dim(c.bold(message))}`);\n\n if (args.copy) {\n clipboardy.writeSync(message);\n spin.success(\"Message copied to clipboard!\");\n }\n\n if (args.apply) {\n await ensureGitRepository();\n\n await ensureStagedChanges();\n\n if (!(await commit(message))) {\n spin.fail(\"Failed to commit staged changes.\");\n process.exit(1);\n }\n\n spin.success(\"Staged changes committed!\");\n }\n}\n","{\n \"name\": \"@snelusha/noto\",\n \"type\": \"module\",\n \"version\": \"0.3.8\",\n \"description\": \"generate clean commit messages in a snap! ✨\",\n \"license\": \"MIT\",\n \"author\": {\n \"name\": \"Sithija Nelusha Silva\",\n \"email\": \"hello@snelusha.dev\",\n \"url\": \"https://snelusha.dev\"\n },\n \"homepage\": \"https://github.com/snelusha/noto\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/snelusha/noto.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/snelusha/noto/issues\"\n },\n \"main\": \"dist/cli.js\",\n \"module\": \"dist/cli.js\",\n \"types\": \"dist/cli.d.ts\",\n \"bin\": {\n \"noto\": \"bin/noto.mjs\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"publish\": \"npm publish --public\"\n },\n \"devDependencies\": {\n \"@types/bun\": \"latest\",\n \"@types/which\": \"^3.0.4\",\n \"@types/yargs\": \"^17.0.33\",\n \"esbuild-plugin-alias\": \"^0.2.1\",\n \"tsup\": \"^8.3.5\"\n },\n \"peerDependencies\": {\n \"typescript\": \"^5.0.0\"\n },\n \"dependencies\": {\n \"@ai-sdk/google\": \"^1.0.16\",\n \"@posva/prompts\": \"^2.4.4\",\n \"ai\": \"^4.0.36\",\n \"clipboardy\": \"^4.0.0\",\n \"dedent\": \"^1.5.3\",\n \"ora\": \"^8.1.1\",\n \"picocolors\": \"^1.1.1\",\n \"simple-git\": \"^3.27.0\",\n \"which\": \"^5.0.0\",\n \"yargs\": \"^17.7.2\",\n \"zod\": \"^3.24.1\"\n }\n}\n"],"mappings":"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","names":["yargs","hideBin","prompts","c","resolve","existsSync","fs","os","process","which","ora","c","dirname","join","existsSync","fs","simpleGit","isGitRepository","getStagedDiff","commit","message","APP_DIR","join","os","counter","openTemp","existsSync","APP_DIR","fs","competitivePath","join","process","fd","error","writeFileSafe","path","data","temp","directory","dirname","spinner","s","text","ora","ensureApiKey","load","c","ensureGitRepository","isGitRepository","ensureStagedChanges","diff","getStagedDiff","storage","storagePath","resolve","APP_DIR","load","fn","existsSync","fs","dump","error","writeFileSafe","config","storage","load","prompts","c","response","value","dump","c","clipboardy","generateObject","createGoogleGenerativeAI","dedent","z","generateCommitMessage","diff","storage","load","google","createGoogleGenerativeAI","object","generateObject","z","dedent","generate","args","storage","load","ensureApiKey","ensureGitRepository","diff","ensureStagedChanges","spin","spinner","message","generateCommitMessage","dump","c","clipboardy","commit","clipboardy","prev","args","storage","load","spin","spinner","message","clipboardy","ensureGitRepository","ensureStagedChanges","commit","version","yargs","hideBin","config","args","prev","generate","version"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/config.ts","../src/storage.ts","../src/utils.ts","../src/git.ts","../src/commands/generate.ts","../src/ai.ts","../src/commands/prev.ts","../package.json"],"sourcesContent":["import yargs from \"yargs\";\n\nimport { hideBin } from \"yargs/helpers\";\n\nimport { config } from \"@/commands/config\";\nimport { generate } from \"@/commands/generate\";\nimport { prev } from \"@/commands/prev\";\n\nimport { version } from \"package\";\n\nyargs(hideBin(process.argv))\n .scriptName(\"noto\")\n .usage(\"$0 [args]\")\n .command(\"config\", \"setup you API key to enable noto.\", () => {}, config)\n .command(\n \"prev\",\n \"access previous commit message\",\n (args) => {\n args.option(\"copy\", {\n alias: \"c\",\n type: \"boolean\",\n description: \"Copy the previous commit message to the clipboard.\",\n });\n args.option(\"apply\", {\n alias: \"a\",\n type: \"boolean\",\n description: \"Commit the staged changes with the previous message.\",\n });\n },\n prev\n )\n .command(\n \"*\",\n \"generate commit message\",\n (args) => {\n args.option(\"copy\", {\n alias: \"c\",\n type: \"boolean\",\n description: \"Copy the generated commit message to the clipboard.\",\n });\n args.option(\"apply\", {\n alias: \"a\",\n type: \"boolean\",\n description: \"Commit the staged changes with the generated message.\",\n });\n },\n generate\n )\n .version(\"version\", version)\n .alias(\"-v\", \"--version\")\n .alias(\"-h\", \"--help\").argv;\n","import prompts from \"@posva/prompts\";\nimport pc from \"picocolors\";\n\nimport { load, dump } from \"@/storage\";\n\nexport async function config() {\n const storage = await load();\n\n if (storage.apiKey) {\n const response = await prompts(\n {\n type: \"confirm\",\n name: \"reset\",\n message: \"Do you want to reset your API key?\",\n },\n {\n onCancel: () => process.exit(0),\n }\n );\n\n if (!response.reset) {\n console.log(\n `Use ${pc.greenBright(\n pc.bold(\"`noto`\")\n )} to generate your commit message!`\n );\n process.exit(0);\n }\n }\n\n const response = await prompts({\n type: \"password\",\n name: \"apiKey\",\n message: \"Please enter your API key:\",\n validate: (value) => (value ? true : \"API key is required!\"),\n });\n if (response.apiKey) {\n storage.apiKey = response.apiKey;\n await dump();\n console.log(\"API key configured successfully!\");\n console.log(\n `Use ${pc.greenBright(pc.bold(\"`noto`\"))} to generate your commit message!`\n );\n }\n}\n","import { resolve } from \"node:path\";\nimport { existsSync, promises as fs } from \"node:fs\";\n\nimport { APP_DIR, writeFileSafe } from \"@/utils\";\n\nexport interface Storage {\n apiKey?: string;\n lastGeneratedMessage?: string;\n}\n\nlet storage: Storage = {};\n\nconst storagePath = resolve(APP_DIR, \"storage.json\");\n\nexport async function load(\n fn?: (storage: Storage) => Promise<boolean> | boolean\n): Promise<Storage> {\n try {\n if (!Object.keys(storage).length) {\n storage = existsSync(storagePath)\n ? JSON.parse((await fs.readFile(storagePath, \"utf-8\")) || \"{}\") || {}\n : {};\n }\n if (fn && (await fn(storage))) {\n await dump();\n }\n } catch (error) {\n console.error(\"error loading storage:\", error);\n storage = {};\n }\n\n return storage;\n}\n\nexport async function dump(): Promise<void> {\n try {\n if (storage) {\n await writeFileSafe(storagePath, JSON.stringify(storage, null, 2));\n }\n } catch (error) {\n console.error(\"error saving storage:\", error);\n }\n}\n","import os from \"node:os\";\nimport process from \"node:process\";\n\nimport which from \"which\";\nimport ora from \"ora\";\nimport pc from \"picocolors\";\n\nimport { dirname, join } from \"node:path\";\nimport { existsSync, promises as fs } from \"node:fs\";\n\nimport type { Buffer } from \"node:buffer\";\n\nimport type { Ora } from \"ora\";\n\nimport { load } from \"@/storage\";\nimport { getStagedDiff, isGitRepository } from \"@/git\";\n\nexport const APP_DIR = join(os.homedir(), \"snelusha-noto\");\n\nexport function remove<T>(arr: T[], v: T) {\n const index = arr.indexOf(v);\n if (index >= 0) arr.splice(index, 1);\n return arr;\n}\n\nexport function exclude<T>(arr: T[], ...v: T[]) {\n return arr.slice().filter((item) => !v.includes(item));\n}\n\nexport function cmdExists(cmd: string) {\n return which.sync(cmd, { nothrow: true }) !== null;\n}\n\ninterface TempFile {\n path: string;\n fd: fs.FileHandle;\n cleanup: () => void;\n}\n\nlet counter = 0;\n\nasync function openTemp(): Promise<TempFile | undefined> {\n if (!existsSync(APP_DIR)) await fs.mkdir(APP_DIR, { recursive: true });\n\n const competitivePath = join(APP_DIR, `.${process.pid}.${counter}`);\n counter += 1;\n\n return fs\n .open(competitivePath, \"wx\")\n .then((fd) => ({\n fd,\n path: competitivePath,\n cleanup() {\n fd.close().then(() => {\n if (existsSync(competitivePath)) fs.unlink(competitivePath);\n });\n },\n }))\n .catch((error: any) => {\n if (error && error.code === \"EEXIST\") return openTemp();\n else return undefined;\n });\n}\n\nexport async function writeFileSafe(\n path: string,\n data: string | Buffer = \"\"\n): Promise<boolean> {\n const temp = await openTemp();\n\n if (temp) {\n try {\n // @ts-expect-error eslint-disable-next-line\n await fs.writeFile(temp.path, data);\n const directory = dirname(path);\n if (!existsSync(directory))\n await fs.mkdir(directory, { recursive: true });\n await fs.rename(temp.path, path);\n return true;\n } catch {\n return false;\n } finally {\n temp.cleanup();\n }\n }\n\n return false;\n}\n\nexport function spinner() {\n let s: Ora | undefined;\n\n return {\n start(text: string) {\n s = ora(text);\n s.spinner = {\n interval: 150,\n frames: [\"✶\", \"✸\", \"✹\", \"✺\", \"✹\", \"✷\"],\n };\n s.start();\n },\n fail(text: string) {\n if (!s) {\n s = ora();\n }\n s.fail(text);\n s = undefined;\n },\n success(text: string) {\n if (!s) {\n s = ora();\n }\n s.succeed(text);\n s = undefined;\n },\n stop() {\n if (s) {\n s.stop();\n s = undefined;\n }\n },\n };\n}\n\nexport async function ensureApiKey() {\n const storage = await load();\n if (!storage.apiKey) {\n console.log(\n `Please run ${pc.cyan(pc.bold(\"`noto config`\"))} to set your API key.`\n );\n process.exit(1);\n }\n}\n\nexport async function ensureGitRepository() {\n if (await isGitRepository()) return;\n console.log(pc.red(\"Oops! No Git repository found in the current directory.\"));\n console.log(\n pc.dim(`You can initialize one by running ${pc.cyan(pc.bold(\"`git init`\"))}`)\n );\n process.exit(1);\n}\n\nexport async function ensureStagedChanges() {\n const diff = await getStagedDiff();\n if (diff) return diff;\n console.log(pc.red(\"Oops! No staged changes found to commit.\"));\n console.log(\n pc.dim(\n `Stage changes with ${pc.cyan(pc.bold(\"`git add <file>`\"))} or ${pc.cyan(\n pc.bold(\"`git add .`\")\n )} for stage all files.`\n )\n );\n process.exit(1);\n}\n","import simpleGit from \"simple-git\";\n\nexport async function isGitRepository() {\n try {\n return await simpleGit().checkIsRepo();\n } catch {\n return false;\n }\n}\n\nexport async function getStagedDiff(): Promise<string | null> {\n try {\n const stagedFiles = await simpleGit().diff([\"--cached\", \"--name-only\"]);\n\n const files = stagedFiles.split(\"\\n\").filter(Boolean);\n\n const excludedPatterns = [\n \"*.lock\",\n \"*.lockb\",\n \"*.yaml.lock\",\n \"*.hcl.lock\",\n \"*.resolved\",\n ];\n const filteredFiles = files.filter(\n (file) =>\n !excludedPatterns.some((pattern) => {\n const regex = new RegExp(pattern.replace(\"*\", \".*\"));\n return regex.test(file);\n })\n );\n\n if (filteredFiles.length === 0) return null;\n\n return await simpleGit().diff([\"--cached\", \"--\", ...filteredFiles]);\n } catch {\n return null;\n }\n}\n\nexport async function commit(message: string): Promise<boolean> {\n try {\n const result = await simpleGit().commit(message);\n return result.summary.changes > 0;\n } catch {\n return false;\n }\n}\n\nexport async function getCommitCount() {\n try {\n const count = await simpleGit().raw([\"rev-list\", \"--count\", \"HEAD\"]);\n return Number(count.trim());\n } catch (error) {\n if (\n /(ambiguous argument.*HEAD|unknown revision or path.*HEAD)/i.test(\n (error as Error).message\n )\n ) {\n return 0;\n }\n return null;\n }\n}\n\nexport async function isFirstCommit() {\n try {\n const count = await getCommitCount();\n return count === 0;\n } catch {\n return false;\n }\n}\n","import pc from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { load, dump } from \"@/storage\";\nimport { commit } from \"@/git\";\nimport { generateCommitMessage } from \"@/ai\";\nimport {\n ensureApiKey,\n ensureGitRepository,\n ensureStagedChanges,\n spinner,\n} from \"@/utils\";\n\nimport type { ArgumentsCamelCase } from \"yargs\";\n\nexport async function generate(args: ArgumentsCamelCase) {\n const storage = await load();\n\n await ensureApiKey();\n await ensureGitRepository();\n\n const diff = await ensureStagedChanges();\n\n const spin = spinner();\n\n try {\n spin.start(\"Generating commit message...\");\n\n const message = await generateCommitMessage(diff);\n\n storage.lastGeneratedMessage = message;\n await dump();\n\n spin.success(`Commit Message: ${pc.dim(pc.bold(message))}`);\n\n if (args.copy) {\n clipboardy.writeSync(message);\n spin.success(\"Message copied to clipboard!\");\n }\n\n if (args.apply) {\n if (!(await commit(message))) {\n spin.fail(\"Failed to commit staged changes.\");\n process.exit(1);\n }\n spin.success(\"Staged changes committed!\");\n }\n } catch (_) {\n spin.fail(\"Failed to generate commit message.\");\n process.exit(1);\n }\n}\n","import { generateObject } from \"ai\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\n\nimport dedent from \"dedent\";\n\nimport { z } from \"zod\";\n\nimport { load } from \"@/storage\";\nimport { isFirstCommit } from \"@/git\";\n\nexport async function generateCommitMessage(diff: string): Promise<string> {\n if (await isFirstCommit()) return \"chore: init repo\";\n\n const storage = await load();\n\n const google = createGoogleGenerativeAI({\n apiKey: storage.apiKey,\n });\n\n const { object } = await generateObject({\n model: google(\"gemini-2.0-flash-exp\", {\n structuredOutputs: false,\n }),\n schema: z.object({\n message: z.string(),\n }),\n messages: [\n {\n role: \"system\",\n content: dedent`\n You are a state-of-the-art AI model tasked with generating a precise Git commit message based on staged changes.\n Adhere strictly to the following instructions, ranked by priority:\n \n 1. Write the commit message in present tense, starting with a present-tense verb such as add, fix, update, remove, improve, or implement. This applies to all repositories, including Java.\n 2. Summarize the key changes only, crafting a concise and clear commit message in the format \"<type>: <description>\".\n 3. Use one of the following standardized types: feat, fix, refactor, docs, test, or chore.\n 4. Ensure the commit message is a single line, fully lowercase, with no scope or body, and omit punctuation such as full stops at the end.\n 5. Limit the length of the commit message to 72 characters.\n 6. Avoid mentioning file names unless a file was renamed or is critical for understanding the changes.\n 7. Prioritize clarity and focus on the most impactful changes for the commit.\n \n You are expected to generate structured outputs that align with the provided guidelines and produce a message optimized for readability and accuracy. Strictly follow all constraints to ensure high-quality results.`,\n },\n {\n role: \"user\",\n content: dedent`generate a commit message for the following staged changes:\\n${diff}`,\n },\n ],\n });\n\n return object.message.trim();\n}\n","import pc from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { load } from \"@/storage\";\nimport { commit } from \"@/git\";\n\nimport {\n ensureApiKey,\n ensureGitRepository,\n ensureStagedChanges,\n spinner,\n} from \"@/utils\";\n\nimport type { ArgumentsCamelCase } from \"yargs\";\n\nexport async function prev(args: ArgumentsCamelCase) {\n const storage = await load();\n\n if (!storage.lastGeneratedMessage) {\n console.log(pc.red(\"No previous commit message found.\"));\n console.log(\n pc.dim(`Generate a new message with ${pc.cyan(pc.bold(\"`noto`\"))} command.`)\n );\n process.exit(1);\n }\n const spin = spinner();\n\n const message = storage.lastGeneratedMessage;\n\n spin.success(`Previous Commit Message: ${pc.dim(pc.bold(message))}`);\n\n if (args.copy) {\n clipboardy.writeSync(message);\n spin.success(\"Message copied to clipboard!\");\n }\n\n if (args.apply) {\n await ensureGitRepository();\n\n await ensureStagedChanges();\n\n if (!(await commit(message))) {\n spin.fail(\"Failed to commit staged changes.\");\n process.exit(1);\n }\n\n spin.success(\"Staged changes committed!\");\n }\n}\n","{\n \"name\": \"@snelusha/noto\",\n \"type\": \"module\",\n \"version\": \"0.4.0\",\n \"description\": \"generate clean commit messages in a snap! ✨\",\n \"license\": \"MIT\",\n \"author\": {\n \"name\": \"Sithija Nelusha Silva\",\n \"email\": \"hello@snelusha.dev\",\n \"url\": \"https://snelusha.dev\"\n },\n \"homepage\": \"https://github.com/snelusha/noto\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/snelusha/noto.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/snelusha/noto/issues\"\n },\n \"main\": \"dist/cli.js\",\n \"module\": \"dist/cli.js\",\n \"types\": \"dist/cli.d.ts\",\n \"bin\": {\n \"noto\": \"bin/noto.mjs\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"publish\": \"npm publish --public\"\n },\n \"devDependencies\": {\n \"@types/bun\": \"latest\",\n \"@types/which\": \"^3.0.4\",\n \"@types/yargs\": \"^17.0.33\",\n \"esbuild-plugin-alias\": \"^0.2.1\",\n \"tsup\": \"^8.3.5\"\n },\n \"peerDependencies\": {\n \"typescript\": \"^5.0.0\"\n },\n \"dependencies\": {\n \"@ai-sdk/google\": \"^1.0.16\",\n \"@posva/prompts\": \"^2.4.4\",\n \"ai\": \"^4.0.36\",\n \"clipboardy\": \"^4.0.0\",\n \"dedent\": \"^1.5.3\",\n \"ora\": \"^8.1.1\",\n \"picocolors\": \"^1.1.1\",\n \"simple-git\": \"^3.27.0\",\n \"which\": \"^5.0.0\",\n \"yargs\": \"^17.7.2\",\n \"zod\": \"^3.24.1\"\n }\n}\n"],"mappings":"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","names":["yargs","hideBin","prompts","pc","resolve","existsSync","fs","os","process","which","ora","pc","dirname","join","existsSync","fs","simpleGit","isGitRepository","getStagedDiff","files","excludedPatterns","filteredFiles","file","pattern","commit","message","getCommitCount","count","error","isFirstCommit","APP_DIR","join","os","counter","openTemp","existsSync","APP_DIR","fs","competitivePath","join","process","fd","error","writeFileSafe","path","data","temp","directory","dirname","spinner","s","text","ora","ensureApiKey","load","pc","ensureGitRepository","isGitRepository","ensureStagedChanges","diff","getStagedDiff","storage","storagePath","resolve","APP_DIR","load","fn","existsSync","fs","dump","error","writeFileSafe","config","storage","load","prompts","pc","response","value","dump","pc","clipboardy","generateObject","createGoogleGenerativeAI","dedent","z","generateCommitMessage","diff","isFirstCommit","storage","load","google","createGoogleGenerativeAI","object","generateObject","z","dedent","generate","args","storage","load","ensureApiKey","ensureGitRepository","diff","ensureStagedChanges","spin","spinner","message","generateCommitMessage","dump","pc","clipboardy","commit","pc","clipboardy","prev","args","storage","load","pc","spin","spinner","message","clipboardy","ensureGitRepository","ensureStagedChanges","commit","version","yargs","hideBin","config","args","prev","generate","version"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@snelusha/noto",
3
3
  "type": "module",
4
- "version": "0.3.8",
4
+ "version": "0.4.0",
5
5
  "description": "generate clean commit messages in a snap! ✨",
6
6
  "license": "MIT",
7
7
  "author": {