@snelusha/noto 1.0.7 → 1.1.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.
Files changed (3) hide show
  1. package/README.md +15 -0
  2. package/dist/index.js +147 -49
  3. package/package.json +7 -7
package/README.md CHANGED
@@ -90,8 +90,23 @@ Retrieve the previously generated commit message:
90
90
  noto prev
91
91
  ```
92
92
 
93
+ Amend the previously generated commit message:
94
+
95
+ ```bash
96
+ noto prev --amend --edit # or simply: noto prev --amend -e
97
+ ```
98
+
99
+ > Note: When using the `--amend` flag with the noto prev command, the `--edit` (`-e`) flag is also required. This combination will allow you to modify (amend) the previous commit message before applying it.
100
+
93
101
  Note: All of the flags shown above (`--apply`, `--copy`, `--type`, `--edit`) can also be used with the `noto prev` command to work with the previously generated commit message.
94
102
 
103
+ Switch between branches in you git repo with an interactive prompt:
104
+
105
+ ```bash
106
+ noto checkout
107
+ ```
108
+
109
+
95
110
  ## Pro Tips
96
111
 
97
112
  - 🚀 Get fast commits on the fly with `noto -e -a` to streamline your workflow!
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
- import * as p6 from "@clack/prompts";
3
- import color7 from "picocolors";
2
+ import * as p7 from "@clack/prompts";
3
+ import color8 from "picocolors";
4
4
 
5
5
  // src/utils/parser.ts
6
6
  import arg from "arg";
@@ -181,11 +181,12 @@ var getStagedDiff = async () => {
181
181
  return null;
182
182
  }
183
183
  };
184
- var commit = async (message) => {
184
+ var commit = async (message, amend) => {
185
185
  try {
186
+ const options = amend ? { "--amend": null } : void 0;
186
187
  const {
187
188
  summary: { changes }
188
- } = await git.commit(message);
189
+ } = await git.commit(message, void 0, options);
189
190
  return Boolean(changes);
190
191
  } catch {
191
192
  return false;
@@ -199,6 +200,32 @@ var push = async () => {
199
200
  return false;
200
201
  }
201
202
  };
203
+ var getCurrentBranch = async () => {
204
+ try {
205
+ const branch = await git.branch();
206
+ return branch.current;
207
+ } catch {
208
+ return null;
209
+ }
210
+ };
211
+ var getBranches = async () => {
212
+ try {
213
+ const branches = await git.branch();
214
+ return Object.keys(branches.branches).filter(
215
+ (b) => !b.startsWith("remotes/")
216
+ );
217
+ } catch {
218
+ return null;
219
+ }
220
+ };
221
+ var checkout = async (branch) => {
222
+ try {
223
+ await git.checkout(branch);
224
+ return true;
225
+ } catch {
226
+ return false;
227
+ }
228
+ };
202
229
 
203
230
  // src/middleware/git.ts
204
231
  var withRepository = (fn, options = { enabled: true }) => {
@@ -477,6 +504,11 @@ var command2 = {
477
504
  flag: "--edit",
478
505
  alias: "-e",
479
506
  description: "edit the last generated commit message"
507
+ },
508
+ {
509
+ type: Boolean,
510
+ flag: "--amend",
511
+ description: "amend the last commit with the last generated message"
480
512
  }
481
513
  ],
482
514
  execute: withAuth(
@@ -488,6 +520,13 @@ var command2 = {
488
520
  return await exit(1);
489
521
  }
490
522
  const isEditMode = options["--edit"];
523
+ const isAmend = options["--amend"];
524
+ if (isAmend && !isEditMode) {
525
+ p4.log.error(
526
+ color4.red("the --amend option requires the --edit option")
527
+ );
528
+ return await exit(1);
529
+ }
491
530
  p4.log.step(
492
531
  isEditMode ? color4.white(lastGeneratedMessage) : color4.green(lastGeneratedMessage)
493
532
  );
@@ -514,7 +553,7 @@ var command2 = {
514
553
  color4.dim("copied last generated commit message to clipboard")
515
554
  );
516
555
  }
517
- if (options["--apply"]) {
556
+ if (options["--apply"] || isAmend) {
518
557
  if (!options.isRepo) {
519
558
  p4.log.error(
520
559
  dedent4`${color4.red("no git repository found in cwd.")}
@@ -522,14 +561,14 @@ var command2 = {
522
561
  );
523
562
  return await exit(1);
524
563
  }
525
- if (!options.diff) {
564
+ if (!options.diff && !isAmend) {
526
565
  p4.log.error(
527
566
  dedent4`${color4.red("no staged changes found.")}
528
567
  ${color4.dim(`run ${color4.cyan("`git add <file>`")} or ${color4.cyan("`git add .`")} to stage changes.`)}`
529
568
  );
530
569
  return await exit(1);
531
570
  }
532
- const success = await commit(lastGeneratedMessage);
571
+ const success = await commit(lastGeneratedMessage, isAmend);
533
572
  if (success) {
534
573
  p4.log.step(color4.dim("commit successful"));
535
574
  } else {
@@ -544,30 +583,89 @@ var command2 = {
544
583
  };
545
584
  var prev_default = command2;
546
585
 
547
- // src/commands/config.ts
586
+ // src/commands/checkout.ts
548
587
  import * as p5 from "@clack/prompts";
549
588
  import color5 from "picocolors";
589
+ import dedent5 from "dedent";
590
+ var command3 = {
591
+ name: "checkout",
592
+ description: "checkout a branch",
593
+ usage: "checkout [options]",
594
+ execute: withRepository(
595
+ async (options) => {
596
+ if (!options.isRepo) {
597
+ p5.log.error(
598
+ dedent5`${color5.red("no git repository found in cwd.")}
599
+ ${color5.dim(`run ${color5.cyan("`git init`")} to initialize a new repository.`)}`
600
+ );
601
+ return await exit(1);
602
+ }
603
+ const branches = await getBranches();
604
+ if (!branches) {
605
+ p5.log.error("failed to fetch branches");
606
+ return await exit(1);
607
+ }
608
+ const currentBranch = await getCurrentBranch();
609
+ const branch = await p5.select({
610
+ message: "select a branch to checkout",
611
+ options: branches.map((branch2) => ({
612
+ value: branch2,
613
+ label: color5.bold(
614
+ branch2 === currentBranch ? color5.green(branch2) : branch2
615
+ ),
616
+ hint: branch2 === currentBranch ? "current branch" : void 0
617
+ })),
618
+ initialValue: currentBranch
619
+ });
620
+ if (p5.isCancel(branch)) {
621
+ p5.log.error("nothing selected!");
622
+ return await exit(1);
623
+ }
624
+ if (!branch) {
625
+ p5.log.error("no branch selected");
626
+ return await exit(1);
627
+ }
628
+ if (branch === currentBranch) {
629
+ p5.log.error(`${color5.red("already on branch")}`);
630
+ return await exit(1);
631
+ }
632
+ const result = await checkout(branch);
633
+ if (!result) {
634
+ p5.log.error(`failed to checkout ${color5.bold(branch)}`);
635
+ return await exit(1);
636
+ }
637
+ p5.log.success(`checked out ${color5.green(branch)}`);
638
+ await exit(0);
639
+ },
640
+ { enabled: false }
641
+ )
642
+ };
643
+ var checkout_default = command3;
644
+
645
+ // src/commands/config.ts
646
+ import * as p6 from "@clack/prompts";
647
+ import color6 from "picocolors";
550
648
  var key = {
551
649
  name: "key",
552
650
  description: "configure api key",
553
651
  usage: "noto config key [options]",
554
652
  execute: async (options) => {
555
653
  if ((await StorageManager.get()).llm?.apiKey) {
556
- const confirm2 = await p5.confirm({
654
+ const confirm2 = await p6.confirm({
557
655
  message: "noto api key already configured, do you want to update it?"
558
656
  });
559
- if (p5.isCancel(confirm2) || !confirm2) {
560
- p5.log.error(color5.red("nothing changed!"));
657
+ if (p6.isCancel(confirm2) || !confirm2) {
658
+ p6.log.error(color6.red("nothing changed!"));
561
659
  return await exit(1);
562
660
  }
563
661
  }
564
662
  let apiKey = options._[0];
565
663
  if (!apiKey) {
566
- const result = await p5.text({
664
+ const result = await p6.text({
567
665
  message: "enter your noto api key"
568
666
  });
569
- if (p5.isCancel(result)) {
570
- p5.log.error(color5.red("nothing changed!"));
667
+ if (p6.isCancel(result)) {
668
+ p6.log.error(color6.red("nothing changed!"));
571
669
  return await exit(1);
572
670
  }
573
671
  apiKey = result;
@@ -579,7 +677,7 @@ var key = {
579
677
  apiKey
580
678
  }
581
679
  }));
582
- p5.log.success(color5.green("noto api key configured!"));
680
+ p6.log.success(color6.green("noto api key configured!"));
583
681
  console.log();
584
682
  }
585
683
  };
@@ -588,7 +686,7 @@ var model = {
588
686
  description: "configure model",
589
687
  usage: "noto config model [options]",
590
688
  execute: async (options) => {
591
- const model2 = await p5.select({
689
+ const model2 = await p6.select({
592
690
  message: "select a model",
593
691
  initialValue: (await StorageManager.get()).llm?.model,
594
692
  options: Object.keys(models).map((model3) => ({
@@ -596,16 +694,16 @@ var model = {
596
694
  value: model3
597
695
  }))
598
696
  });
599
- if (p5.isCancel(model2)) {
600
- p5.log.error(color5.red("nothing changed!"));
697
+ if (p6.isCancel(model2)) {
698
+ p6.log.error(color6.red("nothing changed!"));
601
699
  return await exit(1);
602
700
  }
603
701
  if (model2 === "gemini-2.5-pro-exp-03-25") {
604
- const confirm2 = await p5.confirm({
702
+ const confirm2 = await p6.confirm({
605
703
  message: "this model has a rate limit of 5 RPM (requests per minute) 50 requests per day, do you want to continue?"
606
704
  });
607
- if (p5.isCancel(confirm2) || !confirm2) {
608
- p5.log.error(color5.red("nothing changed!"));
705
+ if (p6.isCancel(confirm2) || !confirm2) {
706
+ p6.log.error(color6.red("nothing changed!"));
609
707
  return await exit(1);
610
708
  }
611
709
  }
@@ -616,7 +714,7 @@ var model = {
616
714
  model: model2
617
715
  }
618
716
  }));
619
- p5.log.success(color5.green("model configured!"));
717
+ p6.log.success(color6.green("model configured!"));
620
718
  console.log();
621
719
  }
622
720
  };
@@ -625,37 +723,37 @@ var reset = {
625
723
  description: "reset configuration",
626
724
  usage: "noto config reset",
627
725
  execute: async () => {
628
- const confirm2 = await p5.confirm({
726
+ const confirm2 = await p6.confirm({
629
727
  message: "are you sure you want to reset the configuration?"
630
728
  });
631
- if (p5.isCancel(confirm2) || !confirm2) {
632
- p5.log.error(color5.red("nothing changed!"));
729
+ if (p6.isCancel(confirm2) || !confirm2) {
730
+ p6.log.error(color6.red("nothing changed!"));
633
731
  return await exit(1);
634
732
  }
635
733
  await StorageManager.clear();
636
- p5.log.success(color5.green("configuration reset!"));
734
+ p6.log.success(color6.green("configuration reset!"));
637
735
  console.log();
638
736
  }
639
737
  };
640
738
  var subCommands = [key, model, reset];
641
- var command3 = {
739
+ var command4 = {
642
740
  name: "config",
643
741
  description: "configure noto",
644
742
  usage: "noto config [subcommand]",
645
743
  execute: async (options) => {
646
- const command4 = await p5.select({
744
+ const command5 = await p6.select({
647
745
  message: "Select a subcommand",
648
746
  options: subCommands.map((cmd2) => ({
649
747
  label: cmd2.description,
650
748
  value: cmd2.name
651
749
  }))
652
750
  });
653
- if (p5.isCancel(command4)) {
751
+ if (p6.isCancel(command5)) {
654
752
  return await exit(1);
655
753
  }
656
- const cmd = getCommand(command4, subCommands);
754
+ const cmd = getCommand(command5, subCommands);
657
755
  if (!cmd) {
658
- p5.log.error(color5.red("unknown config command"));
756
+ p6.log.error(color6.red("unknown config command"));
659
757
  return await exit(1);
660
758
  }
661
759
  options._ = options._.slice(1);
@@ -663,34 +761,34 @@ var command3 = {
663
761
  },
664
762
  subCommands
665
763
  };
666
- var config_default = command3;
764
+ var config_default = command4;
667
765
 
668
766
  // src/commands/help.ts
669
- import color6 from "picocolors";
767
+ import color7 from "picocolors";
670
768
  var help = {
671
769
  name: "help",
672
770
  description: "show help",
673
771
  usage: "noto help [command]",
674
772
  execute: async (options) => {
675
- const command4 = getCommand(options._[0]);
676
- if (command4) {
773
+ const command5 = getCommand(options._[0]);
774
+ if (command5) {
677
775
  console.log();
678
- console.log(color6.bold("Usage"));
679
- console.log(` ${command4.usage}`);
776
+ console.log(color7.bold("Usage"));
777
+ console.log(` ${command5.usage}`);
680
778
  console.log();
681
- console.log(color6.bold("Description"));
682
- console.log(` ${command4.description}`);
779
+ console.log(color7.bold("Description"));
780
+ console.log(` ${command5.description}`);
683
781
  console.log();
684
782
  } else {
685
783
  const commands2 = listCommand();
686
784
  console.log();
687
- console.log(color6.bold("Usage"));
785
+ console.log(color7.bold("Usage"));
688
786
  console.log(` noto [command] [options]`);
689
787
  console.log();
690
- console.log(color6.bold("Commands"));
691
- commands2.forEach((command5) => {
788
+ console.log(color7.bold("Commands"));
789
+ commands2.forEach((command6) => {
692
790
  console.log(
693
- ` ${color6.bold(command5.name)} ${color6.dim(command5.description)}`
791
+ ` ${color7.bold(command6.name)} ${color7.dim(command6.description)}`
694
792
  );
695
793
  });
696
794
  console.log();
@@ -700,7 +798,7 @@ var help = {
700
798
  var help_default = help;
701
799
 
702
800
  // src/commands/index.ts
703
- var commands = [noto_default, prev_default, config_default, help_default];
801
+ var commands = [noto_default, prev_default, checkout_default, config_default, help_default];
704
802
  var getCommand = (name, cmds = commands) => {
705
803
  return cmds.find((cmd) => cmd.name === name);
706
804
  };
@@ -709,7 +807,7 @@ var listCommand = () => {
709
807
  };
710
808
 
711
809
  // package.json
712
- var version = "1.0.7";
810
+ var version = "1.1.0";
713
811
 
714
812
  // src/index.ts
715
813
  var globalSpec = {
@@ -720,15 +818,15 @@ var globalSpec = {
720
818
  };
721
819
  function main() {
722
820
  const args = process.argv.slice(2);
723
- const { command: command4, options: globalOptions } = parse(globalSpec, args);
821
+ const { command: command5, options: globalOptions } = parse(globalSpec, args);
724
822
  console.log();
725
- p6.intro(`${color7.bgCyan(color7.black(" @snelusha/noto "))}`);
726
- if (globalOptions["--version"]) return p6.outro(version);
823
+ p7.intro(`${color8.bgCyan(color8.black(" @snelusha/noto "))}`);
824
+ if (globalOptions["--version"]) return p7.outro(version);
727
825
  if (globalOptions["--help"]) {
728
826
  getCommand("help")?.execute(globalOptions);
729
827
  return;
730
828
  }
731
- const cmd = getCommand(command4) ?? getCommand("noto");
829
+ const cmd = getCommand(command5) ?? getCommand("noto");
732
830
  if (!cmd) return getCommand("noto")?.execute(globalOptions);
733
831
  let commandArgs = args;
734
832
  let selectedCommand = cmd;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snelusha/noto",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "Generate clean commit messages in a snap! ✨",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,7 +12,7 @@
12
12
  "homepage": "https://noto.snelusha.dev",
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "git+https://github.com/snelusha/noto.git",
15
+ "url": "https://github.com/snelusha/noto.git",
16
16
  "directory": "packages/cli"
17
17
  },
18
18
  "bugs": {
@@ -42,21 +42,21 @@
42
42
  "cli"
43
43
  ],
44
44
  "devDependencies": {
45
- "@types/node": "^22.13.13",
45
+ "@types/node": "^22.14.0",
46
46
  "tsup": "^8.4.0",
47
- "typescript": "^5.8.2"
47
+ "typescript": "^5.8.3",
48
+ "vitest": "^3.1.1"
48
49
  },
49
50
  "dependencies": {
50
- "@ai-sdk/google": "^1.2.3",
51
+ "@ai-sdk/google": "^1.2.7",
51
52
  "@clack/prompts": "^0.10.0",
52
- "ai": "^4.2.5",
53
+ "ai": "^4.3.2",
53
54
  "arg": "^5.0.2",
54
55
  "clipboardy": "^4.0.0",
55
56
  "dedent": "^1.5.3",
56
57
  "picocolors": "^1.1.1",
57
58
  "simple-git": "^3.27.0",
58
59
  "tinyexec": "^0.3.2",
59
- "vitest": "^3.0.9",
60
60
  "zod": "^3.24.2"
61
61
  }
62
62
  }