worktree-launcher 1.4.1 → 1.5.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 +8 -8
  2. package/dist/index.js +103 -331
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -44,14 +44,15 @@ Run `wt` with no arguments to open a terminal UI:
44
44
  wt
45
45
  ```
46
46
 
47
- The TUI shows your repo name, current branch, and all existing worktrees. Use keyboard shortcuts to manage them:
47
+ The TUI shows your repo name, current branch, and all existing worktrees.
48
48
 
49
49
  | Key | Action |
50
50
  |-----|--------|
51
- | `n` | Create new worktree (guided wizard) |
51
+ | `n` | Create new worktree |
52
52
  | `d` | Delete selected worktree |
53
53
  | `c` | Launch Claude Code in selected worktree |
54
54
  | `x` | Launch Codex in selected worktree |
55
+ | `p` | Push selected branch to remote |
55
56
  | `Enter` | Print cd command for selected worktree |
56
57
  | `r` | Refresh worktree list |
57
58
  | `q` | Quit |
@@ -60,13 +61,12 @@ Navigate with arrow keys or vim-style `j`/`k`.
60
61
 
61
62
  ### Creating a New Worktree
62
63
 
63
- Press `n` to start the guided creation wizard:
64
+ Press `n` to create a new worktree:
64
65
 
65
- 1. **Branch name** - Enter the name for your new branch
66
- 2. **Base branch** - Create from current branch or default branch (main/master)
67
- 3. **Copy .env files** - Copy environment files to the new worktree
68
- 4. **Push to remote** - Push branch to GitHub immediately
69
- 5. **Launch AI tool** - Choose Claude Code, Codex, or skip
66
+ 1. Enter the branch name
67
+ 2. Choose AI tool to launch (Claude Code, Codex, or Skip)
68
+
69
+ The worktree is created from your current branch, .env files are copied automatically.
70
70
 
71
71
  ## Commands
72
72
 
package/dist/index.js CHANGED
@@ -62,11 +62,13 @@ async function getDefaultBranch() {
62
62
  return "main";
63
63
  }
64
64
  }
65
- async function createWorktree(worktreePath, branchName) {
65
+ async function createWorktree(worktreePath, branchName, startPoint) {
66
66
  validateBranchName(branchName);
67
67
  const exists = await branchExists(branchName);
68
68
  if (exists) {
69
69
  await execFileAsync("git", ["worktree", "add", "--", worktreePath, branchName]);
70
+ } else if (startPoint) {
71
+ await execFileAsync("git", ["worktree", "add", "-b", branchName, "--", worktreePath, startPoint]);
70
72
  } else {
71
73
  await execFileAsync("git", ["worktree", "add", "-b", branchName, "--", worktreePath]);
72
74
  }
@@ -111,8 +113,8 @@ async function pruneWorktrees() {
111
113
  }
112
114
  async function isBranchMerged(branchName) {
113
115
  try {
114
- const defaultBranch2 = await getDefaultBranch();
115
- const { stdout } = await execFileAsync("git", ["branch", "--merged", defaultBranch2]);
116
+ const defaultBranch = await getDefaultBranch();
117
+ const { stdout } = await execFileAsync("git", ["branch", "--merged", defaultBranch]);
116
118
  const mergedBranches = stdout.split("\n").map((b) => b.trim().replace("* ", ""));
117
119
  return mergedBranches.includes(branchName);
118
120
  } catch {
@@ -609,11 +611,8 @@ import path8 from "path";
609
611
  var screen;
610
612
  var worktreeList;
611
613
  var statusBar;
612
- var helpBar;
613
- var headerBox;
614
614
  var mainRepoPath;
615
615
  var currentBranch;
616
- var defaultBranch;
617
616
  var worktrees = [];
618
617
  var selectedIndex = 0;
619
618
  async function interactiveCommand() {
@@ -623,7 +622,6 @@ async function interactiveCommand() {
623
622
  }
624
623
  mainRepoPath = await getGitRoot();
625
624
  currentBranch = await getCurrentBranch();
626
- defaultBranch = await getDefaultBranch();
627
625
  const repoName = path8.basename(mainRepoPath);
628
626
  screen = blessed.screen({
629
627
  smartCSR: true,
@@ -632,17 +630,14 @@ async function interactiveCommand() {
632
630
  terminal: "xterm-256color",
633
631
  warnings: false
634
632
  });
635
- headerBox = blessed.box({
633
+ blessed.box({
636
634
  parent: screen,
637
635
  top: 0,
638
636
  left: 0,
639
637
  width: "100%",
640
638
  height: 1,
641
639
  content: ` ${repoName} (${currentBranch})`,
642
- style: {
643
- fg: "black",
644
- bg: "cyan"
645
- }
640
+ style: { fg: "black", bg: "cyan" }
646
641
  });
647
642
  worktreeList = blessed.list({
648
643
  parent: screen,
@@ -654,18 +649,10 @@ async function interactiveCommand() {
654
649
  vi: true,
655
650
  mouse: true,
656
651
  style: {
657
- selected: {
658
- bg: "cyan",
659
- fg: "black"
660
- },
661
- item: {
662
- fg: "default"
663
- }
652
+ selected: { bg: "cyan", fg: "black" },
653
+ item: { fg: "default" }
664
654
  },
665
- scrollbar: {
666
- ch: " ",
667
- style: { bg: "cyan" }
668
- }
655
+ scrollbar: { ch: " ", style: { bg: "cyan" } }
669
656
  });
670
657
  statusBar = blessed.box({
671
658
  parent: screen,
@@ -674,52 +661,34 @@ async function interactiveCommand() {
674
661
  width: "100%",
675
662
  height: 1,
676
663
  content: "",
677
- style: {
678
- fg: "green"
679
- }
664
+ style: { fg: "green" }
680
665
  });
681
- helpBar = blessed.box({
666
+ blessed.box({
682
667
  parent: screen,
683
668
  bottom: 0,
684
669
  left: 0,
685
670
  width: "100%",
686
671
  height: 1,
687
- content: " [n]ew [d]elete [c]laude [x]codex [Enter]cd [q]uit",
688
- style: {
689
- fg: "black",
690
- bg: "cyan"
691
- }
672
+ content: " [n]ew [d]elete [c]laude [x]codex [p]ush [Enter]cd [q]uit",
673
+ style: { fg: "black", bg: "cyan" }
692
674
  });
693
675
  await refreshWorktrees();
694
676
  worktreeList.on("select", (_item, index) => {
695
677
  selectedIndex = index;
696
678
  showPath();
697
679
  });
698
- screen.key(["q", "C-c"], () => {
699
- cleanExit();
700
- });
701
- screen.key(["n"], () => {
702
- startCreationWizard();
703
- });
704
- screen.key(["d"], async () => {
705
- await deleteSelected();
706
- });
707
- screen.key(["c"], async () => {
708
- await launchAI("claude");
709
- });
710
- screen.key(["x"], async () => {
711
- await launchAI("codex");
712
- });
680
+ screen.key(["q", "C-c"], () => exitScreen());
681
+ screen.key(["n"], () => showNewWorktreeForm());
682
+ screen.key(["d"], () => deleteSelected());
683
+ screen.key(["c"], () => launchTool("claude"));
684
+ screen.key(["x"], () => launchTool("codex"));
685
+ screen.key(["p"], () => pushSelected());
686
+ screen.key(["r"], () => refreshWorktrees());
713
687
  screen.key(["enter"], () => {
714
688
  const wt = worktrees[selectedIndex];
715
- if (wt) {
716
- cleanExit(`
689
+ if (wt) exitScreen(`
717
690
  cd "${wt.path}"
718
691
  `);
719
- }
720
- });
721
- screen.key(["r"], async () => {
722
- await refreshWorktrees();
723
692
  });
724
693
  worktreeList.focus();
725
694
  screen.render();
@@ -731,116 +700,92 @@ async function refreshWorktrees() {
731
700
  const isMain = wt.path === mainRepoPath;
732
701
  const dirName = path8.basename(wt.path);
733
702
  const branch = wt.branch || "(detached)";
734
- const status = isMain ? "[main]" : "";
735
- return ` ${dirName.padEnd(40)} ${branch.padEnd(25)} ${status}`;
703
+ const tag = isMain ? "[main]" : "";
704
+ return ` ${dirName.padEnd(40)} ${branch.padEnd(25)} ${tag}`;
736
705
  });
737
706
  worktreeList.setItems(items);
738
707
  worktreeList.select(selectedIndex);
739
708
  showPath();
740
- screen.render();
741
709
  }
742
710
  function showPath() {
743
711
  const wt = worktrees[selectedIndex];
744
- if (wt) {
745
- setStatus(wt.path);
746
- } else {
747
- setStatus("");
748
- }
712
+ setStatus(wt ? wt.path : "");
749
713
  }
750
714
  function setStatus(msg) {
751
715
  statusBar.setContent(` ${msg}`);
752
716
  screen.render();
753
717
  }
754
- function cleanExit(message) {
718
+ function cleanupScreen() {
755
719
  screen.program.clear();
756
720
  screen.program.disableMouse();
757
721
  screen.program.showCursor();
758
722
  screen.program.normalBuffer();
759
723
  screen.destroy();
760
- if (message) {
761
- console.log(message);
762
- }
763
- process.exit(0);
764
724
  }
765
- function startCreationWizard() {
766
- const state = {
767
- branchName: "",
768
- baseBranch: "current",
769
- copyEnv: true,
770
- pushToRemote: false,
771
- aiTool: "claude"
772
- };
773
- askBranchName(state);
725
+ function exitScreen(message) {
726
+ cleanupScreen();
727
+ if (message) console.log(message);
728
+ process.exit(0);
774
729
  }
775
- function askBranchName(state) {
730
+ function showNewWorktreeForm() {
776
731
  const form = blessed.box({
777
732
  parent: screen,
778
733
  top: "center",
779
734
  left: "center",
780
735
  width: 60,
781
- height: 12,
736
+ height: 10,
782
737
  border: { type: "line" },
783
- style: {
784
- fg: "default",
785
- border: { fg: "cyan" }
786
- },
738
+ style: { fg: "default", border: { fg: "cyan" } },
787
739
  label: " New Worktree "
788
740
  });
789
741
  blessed.text({
790
742
  parent: form,
791
743
  top: 1,
792
744
  left: 2,
793
- content: `Repository: ${path8.basename(mainRepoPath)}`,
745
+ content: `Repository: ${path8.basename(mainRepoPath)} (from ${currentBranch})`,
794
746
  style: { fg: "cyan" }
795
747
  });
796
748
  blessed.text({
797
749
  parent: form,
798
- top: 2,
799
- left: 2,
800
- content: `Current branch: ${currentBranch}`,
801
- style: { fg: "default" }
802
- });
803
- blessed.text({
804
- parent: form,
805
- top: 4,
750
+ top: 3,
806
751
  left: 2,
807
752
  content: "Branch name:",
808
753
  style: { fg: "default" }
809
754
  });
810
755
  const input = blessed.textbox({
811
756
  parent: form,
812
- top: 5,
757
+ top: 4,
813
758
  left: 2,
814
759
  width: 54,
815
760
  height: 1,
816
- style: {
817
- fg: "black",
818
- bg: "white"
819
- },
761
+ style: { fg: "black", bg: "white" },
820
762
  inputOnFocus: true
821
763
  });
822
764
  blessed.text({
823
765
  parent: form,
824
- top: 7,
766
+ top: 6,
825
767
  left: 2,
826
768
  content: "[Enter] next [Esc] cancel",
827
769
  style: { fg: "cyan" }
828
770
  });
829
771
  input.focus();
830
772
  screen.render();
831
- input.on("submit", (value) => {
832
- if (!value || !value.trim()) {
773
+ input.on("submit", () => {
774
+ const value = input.getValue()?.trim();
775
+ if (!value) {
833
776
  form.destroy();
834
777
  screen.render();
778
+ worktreeList.focus();
835
779
  return;
836
780
  }
837
781
  try {
838
- validateBranchName(value.trim());
839
- state.branchName = value.trim();
782
+ validateBranchName(value);
840
783
  form.destroy();
841
- askBaseBranch(state);
784
+ screen.render();
785
+ showAIToolSelector(value);
842
786
  } catch (e) {
843
787
  setStatus(`Error: ${e.message}`);
788
+ input.clearValue();
844
789
  input.focus();
845
790
  screen.render();
846
791
  }
@@ -848,172 +793,19 @@ function askBranchName(state) {
848
793
  input.on("cancel", () => {
849
794
  form.destroy();
850
795
  screen.render();
796
+ worktreeList.focus();
851
797
  });
852
798
  input.readInput();
853
799
  }
854
- function askBaseBranch(state) {
855
- const form = blessed.box({
856
- parent: screen,
857
- top: "center",
858
- left: "center",
859
- width: 50,
860
- height: 10,
861
- border: { type: "line" },
862
- style: {
863
- fg: "default",
864
- border: { fg: "cyan" }
865
- },
866
- label: " Base Branch "
867
- });
868
- blessed.text({
869
- parent: form,
870
- top: 1,
871
- left: 2,
872
- content: "Create worktree from:",
873
- style: { fg: "default" }
874
- });
875
- const list = blessed.list({
876
- parent: form,
877
- top: 3,
878
- left: 2,
879
- width: 44,
880
- height: 3,
881
- keys: true,
882
- vi: true,
883
- style: {
884
- selected: { bg: "cyan", fg: "black" },
885
- item: { fg: "default" }
886
- },
887
- items: [
888
- ` Current branch (${currentBranch})`,
889
- ` Default branch (${defaultBranch})`
890
- ]
891
- });
892
- blessed.text({
893
- parent: form,
894
- top: 7,
895
- left: 2,
896
- content: "[Enter] select [Esc] cancel",
897
- style: { fg: "cyan" }
898
- });
899
- list.focus();
900
- screen.render();
901
- list.on("select", (_item, index) => {
902
- state.baseBranch = index === 0 ? "current" : "default";
903
- form.destroy();
904
- askCopyEnv(state);
905
- });
906
- list.key(["escape"], () => {
907
- form.destroy();
908
- screen.render();
909
- });
910
- }
911
- function askCopyEnv(state) {
912
- const form = blessed.box({
913
- parent: screen,
914
- top: "center",
915
- left: "center",
916
- width: 40,
917
- height: 8,
918
- border: { type: "line" },
919
- style: {
920
- fg: "default",
921
- border: { fg: "cyan" }
922
- },
923
- label: " Environment Files "
924
- });
925
- blessed.text({
926
- parent: form,
927
- top: 1,
928
- left: 2,
929
- content: "Copy .env files to worktree?",
930
- style: { fg: "default" }
931
- });
932
- const list = blessed.list({
933
- parent: form,
934
- top: 3,
935
- left: 2,
936
- width: 34,
937
- height: 2,
938
- keys: true,
939
- vi: true,
940
- style: {
941
- selected: { bg: "cyan", fg: "black" },
942
- item: { fg: "default" }
943
- },
944
- items: [" Yes (recommended)", " No"]
945
- });
946
- list.focus();
947
- screen.render();
948
- list.on("select", (_item, index) => {
949
- state.copyEnv = index === 0;
950
- form.destroy();
951
- askPushToRemote(state);
952
- });
953
- list.key(["escape"], () => {
954
- form.destroy();
955
- screen.render();
956
- });
957
- }
958
- function askPushToRemote(state) {
959
- const form = blessed.box({
960
- parent: screen,
961
- top: "center",
962
- left: "center",
963
- width: 45,
964
- height: 8,
965
- border: { type: "line" },
966
- style: {
967
- fg: "default",
968
- border: { fg: "cyan" }
969
- },
970
- label: " Push to Remote "
971
- });
972
- blessed.text({
973
- parent: form,
974
- top: 1,
975
- left: 2,
976
- content: "Push branch to GitHub immediately?",
977
- style: { fg: "default" }
978
- });
979
- const list = blessed.list({
980
- parent: form,
981
- top: 3,
982
- left: 2,
983
- width: 39,
984
- height: 2,
985
- keys: true,
986
- vi: true,
987
- style: {
988
- selected: { bg: "cyan", fg: "black" },
989
- item: { fg: "default" }
990
- },
991
- items: [" No (push later)", " Yes (visible on GitHub now)"]
992
- });
993
- list.focus();
994
- screen.render();
995
- list.on("select", (_item, index) => {
996
- state.pushToRemote = index === 1;
997
- form.destroy();
998
- askAITool(state);
999
- });
1000
- list.key(["escape"], () => {
1001
- form.destroy();
1002
- screen.render();
1003
- });
1004
- }
1005
- function askAITool(state) {
800
+ function showAIToolSelector(branchName) {
1006
801
  const form = blessed.box({
1007
802
  parent: screen,
1008
803
  top: "center",
1009
804
  left: "center",
1010
805
  width: 40,
1011
- height: 10,
806
+ height: 9,
1012
807
  border: { type: "line" },
1013
- style: {
1014
- fg: "default",
1015
- border: { fg: "cyan" }
1016
- },
808
+ style: { fg: "default", border: { fg: "cyan" } },
1017
809
  label: " Launch AI Tool "
1018
810
  });
1019
811
  blessed.text({
@@ -1035,60 +827,38 @@ function askAITool(state) {
1035
827
  selected: { bg: "cyan", fg: "black" },
1036
828
  item: { fg: "default" }
1037
829
  },
1038
- items: [" Claude Code", " Codex", " Skip (just create worktree)"]
830
+ items: [" Claude Code", " Codex", " Skip"]
1039
831
  });
1040
832
  list.focus();
1041
833
  screen.render();
1042
834
  list.on("select", (_item, index) => {
1043
- state.aiTool = index === 0 ? "claude" : index === 1 ? "codex" : "skip";
835
+ const tool = index === 0 ? "claude" : index === 1 ? "codex" : null;
1044
836
  form.destroy();
1045
- executeCreation(state);
837
+ screen.render();
838
+ createNewWorktree(branchName, tool);
1046
839
  });
1047
840
  list.key(["escape"], () => {
1048
841
  form.destroy();
1049
842
  screen.render();
843
+ worktreeList.focus();
1050
844
  });
1051
845
  }
1052
- async function executeCreation(state) {
1053
- const { branchName, baseBranch, copyEnv, pushToRemote, aiTool } = state;
846
+ async function createNewWorktree(branchName, tool) {
1054
847
  setStatus(`Creating ${branchName}...`);
1055
848
  try {
1056
- if (baseBranch === "default" && currentBranch !== defaultBranch) {
1057
- const worktreePath = getWorktreePath(mainRepoPath, branchName);
1058
- const { execFile: execFile2 } = await import("child_process");
1059
- const { promisify: promisify2 } = await import("util");
1060
- const execFileAsync2 = promisify2(execFile2);
1061
- await execFileAsync2("git", ["worktree", "add", "-b", branchName, "--", worktreePath, defaultBranch]);
1062
- if (copyEnv) {
1063
- await copyEnvFiles(mainRepoPath, worktreePath);
1064
- }
1065
- if (pushToRemote) {
1066
- setStatus(`Pushing ${branchName}...`);
1067
- await pushBranch(branchName, worktreePath);
1068
- }
1069
- await refreshWorktrees();
1070
- setStatus(`Created ${branchName}`);
1071
- if (aiTool !== "skip") {
1072
- await launchInWorktree(worktreePath, aiTool);
1073
- }
1074
- } else {
1075
- const worktreePath = getWorktreePath(mainRepoPath, branchName);
1076
- await createWorktree(worktreePath, branchName);
1077
- if (copyEnv) {
1078
- await copyEnvFiles(mainRepoPath, worktreePath);
1079
- }
1080
- if (pushToRemote) {
1081
- setStatus(`Pushing ${branchName}...`);
1082
- await pushBranch(branchName, worktreePath);
1083
- }
1084
- await refreshWorktrees();
1085
- setStatus(`Created ${branchName}`);
1086
- if (aiTool !== "skip") {
1087
- await launchInWorktree(worktreePath, aiTool);
1088
- }
849
+ const worktreePath = getWorktreePath(mainRepoPath, branchName);
850
+ await createWorktree(worktreePath, branchName);
851
+ await copyEnvFiles(mainRepoPath, worktreePath);
852
+ await refreshWorktrees();
853
+ setStatus(`Created ${branchName}`);
854
+ worktreeList.focus();
855
+ if (tool) {
856
+ await launchInWorktree(worktreePath, tool);
1089
857
  }
1090
858
  } catch (e) {
1091
859
  setStatus(`Error: ${e.message}`);
860
+ worktreeList.focus();
861
+ screen.render();
1092
862
  }
1093
863
  }
1094
864
  async function launchInWorktree(worktreePath, tool) {
@@ -1097,18 +867,42 @@ async function launchInWorktree(worktreePath, tool) {
1097
867
  setStatus(`${tool} is not installed`);
1098
868
  return;
1099
869
  }
1100
- setStatus(`Launching ${tool}...`);
1101
- screen.program.clear();
1102
- screen.program.disableMouse();
1103
- screen.program.showCursor();
1104
- screen.program.normalBuffer();
1105
- screen.destroy();
870
+ cleanupScreen();
1106
871
  launchAITool({ cwd: worktreePath, tool });
1107
872
  console.log(`
1108
873
  ${tool} launched in: ${worktreePath}
1109
874
  `);
1110
875
  process.exit(0);
1111
876
  }
877
+ async function launchTool(tool) {
878
+ const wt = worktrees[selectedIndex];
879
+ if (!wt) return;
880
+ const available = await isToolAvailable(tool);
881
+ if (!available) {
882
+ setStatus(`${tool} is not installed`);
883
+ return;
884
+ }
885
+ cleanupScreen();
886
+ launchAITool({ cwd: wt.path, tool });
887
+ console.log(`
888
+ ${tool} launched in: ${path8.basename(wt.path)}
889
+ `);
890
+ process.exit(0);
891
+ }
892
+ async function pushSelected() {
893
+ const wt = worktrees[selectedIndex];
894
+ if (!wt?.branch) {
895
+ setStatus("No branch to push");
896
+ return;
897
+ }
898
+ setStatus(`Pushing ${wt.branch}...`);
899
+ try {
900
+ await pushBranch(wt.branch, wt.path);
901
+ setStatus(`Pushed ${wt.branch} to origin`);
902
+ } catch (e) {
903
+ setStatus(`Error: ${e.message}`);
904
+ }
905
+ }
1112
906
  async function deleteSelected() {
1113
907
  const wt = worktrees[selectedIndex];
1114
908
  if (!wt) return;
@@ -1117,20 +911,17 @@ async function deleteSelected() {
1117
911
  return;
1118
912
  }
1119
913
  const dirName = path8.basename(wt.path);
1120
- const confirm2 = blessed.question({
914
+ const dialog = blessed.question({
1121
915
  parent: screen,
1122
916
  top: "center",
1123
917
  left: "center",
1124
918
  width: 40,
1125
919
  height: 5,
1126
920
  border: { type: "line" },
1127
- style: {
1128
- fg: "default",
1129
- border: { fg: "red" }
1130
- }
921
+ style: { fg: "default", border: { fg: "red" } }
1131
922
  });
1132
- confirm2.ask(`Delete ${dirName}?`, async (err, yes) => {
1133
- confirm2.destroy();
923
+ dialog.ask(`Delete ${dirName}?`, async (_err, yes) => {
924
+ dialog.destroy();
1134
925
  if (yes) {
1135
926
  setStatus(`Deleting ${dirName}...`);
1136
927
  try {
@@ -1147,34 +938,15 @@ async function deleteSelected() {
1147
938
  if (selectedIndex > 0) selectedIndex--;
1148
939
  await refreshWorktrees();
1149
940
  } else {
1150
- await refreshWorktrees();
941
+ screen.render();
942
+ worktreeList.focus();
1151
943
  }
1152
944
  });
1153
945
  }
1154
- async function launchAI(tool) {
1155
- const wt = worktrees[selectedIndex];
1156
- if (!wt) return;
1157
- const available = await isToolAvailable(tool);
1158
- if (!available) {
1159
- setStatus(`${tool} is not installed`);
1160
- return;
1161
- }
1162
- setStatus(`Launching ${tool}...`);
1163
- screen.program.clear();
1164
- screen.program.disableMouse();
1165
- screen.program.showCursor();
1166
- screen.program.normalBuffer();
1167
- screen.destroy();
1168
- launchAITool({ cwd: wt.path, tool });
1169
- console.log(`
1170
- ${tool} launched in: ${path8.basename(wt.path)}
1171
- `);
1172
- process.exit(0);
1173
- }
1174
946
 
1175
947
  // src/index.ts
1176
948
  var program = new Command();
1177
- program.name("wt").description("CLI tool to streamline git worktrees with AI coding assistants").version("1.4.1").action(async () => {
949
+ program.name("wt").description("CLI tool to streamline git worktrees with AI coding assistants").version("1.5.0").action(async () => {
1178
950
  await interactiveCommand();
1179
951
  });
1180
952
  program.command("new <branch-name>").description("Create a new worktree and launch AI assistant").option("-i, --install", "Run package manager install after creating worktree").option("-s, --skip-launch", "Create worktree without launching AI assistant").option("-p, --push", "Push branch to remote (visible on GitHub)").action(async (branchName, options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worktree-launcher",
3
- "version": "1.4.1",
3
+ "version": "1.5.0",
4
4
  "description": "CLI tool for managing git worktrees with AI coding assistants",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",