git-sync-tui 0.1.2 → 0.1.3

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 (2) hide show
  1. package/dist/cli.js +551 -296
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -1,17 +1,113 @@
1
1
  #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
2
8
 
3
9
  // src/cli.tsx
4
10
  import { render } from "ink";
5
11
  import meow from "meow";
6
12
 
7
13
  // src/app.tsx
8
- import { useState as useState6, useEffect as useEffect3, useRef as useRef2, useCallback as useCallback2 } from "react";
9
- import { Box as Box7, Text as Text7, useApp } from "ink";
10
- import { Spinner as Spinner5 } from "@inkjs/ui";
14
+ import { useState as useState7, useEffect as useEffect4, useRef as useRef2, useCallback as useCallback2 } from "react";
15
+ import { Box as Box9, useApp } from "ink";
16
+ import { Spinner as Spinner6 } from "@inkjs/ui";
11
17
 
12
- // src/components/stash-prompt.tsx
13
- import { Box, Text, useInput } from "ink";
18
+ // src/components/ui.tsx
19
+ import React from "react";
20
+ import { Box, Text } from "ink";
14
21
  import { jsx, jsxs } from "react/jsx-runtime";
22
+ var STEP_LABELS = ["Remote", "Branch", "Commits", "Confirm", "Sync"];
23
+ function StepProgress({ current }) {
24
+ return /* @__PURE__ */ jsx(Box, { children: STEP_LABELS.map((label, i) => {
25
+ const step = i + 1;
26
+ const isActive = step === current;
27
+ const isDone = step < current;
28
+ const isLast = i === STEP_LABELS.length - 1;
29
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
30
+ /* @__PURE__ */ jsxs(Text, { color: isActive ? "cyan" : isDone ? "green" : "gray", dimColor: !isActive && !isDone, children: [
31
+ isDone ? "\u25CF" : isActive ? "\u25C6" : "\u25CB",
32
+ " ",
33
+ isActive ? /* @__PURE__ */ jsx(Text, { bold: true, children: label }) : label
34
+ ] }),
35
+ !isLast && /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: " \u2500 " })
36
+ ] }, label);
37
+ }) });
38
+ }
39
+ function SectionHeader({ title, subtitle }) {
40
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
41
+ /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
42
+ "\u25B8 ",
43
+ title
44
+ ] }),
45
+ subtitle && /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
46
+ " ",
47
+ subtitle
48
+ ] })
49
+ ] });
50
+ }
51
+ function KeyHints({ hints }) {
52
+ return /* @__PURE__ */ jsx(Box, { gap: 1, flexWrap: "wrap", children: hints.map(({ key, label }) => /* @__PURE__ */ jsxs(Box, { children: [
53
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "[" }),
54
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: key }),
55
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "]" }),
56
+ /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
57
+ " ",
58
+ label
59
+ ] })
60
+ ] }, key)) });
61
+ }
62
+ function InlineKeys({ hints }) {
63
+ return /* @__PURE__ */ jsx(Box, { gap: 1, children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
64
+ /* @__PURE__ */ jsxs(Text, { color: "green", children: [
65
+ "[",
66
+ key,
67
+ "]"
68
+ ] }),
69
+ /* @__PURE__ */ jsxs(Text, { children: [
70
+ " ",
71
+ label
72
+ ] }),
73
+ i < hints.length - 1 && /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: " / " })
74
+ ] }, key)) });
75
+ }
76
+ var PANEL_CONFIG = {
77
+ info: { icon: "\u25C6", color: "cyan", borderColor: "cyan" },
78
+ warn: { icon: "\u25B2", color: "yellow", borderColor: "yellow" },
79
+ error: { icon: "\u2716", color: "red", borderColor: "red" },
80
+ success: { icon: "\u2714", color: "green", borderColor: "green" }
81
+ };
82
+ function StatusPanel({ type, title, children }) {
83
+ const { icon, color, borderColor } = PANEL_CONFIG[type];
84
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor, paddingX: 1, children: [
85
+ /* @__PURE__ */ jsxs(Text, { bold: true, color, children: [
86
+ icon,
87
+ " ",
88
+ title
89
+ ] }),
90
+ children
91
+ ] });
92
+ }
93
+ function AppHeader({ step, stashed }) {
94
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
95
+ /* @__PURE__ */ jsxs(Box, { children: [
96
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u25C7 " }),
97
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "git-sync-tui" }),
98
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: " cherry-pick --no-commit" }),
99
+ stashed && /* @__PURE__ */ jsx(Text, { color: "yellow", children: " \u25AA stashed" })
100
+ ] }),
101
+ /* @__PURE__ */ jsxs(Box, { children: [
102
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: " " }),
103
+ /* @__PURE__ */ jsx(StepProgress, { current: step })
104
+ ] })
105
+ ] });
106
+ }
107
+
108
+ // src/components/stash-prompt.tsx
109
+ import { Box as Box2, Text as Text2, useInput } from "ink";
110
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
15
111
  function StashPrompt({ onConfirm, onSkip }) {
16
112
  useInput((input) => {
17
113
  if (input === "y" || input === "Y") {
@@ -20,31 +116,27 @@ function StashPrompt({ onConfirm, onSkip }) {
20
116
  onSkip();
21
117
  }
22
118
  });
23
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
24
- /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "yellow", paddingX: 1, flexDirection: "column", children: [
25
- /* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: "\u68C0\u6D4B\u5230\u5DE5\u4F5C\u533A\u6709\u672A\u63D0\u4EA4\u7684\u53D8\u66F4" }),
26
- /* @__PURE__ */ jsx(Text, { color: "gray", children: "Cherry-pick \u64CD\u4F5C\u53EF\u80FD\u4F1A\u4E0E\u672A\u63D0\u4EA4\u7684\u5185\u5BB9\u51B2\u7A81" })
27
- ] }),
28
- /* @__PURE__ */ jsxs(Box, { children: [
29
- /* @__PURE__ */ jsx(Text, { bold: true, children: "\u662F\u5426\u81EA\u52A8 stash \u4FDD\u5B58\u5F53\u524D\u53D8\u66F4? " }),
30
- /* @__PURE__ */ jsx(Text, { color: "green", children: "[y]" }),
31
- /* @__PURE__ */ jsx(Text, { children: " \u662F / " }),
32
- /* @__PURE__ */ jsx(Text, { color: "red", children: "[n]" }),
33
- /* @__PURE__ */ jsx(Text, { children: " \u5426\uFF0C\u7EE7\u7EED\u64CD\u4F5C" })
119
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", gap: 1, children: [
120
+ /* @__PURE__ */ jsx2(StatusPanel, { type: "warn", title: "\u5DE5\u4F5C\u533A\u6709\u672A\u63D0\u4EA4\u7684\u53D8\u66F4", children: /* @__PURE__ */ jsx2(Text2, { color: "gray", children: " Cherry-pick \u64CD\u4F5C\u53EF\u80FD\u4F1A\u4E0E\u672A\u63D0\u4EA4\u7684\u5185\u5BB9\u51B2\u7A81" }) }),
121
+ /* @__PURE__ */ jsxs2(Box2, { children: [
122
+ /* @__PURE__ */ jsx2(Text2, { bold: true, children: "\u81EA\u52A8 stash \u4FDD\u5B58\u5F53\u524D\u53D8\u66F4? " }),
123
+ /* @__PURE__ */ jsx2(InlineKeys, { hints: [
124
+ { key: "y", label: "\u662F" },
125
+ { key: "n", label: "\u5426\uFF0C\u7EE7\u7EED" }
126
+ ] })
34
127
  ] })
35
128
  ] });
36
129
  }
37
130
 
38
- // src/components/remote-select.tsx
39
- import { useState as useState2 } from "react";
40
- import { Box as Box2, Text as Text2 } from "ink";
41
- import { Select, Spinner, TextInput } from "@inkjs/ui";
42
-
43
- // src/hooks/use-git.ts
44
- import { useState, useEffect, useCallback } from "react";
131
+ // src/components/stash-recovery.tsx
132
+ import { useState, useEffect } from "react";
133
+ import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
134
+ import { Spinner } from "@inkjs/ui";
45
135
 
46
136
  // src/utils/git.ts
47
137
  import simpleGit from "simple-git";
138
+ import { existsSync, writeFileSync, unlinkSync, readFileSync } from "fs";
139
+ import { join } from "path";
48
140
  var gitInstance = null;
49
141
  function getGit(cwd) {
50
142
  if (!gitInstance || cwd) {
@@ -183,10 +275,115 @@ async function stashPop() {
183
275
  return false;
184
276
  }
185
277
  }
278
+ var STASH_GUARD_FILE = "git-sync-tui-stash-guard";
279
+ async function getGitDir() {
280
+ const git = getGit();
281
+ const dir = await git.revparse(["--git-dir"]);
282
+ return dir.trim();
283
+ }
284
+ async function writeStashGuard() {
285
+ try {
286
+ const gitDir = await getGitDir();
287
+ writeFileSync(join(gitDir, STASH_GUARD_FILE), (/* @__PURE__ */ new Date()).toISOString(), "utf-8");
288
+ } catch {
289
+ }
290
+ }
291
+ async function removeStashGuard() {
292
+ try {
293
+ const gitDir = await getGitDir();
294
+ const guardPath = join(gitDir, STASH_GUARD_FILE);
295
+ if (existsSync(guardPath)) {
296
+ unlinkSync(guardPath);
297
+ }
298
+ } catch {
299
+ }
300
+ }
301
+ function removeStashGuardSync() {
302
+ try {
303
+ const { execSync: execSync2 } = __require("child_process");
304
+ const gitDir = String(execSync2("git rev-parse --git-dir", { encoding: "utf-8" })).trim();
305
+ const guardPath = join(gitDir, STASH_GUARD_FILE);
306
+ if (existsSync(guardPath)) {
307
+ unlinkSync(guardPath);
308
+ }
309
+ } catch {
310
+ }
311
+ }
312
+ async function checkStashGuard() {
313
+ try {
314
+ const gitDir = await getGitDir();
315
+ const guardPath = join(gitDir, STASH_GUARD_FILE);
316
+ if (existsSync(guardPath)) {
317
+ const timestamp = readFileSync(guardPath, "utf-8").trim();
318
+ return { exists: true, timestamp };
319
+ }
320
+ } catch {
321
+ }
322
+ return { exists: false };
323
+ }
324
+ async function findStashEntry() {
325
+ const git = getGit();
326
+ try {
327
+ const result = await git.stash(["list"]);
328
+ const lines = result.trim().split("\n");
329
+ for (const line of lines) {
330
+ if (line.includes("Auto-stash by git-sync-tui")) {
331
+ return line;
332
+ }
333
+ }
334
+ } catch {
335
+ }
336
+ return null;
337
+ }
338
+
339
+ // src/components/stash-recovery.tsx
340
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
341
+ function StashRecovery({ timestamp, onRecover, onSkip }) {
342
+ const [stashEntry, setStashEntry] = useState(void 0);
343
+ useEffect(() => {
344
+ findStashEntry().then(setStashEntry);
345
+ }, []);
346
+ useInput2((input) => {
347
+ if (input === "y" || input === "Y") {
348
+ onRecover();
349
+ } else if (input === "n" || input === "N") {
350
+ onSkip();
351
+ }
352
+ });
353
+ if (stashEntry === void 0) {
354
+ return /* @__PURE__ */ jsx3(Spinner, { label: "\u68C0\u67E5 stash \u8BB0\u5F55..." });
355
+ }
356
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", gap: 1, children: [
357
+ /* @__PURE__ */ jsxs3(StatusPanel, { type: "warn", title: "\u68C0\u6D4B\u5230\u4E0A\u6B21\u8FD0\u884C\u4E2D\u65AD", children: [
358
+ timestamp && /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
359
+ " \u4E2D\u65AD\u65F6\u95F4: ",
360
+ timestamp
361
+ ] }),
362
+ stashEntry && /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
363
+ " Stash: ",
364
+ stashEntry
365
+ ] }),
366
+ !stashEntry && /* @__PURE__ */ jsx3(Text3, { color: "red", children: " \u672A\u627E\u5230\u5BF9\u5E94\u7684 stash \u6761\u76EE\uFF08\u53EF\u80FD\u5DF2\u624B\u52A8\u6062\u590D\uFF09" })
367
+ ] }),
368
+ /* @__PURE__ */ jsxs3(Box3, { children: [
369
+ /* @__PURE__ */ jsx3(Text3, { bold: true, children: stashEntry ? "\u6062\u590D stash? " : "\u6E05\u9664\u4E2D\u65AD\u6807\u8BB0? " }),
370
+ /* @__PURE__ */ jsx3(InlineKeys, { hints: [
371
+ { key: "y", label: "\u662F" },
372
+ { key: "n", label: "\u8DF3\u8FC7" }
373
+ ] })
374
+ ] })
375
+ ] });
376
+ }
377
+
378
+ // src/components/remote-select.tsx
379
+ import { useState as useState3 } from "react";
380
+ import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
381
+ import { Select, Spinner as Spinner2, TextInput } from "@inkjs/ui";
186
382
 
187
383
  // src/hooks/use-git.ts
384
+ import { useState as useState2, useEffect as useEffect2, useCallback } from "react";
188
385
  function useAsync(fn, deps = []) {
189
- const [state, setState] = useState({
386
+ const [state, setState] = useState2({
190
387
  data: null,
191
388
  loading: true,
192
389
  error: null
@@ -200,7 +397,7 @@ function useAsync(fn, deps = []) {
200
397
  setState({ data: null, loading: false, error: err.message });
201
398
  }
202
399
  }, deps);
203
- useEffect(() => {
400
+ useEffect2(() => {
204
401
  load();
205
402
  }, [load]);
206
403
  return { ...state, reload: load };
@@ -221,9 +418,9 @@ function useCommits(remote, branch, count = 30) {
221
418
  );
222
419
  }
223
420
  function useCommitStat(hashes) {
224
- const [stat, setStat] = useState("");
225
- const [loading, setLoading] = useState(false);
226
- useEffect(() => {
421
+ const [stat, setStat] = useState2("");
422
+ const [loading, setLoading] = useState2(false);
423
+ useEffect2(() => {
227
424
  if (hashes.length === 0) {
228
425
  setStat("");
229
426
  return;
@@ -241,31 +438,50 @@ function useCommitStat(hashes) {
241
438
  }
242
439
 
243
440
  // src/components/remote-select.tsx
244
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
245
- function RemoteSelect({ onSelect }) {
441
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
442
+ function extractRemoteName(url) {
443
+ const trimmed = url.trim().replace(/\/+$/, "").replace(/\.git$/, "");
444
+ const lastSegment = trimmed.split(/[/\\:]+/).filter(Boolean).pop() || "";
445
+ return lastSegment;
446
+ }
447
+ function RemoteSelect({ onSelect, onBack }) {
246
448
  const { data: remotes, loading, error, reload } = useRemotes();
247
- const [phase, setPhase] = useState2("list");
248
- const [customUrl, setCustomUrl] = useState2("");
249
- const [addError, setAddError] = useState2(null);
449
+ const [phase, setPhase] = useState3("list");
450
+ const [customUrl, setCustomUrl] = useState3("");
451
+ const [addError, setAddError] = useState3(null);
452
+ useInput3((_input, key) => {
453
+ if (key.escape) {
454
+ if (phase === "input-name") {
455
+ setPhase("input-url");
456
+ } else if (phase === "input-url") {
457
+ setPhase("list");
458
+ } else if (phase === "list") {
459
+ onBack?.();
460
+ }
461
+ }
462
+ });
250
463
  if (loading) {
251
- return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsx2(Spinner, { label: "\u6B63\u5728\u83B7\u53D6\u8FDC\u7A0B\u4ED3\u5E93\u5217\u8868..." }) });
464
+ return /* @__PURE__ */ jsx4(Spinner2, { label: "\u83B7\u53D6\u8FDC\u7A0B\u4ED3\u5E93..." });
252
465
  }
253
466
  if (error) {
254
- return /* @__PURE__ */ jsxs2(Text2, { color: "red", children: [
255
- "\u83B7\u53D6\u8FDC\u7A0B\u4ED3\u5E93\u5931\u8D25: ",
467
+ return /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
468
+ "\u2716 \u83B7\u53D6\u8FDC\u7A0B\u4ED3\u5E93\u5931\u8D25: ",
256
469
  error
257
470
  ] });
258
471
  }
259
472
  if (phase === "adding") {
260
- return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsx2(Spinner, { label: "\u6B63\u5728\u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93..." }) });
473
+ return /* @__PURE__ */ jsx4(Spinner2, { label: "\u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93..." });
261
474
  }
262
475
  if (phase === "input-url") {
263
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", gap: 1, children: [
264
- /* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "[1/5] \u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93" }),
265
- addError && /* @__PURE__ */ jsx2(Text2, { color: "red", children: addError }),
266
- /* @__PURE__ */ jsxs2(Box2, { children: [
267
- /* @__PURE__ */ jsx2(Text2, { children: "\u4ED3\u5E93\u5730\u5740: " }),
268
- /* @__PURE__ */ jsx2(
476
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
477
+ /* @__PURE__ */ jsx4(SectionHeader, { title: "\u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93" }),
478
+ addError && /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
479
+ "\u2716 ",
480
+ addError
481
+ ] }),
482
+ /* @__PURE__ */ jsxs4(Box4, { children: [
483
+ /* @__PURE__ */ jsx4(Text4, { color: "gray", children: "URL \u25B8 " }),
484
+ /* @__PURE__ */ jsx4(
269
485
  TextInput,
270
486
  {
271
487
  placeholder: "https://github.com/user/repo.git",
@@ -280,23 +496,24 @@ function RemoteSelect({ onSelect }) {
280
496
  }
281
497
  )
282
498
  ] }),
283
- /* @__PURE__ */ jsx2(Text2, { color: "gray", dimColor: true, children: "\u652F\u6301 HTTPS / SSH \u5730\u5740" })
499
+ /* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, children: " \u652F\u6301 HTTPS / SSH \u5730\u5740" })
284
500
  ] });
285
501
  }
286
502
  if (phase === "input-name") {
287
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", gap: 1, children: [
288
- /* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "[1/5] \u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93" }),
289
- /* @__PURE__ */ jsxs2(Text2, { color: "gray", children: [
290
- "\u5730\u5740: ",
291
- customUrl
503
+ const defaultName = extractRemoteName(customUrl);
504
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
505
+ /* @__PURE__ */ jsx4(SectionHeader, { title: "\u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93", subtitle: customUrl }),
506
+ addError && /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
507
+ "\u2716 ",
508
+ addError
292
509
  ] }),
293
- addError && /* @__PURE__ */ jsx2(Text2, { color: "red", children: addError }),
294
- /* @__PURE__ */ jsxs2(Box2, { children: [
295
- /* @__PURE__ */ jsx2(Text2, { children: "\u8FDC\u7A0B\u540D\u79F0: " }),
296
- /* @__PURE__ */ jsx2(
510
+ /* @__PURE__ */ jsxs4(Box4, { children: [
511
+ /* @__PURE__ */ jsx4(Text4, { color: "gray", children: "\u540D\u79F0 \u25B8 " }),
512
+ /* @__PURE__ */ jsx4(
297
513
  TextInput,
298
514
  {
299
- placeholder: "upstream",
515
+ placeholder: defaultName || "upstream",
516
+ defaultValue: defaultName,
300
517
  onSubmit: async (name) => {
301
518
  const remoteName = name.trim();
302
519
  if (!remoteName) {
@@ -333,9 +550,9 @@ function RemoteSelect({ onSelect }) {
333
550
  value: "__add_custom__"
334
551
  }
335
552
  ];
336
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", gap: 1, children: [
337
- /* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "[1/5] \u9009\u62E9\u8FDC\u7A0B\u4ED3\u5E93" }),
338
- /* @__PURE__ */ jsx2(
553
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
554
+ /* @__PURE__ */ jsx4(SectionHeader, { title: "\u9009\u62E9\u8FDC\u7A0B\u4ED3\u5E93" }),
555
+ /* @__PURE__ */ jsx4(
339
556
  Select,
340
557
  {
341
558
  options,
@@ -352,66 +569,63 @@ function RemoteSelect({ onSelect }) {
352
569
  }
353
570
 
354
571
  // src/components/branch-select.tsx
355
- import { useState as useState3, useMemo } from "react";
356
- import { Box as Box3, Text as Text3 } from "ink";
357
- import { Select as Select2, Spinner as Spinner2, TextInput as TextInput2 } from "@inkjs/ui";
358
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
359
- function BranchSelect({ remote, onSelect }) {
572
+ import { useState as useState4, useMemo } from "react";
573
+ import { Box as Box5, Text as Text5, useInput as useInput4 } from "ink";
574
+ import { Select as Select2, Spinner as Spinner3, TextInput as TextInput2 } from "@inkjs/ui";
575
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
576
+ function BranchSelect({ remote, onSelect, onBack }) {
360
577
  const { data: branches, loading, error } = useBranches(remote);
361
- const [filter, setFilter] = useState3("");
578
+ const [filter, setFilter] = useState4("");
579
+ useInput4((_input, key) => {
580
+ if (key.escape) onBack?.();
581
+ });
362
582
  const filteredOptions = useMemo(() => {
363
583
  if (!branches) return [];
364
584
  const filtered = filter ? branches.filter((b) => b.toLowerCase().includes(filter.toLowerCase())) : branches;
365
585
  return filtered.map((b) => ({ label: b, value: b }));
366
586
  }, [branches, filter]);
367
587
  if (loading) {
368
- return /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Spinner2, { label: `\u6B63\u5728\u83B7\u53D6 ${remote} \u7684\u5206\u652F\u5217\u8868...` }) });
588
+ return /* @__PURE__ */ jsx5(Spinner3, { label: `\u83B7\u53D6 ${remote} \u7684\u5206\u652F\u5217\u8868...` });
369
589
  }
370
590
  if (error) {
371
- return /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
372
- "\u83B7\u53D6\u5206\u652F\u5217\u8868\u5931\u8D25: ",
591
+ return /* @__PURE__ */ jsxs5(Text5, { color: "red", children: [
592
+ "\u2716 \u83B7\u53D6\u5206\u652F\u5217\u8868\u5931\u8D25: ",
373
593
  error
374
594
  ] });
375
595
  }
376
596
  if (!branches || branches.length === 0) {
377
- return /* @__PURE__ */ jsx3(Text3, { color: "red", children: "\u672A\u627E\u5230\u8FDC\u7A0B\u5206\u652F" });
597
+ return /* @__PURE__ */ jsx5(Text5, { color: "red", children: "\u2716 \u672A\u627E\u5230\u8FDC\u7A0B\u5206\u652F" });
378
598
  }
379
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", gap: 1, children: [
380
- /* @__PURE__ */ jsxs3(Text3, { bold: true, color: "cyan", children: [
381
- "[2/5] \u9009\u62E9\u5206\u652F (",
382
- remote,
383
- ")"
384
- ] }),
385
- /* @__PURE__ */ jsxs3(Box3, { children: [
386
- /* @__PURE__ */ jsx3(Text3, { color: "gray", children: "\u641C\u7D22: " }),
387
- /* @__PURE__ */ jsx3(
599
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, children: [
600
+ /* @__PURE__ */ jsx5(SectionHeader, { title: `\u9009\u62E9\u5206\u652F`, subtitle: `${remote} \xB7 ${branches.length} \u4E2A\u5206\u652F` }),
601
+ /* @__PURE__ */ jsxs5(Box5, { children: [
602
+ /* @__PURE__ */ jsx5(Text5, { color: "gray", children: "/ " }),
603
+ /* @__PURE__ */ jsx5(
388
604
  TextInput2,
389
605
  {
390
- placeholder: "\u8F93\u5165\u5173\u952E\u5B57\u8FC7\u6EE4\u5206\u652F...",
606
+ placeholder: "\u8F93\u5165\u5173\u952E\u5B57\u8FC7\u6EE4...",
391
607
  onChange: setFilter
392
608
  }
393
- )
394
- ] }),
395
- /* @__PURE__ */ jsxs3(Text3, { color: "gray", dimColor: true, children: [
396
- "\u5171 ",
397
- branches.length,
398
- " \u4E2A\u5206\u652F",
399
- filter ? `\uFF0C\u5339\u914D ${filteredOptions.length} \u4E2A` : ""
609
+ ),
610
+ filter && /* @__PURE__ */ jsxs5(Text5, { color: "gray", dimColor: true, children: [
611
+ " \xB7 \u5339\u914D ",
612
+ filteredOptions.length
613
+ ] })
400
614
  ] }),
401
- filteredOptions.length > 0 ? /* @__PURE__ */ jsx3(Select2, { options: filteredOptions, onChange: onSelect }) : /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: "\u65E0\u5339\u914D\u5206\u652F" })
615
+ filteredOptions.length > 0 ? /* @__PURE__ */ jsx5(Select2, { options: filteredOptions, onChange: onSelect }) : /* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "\u25B2 \u65E0\u5339\u914D\u5206\u652F" })
402
616
  ] });
403
617
  }
404
618
 
405
619
  // src/components/commit-list.tsx
406
- import { useState as useState4, useMemo as useMemo2, useRef } from "react";
407
- import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
408
- import { Spinner as Spinner3 } from "@inkjs/ui";
409
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
410
- function CommitList({ remote, branch, onSelect }) {
620
+ import { useState as useState5, useMemo as useMemo2, useRef } from "react";
621
+ import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
622
+ import { Spinner as Spinner4 } from "@inkjs/ui";
623
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
624
+ function CommitList({ remote, branch, onSelect, onBack }) {
411
625
  const { data: commits, loading, error } = useCommits(remote, branch, 30);
412
- const [selectedIndex, setSelectedIndex] = useState4(0);
413
- const [selectedHashes, setSelectedHashes] = useState4(/* @__PURE__ */ new Set());
414
- const [shiftMode, setShiftMode] = useState4(false);
626
+ const [selectedIndex, setSelectedIndex] = useState5(0);
627
+ const [selectedHashes, setSelectedHashes] = useState5(/* @__PURE__ */ new Set());
628
+ const [shiftMode, setShiftMode] = useState5(false);
415
629
  const anchorIndexRef = useRef(null);
416
630
  const selectedKey = useMemo2(() => Array.from(selectedHashes).sort().join(","), [selectedHashes]);
417
631
  const selectedArray = useMemo2(() => Array.from(selectedHashes), [selectedKey]);
@@ -458,9 +672,7 @@ function CommitList({ remote, branch, onSelect }) {
458
672
  setSelectedHashes((prev) => {
459
673
  const next = /* @__PURE__ */ new Set();
460
674
  for (const c of commits) {
461
- if (!prev.has(c.hash)) {
462
- next.add(c.hash);
463
- }
675
+ if (!prev.has(c.hash)) next.add(c.hash);
464
676
  }
465
677
  return next;
466
678
  });
@@ -475,7 +687,7 @@ function CommitList({ remote, branch, onSelect }) {
475
687
  return next;
476
688
  });
477
689
  };
478
- useInput2((input, key) => {
690
+ useInput5((input, key) => {
479
691
  if (!commits || commits.length === 0) return;
480
692
  if (key.shift) {
481
693
  if (!shiftMode) {
@@ -501,9 +713,7 @@ function CommitList({ remote, branch, onSelect }) {
501
713
  }
502
714
  return;
503
715
  }
504
- if (shiftMode) {
505
- setShiftMode(false);
506
- }
716
+ if (shiftMode) setShiftMode(false);
507
717
  if (key.upArrow) {
508
718
  setSelectedIndex((prev) => Math.max(0, prev - 1));
509
719
  } else if (key.downArrow) {
@@ -516,6 +726,8 @@ function CommitList({ remote, branch, onSelect }) {
516
726
  invertSelection();
517
727
  } else if (input === "r" || input === "R") {
518
728
  selectToCurrent();
729
+ } else if (key.escape) {
730
+ onBack?.();
519
731
  } else if (key.return) {
520
732
  if (selectedHashes.size > 0) {
521
733
  onSelect(Array.from(selectedHashes), commits);
@@ -523,120 +735,96 @@ function CommitList({ remote, branch, onSelect }) {
523
735
  }
524
736
  });
525
737
  if (loading) {
526
- return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(Spinner3, { label: `\u6B63\u5728\u83B7\u53D6 ${remote}/${branch} \u7684 commit \u5217\u8868...` }) });
738
+ return /* @__PURE__ */ jsx6(Spinner4, { label: `\u83B7\u53D6 ${remote}/${branch} \u7684 commit \u5217\u8868...` });
527
739
  }
528
740
  if (error) {
529
- return /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
530
- "\u83B7\u53D6 commit \u5217\u8868\u5931\u8D25: ",
741
+ return /* @__PURE__ */ jsxs6(Text6, { color: "red", children: [
742
+ "\u2716 \u83B7\u53D6 commit \u5217\u8868\u5931\u8D25: ",
531
743
  error
532
744
  ] });
533
745
  }
534
746
  if (!commits || commits.length === 0) {
535
- return /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: "\u8BE5\u5206\u652F\u6CA1\u6709 commit" });
747
+ return /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "\u25B2 \u8BE5\u5206\u652F\u6CA1\u6709 commit" });
536
748
  }
537
749
  const visibleCount = 10;
538
750
  const startIdx = Math.max(0, Math.min(selectedIndex - Math.floor(visibleCount / 2), commits.length - visibleCount));
539
751
  const visibleCommits = commits.slice(startIdx, startIdx + visibleCount);
540
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
541
- /* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: "[3/5] \u9009\u62E9\u8981\u540C\u6B65\u7684 commit" }),
542
- /* @__PURE__ */ jsxs4(Text4, { color: "gray", dimColor: true, children: [
543
- remote,
544
- "/",
545
- branch,
546
- " \u6700\u8FD1 ",
547
- commits.length,
548
- " \u4E2A commit | \u5DF2\u9009 ",
549
- selectedHashes.size,
550
- " \u4E2A",
551
- shiftMode && /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: " | Shift \u6A21\u5F0F" })
752
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 1, children: [
753
+ /* @__PURE__ */ jsx6(SectionHeader, { title: "\u9009\u62E9\u8981\u540C\u6B65\u7684 commit" }),
754
+ /* @__PURE__ */ jsxs6(Box6, { gap: 2, children: [
755
+ /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
756
+ remote,
757
+ "/",
758
+ branch
759
+ ] }),
760
+ /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
761
+ commits.length,
762
+ " commits"
763
+ ] }),
764
+ /* @__PURE__ */ jsxs6(Text6, { color: selectedHashes.size > 0 ? "cyan" : "gray", bold: selectedHashes.size > 0, children: [
765
+ "\u5DF2\u9009 ",
766
+ selectedHashes.size
767
+ ] }),
768
+ shiftMode && /* @__PURE__ */ jsx6(Text6, { color: "yellow", bold: true, children: "SHIFT" })
552
769
  ] }),
553
- /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
554
- startIdx > 0 && /* @__PURE__ */ jsxs4(Text4, { color: "gray", dimColor: true, children: [
770
+ /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
771
+ startIdx > 0 && /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
555
772
  " \u2191 ",
556
773
  startIdx,
557
- " more..."
774
+ " more"
558
775
  ] }),
559
776
  visibleCommits.map((c, i) => {
560
777
  const actualIdx = startIdx + i;
561
778
  const isSelected = selectedHashes.has(c.hash);
562
779
  const isCursor = actualIdx === selectedIndex;
563
780
  const isAnchor = actualIdx === anchorIndexRef.current;
564
- return /* @__PURE__ */ jsxs4(Text4, { children: [
565
- /* @__PURE__ */ jsxs4(Text4, { backgroundColor: isCursor ? "blue" : void 0, color: isSelected ? "green" : "white", children: [
566
- isCursor ? "\u25B6 " : " ",
567
- isAnchor ? "\u2693 " : isSelected ? "\u25CF " : "\u25CB ",
568
- c.shortHash,
781
+ return /* @__PURE__ */ jsxs6(Box6, { children: [
782
+ /* @__PURE__ */ jsxs6(Text6, { backgroundColor: isCursor ? "blue" : void 0, color: isSelected ? "green" : "white", children: [
783
+ isCursor ? "\u25B8 " : " ",
784
+ isAnchor ? "\u2693" : isSelected ? "\u25CF" : "\u25CB",
785
+ " "
786
+ ] }),
787
+ /* @__PURE__ */ jsx6(Text6, { backgroundColor: isCursor ? "blue" : void 0, color: "yellow", children: c.shortHash }),
788
+ /* @__PURE__ */ jsxs6(Text6, { backgroundColor: isCursor ? "blue" : void 0, color: isSelected ? "green" : "white", children: [
569
789
  " ",
570
790
  c.message
571
791
  ] }),
572
- /* @__PURE__ */ jsxs4(Text4, { color: "gray", dimColor: true, children: [
573
- " (",
792
+ /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
793
+ " ",
574
794
  c.author,
575
- ")"
795
+ " \xB7 ",
796
+ c.date
576
797
  ] })
577
798
  ] }, c.hash);
578
799
  }),
579
- startIdx + visibleCount < commits.length && /* @__PURE__ */ jsxs4(Text4, { color: "gray", dimColor: true, children: [
800
+ startIdx + visibleCount < commits.length && /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
580
801
  " \u2193 ",
581
802
  commits.length - startIdx - visibleCount,
582
- " more..."
803
+ " more"
583
804
  ] })
584
805
  ] }),
585
- /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 0, children: [
586
- /* @__PURE__ */ jsxs4(Box4, { gap: 2, children: [
587
- /* @__PURE__ */ jsxs4(Text4, { children: [
588
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "\u2191/\u2193" }),
589
- " \u5BFC\u822A"
590
- ] }),
591
- /* @__PURE__ */ jsxs4(Text4, { children: [
592
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "Space" }),
593
- " \u9009\u62E9"
594
- ] }),
595
- /* @__PURE__ */ jsxs4(Text4, { children: [
596
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "a" }),
597
- " \u5168\u9009"
598
- ] }),
599
- /* @__PURE__ */ jsxs4(Text4, { children: [
600
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "i" }),
601
- " \u53CD\u9009"
602
- ] }),
603
- /* @__PURE__ */ jsxs4(Text4, { children: [
604
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "Enter" }),
605
- " \u786E\u8BA4"
606
- ] })
607
- ] }),
608
- /* @__PURE__ */ jsxs4(Box4, { gap: 2, children: [
609
- /* @__PURE__ */ jsxs4(Text4, { children: [
610
- /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: "Shift+\u2191/\u2193" }),
611
- " \u8FDE\u7EED\u9009\u62E9"
612
- ] }),
613
- /* @__PURE__ */ jsxs4(Text4, { children: [
614
- /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: "Shift+Space" }),
615
- " \u8303\u56F4\u9009\u62E9"
616
- ] }),
617
- /* @__PURE__ */ jsxs4(Text4, { children: [
618
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: "r" }),
619
- " \u9009\u81F3\u5F00\u5934"
620
- ] })
621
- ] })
806
+ /* @__PURE__ */ jsx6(KeyHints, { hints: [
807
+ { key: "\u2191\u2193", label: "\u5BFC\u822A" },
808
+ { key: "Space", label: "\u9009\u62E9" },
809
+ { key: "a", label: "\u5168\u9009" },
810
+ { key: "i", label: "\u53CD\u9009" },
811
+ { key: "r", label: "\u9009\u81F3\u5F00\u5934" },
812
+ { key: "Shift+\u2191\u2193", label: "\u8FDE\u9009" },
813
+ { key: "Enter", label: "\u786E\u8BA4" },
814
+ { key: "Esc", label: "\u8FD4\u56DE" }
622
815
  ] }),
623
- selectedHashes.size > 0 && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [
624
- /* @__PURE__ */ jsxs4(Text4, { bold: true, color: "yellow", children: [
625
- "\u5DF2\u9009 ",
626
- selectedHashes.size,
627
- " \u4E2A commit \u2014 diff --stat \u9884\u89C8:"
628
- ] }),
629
- statLoading ? /* @__PURE__ */ jsx4(Spinner3, { label: "\u52A0\u8F7D\u4E2D..." }) : /* @__PURE__ */ jsx4(Text4, { color: "gray", children: stat || "(\u65E0\u53D8\u66F4)" })
630
- ] })
816
+ selectedHashes.size > 0 && /* @__PURE__ */ jsx6(StatusPanel, { type: "info", title: `\u5DF2\u9009 ${selectedHashes.size} \u4E2A commit \xB7 diff --stat`, children: statLoading ? /* @__PURE__ */ jsx6(Spinner4, { label: "\u52A0\u8F7D\u4E2D..." }) : /* @__PURE__ */ jsx6(Text6, { color: "gray", children: stat || "(\u65E0\u53D8\u66F4)" }) })
631
817
  ] });
632
818
  }
633
819
 
634
820
  // src/components/confirm-panel.tsx
635
- import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
636
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
821
+ import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
822
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
637
823
  function ConfirmPanel({ commits, selectedHashes, hasMerge, useMainline, onToggleMainline, onConfirm, onCancel }) {
638
- useInput3((input) => {
639
- if (input === "y" || input === "Y") {
824
+ useInput6((input, key) => {
825
+ if (key.escape) {
826
+ onCancel();
827
+ } else if (input === "y" || input === "Y") {
640
828
  onConfirm();
641
829
  } else if (input === "n" || input === "N" || input === "q") {
642
830
  onCancel();
@@ -645,68 +833,57 @@ function ConfirmPanel({ commits, selectedHashes, hasMerge, useMainline, onToggle
645
833
  }
646
834
  });
647
835
  const selectedCommits = selectedHashes.map((hash) => commits.find((c) => c.hash === hash)).filter(Boolean);
648
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, children: [
649
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: "[4/5] \u786E\u8BA4\u6267\u884C" }),
650
- /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
651
- /* @__PURE__ */ jsxs5(Text5, { bold: true, children: [
652
- "\u5C06 cherry-pick --no-commit \u4EE5\u4E0B ",
653
- selectedCommits.length,
654
- " \u4E2A commit:"
836
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", gap: 1, children: [
837
+ /* @__PURE__ */ jsx7(SectionHeader, { title: "\u786E\u8BA4\u6267\u884C" }),
838
+ /* @__PURE__ */ jsx7(StatusPanel, { type: "info", title: `cherry-pick --no-commit \xB7 ${selectedCommits.length} \u4E2A commit`, children: selectedCommits.map((c) => /* @__PURE__ */ jsxs7(Box7, { children: [
839
+ /* @__PURE__ */ jsxs7(Text7, { color: "yellow", children: [
840
+ " ",
841
+ c.shortHash
655
842
  ] }),
656
- selectedCommits.map((c) => /* @__PURE__ */ jsxs5(Text5, { children: [
657
- /* @__PURE__ */ jsxs5(Text5, { color: "green", children: [
658
- " ",
659
- c.shortHash
660
- ] }),
661
- /* @__PURE__ */ jsxs5(Text5, { children: [
662
- " ",
663
- c.message
664
- ] }),
665
- /* @__PURE__ */ jsxs5(Text5, { color: "gray", dimColor: true, children: [
666
- " (",
667
- c.author,
668
- ")"
669
- ] })
670
- ] }, c.hash))
671
- ] }),
672
- hasMerge && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "single", borderColor: "red", paddingX: 1, children: [
673
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: "red", children: "\u68C0\u6D4B\u5230 Merge Commit" }),
674
- /* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "Cherry-pick \u5408\u5E76\u63D0\u4EA4\u9700\u8981\u6307\u5B9A\u7236\u8282\u70B9 (-m 1)" }),
675
- /* @__PURE__ */ jsxs5(Text5, { children: [
676
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "[m]" }),
677
- /* @__PURE__ */ jsx5(Text5, { children: " \u5207\u6362 -m 1: " }),
678
- useMainline ? /* @__PURE__ */ jsx5(Text5, { color: "green", children: "\u5DF2\u542F\u7528" }) : /* @__PURE__ */ jsx5(Text5, { color: "gray", children: "\u672A\u542F\u7528" })
843
+ /* @__PURE__ */ jsxs7(Text7, { children: [
844
+ " ",
845
+ c.message
846
+ ] }),
847
+ /* @__PURE__ */ jsxs7(Text7, { color: "gray", dimColor: true, children: [
848
+ " ",
849
+ c.author
850
+ ] })
851
+ ] }, c.hash)) }),
852
+ hasMerge && /* @__PURE__ */ jsxs7(StatusPanel, { type: "warn", title: "\u68C0\u6D4B\u5230 Merge Commit", children: [
853
+ /* @__PURE__ */ jsx7(Text7, { color: "gray", children: " Cherry-pick \u5408\u5E76\u63D0\u4EA4\u9700\u8981\u6307\u5B9A\u7236\u8282\u70B9 (-m 1)" }),
854
+ /* @__PURE__ */ jsxs7(Box7, { children: [
855
+ /* @__PURE__ */ jsx7(Text7, { children: " " }),
856
+ /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: "[m]" }),
857
+ /* @__PURE__ */ jsx7(Text7, { children: " \u5207\u6362 -m 1: " }),
858
+ useMainline ? /* @__PURE__ */ jsx7(Text7, { color: "green", bold: true, children: "\u5DF2\u542F\u7528" }) : /* @__PURE__ */ jsx7(Text7, { color: "gray", children: "\u672A\u542F\u7528" })
679
859
  ] })
680
860
  ] }),
681
- /* @__PURE__ */ jsxs5(Box5, { children: [
682
- /* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "\u26A0 " }),
683
- /* @__PURE__ */ jsx5(Text5, { children: "\u4F7F\u7528 --no-commit \u6A21\u5F0F\uFF0C\u6539\u52A8\u5C06\u6682\u5B58\u5230\u5DE5\u4F5C\u533A\uFF0C\u9700\u624B\u52A8 commit" })
861
+ /* @__PURE__ */ jsxs7(Box7, { children: [
862
+ /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: "\u25B2 " }),
863
+ /* @__PURE__ */ jsx7(Text7, { color: "gray", children: "--no-commit \u6A21\u5F0F\uFF0C\u6539\u52A8\u5C06\u6682\u5B58\u5230\u5DE5\u4F5C\u533A\uFF0C\u9700\u624B\u52A8 commit" })
684
864
  ] }),
685
- /* @__PURE__ */ jsxs5(Box5, { children: [
686
- /* @__PURE__ */ jsx5(Text5, { bold: true, children: "\u786E\u8BA4\u6267\u884C? " }),
687
- /* @__PURE__ */ jsx5(Text5, { color: "green", children: "[y]" }),
688
- /* @__PURE__ */ jsx5(Text5, { children: " \u786E\u8BA4 / " }),
689
- /* @__PURE__ */ jsx5(Text5, { color: "red", children: "[n]" }),
690
- /* @__PURE__ */ jsx5(Text5, { children: " \u53D6\u6D88" }),
691
- hasMerge && /* @__PURE__ */ jsxs5(Text5, { children: [
692
- " / ",
693
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "[m]" }),
694
- " \u5207\u6362 -m 1"
865
+ /* @__PURE__ */ jsxs7(Box7, { children: [
866
+ /* @__PURE__ */ jsx7(Text7, { bold: true, children: "\u786E\u8BA4\u6267\u884C? " }),
867
+ /* @__PURE__ */ jsx7(InlineKeys, { hints: [
868
+ { key: "y", label: "\u786E\u8BA4" },
869
+ { key: "n", label: "\u53D6\u6D88" },
870
+ ...hasMerge ? [{ key: "m", label: "\u5207\u6362 -m 1" }] : [],
871
+ { key: "Esc", label: "\u8FD4\u56DE" }
695
872
  ] })
696
873
  ] })
697
874
  ] });
698
875
  }
699
876
 
700
877
  // src/components/result-panel.tsx
701
- import { useState as useState5, useEffect as useEffect2 } from "react";
702
- import { Box as Box6, Text as Text6 } from "ink";
703
- import { Spinner as Spinner4 } from "@inkjs/ui";
704
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
878
+ import { useState as useState6, useEffect as useEffect3 } from "react";
879
+ import { Box as Box8, Text as Text8 } from "ink";
880
+ import { Spinner as Spinner5 } from "@inkjs/ui";
881
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
705
882
  function ResultPanel({ selectedHashes, useMainline, stashed, onStashRestored, onDone }) {
706
- const [phase, setPhase] = useState5("executing");
707
- const [result, setResult] = useState5(null);
708
- const [stagedStat, setStagedStat] = useState5("");
709
- const [stashRestored, setStashRestored] = useState5(null);
883
+ const [phase, setPhase] = useState6("executing");
884
+ const [result, setResult] = useState6(null);
885
+ const [stagedStat, setStagedStat] = useState6("");
886
+ const [stashRestored, setStashRestored] = useState6(null);
710
887
  const tryRestoreStash = async () => {
711
888
  if (!stashed) return true;
712
889
  setPhase("restoring");
@@ -715,7 +892,7 @@ function ResultPanel({ selectedHashes, useMainline, stashed, onStashRestored, on
715
892
  if (ok) onStashRestored();
716
893
  return ok;
717
894
  };
718
- useEffect2(() => {
895
+ useEffect3(() => {
719
896
  async function run() {
720
897
  const res = await cherryPick(selectedHashes, useMainline);
721
898
  setResult(res);
@@ -732,62 +909,93 @@ function ResultPanel({ selectedHashes, useMainline, stashed, onStashRestored, on
732
909
  run();
733
910
  }, []);
734
911
  if (phase === "executing") {
735
- return /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsx6(Spinner4, { label: `\u6B63\u5728\u6267\u884C cherry-pick --no-commit (${selectedHashes.length} \u4E2A commit)...` }) });
912
+ return /* @__PURE__ */ jsx8(Spinner5, { label: `cherry-pick --no-commit (${selectedHashes.length} \u4E2A commit)...` });
736
913
  }
737
914
  if (phase === "restoring") {
738
- return /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsx6(Spinner4, { label: "\u6B63\u5728\u6062\u590D\u5DE5\u4F5C\u533A (git stash pop)..." }) });
915
+ return /* @__PURE__ */ jsx8(Spinner5, { label: "\u6062\u590D\u5DE5\u4F5C\u533A (git stash pop)..." });
739
916
  }
740
917
  if (phase === "error" && result) {
741
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 1, children: [
742
- /* @__PURE__ */ jsx6(Text6, { bold: true, color: "red", children: "[5/5] Cherry-pick \u9047\u5230\u51B2\u7A81" }),
743
- result.conflictFiles && result.conflictFiles.length > 0 && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", borderStyle: "single", borderColor: "red", paddingX: 1, children: [
744
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: "\u51B2\u7A81\u6587\u4EF6:" }),
745
- result.conflictFiles.map((f) => /* @__PURE__ */ jsxs6(Text6, { color: "red", children: [
746
- " ",
747
- f
748
- ] }, f))
918
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
919
+ /* @__PURE__ */ jsx8(SectionHeader, { title: "Cherry-pick \u9047\u5230\u51B2\u7A81" }),
920
+ result.conflictFiles && result.conflictFiles.length > 0 && /* @__PURE__ */ jsx8(StatusPanel, { type: "error", title: "\u51B2\u7A81\u6587\u4EF6", children: result.conflictFiles.map((f) => /* @__PURE__ */ jsxs8(Text8, { color: "red", children: [
921
+ " ",
922
+ f
923
+ ] }, f)) }),
924
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
925
+ /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "\u25B8 \u624B\u52A8\u89E3\u51B3\u51B2\u7A81\u540E\u6267\u884C git add \u548C git commit" }),
926
+ /* @__PURE__ */ jsx8(Text8, { color: "gray", dimColor: true, children: "\u25B8 \u6216\u6267\u884C git cherry-pick --abort \u653E\u5F03\u64CD\u4F5C" })
749
927
  ] }),
750
- /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "\u8BF7\u624B\u52A8\u89E3\u51B3\u51B2\u7A81\u540E\u6267\u884C git add \u548C git commit" }),
751
- /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "\u6216\u6267\u884C git cherry-pick --abort \u653E\u5F03\u64CD\u4F5C" }),
752
- stashed && stashRestored === false && /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "\u6CE8\u610F: stash \u6062\u590D\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8 git stash pop" }),
753
- stashed && stashRestored === true && /* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u5DF2\u6062\u590D\u5DE5\u4F5C\u533A\u53D8\u66F4 (stash pop)" })
928
+ stashed && stashRestored === false && /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "\u25B2 stash \u6062\u590D\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8 git stash pop" }),
929
+ stashed && stashRestored === true && /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u2714 \u5DF2\u6062\u590D\u5DE5\u4F5C\u533A\u53D8\u66F4 (stash pop)" })
754
930
  ] });
755
931
  }
756
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 1, children: [
757
- /* @__PURE__ */ jsx6(Text6, { bold: true, color: "green", children: "[5/5] \u540C\u6B65\u5B8C\u6210!" }),
758
- /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: [
759
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: "\u6682\u5B58\u533A\u53D8\u66F4\u6982\u89C8 (git diff --cached --stat):" }),
760
- /* @__PURE__ */ jsx6(Text6, { color: "gray", children: stagedStat || "(\u65E0\u53D8\u66F4)" })
761
- ] }),
762
- stashed && (stashRestored ? /* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u5DF2\u6062\u590D\u5DE5\u4F5C\u533A\u53D8\u66F4 (stash pop)" }) : /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "stash pop \u5931\u8D25\uFF0C\u8BF7\u624B\u52A8 git stash pop" })),
763
- /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "\u6539\u52A8\u5DF2\u6682\u5B58\u5230\u5DE5\u4F5C\u533A (--no-commit \u6A21\u5F0F)" }),
764
- /* @__PURE__ */ jsx6(Text6, { children: "\u8BF7\u5BA1\u67E5\u540E\u624B\u52A8\u6267\u884C:" }),
765
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: " git diff --cached # \u67E5\u770B\u8BE6\u7EC6 diff" }),
766
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: ' git commit -m "\u540C\u6B65 commit" # \u63D0\u4EA4' }),
767
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: " git reset HEAD # \u6216\u653E\u5F03\u6240\u6709\u6539\u52A8" })
932
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
933
+ /* @__PURE__ */ jsx8(SectionHeader, { title: "\u540C\u6B65\u5B8C\u6210" }),
934
+ /* @__PURE__ */ jsx8(StatusPanel, { type: "success", title: "\u6682\u5B58\u533A\u53D8\u66F4 (git diff --cached --stat)", children: /* @__PURE__ */ jsx8(Text8, { color: "gray", children: stagedStat || "(\u65E0\u53D8\u66F4)" }) }),
935
+ stashed && (stashRestored ? /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u2714 \u5DF2\u6062\u590D\u5DE5\u4F5C\u533A\u53D8\u66F4 (stash pop)" }) : /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "\u25B2 stash pop \u5931\u8D25\uFF0C\u8BF7\u624B\u52A8 git stash pop" })),
936
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
937
+ /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "\u25B2 \u6539\u52A8\u5DF2\u6682\u5B58\u5230\u5DE5\u4F5C\u533A (--no-commit \u6A21\u5F0F)" }),
938
+ /* @__PURE__ */ jsx8(Text8, { color: "gray", dimColor: true, children: " \u5BA1\u67E5\u540E\u624B\u52A8\u6267\u884C:" }),
939
+ /* @__PURE__ */ jsxs8(Text8, { color: "cyan", children: [
940
+ " git diff --cached ",
941
+ /* @__PURE__ */ jsx8(Text8, { color: "gray", dimColor: true, children: "# \u67E5\u770B\u8BE6\u7EC6 diff" })
942
+ ] }),
943
+ /* @__PURE__ */ jsxs8(Text8, { color: "cyan", children: [
944
+ ' git commit -m "sync: ..." ',
945
+ /* @__PURE__ */ jsx8(Text8, { color: "gray", dimColor: true, children: "# \u63D0\u4EA4" })
946
+ ] }),
947
+ /* @__PURE__ */ jsxs8(Text8, { color: "cyan", children: [
948
+ " git reset HEAD ",
949
+ /* @__PURE__ */ jsx8(Text8, { color: "gray", dimColor: true, children: "# \u6216\u653E\u5F03" })
950
+ ] })
951
+ ] })
768
952
  ] });
769
953
  }
770
954
 
771
955
  // src/app.tsx
772
956
  import { execSync } from "child_process";
773
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
957
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
958
+ var STEP_NUMBER = {
959
+ checking: 0,
960
+ "stash-recovery": 0,
961
+ "stash-prompt": 0,
962
+ remote: 1,
963
+ branch: 2,
964
+ commits: 3,
965
+ confirm: 4,
966
+ result: 5
967
+ };
968
+ var STEP_DEBOUNCE = 100;
774
969
  function App() {
775
970
  const { exit } = useApp();
776
- const [step, setStep] = useState6("checking");
777
- const [remote, setRemote] = useState6("");
778
- const [branch, setBranch] = useState6("");
779
- const [selectedHashes, setSelectedHashes] = useState6([]);
780
- const [commits, setCommits] = useState6([]);
781
- const [hasMerge, setHasMerge] = useState6(false);
782
- const [useMainline, setUseMainline] = useState6(false);
783
- const [stashed, setStashed] = useState6(false);
971
+ const [step, setStepRaw] = useState7("checking");
972
+ const [inputReady, setInputReady] = useState7(true);
973
+ const [remote, setRemote] = useState7("");
974
+ const [branch, setBranch] = useState7("");
975
+ const [selectedHashes, setSelectedHashes] = useState7([]);
976
+ const [commits, setCommits] = useState7([]);
977
+ const [hasMerge, setHasMerge] = useState7(false);
978
+ const [useMainline, setUseMainline] = useState7(false);
979
+ const [stashed, setStashed] = useState7(false);
980
+ const [guardTimestamp, setGuardTimestamp] = useState7();
784
981
  const stashedRef = useRef2(false);
785
982
  const stashRestoredRef = useRef2(false);
983
+ const mountedRef = useRef2(true);
984
+ const debounceTimer = useRef2(null);
985
+ const setStep = useCallback2((newStep) => {
986
+ setInputReady(false);
987
+ setStepRaw(newStep);
988
+ if (debounceTimer.current) clearTimeout(debounceTimer.current);
989
+ debounceTimer.current = setTimeout(() => {
990
+ if (mountedRef.current) setInputReady(true);
991
+ }, STEP_DEBOUNCE);
992
+ }, []);
786
993
  const restoreStashSync = useCallback2(() => {
787
994
  if (stashedRef.current && !stashRestoredRef.current) {
788
995
  try {
789
996
  execSync("git stash pop", { stdio: "ignore" });
790
997
  stashRestoredRef.current = true;
998
+ removeStashGuardSync();
791
999
  } catch {
792
1000
  try {
793
1001
  process.stderr.write("\n\u26A0 stash \u81EA\u52A8\u6062\u590D\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C: git stash pop\n");
@@ -798,71 +1006,117 @@ function App() {
798
1006
  }, []);
799
1007
  const markStashRestored = useCallback2(() => {
800
1008
  stashRestoredRef.current = true;
1009
+ removeStashGuard();
801
1010
  }, []);
802
- useEffect3(() => {
803
- isWorkingDirClean().then((clean) => {
804
- if (clean) {
805
- setStep("remote");
806
- } else {
807
- setStep("stash-prompt");
1011
+ useEffect4(() => {
1012
+ mountedRef.current = true;
1013
+ async function check() {
1014
+ const guard = await checkStashGuard();
1015
+ if (!mountedRef.current) return;
1016
+ if (guard.exists) {
1017
+ setGuardTimestamp(guard.timestamp);
1018
+ setStep("stash-recovery");
1019
+ return;
808
1020
  }
809
- });
1021
+ const clean = await isWorkingDirClean();
1022
+ if (!mountedRef.current) return;
1023
+ setStep(clean ? "remote" : "stash-prompt");
1024
+ }
1025
+ check();
810
1026
  const onSignal = () => {
811
1027
  restoreStashSync();
812
1028
  process.exit(0);
813
1029
  };
814
1030
  process.on("SIGINT", onSignal);
815
1031
  process.on("SIGTERM", onSignal);
816
- process.on("beforeExit", restoreStashSync);
1032
+ process.on("SIGHUP", onSignal);
817
1033
  return () => {
1034
+ mountedRef.current = false;
1035
+ if (debounceTimer.current) clearTimeout(debounceTimer.current);
818
1036
  process.off("SIGINT", onSignal);
819
1037
  process.off("SIGTERM", onSignal);
820
- process.off("beforeExit", restoreStashSync);
1038
+ process.off("SIGHUP", onSignal);
821
1039
  };
822
- }, [restoreStashSync]);
1040
+ }, [restoreStashSync, setStep]);
823
1041
  const doStash = async () => {
824
1042
  const ok = await stash();
825
1043
  if (ok) {
826
1044
  setStashed(true);
827
1045
  stashedRef.current = true;
1046
+ await writeStashGuard();
828
1047
  }
829
- setStep("remote");
1048
+ if (mountedRef.current) setStep("remote");
830
1049
  };
831
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
832
- /* @__PURE__ */ jsxs7(Box7, { marginBottom: 1, children: [
833
- /* @__PURE__ */ jsx7(Text7, { bold: true, inverse: true, color: "white", children: " git-sync-tui " }),
834
- /* @__PURE__ */ jsx7(Text7, { children: " " }),
835
- /* @__PURE__ */ jsx7(Text7, { color: "gray", children: "\u4EA4\u4E92\u5F0F commit \u540C\u6B65\u5DE5\u5177 (cherry-pick --no-commit)" }),
836
- stashed && /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: " (\u5DF2\u81EA\u52A8 stash)" })
837
- ] }),
838
- step === "checking" && /* @__PURE__ */ jsx7(Spinner5, { label: "\u68C0\u67E5\u5DE5\u4F5C\u533A\u72B6\u6001..." }),
839
- step === "stash-prompt" && /* @__PURE__ */ jsx7(
1050
+ const doStashRecover = async () => {
1051
+ const entry = await findStashEntry();
1052
+ if (entry) {
1053
+ await stashPop();
1054
+ }
1055
+ await removeStashGuard();
1056
+ if (!mountedRef.current) return;
1057
+ const clean = await isWorkingDirClean();
1058
+ if (mountedRef.current) setStep(clean ? "remote" : "stash-prompt");
1059
+ };
1060
+ const skipStashRecover = async () => {
1061
+ await removeStashGuard();
1062
+ if (!mountedRef.current) return;
1063
+ const clean = await isWorkingDirClean();
1064
+ if (mountedRef.current) setStep(clean ? "remote" : "stash-prompt");
1065
+ };
1066
+ const goBack = useCallback2((fromStep) => {
1067
+ const backMap = {
1068
+ branch: "remote",
1069
+ commits: "branch",
1070
+ confirm: "commits"
1071
+ };
1072
+ const prev = backMap[fromStep];
1073
+ if (prev) {
1074
+ setStep(prev);
1075
+ } else {
1076
+ restoreStashSync();
1077
+ exit();
1078
+ }
1079
+ }, [setStep, restoreStashSync, exit]);
1080
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
1081
+ /* @__PURE__ */ jsx9(AppHeader, { step: STEP_NUMBER[step], stashed }),
1082
+ step === "checking" && /* @__PURE__ */ jsx9(Spinner6, { label: "\u68C0\u67E5\u5DE5\u4F5C\u533A\u72B6\u6001..." }),
1083
+ step === "stash-recovery" && inputReady && /* @__PURE__ */ jsx9(
1084
+ StashRecovery,
1085
+ {
1086
+ timestamp: guardTimestamp,
1087
+ onRecover: doStashRecover,
1088
+ onSkip: skipStashRecover
1089
+ }
1090
+ ),
1091
+ step === "stash-prompt" && inputReady && /* @__PURE__ */ jsx9(
840
1092
  StashPrompt,
841
1093
  {
842
1094
  onConfirm: doStash,
843
1095
  onSkip: () => setStep("remote")
844
1096
  }
845
1097
  ),
846
- step === "remote" && /* @__PURE__ */ jsx7(
1098
+ step === "remote" && inputReady && /* @__PURE__ */ jsx9(
847
1099
  RemoteSelect,
848
1100
  {
849
1101
  onSelect: (r) => {
850
1102
  setRemote(r);
851
1103
  setStep("branch");
852
- }
1104
+ },
1105
+ onBack: () => goBack("remote")
853
1106
  }
854
1107
  ),
855
- step === "branch" && /* @__PURE__ */ jsx7(
1108
+ step === "branch" && inputReady && /* @__PURE__ */ jsx9(
856
1109
  BranchSelect,
857
1110
  {
858
1111
  remote,
859
1112
  onSelect: (b) => {
860
1113
  setBranch(b);
861
1114
  setStep("commits");
862
- }
1115
+ },
1116
+ onBack: () => goBack("branch")
863
1117
  }
864
1118
  ),
865
- step === "commits" && /* @__PURE__ */ jsx7(
1119
+ step === "commits" && inputReady && /* @__PURE__ */ jsx9(
866
1120
  CommitList,
867
1121
  {
868
1122
  remote,
@@ -873,10 +1127,11 @@ function App() {
873
1127
  const merge = await hasMergeCommits(hashes);
874
1128
  setHasMerge(merge);
875
1129
  setStep("confirm");
876
- }
1130
+ },
1131
+ onBack: () => goBack("commits")
877
1132
  }
878
1133
  ),
879
- step === "confirm" && /* @__PURE__ */ jsx7(
1134
+ step === "confirm" && inputReady && /* @__PURE__ */ jsx9(
880
1135
  ConfirmPanel,
881
1136
  {
882
1137
  commits,
@@ -885,10 +1140,10 @@ function App() {
885
1140
  useMainline,
886
1141
  onToggleMainline: () => setUseMainline((v) => !v),
887
1142
  onConfirm: () => setStep("result"),
888
- onCancel: () => setStep("commits")
1143
+ onCancel: () => goBack("confirm")
889
1144
  }
890
1145
  ),
891
- step === "result" && /* @__PURE__ */ jsx7(
1146
+ step === "result" && /* @__PURE__ */ jsx9(
892
1147
  ResultPanel,
893
1148
  {
894
1149
  selectedHashes,
@@ -905,7 +1160,7 @@ function App() {
905
1160
  }
906
1161
 
907
1162
  // src/cli.tsx
908
- import { jsx as jsx8 } from "react/jsx-runtime";
1163
+ import { jsx as jsx10 } from "react/jsx-runtime";
909
1164
  var cli = meow(
910
1165
  `
911
1166
  \u7528\u6CD5
@@ -932,4 +1187,4 @@ var cli = meow(
932
1187
  importMeta: import.meta
933
1188
  }
934
1189
  );
935
- render(/* @__PURE__ */ jsx8(App, {}));
1190
+ render(/* @__PURE__ */ jsx10(App, {}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "git-sync-tui",
3
3
  "type": "module",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "packageManager": "pnpm@10.32.1",
6
6
  "description": "Interactive TUI tool for cross-repo git commit synchronization (cherry-pick --no-commit)",
7
7
  "author": "KiWi233333",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "scripts": {
33
33
  "start": "tsx src/cli.tsx",
34
- "dev": "tsx watch src/cli.tsx",
34
+ "dev": "tsx src/cli.tsx",
35
35
  "build": "tsup",
36
36
  "prepublishOnly": "pnpm run build",
37
37
  "release": "pnpm run release:patch",