git-stack-cli 1.3.6 → 1.4.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.
@@ -26560,14 +26560,14 @@ async function sleep(time) {
26560
26560
  return new Promise((resolve) => setTimeout(resolve, time));
26561
26561
  }
26562
26562
 
26563
- function reducer$1(state, patch) {
26563
+ function reducer$3(state, patch) {
26564
26564
  return { ...state, ...patch };
26565
26565
  }
26566
26566
  function AutoUpdate(props) {
26567
26567
  const props_ref = reactExports.useRef(props);
26568
26568
  props_ref.current = props;
26569
26569
  const [output, set_output] = reactExports.useState([]);
26570
- const [state, patch] = reactExports.useReducer(reducer$1, {
26570
+ const [state, patch] = reactExports.useReducer(reducer$3, {
26571
26571
  error: null,
26572
26572
  local_version: null,
26573
26573
  latest_version: null,
@@ -26676,67 +26676,6 @@ function AutoUpdate(props) {
26676
26676
  status));
26677
26677
  }
26678
26678
 
26679
- function serialize(obj) {
26680
- if (obj instanceof Map) {
26681
- return {
26682
- _type: "Map",
26683
- _value: Array.from(obj.entries()).map(([k, v]) => [k, serialize(v)]),
26684
- };
26685
- }
26686
- else if (Array.isArray(obj)) {
26687
- return obj.map(serialize);
26688
- }
26689
- else if (obj !== null && typeof obj === "object") {
26690
- const serializedObj = {};
26691
- for (const [key, value] of Object.entries(obj)) {
26692
- serializedObj[key] = serialize(value);
26693
- }
26694
- return serializedObj;
26695
- }
26696
- return obj;
26697
- }
26698
- function deserialize(obj) {
26699
- if (obj && obj._type === "Map") {
26700
- return new Map(obj._value.map(([k, v]) => [k, deserialize(v)]));
26701
- }
26702
- else if (Array.isArray(obj)) {
26703
- return obj.map(deserialize);
26704
- }
26705
- else if (obj !== null && typeof obj === "object") {
26706
- const deserializedObj = {};
26707
- for (const [key, value] of Object.entries(obj)) {
26708
- deserializedObj[key] = deserialize(value);
26709
- }
26710
- return deserializedObj;
26711
- }
26712
- return obj;
26713
- }
26714
-
26715
- function Debug() {
26716
- const actions = Store.useActions();
26717
- const state = Store.useState((state) => state);
26718
- const argv = Store.useState((state) => state.argv);
26719
- const debug = Store.useState((state) => state.select.debug(state));
26720
- reactExports.useEffect(function debugMessageOnce() {
26721
- if (debug) {
26722
- actions.output(reactExports.createElement(Text, { color: colors.yellow }, "Debug mode enabled"));
26723
- }
26724
- }, [argv]);
26725
- reactExports.useEffect(function syncStateJson() {
26726
- if (!argv?.["write-state-json"]) {
26727
- return;
26728
- }
26729
- const output_file = path.join(state.cwd, "git-stack-state.json");
26730
- if (fs.existsSync(output_file)) {
26731
- fs.rmSync(output_file);
26732
- }
26733
- const serialized = serialize(state);
26734
- const content = JSON.stringify(serialized, null, 2);
26735
- fs.writeFileSync(output_file, content);
26736
- }, [argv, state]);
26737
- return null;
26738
- }
26739
-
26740
26679
  function cache(cacheable) {
26741
26680
  let status = "pending";
26742
26681
  let response;
@@ -26831,6 +26770,113 @@ function Command(props) {
26831
26770
  return (reactExports.createElement(Text, { bold: true, color: text_color }, props.children));
26832
26771
  }
26833
26772
 
26773
+ function reducer$2(state, patch) {
26774
+ return { ...state, ...patch };
26775
+ }
26776
+ function CherryPickCheck(props) {
26777
+ const actions = Store.useActions();
26778
+ const [state, patch] = reactExports.useReducer(reducer$2, {
26779
+ status: "init",
26780
+ });
26781
+ switch (state.status) {
26782
+ case "done":
26783
+ return props.children;
26784
+ case "prompt":
26785
+ return (reactExports.createElement(YesNoPrompt, { message: reactExports.createElement(Text, { color: colors.yellow },
26786
+ reactExports.createElement(Command, null, "git cherry-pick"),
26787
+ " detected, would you like to abort it?"), onYes: async () => {
26788
+ await cli(`git cherry-pick --abort`);
26789
+ patch({ status: "done" });
26790
+ }, onNo: async () => {
26791
+ actions.exit(0);
26792
+ } }));
26793
+ default:
26794
+ return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
26795
+ "Checking for ",
26796
+ reactExports.createElement(Command, null, "git cherry-pick"),
26797
+ "\u2026"), function: cherry_pick_check }));
26798
+ }
26799
+ async function cherry_pick_check() {
26800
+ const actions = Store.getState().actions;
26801
+ try {
26802
+ const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
26803
+ const is_cherry_pick = fs.existsSync(path.join(git_dir, "CHERRY_PICK_HEAD"));
26804
+ const status = is_cherry_pick ? "prompt" : "done";
26805
+ patch({ status });
26806
+ }
26807
+ catch (err) {
26808
+ actions.error("Must be run from within a git repository.");
26809
+ if (err instanceof Error) {
26810
+ if (actions.isDebug()) {
26811
+ actions.error(err.message);
26812
+ }
26813
+ }
26814
+ actions.exit(9);
26815
+ }
26816
+ }
26817
+ }
26818
+
26819
+ function serialize(obj) {
26820
+ if (obj instanceof Map) {
26821
+ return {
26822
+ _type: "Map",
26823
+ _value: Array.from(obj.entries()).map(([k, v]) => [k, serialize(v)]),
26824
+ };
26825
+ }
26826
+ else if (Array.isArray(obj)) {
26827
+ return obj.map(serialize);
26828
+ }
26829
+ else if (obj !== null && typeof obj === "object") {
26830
+ const serializedObj = {};
26831
+ for (const [key, value] of Object.entries(obj)) {
26832
+ serializedObj[key] = serialize(value);
26833
+ }
26834
+ return serializedObj;
26835
+ }
26836
+ return obj;
26837
+ }
26838
+ function deserialize(obj) {
26839
+ if (obj && obj._type === "Map") {
26840
+ return new Map(obj._value.map(([k, v]) => [k, deserialize(v)]));
26841
+ }
26842
+ else if (Array.isArray(obj)) {
26843
+ return obj.map(deserialize);
26844
+ }
26845
+ else if (obj !== null && typeof obj === "object") {
26846
+ const deserializedObj = {};
26847
+ for (const [key, value] of Object.entries(obj)) {
26848
+ deserializedObj[key] = deserialize(value);
26849
+ }
26850
+ return deserializedObj;
26851
+ }
26852
+ return obj;
26853
+ }
26854
+
26855
+ function Debug() {
26856
+ const actions = Store.useActions();
26857
+ const state = Store.useState((state) => state);
26858
+ const argv = Store.useState((state) => state.argv);
26859
+ const debug = Store.useState((state) => state.select.debug(state));
26860
+ reactExports.useEffect(function debugMessageOnce() {
26861
+ if (debug) {
26862
+ actions.output(reactExports.createElement(Text, { color: colors.yellow }, "Debug mode enabled"));
26863
+ }
26864
+ }, [argv]);
26865
+ reactExports.useEffect(function syncStateJson() {
26866
+ if (!argv?.["write-state-json"]) {
26867
+ return;
26868
+ }
26869
+ const output_file = path.join(state.cwd, "git-stack-state.json");
26870
+ if (fs.existsSync(output_file)) {
26871
+ fs.rmSync(output_file);
26872
+ }
26873
+ const serialized = serialize(state);
26874
+ const content = JSON.stringify(serialized, null, 2);
26875
+ fs.writeFileSync(output_file, content);
26876
+ }, [argv, state]);
26877
+ return null;
26878
+ }
26879
+
26834
26880
  function Url(props) {
26835
26881
  return (reactExports.createElement(Text, { bold: true, color: colors.blue, ...props }, props.children));
26836
26882
  }
@@ -26892,7 +26938,7 @@ function CheckGit(props) {
26892
26938
  return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
26893
26939
  "Checking ",
26894
26940
  reactExports.createElement(Command, null, "git"),
26895
- " install..."), function: async () => {
26941
+ " install\u2026"), function: async () => {
26896
26942
  // await Promise.all([
26897
26943
  // cli(`for i in $(seq 1 5); do echo $i; sleep 1; done`),
26898
26944
  // cli(`for i in $(seq 5 1); do printf "$i "; sleep 1; done; echo`),
@@ -26912,7 +26958,7 @@ function CheckGithubCli(props) {
26912
26958
  reactExports.createElement(Text, null,
26913
26959
  "Checking ",
26914
26960
  reactExports.createElement(Command, null, "gh"),
26915
- " install...")), function: async () => {
26961
+ " install\u2026")), function: async () => {
26916
26962
  if (is_command_available("gh")) {
26917
26963
  return;
26918
26964
  }
@@ -26932,7 +26978,7 @@ function CheckGithubCliAuth(props) {
26932
26978
  reactExports.createElement(Text, null,
26933
26979
  "Checking ",
26934
26980
  reactExports.createElement(Command, null, "gh auth status"),
26935
- "...")), function: async () => {
26981
+ "\u2026")), function: async () => {
26936
26982
  const options = { ignoreExitCode: true };
26937
26983
  const auth_status$1 = await cli(`gh auth status`, options);
26938
26984
  if (auth_status$1.code === 0) {
@@ -26965,7 +27011,7 @@ function CheckGitRevise(props) {
26965
27011
  reactExports.createElement(Text, null,
26966
27012
  "Checking ",
26967
27013
  reactExports.createElement(Command, null, "git revise"),
26968
- " install...")), function: async () => {
27014
+ " install\u2026")), function: async () => {
26969
27015
  if (is_command_available("git-revise")) {
26970
27016
  return;
26971
27017
  }
@@ -26982,8 +27028,53 @@ function CheckGitRevise(props) {
26982
27028
  } }, props.children));
26983
27029
  }
26984
27030
 
27031
+ function reducer$1(state, patch) {
27032
+ return { ...state, ...patch };
27033
+ }
27034
+ function DirtyCheck(props) {
27035
+ const actions = Store.useActions();
27036
+ const [state, patch] = reactExports.useReducer(reducer$1, {
27037
+ status: "init",
27038
+ });
27039
+ switch (state.status) {
27040
+ case "done":
27041
+ return props.children;
27042
+ case "prompt":
27043
+ return (reactExports.createElement(YesNoPrompt, { message: reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow }), message: "{git} repo is dirty, changed may be lost during {git_stack}, are you sure you wannt to proceed?", values: {
27044
+ git: reactExports.createElement(Command, null, "git"),
27045
+ git_stack: reactExports.createElement(Command, null, "git stack"),
27046
+ } }), onYes: async () => {
27047
+ patch({ status: "done" });
27048
+ }, onNo: async () => {
27049
+ actions.exit(0);
27050
+ } }));
27051
+ default:
27052
+ return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
27053
+ "Ensuring ",
27054
+ reactExports.createElement(Command, null, "git status --porcelain"),
27055
+ "\u2026"), function: rebase_check }));
27056
+ }
27057
+ async function rebase_check() {
27058
+ const actions = Store.getState().actions;
27059
+ try {
27060
+ const git_dirty = (await cli(`git status --porcelain`)).stdout;
27061
+ const status = git_dirty ? "prompt" : "done";
27062
+ patch({ status });
27063
+ }
27064
+ catch (err) {
27065
+ actions.error("Must be run from within a git repository.");
27066
+ if (err instanceof Error) {
27067
+ if (actions.isDebug()) {
27068
+ actions.error(err.message);
27069
+ }
27070
+ }
27071
+ actions.exit(9);
27072
+ }
27073
+ }
27074
+ }
27075
+
26985
27076
  function GatherMetadata(props) {
26986
- const fallback = (reactExports.createElement(Text, { color: colors.yellow }, "Gathering local git information..."));
27077
+ const fallback = (reactExports.createElement(Text, { color: colors.yellow }, "Gathering local git information\u2026"));
26987
27078
  return (reactExports.createElement(Await, { fallback: fallback, function: gather_metadata$1 }, props.children));
26988
27079
  }
26989
27080
  async function gather_metadata$1() {
@@ -27445,7 +27536,7 @@ const UNASSIGNED = "unassigned";
27445
27536
 
27446
27537
  function LocalCommitStatus(props) {
27447
27538
  const argv = Store.useState((state) => state.argv);
27448
- const fallback = (reactExports.createElement(Text, { color: colors.yellow }, "Fetching PR status from Github..."));
27539
+ const fallback = (reactExports.createElement(Text, { color: colors.yellow }, "Fetching PR status from Github\u2026"));
27449
27540
  if (argv["mock-metadata"]) {
27450
27541
  return (reactExports.createElement(Await, { fallback: fallback, function: mock_metadata }, props.children));
27451
27542
  }
@@ -27539,7 +27630,7 @@ function encode(value) {
27539
27630
  }
27540
27631
 
27541
27632
  function LocalMergeRebase() {
27542
- return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits..."), function: run$3 }));
27633
+ return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits\u2026"), function: run$3 }));
27543
27634
  }
27544
27635
  async function run$3() {
27545
27636
  const state = Store.getState();
@@ -27647,7 +27738,7 @@ async function run$3() {
27647
27738
  actions.output(reactExports.createElement(Text, { color: colors.yellow },
27648
27739
  "Restoring ",
27649
27740
  reactExports.createElement(Brackets, null, branch_name),
27650
- "..."));
27741
+ "\u2026"));
27651
27742
  restore_git();
27652
27743
  actions.output(reactExports.createElement(Text, { color: colors.yellow },
27653
27744
  "Restored ",
@@ -27810,7 +27901,7 @@ const RE = {
27810
27901
  };
27811
27902
 
27812
27903
  function ManualRebase() {
27813
- return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits..."), function: run$2 }));
27904
+ return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits\u2026"), function: run$2 }));
27814
27905
  }
27815
27906
  async function run$2() {
27816
27907
  const state = Store.getState();
@@ -28129,7 +28220,7 @@ echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
28129
28220
  actions.output(reactExports.createElement(Text, { color: colors.yellow },
28130
28221
  "Restoring ",
28131
28222
  reactExports.createElement(Brackets, null, branch_name),
28132
- "..."));
28223
+ "\u2026"));
28133
28224
  restore_git();
28134
28225
  actions.output(reactExports.createElement(Text, { color: colors.yellow },
28135
28226
  "Restored ",
@@ -28883,22 +28974,27 @@ function RebaseCheck(props) {
28883
28974
  case "done":
28884
28975
  return props.children;
28885
28976
  case "prompt":
28886
- return (reactExports.createElement(YesNoPrompt, { message: reactExports.createElement(Text, { color: colors.yellow }, "Rebase detected, would you like to abort it?"), onYes: async () => {
28977
+ return (reactExports.createElement(YesNoPrompt, { message: reactExports.createElement(Text, { color: colors.yellow },
28978
+ reactExports.createElement(Command, null, "git rebase"),
28979
+ " detected, would you like to abort it?"), onYes: async () => {
28887
28980
  await cli(`git rebase --abort`);
28888
28981
  patch({ status: "done" });
28889
28982
  }, onNo: async () => {
28890
28983
  actions.exit(0);
28891
28984
  } }));
28892
28985
  default:
28893
- return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Checking for rebase..."), function: rebase_check }));
28986
+ return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
28987
+ "Checking for ",
28988
+ reactExports.createElement(Command, null, "git rebase"),
28989
+ "\u2026"), function: rebase_check }));
28894
28990
  }
28895
28991
  async function rebase_check() {
28896
28992
  const actions = Store.getState().actions;
28897
28993
  try {
28898
- const repo_root = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
28994
+ const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
28899
28995
  let is_rebase = false;
28900
- is_rebase ||= fs.existsSync(path.join(repo_root, "rebase-apply"));
28901
- is_rebase ||= fs.existsSync(path.join(repo_root, "rebase-merge"));
28996
+ is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-apply"));
28997
+ is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-merge"));
28902
28998
  const status = is_rebase ? "prompt" : "done";
28903
28999
  patch({ status });
28904
29000
  }
@@ -28937,12 +29033,14 @@ function App() {
28937
29033
  actions.exit(0);
28938
29034
  }
28939
29035
  } },
28940
- reactExports.createElement(RebaseCheck, null,
28941
- reactExports.createElement(DependencyCheck, null,
28942
- !argv.verbose ? null : reactExports.createElement(GithubApiError, null),
28943
- reactExports.createElement(GatherMetadata, null,
28944
- reactExports.createElement(LocalCommitStatus, null,
28945
- reactExports.createElement(Main, null))))))));
29036
+ reactExports.createElement(DependencyCheck, null,
29037
+ reactExports.createElement(DirtyCheck, null,
29038
+ reactExports.createElement(RebaseCheck, null,
29039
+ reactExports.createElement(CherryPickCheck, null,
29040
+ !argv.verbose ? null : reactExports.createElement(GithubApiError, null),
29041
+ reactExports.createElement(GatherMetadata, null,
29042
+ reactExports.createElement(LocalCommitStatus, null,
29043
+ reactExports.createElement(Main, null))))))))));
28946
29044
  }
28947
29045
 
28948
29046
  const align = {
@@ -34320,7 +34418,7 @@ async function command() {
34320
34418
  .wrap(123)
34321
34419
  // disallow unknown options
34322
34420
  .strict()
34323
- .version("1.3.6" )
34421
+ .version("1.4.0" )
34324
34422
  .showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`")
34325
34423
  .help("help", "Show usage via `git stack help`").argv);
34326
34424
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-stack-cli",
3
- "version": "1.3.6",
3
+ "version": "1.4.0",
4
4
  "description": "",
5
5
  "author": "magus",
6
6
  "license": "MIT",
package/src/app/App.tsx CHANGED
@@ -1,8 +1,10 @@
1
1
  import * as React from "react";
2
2
 
3
3
  import { AutoUpdate } from "~/app/AutoUpdate";
4
+ import { CherryPickCheck } from "~/app/CherryPickCheck";
4
5
  import { Debug } from "~/app/Debug";
5
6
  import { DependencyCheck } from "~/app/DependencyCheck";
7
+ import { DirtyCheck } from "~/app/DirtyCheck";
6
8
  import { GatherMetadata } from "~/app/GatherMetadata";
7
9
  import { GithubApiError } from "~/app/GithubApiError";
8
10
  import { LocalCommitStatus } from "~/app/LocalCommitStatus";
@@ -48,17 +50,21 @@ export function App() {
48
50
  }
49
51
  }}
50
52
  >
51
- <RebaseCheck>
52
- <DependencyCheck>
53
- {!argv.verbose ? null : <GithubApiError />}
53
+ <DependencyCheck>
54
+ <DirtyCheck>
55
+ <RebaseCheck>
56
+ <CherryPickCheck>
57
+ {!argv.verbose ? null : <GithubApiError />}
54
58
 
55
- <GatherMetadata>
56
- <LocalCommitStatus>
57
- <Main />
58
- </LocalCommitStatus>
59
- </GatherMetadata>
60
- </DependencyCheck>
61
- </RebaseCheck>
59
+ <GatherMetadata>
60
+ <LocalCommitStatus>
61
+ <Main />
62
+ </LocalCommitStatus>
63
+ </GatherMetadata>
64
+ </CherryPickCheck>
65
+ </RebaseCheck>
66
+ </DirtyCheck>
67
+ </DependencyCheck>
62
68
  </AutoUpdate>
63
69
  </Providers>
64
70
  );
@@ -0,0 +1,94 @@
1
+ import * as React from "react";
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ import * as Ink from "ink-cjs";
7
+
8
+ import { Await } from "~/app/Await";
9
+ import { Command } from "~/app/Command";
10
+ import { Store } from "~/app/Store";
11
+ import { YesNoPrompt } from "~/app/YesNoPrompt";
12
+ import { cli } from "~/core/cli";
13
+ import { colors } from "~/core/colors";
14
+
15
+ type Props = {
16
+ children: React.ReactNode;
17
+ };
18
+
19
+ type State = {
20
+ status: "init" | "prompt" | "done";
21
+ };
22
+
23
+ function reducer(state: State, patch: Partial<State>) {
24
+ return { ...state, ...patch };
25
+ }
26
+
27
+ export function CherryPickCheck(props: Props) {
28
+ const actions = Store.useActions();
29
+
30
+ const [state, patch] = React.useReducer(reducer, {
31
+ status: "init",
32
+ });
33
+
34
+ switch (state.status) {
35
+ case "done":
36
+ return props.children;
37
+
38
+ case "prompt":
39
+ return (
40
+ <YesNoPrompt
41
+ message={
42
+ <Ink.Text color={colors.yellow}>
43
+ <Command>git cherry-pick</Command> detected, would you like to
44
+ abort it?
45
+ </Ink.Text>
46
+ }
47
+ onYes={async () => {
48
+ await cli(`git cherry-pick --abort`);
49
+ patch({ status: "done" });
50
+ }}
51
+ onNo={async () => {
52
+ actions.exit(0);
53
+ }}
54
+ />
55
+ );
56
+
57
+ default:
58
+ return (
59
+ <Await
60
+ fallback={
61
+ <Ink.Text color={colors.yellow}>
62
+ Checking for <Command>git cherry-pick</Command>…
63
+ </Ink.Text>
64
+ }
65
+ function={cherry_pick_check}
66
+ />
67
+ );
68
+ }
69
+
70
+ async function cherry_pick_check() {
71
+ const actions = Store.getState().actions;
72
+
73
+ try {
74
+ const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
75
+
76
+ const is_cherry_pick = fs.existsSync(
77
+ path.join(git_dir, "CHERRY_PICK_HEAD")
78
+ );
79
+
80
+ const status = is_cherry_pick ? "prompt" : "done";
81
+ patch({ status });
82
+ } catch (err) {
83
+ actions.error("Must be run from within a git repository.");
84
+
85
+ if (err instanceof Error) {
86
+ if (actions.isDebug()) {
87
+ actions.error(err.message);
88
+ }
89
+ }
90
+
91
+ actions.exit(9);
92
+ }
93
+ }
94
+ }
@@ -39,7 +39,7 @@ function CheckGit(props: Props) {
39
39
  <Await
40
40
  fallback={
41
41
  <Ink.Text color={colors.yellow}>
42
- Checking <Command>git</Command> install...
42
+ Checking <Command>git</Command> install
43
43
  </Ink.Text>
44
44
  }
45
45
  function={async () => {
@@ -74,7 +74,7 @@ function CheckGithubCli(props: Props) {
74
74
  fallback={
75
75
  <Ink.Text color={colors.yellow}>
76
76
  <Ink.Text>
77
- Checking <Command>gh</Command> install...
77
+ Checking <Command>gh</Command> install
78
78
  </Ink.Text>
79
79
  </Ink.Text>
80
80
  }
@@ -117,7 +117,7 @@ function CheckGithubCliAuth(props: Props) {
117
117
  fallback={
118
118
  <Ink.Text color={colors.yellow}>
119
119
  <Ink.Text>
120
- Checking <Command>gh auth status</Command>...
120
+ Checking <Command>gh auth status</Command>…
121
121
  </Ink.Text>
122
122
  </Ink.Text>
123
123
  }
@@ -175,7 +175,7 @@ function CheckGitRevise(props: Props) {
175
175
  fallback={
176
176
  <Ink.Text color={colors.yellow}>
177
177
  <Ink.Text>
178
- Checking <Command>git revise</Command> install...
178
+ Checking <Command>git revise</Command> install
179
179
  </Ink.Text>
180
180
  </Ink.Text>
181
181
  }
@@ -0,0 +1,91 @@
1
+ import * as React from "react";
2
+
3
+ import * as Ink from "ink-cjs";
4
+
5
+ import { Await } from "~/app/Await";
6
+ import { Command } from "~/app/Command";
7
+ import { FormatText } from "~/app/FormatText";
8
+ import { Store } from "~/app/Store";
9
+ import { YesNoPrompt } from "~/app/YesNoPrompt";
10
+ import { cli } from "~/core/cli";
11
+ import { colors } from "~/core/colors";
12
+
13
+ type Props = {
14
+ children: React.ReactNode;
15
+ };
16
+
17
+ type State = {
18
+ status: "init" | "prompt" | "done";
19
+ };
20
+
21
+ function reducer(state: State, patch: Partial<State>) {
22
+ return { ...state, ...patch };
23
+ }
24
+
25
+ export function DirtyCheck(props: Props) {
26
+ const actions = Store.useActions();
27
+
28
+ const [state, patch] = React.useReducer(reducer, {
29
+ status: "init",
30
+ });
31
+
32
+ switch (state.status) {
33
+ case "done":
34
+ return props.children;
35
+
36
+ case "prompt":
37
+ return (
38
+ <YesNoPrompt
39
+ message={
40
+ <FormatText
41
+ wrapper={<Ink.Text color={colors.yellow} />}
42
+ message="{git} repo is dirty, changed may be lost during {git_stack}, are you sure you wannt to proceed?"
43
+ values={{
44
+ git: <Command>git</Command>,
45
+ git_stack: <Command>git stack</Command>,
46
+ }}
47
+ />
48
+ }
49
+ onYes={async () => {
50
+ patch({ status: "done" });
51
+ }}
52
+ onNo={async () => {
53
+ actions.exit(0);
54
+ }}
55
+ />
56
+ );
57
+
58
+ default:
59
+ return (
60
+ <Await
61
+ fallback={
62
+ <Ink.Text color={colors.yellow}>
63
+ Ensuring <Command>git status --porcelain</Command>…
64
+ </Ink.Text>
65
+ }
66
+ function={rebase_check}
67
+ />
68
+ );
69
+ }
70
+
71
+ async function rebase_check() {
72
+ const actions = Store.getState().actions;
73
+
74
+ try {
75
+ const git_dirty = (await cli(`git status --porcelain`)).stdout;
76
+
77
+ const status = git_dirty ? "prompt" : "done";
78
+ patch({ status });
79
+ } catch (err) {
80
+ actions.error("Must be run from within a git repository.");
81
+
82
+ if (err instanceof Error) {
83
+ if (actions.isDebug()) {
84
+ actions.error(err.message);
85
+ }
86
+ }
87
+
88
+ actions.exit(9);
89
+ }
90
+ }
91
+ }
@@ -16,9 +16,7 @@ type Props = {
16
16
 
17
17
  export function GatherMetadata(props: Props) {
18
18
  const fallback = (
19
- <Ink.Text color={colors.yellow}>
20
- Gathering local git information...
21
- </Ink.Text>
19
+ <Ink.Text color={colors.yellow}>Gathering local git information…</Ink.Text>
22
20
  );
23
21
 
24
22
  return (
@@ -16,7 +16,7 @@ export function LocalCommitStatus(props: Props) {
16
16
  const argv = Store.useState((state) => state.argv);
17
17
 
18
18
  const fallback = (
19
- <Ink.Text color={colors.yellow}>Fetching PR status from Github...</Ink.Text>
19
+ <Ink.Text color={colors.yellow}>Fetching PR status from Github…</Ink.Text>
20
20
  );
21
21
 
22
22
  if (argv["mock-metadata"]) {
@@ -18,7 +18,7 @@ import { short_id } from "~/core/short_id";
18
18
  export function LocalMergeRebase() {
19
19
  return (
20
20
  <Await
21
- fallback={<Ink.Text color={colors.yellow}>Rebasing commits...</Ink.Text>}
21
+ fallback={<Ink.Text color={colors.yellow}>Rebasing commits…</Ink.Text>}
22
22
  function={run}
23
23
  />
24
24
  );
@@ -174,7 +174,7 @@ async function run() {
174
174
  function handle_exit() {
175
175
  actions.output(
176
176
  <Ink.Text color={colors.yellow}>
177
- Restoring <Brackets>{branch_name}</Brackets>...
177
+ Restoring <Brackets>{branch_name}</Brackets>…
178
178
  </Ink.Text>
179
179
  );
180
180
 
@@ -23,7 +23,7 @@ import { short_id } from "~/core/short_id";
23
23
  export function ManualRebase() {
24
24
  return (
25
25
  <Await
26
- fallback={<Ink.Text color={colors.yellow}>Rebasing commits...</Ink.Text>}
26
+ fallback={<Ink.Text color={colors.yellow}>Rebasing commits…</Ink.Text>}
27
27
  function={run}
28
28
  />
29
29
  );
@@ -423,7 +423,7 @@ async function run() {
423
423
  function handle_exit() {
424
424
  actions.output(
425
425
  <Ink.Text color={colors.yellow}>
426
- Restoring <Brackets>{branch_name}</Brackets>...
426
+ Restoring <Brackets>{branch_name}</Brackets>…
427
427
  </Ink.Text>
428
428
  );
429
429
 
@@ -6,6 +6,7 @@ import path from "node:path";
6
6
  import * as Ink from "ink-cjs";
7
7
 
8
8
  import { Await } from "~/app/Await";
9
+ import { Command } from "~/app/Command";
9
10
  import { Store } from "~/app/Store";
10
11
  import { YesNoPrompt } from "~/app/YesNoPrompt";
11
12
  import { cli } from "~/core/cli";
@@ -39,7 +40,8 @@ export function RebaseCheck(props: Props) {
39
40
  <YesNoPrompt
40
41
  message={
41
42
  <Ink.Text color={colors.yellow}>
42
- Rebase detected, would you like to abort it?
43
+ <Command>git rebase</Command> detected, would you like to abort
44
+ it?
43
45
  </Ink.Text>
44
46
  }
45
47
  onYes={async () => {
@@ -56,7 +58,9 @@ export function RebaseCheck(props: Props) {
56
58
  return (
57
59
  <Await
58
60
  fallback={
59
- <Ink.Text color={colors.yellow}>Checking for rebase...</Ink.Text>
61
+ <Ink.Text color={colors.yellow}>
62
+ Checking for <Command>git rebase</Command>…
63
+ </Ink.Text>
60
64
  }
61
65
  function={rebase_check}
62
66
  />
@@ -67,11 +71,11 @@ export function RebaseCheck(props: Props) {
67
71
  const actions = Store.getState().actions;
68
72
 
69
73
  try {
70
- const repo_root = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
74
+ const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
71
75
 
72
76
  let is_rebase = false;
73
- is_rebase ||= fs.existsSync(path.join(repo_root, "rebase-apply"));
74
- is_rebase ||= fs.existsSync(path.join(repo_root, "rebase-merge"));
77
+ is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-apply"));
78
+ is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-merge"));
75
79
 
76
80
  const status = is_rebase ? "prompt" : "done";
77
81
  patch({ status });