@snelusha/noto 1.0.0-beta.2 → 1.0.0-beta.4
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/index.js +222 -66
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import * as
|
|
3
|
-
import
|
|
2
|
+
import * as p6 from "@clack/prompts";
|
|
3
|
+
import color6 from "picocolors";
|
|
4
4
|
|
|
5
5
|
// src/utils/parser.ts
|
|
6
6
|
import arg from "arg";
|
|
@@ -15,6 +15,7 @@ var parse = (schema, raw) => {
|
|
|
15
15
|
// src/commands/noto.ts
|
|
16
16
|
import * as p3 from "@clack/prompts";
|
|
17
17
|
import color3 from "picocolors";
|
|
18
|
+
import clipboard from "clipboardy";
|
|
18
19
|
|
|
19
20
|
// src/middleware/auth.ts
|
|
20
21
|
import * as p from "@clack/prompts";
|
|
@@ -46,7 +47,8 @@ var StorageSchema = z2.object({
|
|
|
46
47
|
llm: z2.object({
|
|
47
48
|
apiKey: z2.string().optional(),
|
|
48
49
|
model: AvailableModelsSchema.optional()
|
|
49
|
-
}).optional()
|
|
50
|
+
}).optional(),
|
|
51
|
+
lastGeneratedMessage: z2.string().optional()
|
|
50
52
|
});
|
|
51
53
|
var StorageManager = class {
|
|
52
54
|
static storagePath = resolve(
|
|
@@ -93,19 +95,25 @@ var StorageManager = class {
|
|
|
93
95
|
}
|
|
94
96
|
};
|
|
95
97
|
|
|
98
|
+
// src/utils/process.ts
|
|
99
|
+
var exit = async (code) => {
|
|
100
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1));
|
|
101
|
+
console.log();
|
|
102
|
+
process.exit(code);
|
|
103
|
+
};
|
|
104
|
+
|
|
96
105
|
// src/middleware/auth.ts
|
|
97
|
-
var withAuth = (fn) => {
|
|
98
|
-
return async (
|
|
106
|
+
var withAuth = (fn, options = {}) => {
|
|
107
|
+
return async (opts) => {
|
|
99
108
|
const storage = await StorageManager.get();
|
|
100
|
-
if (!storage.llm?.apiKey) {
|
|
109
|
+
if (!storage.llm?.apiKey && !options.silent) {
|
|
101
110
|
p.log.error(
|
|
102
111
|
dedent`${color.red("noto api key is missing.")}
|
|
103
112
|
${color.dim(`run ${color.cyan("`noto config key`")} to set it up.`)}`
|
|
104
113
|
);
|
|
105
|
-
|
|
106
|
-
process.exit(1);
|
|
114
|
+
return await exit(1);
|
|
107
115
|
}
|
|
108
|
-
return fn(
|
|
116
|
+
return fn(opts);
|
|
109
117
|
};
|
|
110
118
|
};
|
|
111
119
|
|
|
@@ -127,33 +135,50 @@ var getStagedDiff = async () => {
|
|
|
127
135
|
return null;
|
|
128
136
|
}
|
|
129
137
|
};
|
|
138
|
+
var commit = async (message) => {
|
|
139
|
+
try {
|
|
140
|
+
const {
|
|
141
|
+
summary: { changes }
|
|
142
|
+
} = await git.commit(message);
|
|
143
|
+
return Boolean(changes);
|
|
144
|
+
} catch {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
130
148
|
|
|
131
149
|
// src/middleware/git.ts
|
|
132
|
-
var withRepository = (fn) => {
|
|
133
|
-
return async (
|
|
150
|
+
var withRepository = (fn, options = {}) => {
|
|
151
|
+
return async (opts) => {
|
|
134
152
|
const isRepo = await isGitRepository();
|
|
135
|
-
if (!isRepo) {
|
|
153
|
+
if (!isRepo && !options.silent) {
|
|
136
154
|
p2.log.error(
|
|
137
155
|
dedent2`${color2.red("no git repository found in cwd.")}
|
|
138
156
|
${color2.dim(`run ${color2.cyan("`git init`")} to initialize a new repository.`)}`
|
|
139
157
|
);
|
|
140
|
-
|
|
141
|
-
process.exit(1);
|
|
158
|
+
return await exit(1);
|
|
142
159
|
}
|
|
160
|
+
opts.isRepo = isRepo;
|
|
143
161
|
const diff = await getStagedDiff();
|
|
144
|
-
if (!diff) {
|
|
162
|
+
if (!diff && !options.silent) {
|
|
145
163
|
p2.log.error(
|
|
146
164
|
dedent2`${color2.red("no staged changes found.")}
|
|
147
165
|
${color2.dim(`run ${color2.cyan("`git add <file>`")} or ${color2.cyan("`git add .`")} to stage changes.`)}`
|
|
148
166
|
);
|
|
149
|
-
|
|
150
|
-
process.exit(1);
|
|
167
|
+
return await exit(1);
|
|
151
168
|
}
|
|
152
|
-
|
|
153
|
-
return fn(
|
|
169
|
+
opts.diff = diff;
|
|
170
|
+
return fn(opts);
|
|
154
171
|
};
|
|
155
172
|
};
|
|
156
173
|
|
|
174
|
+
// src/ai/index.ts
|
|
175
|
+
import { generateObject } from "ai";
|
|
176
|
+
import z3 from "zod";
|
|
177
|
+
import dedent3 from "dedent";
|
|
178
|
+
|
|
179
|
+
// src/ai/models.ts
|
|
180
|
+
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
181
|
+
|
|
157
182
|
// src/errors.ts
|
|
158
183
|
var NotoError = class _NotoError extends Error {
|
|
159
184
|
code;
|
|
@@ -164,13 +189,7 @@ var NotoError = class _NotoError extends Error {
|
|
|
164
189
|
}
|
|
165
190
|
};
|
|
166
191
|
|
|
167
|
-
// src/ai/index.ts
|
|
168
|
-
import { generateObject } from "ai";
|
|
169
|
-
import z3 from "zod";
|
|
170
|
-
import dedent3 from "dedent";
|
|
171
|
-
|
|
172
192
|
// src/ai/models.ts
|
|
173
|
-
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
174
193
|
var google = createGoogleGenerativeAI({
|
|
175
194
|
apiKey: (await StorageManager.get()).llm?.apiKey ?? "api-key"
|
|
176
195
|
});
|
|
@@ -240,53 +259,193 @@ var command = {
|
|
|
240
259
|
name: "noto",
|
|
241
260
|
description: "generate commit message",
|
|
242
261
|
usage: "noto [options]",
|
|
243
|
-
options: [
|
|
262
|
+
options: [
|
|
263
|
+
{
|
|
264
|
+
type: Boolean,
|
|
265
|
+
flag: "--copy",
|
|
266
|
+
alias: "-c",
|
|
267
|
+
description: "copy the generated commit message to clipboard"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
type: Boolean,
|
|
271
|
+
flag: "--apply",
|
|
272
|
+
alias: "-a",
|
|
273
|
+
description: "commit the generated message directly"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
type: Boolean,
|
|
277
|
+
flag: "--edit",
|
|
278
|
+
alias: "-e",
|
|
279
|
+
description: "edit the generated commit message"
|
|
280
|
+
}
|
|
281
|
+
],
|
|
244
282
|
execute: withAuth(
|
|
245
283
|
withRepository(async (options) => {
|
|
246
284
|
const spin = p3.spinner();
|
|
247
285
|
try {
|
|
248
286
|
const { diff } = options;
|
|
287
|
+
const isEditMode = options["--edit"];
|
|
249
288
|
spin.start("generating commit message");
|
|
250
|
-
|
|
251
|
-
spin.stop(color3.green(message));
|
|
289
|
+
let message = await generateCommitMessage(diff);
|
|
290
|
+
spin.stop(isEditMode ? color3.white(message) : color3.green(message));
|
|
291
|
+
if (isEditMode) {
|
|
292
|
+
const editedMessage = await p3.text({
|
|
293
|
+
message: "edit the generated commit message",
|
|
294
|
+
initialValue: message,
|
|
295
|
+
placeholder: message
|
|
296
|
+
});
|
|
297
|
+
if (p3.isCancel(editedMessage)) {
|
|
298
|
+
p3.log.error(color3.red("nothing changed!"));
|
|
299
|
+
return await exit(1);
|
|
300
|
+
}
|
|
301
|
+
message = editedMessage;
|
|
302
|
+
p3.log.step(color3.green(message));
|
|
303
|
+
}
|
|
304
|
+
await StorageManager.update((current) => ({
|
|
305
|
+
...current,
|
|
306
|
+
lastGeneratedMessage: message
|
|
307
|
+
}));
|
|
308
|
+
if (options["--copy"]) {
|
|
309
|
+
clipboard.writeSync(message);
|
|
310
|
+
p3.log.step(color3.dim("copied commit message to clipboard"));
|
|
311
|
+
}
|
|
312
|
+
if (options["--apply"]) {
|
|
313
|
+
const success = await commit(message);
|
|
314
|
+
if (success) {
|
|
315
|
+
p3.log.step(color3.dim("commit successful"));
|
|
316
|
+
} else {
|
|
317
|
+
p3.log.error(color3.red("failed to commit changes"));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
process.stdout.write("\n");
|
|
252
321
|
} catch {
|
|
253
322
|
spin.stop(color3.red("failed to generate commit message"), 1);
|
|
254
|
-
|
|
255
|
-
process.exit(1);
|
|
323
|
+
return await exit(1);
|
|
256
324
|
}
|
|
257
|
-
console.log();
|
|
258
325
|
})
|
|
259
326
|
)
|
|
260
327
|
};
|
|
261
328
|
var noto_default = command;
|
|
262
329
|
|
|
263
|
-
// src/commands/
|
|
330
|
+
// src/commands/prev.ts
|
|
264
331
|
import * as p4 from "@clack/prompts";
|
|
265
332
|
import color4 from "picocolors";
|
|
333
|
+
import dedent4 from "dedent";
|
|
334
|
+
import clipboard2 from "clipboardy";
|
|
335
|
+
var command2 = {
|
|
336
|
+
name: "prev",
|
|
337
|
+
description: "access the last generated commit message",
|
|
338
|
+
usage: "noto prev [options]",
|
|
339
|
+
options: [
|
|
340
|
+
{
|
|
341
|
+
type: Boolean,
|
|
342
|
+
flag: "--copy",
|
|
343
|
+
alias: "-c",
|
|
344
|
+
description: "copy the last generated commit message to clipboard"
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
type: Boolean,
|
|
348
|
+
flag: "--apply",
|
|
349
|
+
alias: "-a",
|
|
350
|
+
description: "commit the last generated message directly"
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
type: Boolean,
|
|
354
|
+
flag: "--edit",
|
|
355
|
+
alias: "-e",
|
|
356
|
+
description: "edit the last generated commit message"
|
|
357
|
+
}
|
|
358
|
+
],
|
|
359
|
+
execute: withAuth(
|
|
360
|
+
withRepository(
|
|
361
|
+
async (options) => {
|
|
362
|
+
let lastGeneratedMessage = (await StorageManager.get()).lastGeneratedMessage;
|
|
363
|
+
if (!lastGeneratedMessage) {
|
|
364
|
+
p4.log.error(color4.red("no previous commit message found"));
|
|
365
|
+
return await exit(1);
|
|
366
|
+
}
|
|
367
|
+
const isEditMode = options["--edit"];
|
|
368
|
+
p4.log.step(
|
|
369
|
+
isEditMode ? color4.white(lastGeneratedMessage) : color4.green(lastGeneratedMessage)
|
|
370
|
+
);
|
|
371
|
+
if (options["--edit"]) {
|
|
372
|
+
const editedMessage = await p4.text({
|
|
373
|
+
message: "edit the last generated commit message",
|
|
374
|
+
initialValue: lastGeneratedMessage,
|
|
375
|
+
placeholder: lastGeneratedMessage
|
|
376
|
+
});
|
|
377
|
+
if (p4.isCancel(editedMessage)) {
|
|
378
|
+
p4.log.error(color4.red("nothing changed!"));
|
|
379
|
+
return await exit(1);
|
|
380
|
+
}
|
|
381
|
+
lastGeneratedMessage = editedMessage;
|
|
382
|
+
await StorageManager.update((current) => ({
|
|
383
|
+
...current,
|
|
384
|
+
lastGeneratedMessage: editedMessage
|
|
385
|
+
}));
|
|
386
|
+
p4.log.step(color4.green(lastGeneratedMessage));
|
|
387
|
+
}
|
|
388
|
+
if (options["--copy"]) {
|
|
389
|
+
clipboard2.writeSync(lastGeneratedMessage);
|
|
390
|
+
p4.log.step(
|
|
391
|
+
color4.dim("copied last generated commit message to clipboard")
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
if (options["--apply"]) {
|
|
395
|
+
if (!options.isRepo) {
|
|
396
|
+
p4.log.error(
|
|
397
|
+
dedent4`${color4.red("no git repository found in cwd.")}
|
|
398
|
+
${color4.dim(`run ${color4.cyan("`git init`")} to initialize a new repository.`)}`
|
|
399
|
+
);
|
|
400
|
+
return await exit(1);
|
|
401
|
+
}
|
|
402
|
+
if (!options.diff) {
|
|
403
|
+
p4.log.error(
|
|
404
|
+
dedent4`${color4.red("no staged changes found.")}
|
|
405
|
+
${color4.dim(`run ${color4.cyan("`git add <file>`")} or ${color4.cyan("`git add .`")} to stage changes.`)}`
|
|
406
|
+
);
|
|
407
|
+
return await exit(1);
|
|
408
|
+
}
|
|
409
|
+
const success = await commit(lastGeneratedMessage);
|
|
410
|
+
if (success) {
|
|
411
|
+
p4.log.step(color4.dim("commit successful"));
|
|
412
|
+
} else {
|
|
413
|
+
p4.log.error(color4.red("failed to commit changes"));
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
console.log();
|
|
417
|
+
},
|
|
418
|
+
{ silent: true }
|
|
419
|
+
)
|
|
420
|
+
)
|
|
421
|
+
};
|
|
422
|
+
var prev_default = command2;
|
|
423
|
+
|
|
424
|
+
// src/commands/config.ts
|
|
425
|
+
import * as p5 from "@clack/prompts";
|
|
426
|
+
import color5 from "picocolors";
|
|
266
427
|
var key = {
|
|
267
428
|
name: "key",
|
|
268
429
|
description: "configure api key",
|
|
269
430
|
usage: "noto config key [options]",
|
|
270
431
|
execute: async (options) => {
|
|
271
432
|
if ((await StorageManager.get()).llm?.apiKey) {
|
|
272
|
-
const confirm2 = await
|
|
433
|
+
const confirm2 = await p5.confirm({
|
|
273
434
|
message: "noto api key already configured, do you want to update it?"
|
|
274
435
|
});
|
|
275
|
-
if (
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
process.exit(1);
|
|
436
|
+
if (p5.isCancel(confirm2) || !confirm2) {
|
|
437
|
+
p5.log.error(color5.red("nothing changed!"));
|
|
438
|
+
return await exit(1);
|
|
279
439
|
}
|
|
280
440
|
}
|
|
281
441
|
let apiKey = options._[0];
|
|
282
442
|
if (!apiKey) {
|
|
283
|
-
const result = await
|
|
443
|
+
const result = await p5.text({
|
|
284
444
|
message: "enter your noto api key"
|
|
285
445
|
});
|
|
286
|
-
if (
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
process.exit(1);
|
|
446
|
+
if (p5.isCancel(result)) {
|
|
447
|
+
p5.log.error(color5.red("nothing changed!"));
|
|
448
|
+
return await exit(1);
|
|
290
449
|
}
|
|
291
450
|
apiKey = result;
|
|
292
451
|
}
|
|
@@ -297,7 +456,7 @@ var key = {
|
|
|
297
456
|
apiKey
|
|
298
457
|
}
|
|
299
458
|
}));
|
|
300
|
-
|
|
459
|
+
p5.log.success(color5.green("noto api key configured!"));
|
|
301
460
|
console.log();
|
|
302
461
|
}
|
|
303
462
|
};
|
|
@@ -306,7 +465,7 @@ var model = {
|
|
|
306
465
|
description: "configure model",
|
|
307
466
|
usage: "noto config model [options]",
|
|
308
467
|
execute: async (options) => {
|
|
309
|
-
const model2 = await
|
|
468
|
+
const model2 = await p5.select({
|
|
310
469
|
message: "select a model",
|
|
311
470
|
initialValue: (await StorageManager.get()).llm?.model,
|
|
312
471
|
options: Object.keys(models).map((model3) => ({
|
|
@@ -314,10 +473,9 @@ var model = {
|
|
|
314
473
|
value: model3
|
|
315
474
|
}))
|
|
316
475
|
});
|
|
317
|
-
if (
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
process.exit();
|
|
476
|
+
if (p5.isCancel(model2)) {
|
|
477
|
+
p5.log.error(color5.red("nothing changed!"));
|
|
478
|
+
return await exit(1);
|
|
321
479
|
}
|
|
322
480
|
await StorageManager.update((current) => ({
|
|
323
481
|
...current,
|
|
@@ -326,48 +484,46 @@ var model = {
|
|
|
326
484
|
model: model2
|
|
327
485
|
}
|
|
328
486
|
}));
|
|
329
|
-
|
|
487
|
+
p5.log.success(color5.green("model configured!"));
|
|
330
488
|
console.log();
|
|
331
489
|
}
|
|
332
490
|
};
|
|
333
491
|
var subCommands = [key, model];
|
|
334
|
-
var
|
|
492
|
+
var command3 = {
|
|
335
493
|
name: "config",
|
|
336
494
|
description: "configure noto",
|
|
337
495
|
usage: "noto config [subcommand]",
|
|
338
496
|
execute: async (options) => {
|
|
339
|
-
const
|
|
497
|
+
const command4 = await p5.select({
|
|
340
498
|
message: "Select a subcommand",
|
|
341
499
|
options: subCommands.map((cmd2) => ({
|
|
342
500
|
label: cmd2.description,
|
|
343
501
|
value: cmd2.name
|
|
344
502
|
}))
|
|
345
503
|
});
|
|
346
|
-
if (
|
|
347
|
-
|
|
348
|
-
process.exit(1);
|
|
504
|
+
if (p5.isCancel(command4)) {
|
|
505
|
+
return await exit(1);
|
|
349
506
|
}
|
|
350
|
-
const cmd = getCommand(
|
|
507
|
+
const cmd = getCommand(command4, subCommands);
|
|
351
508
|
if (!cmd) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
process.exit(1);
|
|
509
|
+
p5.log.error(color5.red("unknown config command"));
|
|
510
|
+
return await exit(1);
|
|
355
511
|
}
|
|
356
512
|
options._ = options._.slice(1);
|
|
357
513
|
cmd.execute(options);
|
|
358
514
|
},
|
|
359
515
|
subCommands
|
|
360
516
|
};
|
|
361
|
-
var config_default =
|
|
517
|
+
var config_default = command3;
|
|
362
518
|
|
|
363
519
|
// src/commands/index.ts
|
|
364
|
-
var commands = [noto_default, config_default];
|
|
520
|
+
var commands = [noto_default, prev_default, config_default];
|
|
365
521
|
var getCommand = (name, cmds = commands) => {
|
|
366
522
|
return cmds.find((cmd) => cmd.name === name);
|
|
367
523
|
};
|
|
368
524
|
|
|
369
525
|
// package.json
|
|
370
|
-
var version = "1.0.0-beta.
|
|
526
|
+
var version = "1.0.0-beta.4";
|
|
371
527
|
|
|
372
528
|
// src/index.ts
|
|
373
529
|
var globalSpec = {
|
|
@@ -378,13 +534,13 @@ var globalSpec = {
|
|
|
378
534
|
};
|
|
379
535
|
function main() {
|
|
380
536
|
const args = process.argv.slice(2);
|
|
381
|
-
const { command:
|
|
537
|
+
const { command: command4, options: globalOptions } = parse(globalSpec, args);
|
|
382
538
|
console.log();
|
|
383
|
-
|
|
384
|
-
if (globalOptions["--version"]) return
|
|
385
|
-
const cmd = getCommand(
|
|
539
|
+
p6.intro(`${color6.bgCyan(color6.black(" @snelusha/noto "))}`);
|
|
540
|
+
if (globalOptions["--version"]) return p6.outro(version);
|
|
541
|
+
const cmd = getCommand(command4) ?? getCommand("noto");
|
|
386
542
|
if (!cmd) return getCommand("noto")?.execute(globalOptions);
|
|
387
|
-
let commandArgs =
|
|
543
|
+
let commandArgs = args;
|
|
388
544
|
let selectedCommand = cmd;
|
|
389
545
|
if (cmd.subCommands && commandArgs.length) {
|
|
390
546
|
const possibleCommand = commandArgs[0];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snelusha/noto",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.4",
|
|
4
4
|
"description": "Generate clean commit messages in a snap! ✨",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"@clack/prompts": "^0.10.0",
|
|
44
44
|
"ai": "^4.1.40",
|
|
45
45
|
"arg": "^5.0.2",
|
|
46
|
+
"clipboardy": "^4.0.0",
|
|
46
47
|
"dedent": "^1.5.3",
|
|
47
48
|
"picocolors": "^1.1.1",
|
|
48
49
|
"simple-git": "^3.27.0",
|