@snelusha/noto 1.0.0-beta.3 → 1.0.0-beta.5
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 +229 -61
- package/package.json +1 -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";
|
|
@@ -47,7 +47,8 @@ var StorageSchema = z2.object({
|
|
|
47
47
|
llm: z2.object({
|
|
48
48
|
apiKey: z2.string().optional(),
|
|
49
49
|
model: AvailableModelsSchema.optional()
|
|
50
|
-
}).optional()
|
|
50
|
+
}).optional(),
|
|
51
|
+
lastGeneratedMessage: z2.string().optional()
|
|
51
52
|
});
|
|
52
53
|
var StorageManager = class {
|
|
53
54
|
static storagePath = resolve(
|
|
@@ -94,19 +95,25 @@ var StorageManager = class {
|
|
|
94
95
|
}
|
|
95
96
|
};
|
|
96
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
|
+
|
|
97
105
|
// src/middleware/auth.ts
|
|
98
|
-
var withAuth = (fn) => {
|
|
99
|
-
return async (
|
|
106
|
+
var withAuth = (fn, options = {}) => {
|
|
107
|
+
return async (opts) => {
|
|
100
108
|
const storage = await StorageManager.get();
|
|
101
|
-
if (!storage.llm?.apiKey) {
|
|
109
|
+
if (!storage.llm?.apiKey && !options.silent) {
|
|
102
110
|
p.log.error(
|
|
103
111
|
dedent`${color.red("noto api key is missing.")}
|
|
104
112
|
${color.dim(`run ${color.cyan("`noto config key`")} to set it up.`)}`
|
|
105
113
|
);
|
|
106
|
-
|
|
107
|
-
process.exit(1);
|
|
114
|
+
return await exit(1);
|
|
108
115
|
}
|
|
109
|
-
return fn(
|
|
116
|
+
return fn(opts);
|
|
110
117
|
};
|
|
111
118
|
};
|
|
112
119
|
|
|
@@ -140,28 +147,27 @@ var commit = async (message) => {
|
|
|
140
147
|
};
|
|
141
148
|
|
|
142
149
|
// src/middleware/git.ts
|
|
143
|
-
var withRepository = (fn) => {
|
|
144
|
-
return async (
|
|
150
|
+
var withRepository = (fn, options = {}) => {
|
|
151
|
+
return async (opts) => {
|
|
145
152
|
const isRepo = await isGitRepository();
|
|
146
|
-
if (!isRepo) {
|
|
153
|
+
if (!isRepo && !options.silent) {
|
|
147
154
|
p2.log.error(
|
|
148
155
|
dedent2`${color2.red("no git repository found in cwd.")}
|
|
149
156
|
${color2.dim(`run ${color2.cyan("`git init`")} to initialize a new repository.`)}`
|
|
150
157
|
);
|
|
151
|
-
|
|
152
|
-
process.exit(1);
|
|
158
|
+
return await exit(1);
|
|
153
159
|
}
|
|
160
|
+
opts.isRepo = isRepo;
|
|
154
161
|
const diff = await getStagedDiff();
|
|
155
|
-
if (!diff) {
|
|
162
|
+
if (!diff && !options.silent) {
|
|
156
163
|
p2.log.error(
|
|
157
164
|
dedent2`${color2.red("no staged changes found.")}
|
|
158
165
|
${color2.dim(`run ${color2.cyan("`git add <file>`")} or ${color2.cyan("`git add .`")} to stage changes.`)}`
|
|
159
166
|
);
|
|
160
|
-
|
|
161
|
-
process.exit(1);
|
|
167
|
+
return await exit(1);
|
|
162
168
|
}
|
|
163
|
-
|
|
164
|
-
return fn(
|
|
169
|
+
opts.diff = diff;
|
|
170
|
+
return fn(opts);
|
|
165
171
|
};
|
|
166
172
|
};
|
|
167
173
|
|
|
@@ -214,7 +220,7 @@ var getModel = async () => {
|
|
|
214
220
|
};
|
|
215
221
|
|
|
216
222
|
// src/ai/index.ts
|
|
217
|
-
var generateCommitMessage = async (diff) => {
|
|
223
|
+
var generateCommitMessage = async (diff, type) => {
|
|
218
224
|
const model2 = await getModel();
|
|
219
225
|
const { object } = await generateObject({
|
|
220
226
|
model: model2,
|
|
@@ -236,7 +242,11 @@ var generateCommitMessage = async (diff) => {
|
|
|
236
242
|
6. Avoid mentioning file names unless a file was renamed or is critical for understanding the changes.
|
|
237
243
|
7. Prioritize clarity and focus on the most impactful changes for the commit.
|
|
238
244
|
|
|
239
|
-
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
|
|
245
|
+
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.
|
|
246
|
+
|
|
247
|
+
${type ? `if a type is provided (e.g., feat, fix), include it in the commit message in the format "type: message"
|
|
248
|
+
|
|
249
|
+
type: ${type}` : ""}`
|
|
240
250
|
},
|
|
241
251
|
{
|
|
242
252
|
role: "user",
|
|
@@ -254,6 +264,12 @@ var command = {
|
|
|
254
264
|
description: "generate commit message",
|
|
255
265
|
usage: "noto [options]",
|
|
256
266
|
options: [
|
|
267
|
+
{
|
|
268
|
+
type: Boolean,
|
|
269
|
+
flag: "--type",
|
|
270
|
+
alias: "-t",
|
|
271
|
+
description: "generate commit message based on type"
|
|
272
|
+
},
|
|
257
273
|
{
|
|
258
274
|
type: Boolean,
|
|
259
275
|
flag: "--copy",
|
|
@@ -265,6 +281,12 @@ var command = {
|
|
|
265
281
|
flag: "--apply",
|
|
266
282
|
alias: "-a",
|
|
267
283
|
description: "commit the generated message directly"
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
type: Boolean,
|
|
287
|
+
flag: "--edit",
|
|
288
|
+
alias: "-e",
|
|
289
|
+
description: "edit the generated commit message"
|
|
268
290
|
}
|
|
269
291
|
],
|
|
270
292
|
execute: withAuth(
|
|
@@ -272,9 +294,67 @@ var command = {
|
|
|
272
294
|
const spin = p3.spinner();
|
|
273
295
|
try {
|
|
274
296
|
const { diff } = options;
|
|
297
|
+
const isEditMode = options["--edit"];
|
|
298
|
+
if (options["--type"]) {
|
|
299
|
+
const type = await p3.select({
|
|
300
|
+
message: "select the type of commit message",
|
|
301
|
+
options: [
|
|
302
|
+
{
|
|
303
|
+
label: "chore",
|
|
304
|
+
value: "chore"
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
label: "feat",
|
|
308
|
+
value: "feat"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
label: "fix",
|
|
312
|
+
value: "fix"
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
label: "docs",
|
|
316
|
+
value: "docs"
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
label: "refactor",
|
|
320
|
+
value: "refactor"
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
label: "perf",
|
|
324
|
+
value: "perf"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
label: "test",
|
|
328
|
+
value: "test"
|
|
329
|
+
}
|
|
330
|
+
]
|
|
331
|
+
});
|
|
332
|
+
if (p3.isCancel(type)) {
|
|
333
|
+
p3.log.error(color3.red("nothing selected!"));
|
|
334
|
+
return await exit(1);
|
|
335
|
+
}
|
|
336
|
+
options.type = type;
|
|
337
|
+
}
|
|
275
338
|
spin.start("generating commit message");
|
|
276
|
-
|
|
277
|
-
spin.stop(color3.green(message));
|
|
339
|
+
let message = await generateCommitMessage(diff, options.type);
|
|
340
|
+
spin.stop(isEditMode ? color3.white(message) : color3.green(message));
|
|
341
|
+
if (isEditMode) {
|
|
342
|
+
const editedMessage = await p3.text({
|
|
343
|
+
message: "edit the generated commit message",
|
|
344
|
+
initialValue: message,
|
|
345
|
+
placeholder: message
|
|
346
|
+
});
|
|
347
|
+
if (p3.isCancel(editedMessage)) {
|
|
348
|
+
p3.log.error(color3.red("nothing changed!"));
|
|
349
|
+
return await exit(1);
|
|
350
|
+
}
|
|
351
|
+
message = editedMessage;
|
|
352
|
+
p3.log.step(color3.green(message));
|
|
353
|
+
}
|
|
354
|
+
await StorageManager.update((current) => ({
|
|
355
|
+
...current,
|
|
356
|
+
lastGeneratedMessage: message
|
|
357
|
+
}));
|
|
278
358
|
if (options["--copy"]) {
|
|
279
359
|
clipboard.writeSync(message);
|
|
280
360
|
p3.log.step(color3.dim("copied commit message to clipboard"));
|
|
@@ -287,44 +367,135 @@ var command = {
|
|
|
287
367
|
p3.log.error(color3.red("failed to commit changes"));
|
|
288
368
|
}
|
|
289
369
|
}
|
|
370
|
+
process.stdout.write("\n");
|
|
290
371
|
} catch {
|
|
291
372
|
spin.stop(color3.red("failed to generate commit message"), 1);
|
|
292
|
-
|
|
293
|
-
} finally {
|
|
294
|
-
process.stdout.write("\n");
|
|
373
|
+
return await exit(1);
|
|
295
374
|
}
|
|
296
375
|
})
|
|
297
376
|
)
|
|
298
377
|
};
|
|
299
378
|
var noto_default = command;
|
|
300
379
|
|
|
301
|
-
// src/commands/
|
|
380
|
+
// src/commands/prev.ts
|
|
302
381
|
import * as p4 from "@clack/prompts";
|
|
303
382
|
import color4 from "picocolors";
|
|
383
|
+
import dedent4 from "dedent";
|
|
384
|
+
import clipboard2 from "clipboardy";
|
|
385
|
+
var command2 = {
|
|
386
|
+
name: "prev",
|
|
387
|
+
description: "access the last generated commit message",
|
|
388
|
+
usage: "noto prev [options]",
|
|
389
|
+
options: [
|
|
390
|
+
{
|
|
391
|
+
type: Boolean,
|
|
392
|
+
flag: "--copy",
|
|
393
|
+
alias: "-c",
|
|
394
|
+
description: "copy the last generated commit message to clipboard"
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
type: Boolean,
|
|
398
|
+
flag: "--apply",
|
|
399
|
+
alias: "-a",
|
|
400
|
+
description: "commit the last generated message directly"
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
type: Boolean,
|
|
404
|
+
flag: "--edit",
|
|
405
|
+
alias: "-e",
|
|
406
|
+
description: "edit the last generated commit message"
|
|
407
|
+
}
|
|
408
|
+
],
|
|
409
|
+
execute: withAuth(
|
|
410
|
+
withRepository(
|
|
411
|
+
async (options) => {
|
|
412
|
+
let lastGeneratedMessage = (await StorageManager.get()).lastGeneratedMessage;
|
|
413
|
+
if (!lastGeneratedMessage) {
|
|
414
|
+
p4.log.error(color4.red("no previous commit message found"));
|
|
415
|
+
return await exit(1);
|
|
416
|
+
}
|
|
417
|
+
const isEditMode = options["--edit"];
|
|
418
|
+
p4.log.step(
|
|
419
|
+
isEditMode ? color4.white(lastGeneratedMessage) : color4.green(lastGeneratedMessage)
|
|
420
|
+
);
|
|
421
|
+
if (options["--edit"]) {
|
|
422
|
+
const editedMessage = await p4.text({
|
|
423
|
+
message: "edit the last generated commit message",
|
|
424
|
+
initialValue: lastGeneratedMessage,
|
|
425
|
+
placeholder: lastGeneratedMessage
|
|
426
|
+
});
|
|
427
|
+
if (p4.isCancel(editedMessage)) {
|
|
428
|
+
p4.log.error(color4.red("nothing changed!"));
|
|
429
|
+
return await exit(1);
|
|
430
|
+
}
|
|
431
|
+
lastGeneratedMessage = editedMessage;
|
|
432
|
+
await StorageManager.update((current) => ({
|
|
433
|
+
...current,
|
|
434
|
+
lastGeneratedMessage: editedMessage
|
|
435
|
+
}));
|
|
436
|
+
p4.log.step(color4.green(lastGeneratedMessage));
|
|
437
|
+
}
|
|
438
|
+
if (options["--copy"]) {
|
|
439
|
+
clipboard2.writeSync(lastGeneratedMessage);
|
|
440
|
+
p4.log.step(
|
|
441
|
+
color4.dim("copied last generated commit message to clipboard")
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
if (options["--apply"]) {
|
|
445
|
+
if (!options.isRepo) {
|
|
446
|
+
p4.log.error(
|
|
447
|
+
dedent4`${color4.red("no git repository found in cwd.")}
|
|
448
|
+
${color4.dim(`run ${color4.cyan("`git init`")} to initialize a new repository.`)}`
|
|
449
|
+
);
|
|
450
|
+
return await exit(1);
|
|
451
|
+
}
|
|
452
|
+
if (!options.diff) {
|
|
453
|
+
p4.log.error(
|
|
454
|
+
dedent4`${color4.red("no staged changes found.")}
|
|
455
|
+
${color4.dim(`run ${color4.cyan("`git add <file>`")} or ${color4.cyan("`git add .`")} to stage changes.`)}`
|
|
456
|
+
);
|
|
457
|
+
return await exit(1);
|
|
458
|
+
}
|
|
459
|
+
const success = await commit(lastGeneratedMessage);
|
|
460
|
+
if (success) {
|
|
461
|
+
p4.log.step(color4.dim("commit successful"));
|
|
462
|
+
} else {
|
|
463
|
+
p4.log.error(color4.red("failed to commit changes"));
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
console.log();
|
|
467
|
+
},
|
|
468
|
+
{ silent: true }
|
|
469
|
+
)
|
|
470
|
+
)
|
|
471
|
+
};
|
|
472
|
+
var prev_default = command2;
|
|
473
|
+
|
|
474
|
+
// src/commands/config.ts
|
|
475
|
+
import * as p5 from "@clack/prompts";
|
|
476
|
+
import color5 from "picocolors";
|
|
304
477
|
var key = {
|
|
305
478
|
name: "key",
|
|
306
479
|
description: "configure api key",
|
|
307
480
|
usage: "noto config key [options]",
|
|
308
481
|
execute: async (options) => {
|
|
309
482
|
if ((await StorageManager.get()).llm?.apiKey) {
|
|
310
|
-
const confirm2 = await
|
|
483
|
+
const confirm2 = await p5.confirm({
|
|
311
484
|
message: "noto api key already configured, do you want to update it?"
|
|
312
485
|
});
|
|
313
|
-
if (
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
process.exit(1);
|
|
486
|
+
if (p5.isCancel(confirm2) || !confirm2) {
|
|
487
|
+
p5.log.error(color5.red("nothing changed!"));
|
|
488
|
+
return await exit(1);
|
|
317
489
|
}
|
|
318
490
|
}
|
|
319
491
|
let apiKey = options._[0];
|
|
320
492
|
if (!apiKey) {
|
|
321
|
-
const result = await
|
|
493
|
+
const result = await p5.text({
|
|
322
494
|
message: "enter your noto api key"
|
|
323
495
|
});
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
process.exit(1);
|
|
496
|
+
if (p5.isCancel(result)) {
|
|
497
|
+
p5.log.error(color5.red("nothing changed!"));
|
|
498
|
+
return await exit(1);
|
|
328
499
|
}
|
|
329
500
|
apiKey = result;
|
|
330
501
|
}
|
|
@@ -335,7 +506,7 @@ var key = {
|
|
|
335
506
|
apiKey
|
|
336
507
|
}
|
|
337
508
|
}));
|
|
338
|
-
|
|
509
|
+
p5.log.success(color5.green("noto api key configured!"));
|
|
339
510
|
console.log();
|
|
340
511
|
}
|
|
341
512
|
};
|
|
@@ -344,7 +515,7 @@ var model = {
|
|
|
344
515
|
description: "configure model",
|
|
345
516
|
usage: "noto config model [options]",
|
|
346
517
|
execute: async (options) => {
|
|
347
|
-
const model2 = await
|
|
518
|
+
const model2 = await p5.select({
|
|
348
519
|
message: "select a model",
|
|
349
520
|
initialValue: (await StorageManager.get()).llm?.model,
|
|
350
521
|
options: Object.keys(models).map((model3) => ({
|
|
@@ -352,10 +523,9 @@ var model = {
|
|
|
352
523
|
value: model3
|
|
353
524
|
}))
|
|
354
525
|
});
|
|
355
|
-
if (
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
process.exit();
|
|
526
|
+
if (p5.isCancel(model2)) {
|
|
527
|
+
p5.log.error(color5.red("nothing changed!"));
|
|
528
|
+
return await exit(1);
|
|
359
529
|
}
|
|
360
530
|
await StorageManager.update((current) => ({
|
|
361
531
|
...current,
|
|
@@ -364,48 +534,46 @@ var model = {
|
|
|
364
534
|
model: model2
|
|
365
535
|
}
|
|
366
536
|
}));
|
|
367
|
-
|
|
537
|
+
p5.log.success(color5.green("model configured!"));
|
|
368
538
|
console.log();
|
|
369
539
|
}
|
|
370
540
|
};
|
|
371
541
|
var subCommands = [key, model];
|
|
372
|
-
var
|
|
542
|
+
var command3 = {
|
|
373
543
|
name: "config",
|
|
374
544
|
description: "configure noto",
|
|
375
545
|
usage: "noto config [subcommand]",
|
|
376
546
|
execute: async (options) => {
|
|
377
|
-
const
|
|
547
|
+
const command4 = await p5.select({
|
|
378
548
|
message: "Select a subcommand",
|
|
379
549
|
options: subCommands.map((cmd2) => ({
|
|
380
550
|
label: cmd2.description,
|
|
381
551
|
value: cmd2.name
|
|
382
552
|
}))
|
|
383
553
|
});
|
|
384
|
-
if (
|
|
385
|
-
|
|
386
|
-
process.exit(1);
|
|
554
|
+
if (p5.isCancel(command4)) {
|
|
555
|
+
return await exit(1);
|
|
387
556
|
}
|
|
388
|
-
const cmd = getCommand(
|
|
557
|
+
const cmd = getCommand(command4, subCommands);
|
|
389
558
|
if (!cmd) {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
process.exit(1);
|
|
559
|
+
p5.log.error(color5.red("unknown config command"));
|
|
560
|
+
return await exit(1);
|
|
393
561
|
}
|
|
394
562
|
options._ = options._.slice(1);
|
|
395
563
|
cmd.execute(options);
|
|
396
564
|
},
|
|
397
565
|
subCommands
|
|
398
566
|
};
|
|
399
|
-
var config_default =
|
|
567
|
+
var config_default = command3;
|
|
400
568
|
|
|
401
569
|
// src/commands/index.ts
|
|
402
|
-
var commands = [noto_default, config_default];
|
|
570
|
+
var commands = [noto_default, prev_default, config_default];
|
|
403
571
|
var getCommand = (name, cmds = commands) => {
|
|
404
572
|
return cmds.find((cmd) => cmd.name === name);
|
|
405
573
|
};
|
|
406
574
|
|
|
407
575
|
// package.json
|
|
408
|
-
var version = "1.0.0-beta.
|
|
576
|
+
var version = "1.0.0-beta.4";
|
|
409
577
|
|
|
410
578
|
// src/index.ts
|
|
411
579
|
var globalSpec = {
|
|
@@ -416,16 +584,16 @@ var globalSpec = {
|
|
|
416
584
|
};
|
|
417
585
|
function main() {
|
|
418
586
|
const args = process.argv.slice(2);
|
|
419
|
-
const { command:
|
|
587
|
+
const { command: command4, options: globalOptions } = parse(globalSpec, args);
|
|
420
588
|
console.log();
|
|
421
|
-
|
|
422
|
-
if (globalOptions["--version"]) return
|
|
423
|
-
const cmd = getCommand(
|
|
589
|
+
p6.intro(`${color6.bgCyan(color6.black(" @snelusha/noto "))}`);
|
|
590
|
+
if (globalOptions["--version"]) return p6.outro(version);
|
|
591
|
+
const cmd = getCommand(command4) ?? getCommand("noto");
|
|
424
592
|
if (!cmd) return getCommand("noto")?.execute(globalOptions);
|
|
425
593
|
let commandArgs = args;
|
|
426
594
|
let selectedCommand = cmd;
|
|
427
595
|
if (cmd.subCommands && commandArgs.length) {
|
|
428
|
-
const possibleCommand = commandArgs[
|
|
596
|
+
const possibleCommand = commandArgs[1];
|
|
429
597
|
const subCommand = cmd.subCommands.find(
|
|
430
598
|
(cmd2) => cmd2.name === possibleCommand || cmd2.aliases && cmd2.aliases.includes(possibleCommand)
|
|
431
599
|
);
|