@snelusha/noto 0.3.6 → 0.3.7
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 +2 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
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`
|
|
2
2
|
You are a state-of-the-art AI model tasked with generating a precise Git commit message based on staged changes.
|
|
3
3
|
Adhere strictly to the following instructions, ranked by priority:
|
|
4
4
|
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
6. Avoid mentioning file names unless a file was renamed or is critical for understanding the changes.
|
|
11
11
|
7. Prioritize clarity and focus on the most impactful changes for the commit.
|
|
12
12
|
|
|
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:
|
|
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.6";(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
14
|
//# sourceMappingURL=cli.cjs.map
|
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/storage.ts","../src/utils.ts","../src/git.ts","../src/ai.ts","../package.json"],"sourcesContent":["import yargs from \"yargs\";\nimport prompts from \"@posva/prompts\";\nimport c from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { hideBin } from \"yargs/helpers\";\n\nimport { dump, load } from \"@/storage\";\nimport { commit, getStagedDiff, isGitRepository } from \"@/git\";\nimport { generateCommitMessage } from \"@/ai\";\n\nimport { spinner } from \"@/utils\";\n\nimport { version } from \"package\";\n\nyargs(hideBin(process.argv))\n .scriptName(\"noto\")\n .usage(\"$0 [args]\")\n .command(\n \"config\",\n \"setup you API key to enable noto.\",\n () => {},\n async () => {\n const storage = await load();\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 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 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(\n c.bold(\"`noto`\")\n )} to generate your commit message!`\n );\n }\n }\n )\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 async (args) => {\n const spin = spinner();\n\n const storage = await load();\n if (!storage.lastGeneratedMessage) {\n console.log(c.red(\"No previous commit message found.\"));\n console.log(\n c.dim(\n `Generate a new message with ${c.cyan(c.bold(\"`noto`\"))} command.`\n )\n );\n process.exit(1);\n }\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 if (!(await isGitRepository())) {\n console.log(\n c.red(\"Oops! No Git repository found in the current directory.\")\n );\n console.log(\n c.dim(\n `You can initialize one by running ${c.cyan(\n c.bold(\"`git init`\")\n )}`\n )\n );\n process.exit(1);\n }\n\n const diff = await getStagedDiff();\n if (!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(\n c.bold(\"`git add <file>`\")\n )} or ${c.cyan(c.bold(\"`git add .`\"))} for stage all files.`\n )\n );\n process.exit(1);\n }\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 successfully!\");\n }\n }\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 async (args) => {\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 if (!(await isGitRepository())) {\n console.log(\n c.red(\"Oops! No Git repository found in the current directory.\")\n );\n console.log(\n c.dim(\n `You can initialize one by running ${c.cyan(c.bold(\"`git init`\"))}`\n )\n );\n process.exit(1);\n }\n\n const diff = await getStagedDiff();\n if (!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(\n c.bold(\"`git add <file>`\")\n )} or ${c.cyan(c.bold(\"`git add .`\"))} for stage all files.`\n )\n );\n process.exit(1);\n }\n\n const spin = spinner();\n try {\n spin.start(\"Generating commit message...\");\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 successfully!\");\n }\n } catch (error) {\n spin.fail(\"Failed to generate commit message.\");\n process.exit(1);\n }\n }\n )\n .version(\"version\", version)\n .alias(\"-v\", \"--version\")\n .alias(\"-h\", \"--help\").argv;\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\";\nimport which from \"which\";\nimport ora from \"ora\";\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\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","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 { 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","{\n \"name\": \"@snelusha/noto\",\n \"type\": \"module\",\n \"version\": \"0.3.5\",\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\": \"unbuild\",\n \"tsup\": \"tsup\",\n \"publish\": \"npm publish --public\",\n \"start\": \"bun dist/cli.js\"\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.12\",\n \"@posva/prompts\": \"^2.4.4\",\n \"ai\": \"^4.0.26\",\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_prompts","import_picocolors","import_clipboardy","import_helpers","import_node_path","import_node_fs","import_node_os","import_node_process","import_which","import_ora","import_node_path","import_node_fs","APP_DIR","os","counter","openTemp","APP_DIR","fs","competitivePath","process","fd","error","writeFileSafe","path","data","temp","directory","spinner","s","text","ora","storage","storagePath","APP_DIR","load","fn","fs","dump","error","writeFileSafe","import_simple_git","isGitRepository","simpleGit","getStagedDiff","commit","message","import_ai","import_google","import_dedent","import_zod","generateCommitMessage","diff","storage","load","google","object","dedent","version","yargs","storage","load","prompts","c","response","value","dump","args","spin","spinner","message","clipboardy","isGitRepository","getStagedDiff","commit","diff","generateCommitMessage","version"]}
|
|
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.6\",\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.12\",\n \"@posva/prompts\": \"^2.4.4\",\n \"ai\": \"^4.0.26\",\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"]}
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
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`
|
|
2
2
|
You are a state-of-the-art AI model tasked with generating a precise Git commit message based on staged changes.
|
|
3
3
|
Adhere strictly to the following instructions, ranked by priority:
|
|
4
4
|
|
|
@@ -10,5 +10,5 @@ import D from"yargs";import I from"@posva/prompts";import t from"picocolors";imp
|
|
|
10
10
|
6. Avoid mentioning file names unless a file was renamed or is critical for understanding the changes.
|
|
11
11
|
7. Prioritize clarity and focus on the most impactful changes for the commit.
|
|
12
12
|
|
|
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:
|
|
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.6";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
14
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/storage.ts","../src/utils.ts","../src/git.ts","../src/ai.ts","../package.json"],"sourcesContent":["import yargs from \"yargs\";\nimport prompts from \"@posva/prompts\";\nimport c from \"picocolors\";\nimport clipboardy from \"clipboardy\";\n\nimport { hideBin } from \"yargs/helpers\";\n\nimport { dump, load } from \"@/storage\";\nimport { commit, getStagedDiff, isGitRepository } from \"@/git\";\nimport { generateCommitMessage } from \"@/ai\";\n\nimport { spinner } from \"@/utils\";\n\nimport { version } from \"package\";\n\nyargs(hideBin(process.argv))\n .scriptName(\"noto\")\n .usage(\"$0 [args]\")\n .command(\n \"config\",\n \"setup you API key to enable noto.\",\n () => {},\n async () => {\n const storage = await load();\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 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 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(\n c.bold(\"`noto`\")\n )} to generate your commit message!`\n );\n }\n }\n )\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 async (args) => {\n const spin = spinner();\n\n const storage = await load();\n if (!storage.lastGeneratedMessage) {\n console.log(c.red(\"No previous commit message found.\"));\n console.log(\n c.dim(\n `Generate a new message with ${c.cyan(c.bold(\"`noto`\"))} command.`\n )\n );\n process.exit(1);\n }\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 if (!(await isGitRepository())) {\n console.log(\n c.red(\"Oops! No Git repository found in the current directory.\")\n );\n console.log(\n c.dim(\n `You can initialize one by running ${c.cyan(\n c.bold(\"`git init`\")\n )}`\n )\n );\n process.exit(1);\n }\n\n const diff = await getStagedDiff();\n if (!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(\n c.bold(\"`git add <file>`\")\n )} or ${c.cyan(c.bold(\"`git add .`\"))} for stage all files.`\n )\n );\n process.exit(1);\n }\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 successfully!\");\n }\n }\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 async (args) => {\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 if (!(await isGitRepository())) {\n console.log(\n c.red(\"Oops! No Git repository found in the current directory.\")\n );\n console.log(\n c.dim(\n `You can initialize one by running ${c.cyan(c.bold(\"`git init`\"))}`\n )\n );\n process.exit(1);\n }\n\n const diff = await getStagedDiff();\n if (!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(\n c.bold(\"`git add <file>`\")\n )} or ${c.cyan(c.bold(\"`git add .`\"))} for stage all files.`\n )\n );\n process.exit(1);\n }\n\n const spin = spinner();\n try {\n spin.start(\"Generating commit message...\");\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 successfully!\");\n }\n } catch (error) {\n spin.fail(\"Failed to generate commit message.\");\n process.exit(1);\n }\n }\n )\n .version(\"version\", version)\n .alias(\"-v\", \"--version\")\n .alias(\"-h\", \"--help\").argv;\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\";\nimport which from \"which\";\nimport ora from \"ora\";\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\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","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 { 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","{\n \"name\": \"@snelusha/noto\",\n \"type\": \"module\",\n \"version\": \"0.3.5\",\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\": \"unbuild\",\n \"tsup\": \"tsup\",\n \"publish\": \"npm publish --public\",\n \"start\": \"bun dist/cli.js\"\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.12\",\n \"@posva/prompts\": \"^2.4.4\",\n \"ai\": \"^4.0.26\",\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","prompts","c","clipboardy","hideBin","resolve","existsSync","fs","os","process","which","ora","dirname","join","existsSync","fs","APP_DIR","counter","openTemp","existsSync","APP_DIR","fs","competitivePath","join","process","fd","error","writeFileSafe","path","data","temp","directory","dirname","spinner","s","text","ora","storage","storagePath","resolve","APP_DIR","load","fn","existsSync","fs","dump","error","writeFileSafe","simpleGit","isGitRepository","getStagedDiff","commit","message","generateObject","createGoogleGenerativeAI","dedent","z","generateCommitMessage","diff","storage","load","google","createGoogleGenerativeAI","object","generateObject","z","dedent","version","yargs","hideBin","storage","load","prompts","c","response","value","dump","args","spin","spinner","message","clipboardy","isGitRepository","getStagedDiff","commit","diff","generateCommitMessage","version"]}
|
|
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.6\",\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.12\",\n \"@posva/prompts\": \"^2.4.4\",\n \"ai\": \"^4.0.26\",\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"]}
|