@snelusha/noto 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -5
- package/dist/cli.cjs +139 -36
- package/dist/cli.mjs +137 -36
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **
|
|
11
|
+
- **Instant Commit Messages**: Generate clear, context-aware messages based on staged changes.
|
|
12
|
+
|
|
13
|
+
- **Seamless Git Integration**: Apply messages directly, skip the copy-paste.
|
|
14
|
+
|
|
12
15
|
- **No Installation Required:** Use instantly with `npx @snelusha/noto` — just run and go!
|
|
13
16
|
|
|
14
17
|
## Getting Started
|
|
@@ -23,14 +26,33 @@
|
|
|
23
26
|
Here, you’ll need to input your Google GenAI API Key.
|
|
24
27
|
|
|
25
28
|
2. **Generate commit messages**
|
|
26
|
-
|
|
29
|
+
To generate a commit message, simply run:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
noto
|
|
33
|
+
|
|
34
|
+
# apply the generated message:
|
|
35
|
+
noto --apply
|
|
36
|
+
# or
|
|
37
|
+
noto -a
|
|
27
38
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
# copy the generated message:
|
|
40
|
+
noto --copy
|
|
41
|
+
# or
|
|
42
|
+
noto -c
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Pro Tips
|
|
46
|
+
|
|
47
|
+
- 🚀 Get fast commits on the fly with `noto -a` to streamline your workflow!
|
|
48
|
+
|
|
49
|
+
## Contributing
|
|
50
|
+
|
|
51
|
+
We welcome contributions and suggestions! If you have ideas or improvements, feel free to reach out or open a pull request.
|
|
31
52
|
|
|
32
53
|
Thank you for using `noto`! If you have any feedback or suggestions, feel free to reach out or contribute to the project. ✨
|
|
33
54
|
|
|
34
55
|
## License
|
|
56
|
+
|
|
35
57
|
This project is licensed under the MIT License.
|
|
36
58
|
© 2024 [Sithija Nelusha Silva](https://github.com/snelusha)
|
package/dist/cli.cjs
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
const yargs = require('yargs');
|
|
4
4
|
const prompts = require('@posva/prompts');
|
|
5
5
|
const c = require('picocolors');
|
|
6
|
+
const clipboardy = require('clipboardy');
|
|
6
7
|
const helpers = require('yargs/helpers');
|
|
7
8
|
const node_path = require('node:path');
|
|
8
9
|
const node_fs = require('node:fs');
|
|
9
10
|
const os = require('node:os');
|
|
10
11
|
const process$1 = require('node:process');
|
|
11
12
|
require('which');
|
|
13
|
+
const ora = require('ora');
|
|
12
14
|
const tinyexec = require('tinyexec');
|
|
13
15
|
const ai = require('ai');
|
|
14
16
|
const google = require('@ai-sdk/google');
|
|
@@ -18,15 +20,17 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
18
20
|
const yargs__default = /*#__PURE__*/_interopDefaultCompat(yargs);
|
|
19
21
|
const prompts__default = /*#__PURE__*/_interopDefaultCompat(prompts);
|
|
20
22
|
const c__default = /*#__PURE__*/_interopDefaultCompat(c);
|
|
23
|
+
const clipboardy__default = /*#__PURE__*/_interopDefaultCompat(clipboardy);
|
|
21
24
|
const os__default = /*#__PURE__*/_interopDefaultCompat(os);
|
|
22
25
|
const process__default = /*#__PURE__*/_interopDefaultCompat(process$1);
|
|
26
|
+
const ora__default = /*#__PURE__*/_interopDefaultCompat(ora);
|
|
23
27
|
|
|
24
|
-
const
|
|
28
|
+
const TEMP_DIR = node_path.join(os__default.tmpdir(), "snelusha-noto");
|
|
25
29
|
let counter = 0;
|
|
26
30
|
async function openTemp() {
|
|
27
|
-
if (!node_fs.existsSync(
|
|
28
|
-
await node_fs.promises.mkdir(
|
|
29
|
-
const competitivePath = node_path.join(
|
|
31
|
+
if (!node_fs.existsSync(TEMP_DIR))
|
|
32
|
+
await node_fs.promises.mkdir(TEMP_DIR, { recursive: true });
|
|
33
|
+
const competitivePath = node_path.join(TEMP_DIR, `.${process__default.pid}.${counter}`);
|
|
30
34
|
counter += 1;
|
|
31
35
|
return node_fs.promises.open(competitivePath, "wx").then((fd) => ({
|
|
32
36
|
fd,
|
|
@@ -62,22 +66,56 @@ async function writeFileSafe(path, data = "") {
|
|
|
62
66
|
}
|
|
63
67
|
return false;
|
|
64
68
|
}
|
|
69
|
+
function spinner() {
|
|
70
|
+
let s;
|
|
71
|
+
return {
|
|
72
|
+
start(text) {
|
|
73
|
+
s = ora__default(text);
|
|
74
|
+
s.spinner = {
|
|
75
|
+
interval: 150,
|
|
76
|
+
frames: ["\u2736", "\u2738", "\u2739", "\u273A", "\u2739", "\u2737"]
|
|
77
|
+
};
|
|
78
|
+
s.start();
|
|
79
|
+
},
|
|
80
|
+
fail(text) {
|
|
81
|
+
if (s)
|
|
82
|
+
s.fail(text);
|
|
83
|
+
},
|
|
84
|
+
success(text) {
|
|
85
|
+
if (s)
|
|
86
|
+
s.succeed(text);
|
|
87
|
+
},
|
|
88
|
+
stop() {
|
|
89
|
+
if (s)
|
|
90
|
+
s.stop();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
65
94
|
|
|
66
|
-
let storage;
|
|
67
|
-
const storagePath = node_path.resolve(
|
|
95
|
+
let storage = {};
|
|
96
|
+
const storagePath = node_path.resolve(TEMP_DIR, "storage.json");
|
|
68
97
|
async function load(fn) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (await fn(storage))
|
|
98
|
+
try {
|
|
99
|
+
if (!Object.keys(storage).length) {
|
|
100
|
+
storage = node_fs.existsSync(storagePath) ? JSON.parse(await node_fs.promises.readFile(storagePath, "utf-8") || "{}") || {} : {};
|
|
101
|
+
}
|
|
102
|
+
if (fn && await fn(storage)) {
|
|
74
103
|
await dump();
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error("error loading storage:", error);
|
|
107
|
+
storage = {};
|
|
75
108
|
}
|
|
76
109
|
return storage;
|
|
77
110
|
}
|
|
78
111
|
async function dump() {
|
|
79
|
-
|
|
80
|
-
|
|
112
|
+
try {
|
|
113
|
+
if (storage) {
|
|
114
|
+
await writeFileSafe(storagePath, JSON.stringify(storage, null, 2));
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error("error saving storage:", error);
|
|
118
|
+
}
|
|
81
119
|
}
|
|
82
120
|
|
|
83
121
|
function isGitRepository(path) {
|
|
@@ -85,12 +123,20 @@ function isGitRepository(path) {
|
|
|
85
123
|
}
|
|
86
124
|
async function getStagedDiff() {
|
|
87
125
|
try {
|
|
88
|
-
const
|
|
89
|
-
return
|
|
126
|
+
const diff = (await tinyexec.x("git", ["diff", "--cached"])).stdout.toString();
|
|
127
|
+
return diff;
|
|
90
128
|
} catch {
|
|
91
129
|
return null;
|
|
92
130
|
}
|
|
93
131
|
}
|
|
132
|
+
async function commit(message) {
|
|
133
|
+
try {
|
|
134
|
+
const result = await tinyexec.x("git", ["commit", "-m", message]);
|
|
135
|
+
return result.stdout.includes("files changed");
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
94
140
|
|
|
95
141
|
async function generateCommitMessage(diff) {
|
|
96
142
|
const storage = await load();
|
|
@@ -116,56 +162,113 @@ ${diff}`
|
|
|
116
162
|
|
|
117
163
|
yargs__default(helpers.hideBin(process.argv)).scriptName("noto").usage("$0 [args]").command(
|
|
118
164
|
"config",
|
|
119
|
-
"
|
|
165
|
+
"setup you API key to enable noto.",
|
|
120
166
|
() => {
|
|
121
167
|
},
|
|
122
168
|
async () => {
|
|
123
169
|
const storage = await load();
|
|
124
170
|
if (storage.apiKey) {
|
|
125
|
-
const response2 = await prompts__default(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
171
|
+
const response2 = await prompts__default(
|
|
172
|
+
{
|
|
173
|
+
type: "confirm",
|
|
174
|
+
name: "reset",
|
|
175
|
+
message: "Do you want to reset your API key?"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
onCancel: () => process.exit(0)
|
|
179
|
+
}
|
|
180
|
+
);
|
|
130
181
|
if (!response2.reset) {
|
|
131
|
-
console.log(
|
|
182
|
+
console.log(
|
|
183
|
+
`Use ${c__default.greenBright(
|
|
184
|
+
c__default.bold("`noto`")
|
|
185
|
+
)} to generate your commit message!`
|
|
186
|
+
);
|
|
132
187
|
return process.exit(0);
|
|
133
188
|
}
|
|
134
189
|
}
|
|
135
190
|
const response = await prompts__default({
|
|
136
|
-
type: "
|
|
191
|
+
type: "password",
|
|
137
192
|
name: "apiKey",
|
|
138
|
-
message: "
|
|
139
|
-
validate: (value) => value ? true : "API key is required"
|
|
193
|
+
message: "Please enter your API key:",
|
|
194
|
+
validate: (value) => value ? true : "API key is required!"
|
|
140
195
|
});
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
196
|
+
if (response.apiKey) {
|
|
197
|
+
storage.apiKey = response.apiKey;
|
|
198
|
+
dump();
|
|
199
|
+
console.log("API key saved successfully!");
|
|
200
|
+
console.log(
|
|
201
|
+
`Use ${c__default.greenBright(
|
|
202
|
+
c__default.bold("`noto`")
|
|
203
|
+
)} to generate your commit message!`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
144
206
|
}
|
|
145
207
|
).command(
|
|
146
208
|
"*",
|
|
147
209
|
"generate commit message",
|
|
148
|
-
() => {
|
|
210
|
+
(args) => {
|
|
211
|
+
args.option("copy", {
|
|
212
|
+
alias: "c",
|
|
213
|
+
type: "boolean",
|
|
214
|
+
description: "Copy the generated commit message to the clipboard."
|
|
215
|
+
});
|
|
216
|
+
args.option("apply", {
|
|
217
|
+
alias: "a",
|
|
218
|
+
type: "boolean",
|
|
219
|
+
description: "Commit the staged changes with the generated message."
|
|
220
|
+
});
|
|
149
221
|
},
|
|
150
|
-
async () => {
|
|
222
|
+
async (args) => {
|
|
151
223
|
const storage = await load();
|
|
152
224
|
if (!storage.apiKey) {
|
|
153
225
|
console.log(
|
|
154
|
-
`Please run ${c__default.bold("`noto config`")} to set your API key.`
|
|
226
|
+
`Please run ${c__default.cyan(c__default.bold("`noto config`"))} to set your API key.`
|
|
155
227
|
);
|
|
156
228
|
process.exit(1);
|
|
157
229
|
}
|
|
158
230
|
const cwd = process.cwd();
|
|
159
231
|
if (!isGitRepository(cwd)) {
|
|
160
|
-
console.log(
|
|
232
|
+
console.log(
|
|
233
|
+
c__default.red("Oops! No Git repository found in the current directory.")
|
|
234
|
+
);
|
|
235
|
+
console.log(
|
|
236
|
+
`You can initialize one by running ${c__default.cyan(c__default.bold("`git init`"))}`
|
|
237
|
+
);
|
|
161
238
|
process.exit(1);
|
|
162
239
|
}
|
|
163
240
|
const diff = await getStagedDiff();
|
|
164
241
|
if (!diff) {
|
|
165
|
-
console.log(c__default.red("
|
|
242
|
+
console.log(c__default.red("Oops! No staged changes found to commit."));
|
|
243
|
+
console.log(
|
|
244
|
+
`Stage changes with ${c__default.cyan(c__default.bold("`git add <file>`"))} or ${c__default.cyan(
|
|
245
|
+
c__default.bold("`git add .`")
|
|
246
|
+
)} for stage all files.`
|
|
247
|
+
);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
const spin = spinner();
|
|
251
|
+
try {
|
|
252
|
+
spin.start("Generating commit message...");
|
|
253
|
+
const message = await generateCommitMessage(diff);
|
|
254
|
+
const copy = args.copy;
|
|
255
|
+
const apply = args.apply;
|
|
256
|
+
spin.success(`Commit Message: ${c__default.dim(c__default.bold(message))}`);
|
|
257
|
+
if (copy) {
|
|
258
|
+
clipboardy__default.writeSync(message);
|
|
259
|
+
spin.success("Message copied to clipboard!");
|
|
260
|
+
}
|
|
261
|
+
if (apply) {
|
|
262
|
+
spin.start("Committing staged changes...");
|
|
263
|
+
if (!await commit(message)) {
|
|
264
|
+
spin.fail("Failed to commit staged changes.");
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
spin.success("Staged changes committed successfully!");
|
|
268
|
+
}
|
|
269
|
+
} catch (error) {
|
|
270
|
+
spin.fail("Failed to generate commit message.");
|
|
166
271
|
process.exit(1);
|
|
167
272
|
}
|
|
168
|
-
const message = await generateCommitMessage(diff);
|
|
169
|
-
console.log(c__default.white(message));
|
|
170
273
|
}
|
|
171
|
-
).alias("-v", "--version").alias("-h", "--help").argv;
|
|
274
|
+
).version().alias("-v", "--version").alias("-h", "--help").argv;
|
package/dist/cli.mjs
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import yargs from 'yargs';
|
|
2
2
|
import prompts from '@posva/prompts';
|
|
3
3
|
import c from 'picocolors';
|
|
4
|
+
import clipboardy from 'clipboardy';
|
|
4
5
|
import { hideBin } from 'yargs/helpers';
|
|
5
6
|
import { join, dirname, resolve } from 'node:path';
|
|
6
7
|
import { promises, existsSync } from 'node:fs';
|
|
7
8
|
import os from 'node:os';
|
|
8
9
|
import process$1 from 'node:process';
|
|
9
10
|
import 'which';
|
|
11
|
+
import ora from 'ora';
|
|
10
12
|
import { x } from 'tinyexec';
|
|
11
13
|
import { generateText } from 'ai';
|
|
12
14
|
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
13
15
|
|
|
14
|
-
const
|
|
16
|
+
const TEMP_DIR = join(os.tmpdir(), "snelusha-noto");
|
|
15
17
|
let counter = 0;
|
|
16
18
|
async function openTemp() {
|
|
17
|
-
if (!existsSync(
|
|
18
|
-
await promises.mkdir(
|
|
19
|
-
const competitivePath = join(
|
|
19
|
+
if (!existsSync(TEMP_DIR))
|
|
20
|
+
await promises.mkdir(TEMP_DIR, { recursive: true });
|
|
21
|
+
const competitivePath = join(TEMP_DIR, `.${process$1.pid}.${counter}`);
|
|
20
22
|
counter += 1;
|
|
21
23
|
return promises.open(competitivePath, "wx").then((fd) => ({
|
|
22
24
|
fd,
|
|
@@ -52,22 +54,56 @@ async function writeFileSafe(path, data = "") {
|
|
|
52
54
|
}
|
|
53
55
|
return false;
|
|
54
56
|
}
|
|
57
|
+
function spinner() {
|
|
58
|
+
let s;
|
|
59
|
+
return {
|
|
60
|
+
start(text) {
|
|
61
|
+
s = ora(text);
|
|
62
|
+
s.spinner = {
|
|
63
|
+
interval: 150,
|
|
64
|
+
frames: ["\u2736", "\u2738", "\u2739", "\u273A", "\u2739", "\u2737"]
|
|
65
|
+
};
|
|
66
|
+
s.start();
|
|
67
|
+
},
|
|
68
|
+
fail(text) {
|
|
69
|
+
if (s)
|
|
70
|
+
s.fail(text);
|
|
71
|
+
},
|
|
72
|
+
success(text) {
|
|
73
|
+
if (s)
|
|
74
|
+
s.succeed(text);
|
|
75
|
+
},
|
|
76
|
+
stop() {
|
|
77
|
+
if (s)
|
|
78
|
+
s.stop();
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
55
82
|
|
|
56
|
-
let storage;
|
|
57
|
-
const storagePath = resolve(
|
|
83
|
+
let storage = {};
|
|
84
|
+
const storagePath = resolve(TEMP_DIR, "storage.json");
|
|
58
85
|
async function load(fn) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (await fn(storage))
|
|
86
|
+
try {
|
|
87
|
+
if (!Object.keys(storage).length) {
|
|
88
|
+
storage = existsSync(storagePath) ? JSON.parse(await promises.readFile(storagePath, "utf-8") || "{}") || {} : {};
|
|
89
|
+
}
|
|
90
|
+
if (fn && await fn(storage)) {
|
|
64
91
|
await dump();
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error("error loading storage:", error);
|
|
95
|
+
storage = {};
|
|
65
96
|
}
|
|
66
97
|
return storage;
|
|
67
98
|
}
|
|
68
99
|
async function dump() {
|
|
69
|
-
|
|
70
|
-
|
|
100
|
+
try {
|
|
101
|
+
if (storage) {
|
|
102
|
+
await writeFileSafe(storagePath, JSON.stringify(storage, null, 2));
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error("error saving storage:", error);
|
|
106
|
+
}
|
|
71
107
|
}
|
|
72
108
|
|
|
73
109
|
function isGitRepository(path) {
|
|
@@ -75,12 +111,20 @@ function isGitRepository(path) {
|
|
|
75
111
|
}
|
|
76
112
|
async function getStagedDiff() {
|
|
77
113
|
try {
|
|
78
|
-
const
|
|
79
|
-
return
|
|
114
|
+
const diff = (await x("git", ["diff", "--cached"])).stdout.toString();
|
|
115
|
+
return diff;
|
|
80
116
|
} catch {
|
|
81
117
|
return null;
|
|
82
118
|
}
|
|
83
119
|
}
|
|
120
|
+
async function commit(message) {
|
|
121
|
+
try {
|
|
122
|
+
const result = await x("git", ["commit", "-m", message]);
|
|
123
|
+
return result.stdout.includes("files changed");
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
84
128
|
|
|
85
129
|
async function generateCommitMessage(diff) {
|
|
86
130
|
const storage = await load();
|
|
@@ -106,56 +150,113 @@ ${diff}`
|
|
|
106
150
|
|
|
107
151
|
yargs(hideBin(process.argv)).scriptName("noto").usage("$0 [args]").command(
|
|
108
152
|
"config",
|
|
109
|
-
"
|
|
153
|
+
"setup you API key to enable noto.",
|
|
110
154
|
() => {
|
|
111
155
|
},
|
|
112
156
|
async () => {
|
|
113
157
|
const storage = await load();
|
|
114
158
|
if (storage.apiKey) {
|
|
115
|
-
const response2 = await prompts(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
159
|
+
const response2 = await prompts(
|
|
160
|
+
{
|
|
161
|
+
type: "confirm",
|
|
162
|
+
name: "reset",
|
|
163
|
+
message: "Do you want to reset your API key?"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
onCancel: () => process.exit(0)
|
|
167
|
+
}
|
|
168
|
+
);
|
|
120
169
|
if (!response2.reset) {
|
|
121
|
-
console.log(
|
|
170
|
+
console.log(
|
|
171
|
+
`Use ${c.greenBright(
|
|
172
|
+
c.bold("`noto`")
|
|
173
|
+
)} to generate your commit message!`
|
|
174
|
+
);
|
|
122
175
|
return process.exit(0);
|
|
123
176
|
}
|
|
124
177
|
}
|
|
125
178
|
const response = await prompts({
|
|
126
|
-
type: "
|
|
179
|
+
type: "password",
|
|
127
180
|
name: "apiKey",
|
|
128
|
-
message: "
|
|
129
|
-
validate: (value) => value ? true : "API key is required"
|
|
181
|
+
message: "Please enter your API key:",
|
|
182
|
+
validate: (value) => value ? true : "API key is required!"
|
|
130
183
|
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
184
|
+
if (response.apiKey) {
|
|
185
|
+
storage.apiKey = response.apiKey;
|
|
186
|
+
dump();
|
|
187
|
+
console.log("API key saved successfully!");
|
|
188
|
+
console.log(
|
|
189
|
+
`Use ${c.greenBright(
|
|
190
|
+
c.bold("`noto`")
|
|
191
|
+
)} to generate your commit message!`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
134
194
|
}
|
|
135
195
|
).command(
|
|
136
196
|
"*",
|
|
137
197
|
"generate commit message",
|
|
138
|
-
() => {
|
|
198
|
+
(args) => {
|
|
199
|
+
args.option("copy", {
|
|
200
|
+
alias: "c",
|
|
201
|
+
type: "boolean",
|
|
202
|
+
description: "Copy the generated commit message to the clipboard."
|
|
203
|
+
});
|
|
204
|
+
args.option("apply", {
|
|
205
|
+
alias: "a",
|
|
206
|
+
type: "boolean",
|
|
207
|
+
description: "Commit the staged changes with the generated message."
|
|
208
|
+
});
|
|
139
209
|
},
|
|
140
|
-
async () => {
|
|
210
|
+
async (args) => {
|
|
141
211
|
const storage = await load();
|
|
142
212
|
if (!storage.apiKey) {
|
|
143
213
|
console.log(
|
|
144
|
-
`Please run ${c.bold("`noto config`")} to set your API key.`
|
|
214
|
+
`Please run ${c.cyan(c.bold("`noto config`"))} to set your API key.`
|
|
145
215
|
);
|
|
146
216
|
process.exit(1);
|
|
147
217
|
}
|
|
148
218
|
const cwd = process.cwd();
|
|
149
219
|
if (!isGitRepository(cwd)) {
|
|
150
|
-
console.log(
|
|
220
|
+
console.log(
|
|
221
|
+
c.red("Oops! No Git repository found in the current directory.")
|
|
222
|
+
);
|
|
223
|
+
console.log(
|
|
224
|
+
`You can initialize one by running ${c.cyan(c.bold("`git init`"))}`
|
|
225
|
+
);
|
|
151
226
|
process.exit(1);
|
|
152
227
|
}
|
|
153
228
|
const diff = await getStagedDiff();
|
|
154
229
|
if (!diff) {
|
|
155
|
-
console.log(c.red("
|
|
230
|
+
console.log(c.red("Oops! No staged changes found to commit."));
|
|
231
|
+
console.log(
|
|
232
|
+
`Stage changes with ${c.cyan(c.bold("`git add <file>`"))} or ${c.cyan(
|
|
233
|
+
c.bold("`git add .`")
|
|
234
|
+
)} for stage all files.`
|
|
235
|
+
);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
const spin = spinner();
|
|
239
|
+
try {
|
|
240
|
+
spin.start("Generating commit message...");
|
|
241
|
+
const message = await generateCommitMessage(diff);
|
|
242
|
+
const copy = args.copy;
|
|
243
|
+
const apply = args.apply;
|
|
244
|
+
spin.success(`Commit Message: ${c.dim(c.bold(message))}`);
|
|
245
|
+
if (copy) {
|
|
246
|
+
clipboardy.writeSync(message);
|
|
247
|
+
spin.success("Message copied to clipboard!");
|
|
248
|
+
}
|
|
249
|
+
if (apply) {
|
|
250
|
+
spin.start("Committing staged changes...");
|
|
251
|
+
if (!await commit(message)) {
|
|
252
|
+
spin.fail("Failed to commit staged changes.");
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
spin.success("Staged changes committed successfully!");
|
|
256
|
+
}
|
|
257
|
+
} catch (error) {
|
|
258
|
+
spin.fail("Failed to generate commit message.");
|
|
156
259
|
process.exit(1);
|
|
157
260
|
}
|
|
158
|
-
const message = await generateCommitMessage(diff);
|
|
159
|
-
console.log(c.white(message));
|
|
160
261
|
}
|
|
161
|
-
).alias("-v", "--version").alias("-h", "--help").argv;
|
|
262
|
+
).version().alias("-v", "--version").alias("-h", "--help").argv;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snelusha/noto",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"description": "generate clean commit messages in a snap! ✨",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
],
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "unbuild",
|
|
31
|
-
"start": "esno cli.ts"
|
|
31
|
+
"start": "esno cli.ts",
|
|
32
|
+
"publish": "npm publish --public"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"@types/bun": "latest",
|
|
@@ -43,6 +44,8 @@
|
|
|
43
44
|
"@ai-sdk/google": "^0.0.51",
|
|
44
45
|
"@posva/prompts": "^2.4.4",
|
|
45
46
|
"ai": "^3.4.9",
|
|
47
|
+
"clipboardy": "^4.0.0",
|
|
48
|
+
"ora": "^8.1.0",
|
|
46
49
|
"picocolors": "^1.1.0",
|
|
47
50
|
"tinyexec": "^0.3.0",
|
|
48
51
|
"unbuild": "^2.0.0",
|