git-sync-tui 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +332 -121
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import { render } from "ink";
|
|
|
11
11
|
import meow from "meow";
|
|
12
12
|
|
|
13
13
|
// src/app.tsx
|
|
14
|
-
import { useState as useState7, useEffect as
|
|
14
|
+
import { useState as useState7, useEffect as useEffect5, useRef as useRef3, useCallback as useCallback2 } from "react";
|
|
15
15
|
import { Box as Box9, useApp } from "ink";
|
|
16
16
|
import { Spinner as Spinner6 } from "@inkjs/ui";
|
|
17
17
|
|
|
@@ -32,14 +32,18 @@ function StepProgress({ current }) {
|
|
|
32
32
|
" ",
|
|
33
33
|
isActive ? /* @__PURE__ */ jsx(Text, { bold: true, children: label }) : label
|
|
34
34
|
] }),
|
|
35
|
-
!isLast && /* @__PURE__ */
|
|
35
|
+
!isLast && /* @__PURE__ */ jsxs(Text, { color: isDone ? "green" : "gray", dimColor: !isDone, children: [
|
|
36
|
+
" ",
|
|
37
|
+
"\u2500\u2500\u2500",
|
|
38
|
+
" "
|
|
39
|
+
] })
|
|
36
40
|
] }, label);
|
|
37
41
|
}) });
|
|
38
42
|
}
|
|
39
43
|
function SectionHeader({ title, subtitle }) {
|
|
40
44
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
41
45
|
/* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
42
|
-
"\
|
|
46
|
+
"\u25BE ",
|
|
43
47
|
title
|
|
44
48
|
] }),
|
|
45
49
|
subtitle && /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
|
|
@@ -50,10 +54,8 @@ function SectionHeader({ title, subtitle }) {
|
|
|
50
54
|
}
|
|
51
55
|
function KeyHints({ hints }) {
|
|
52
56
|
return /* @__PURE__ */ jsx(Box, { gap: 1, flexWrap: "wrap", children: hints.map(({ key, label }) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
53
|
-
/* @__PURE__ */ jsx(Text, {
|
|
54
|
-
/* @__PURE__ */
|
|
55
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "]" }),
|
|
56
|
-
/* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
|
|
57
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor: "gray", color: "white", bold: true, children: ` ${key} ` }),
|
|
58
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
57
59
|
" ",
|
|
58
60
|
label
|
|
59
61
|
] })
|
|
@@ -61,7 +63,7 @@ function KeyHints({ hints }) {
|
|
|
61
63
|
}
|
|
62
64
|
function InlineKeys({ hints }) {
|
|
63
65
|
return /* @__PURE__ */ jsx(Box, { gap: 1, children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
64
|
-
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
66
|
+
/* @__PURE__ */ jsxs(Text, { color: "green", bold: true, children: [
|
|
65
67
|
"[",
|
|
66
68
|
key,
|
|
67
69
|
"]"
|
|
@@ -92,13 +94,12 @@ function StatusPanel({ type, title, children }) {
|
|
|
92
94
|
}
|
|
93
95
|
function AppHeader({ step, stashed }) {
|
|
94
96
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
95
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
96
|
-
/* @__PURE__ */ jsx(Text, {
|
|
97
|
-
/* @__PURE__ */ jsx(Text, {
|
|
98
|
-
/* @__PURE__ */ jsx(Text, { color: "
|
|
99
|
-
stashed && /* @__PURE__ */ jsx(Text, { color: "yellow", children: " \u25AA stashed" })
|
|
97
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
98
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor: "cyan", color: "white", bold: true, children: " git-sync-tui " }),
|
|
99
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "cherry-pick --no-commit" }),
|
|
100
|
+
stashed && /* @__PURE__ */ jsx(Text, { backgroundColor: "yellow", color: "white", bold: true, children: " STASHED " })
|
|
100
101
|
] }),
|
|
101
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
102
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 0, children: [
|
|
102
103
|
/* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: " " }),
|
|
103
104
|
/* @__PURE__ */ jsx(StepProgress, { current: step })
|
|
104
105
|
] })
|
|
@@ -158,28 +159,20 @@ async function addRemote(name, url) {
|
|
|
158
159
|
}
|
|
159
160
|
async function getRemoteBranches(remote2) {
|
|
160
161
|
const git = getGit();
|
|
161
|
-
let fetchOk = false;
|
|
162
162
|
try {
|
|
163
|
-
await git.
|
|
164
|
-
|
|
163
|
+
const lsResult = await git.raw(["ls-remote", "--heads", remote2]);
|
|
164
|
+
if (lsResult.trim()) {
|
|
165
|
+
return lsResult.trim().split("\n").map((line) => line.replace(/^.*refs\/heads\//, "")).filter(Boolean).sort();
|
|
166
|
+
}
|
|
165
167
|
} catch {
|
|
166
168
|
}
|
|
167
169
|
const result = await git.branch(["-r"]);
|
|
168
170
|
const prefix = `${remote2}/`;
|
|
169
171
|
const branches = result.all.filter((b) => b.startsWith(prefix) && !b.includes("HEAD")).map((b) => b.replace(prefix, "")).sort();
|
|
170
172
|
if (branches.length > 0) return branches;
|
|
171
|
-
|
|
172
|
-
const lsResult = await git.raw(["ls-remote", "--heads", remote2]);
|
|
173
|
-
if (!lsResult.trim()) return [];
|
|
174
|
-
return lsResult.trim().split("\n").map((line) => line.replace(/^.*refs\/heads\//, "")).filter(Boolean).sort();
|
|
175
|
-
} catch {
|
|
176
|
-
if (!fetchOk) {
|
|
177
|
-
throw new Error(`\u65E0\u6CD5\u8FDE\u63A5\u8FDC\u7A0B\u4ED3\u5E93 '${remote2}'\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u4ED3\u5E93\u5730\u5740`);
|
|
178
|
-
}
|
|
179
|
-
return [];
|
|
180
|
-
}
|
|
173
|
+
throw new Error(`\u65E0\u6CD5\u83B7\u53D6\u8FDC\u7A0B\u4ED3\u5E93 '${remote2}' \u7684\u5206\u652F\u5217\u8868\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u4ED3\u5E93\u5730\u5740`);
|
|
181
174
|
}
|
|
182
|
-
async function getCommits(remote2, branch2, count2 =
|
|
175
|
+
async function getCommits(remote2, branch2, count2 = 100) {
|
|
183
176
|
const git = getGit();
|
|
184
177
|
const ref = `${remote2}/${branch2}`;
|
|
185
178
|
try {
|
|
@@ -204,6 +197,27 @@ async function getCommits(remote2, branch2, count2 = 30) {
|
|
|
204
197
|
return { hash, shortHash, message: message || "", author: author || "", date: date || "" };
|
|
205
198
|
});
|
|
206
199
|
}
|
|
200
|
+
async function getUnsyncedCommits(remote2, branch2, count2 = 100) {
|
|
201
|
+
const git = getGit();
|
|
202
|
+
const ref = `${remote2}/${branch2}`;
|
|
203
|
+
const allCommits = await getCommits(remote2, branch2, count2);
|
|
204
|
+
try {
|
|
205
|
+
const result = await git.raw([
|
|
206
|
+
"cherry",
|
|
207
|
+
"HEAD",
|
|
208
|
+
ref
|
|
209
|
+
]);
|
|
210
|
+
const unsyncedHashes = new Set(
|
|
211
|
+
result.trim().split("\n").filter((line) => line.startsWith("+ ")).map((line) => line.substring(2).trim())
|
|
212
|
+
);
|
|
213
|
+
return allCommits.map((c) => ({
|
|
214
|
+
...c,
|
|
215
|
+
synced: !unsyncedHashes.has(c.hash)
|
|
216
|
+
}));
|
|
217
|
+
} catch {
|
|
218
|
+
return allCommits;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
207
221
|
async function getMultiCommitStat(hashes) {
|
|
208
222
|
if (hashes.length === 0) return "";
|
|
209
223
|
const git = getGit();
|
|
@@ -393,10 +407,10 @@ function StashRecovery({ timestamp, onRecover, onSkip }) {
|
|
|
393
407
|
// src/components/remote-select.tsx
|
|
394
408
|
import { useState as useState3 } from "react";
|
|
395
409
|
import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
|
|
396
|
-
import {
|
|
410
|
+
import { Spinner as Spinner2, TextInput } from "@inkjs/ui";
|
|
397
411
|
|
|
398
412
|
// src/hooks/use-git.ts
|
|
399
|
-
import { useState as useState2, useEffect as useEffect2, useCallback } from "react";
|
|
413
|
+
import { useState as useState2, useEffect as useEffect2, useCallback, useRef } from "react";
|
|
400
414
|
function useAsync(fn, deps = []) {
|
|
401
415
|
const [state, setState] = useState2({
|
|
402
416
|
data: null,
|
|
@@ -426,11 +440,49 @@ function useBranches(remote2) {
|
|
|
426
440
|
[remote2]
|
|
427
441
|
);
|
|
428
442
|
}
|
|
429
|
-
function useCommits(remote2, branch2,
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
);
|
|
443
|
+
function useCommits(remote2, branch2, pageSize = 100) {
|
|
444
|
+
const [data, setData] = useState2(null);
|
|
445
|
+
const [loading, setLoading] = useState2(true);
|
|
446
|
+
const [loadingMore, setLoadingMore] = useState2(false);
|
|
447
|
+
const [error2, setError] = useState2(null);
|
|
448
|
+
const [hasMore, setHasMore] = useState2(true);
|
|
449
|
+
const loadedRef = useRef(0);
|
|
450
|
+
useEffect2(() => {
|
|
451
|
+
if (!remote2 || !branch2) {
|
|
452
|
+
setData([]);
|
|
453
|
+
setLoading(false);
|
|
454
|
+
setHasMore(false);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
setData(null);
|
|
458
|
+
setLoading(true);
|
|
459
|
+
setError(null);
|
|
460
|
+
setHasMore(true);
|
|
461
|
+
loadedRef.current = 0;
|
|
462
|
+
getUnsyncedCommits(remote2, branch2, pageSize).then((commits2) => {
|
|
463
|
+
setData(commits2);
|
|
464
|
+
setLoading(false);
|
|
465
|
+
loadedRef.current = commits2.length;
|
|
466
|
+
setHasMore(commits2.length >= pageSize);
|
|
467
|
+
}).catch((err) => {
|
|
468
|
+
setError(err.message);
|
|
469
|
+
setLoading(false);
|
|
470
|
+
});
|
|
471
|
+
}, [remote2, branch2, pageSize]);
|
|
472
|
+
const loadMore = useCallback(async () => {
|
|
473
|
+
if (!remote2 || !branch2 || loadingMore || !hasMore) return;
|
|
474
|
+
setLoadingMore(true);
|
|
475
|
+
try {
|
|
476
|
+
const nextCount = loadedRef.current + pageSize;
|
|
477
|
+
const allCommits = await getUnsyncedCommits(remote2, branch2, nextCount);
|
|
478
|
+
setData(allCommits);
|
|
479
|
+
setHasMore(allCommits.length >= nextCount);
|
|
480
|
+
loadedRef.current = allCommits.length;
|
|
481
|
+
} catch {
|
|
482
|
+
}
|
|
483
|
+
setLoadingMore(false);
|
|
484
|
+
}, [remote2, branch2, pageSize, loadingMore, hasMore]);
|
|
485
|
+
return { data, loading, loadingMore, error: error2, hasMore, loadMore };
|
|
434
486
|
}
|
|
435
487
|
function useCommitStat(hashes) {
|
|
436
488
|
const [stat, setStat] = useState2("");
|
|
@@ -462,16 +514,32 @@ function extractRemoteName(url) {
|
|
|
462
514
|
function RemoteSelect({ onSelect, onBack }) {
|
|
463
515
|
const { data: remotes, loading, error: error2, reload } = useRemotes();
|
|
464
516
|
const [phase, setPhase] = useState3("list");
|
|
517
|
+
const [cursorIndex, setCursorIndex] = useState3(0);
|
|
465
518
|
const [customUrl, setCustomUrl] = useState3("");
|
|
466
519
|
const [addError, setAddError] = useState3(null);
|
|
467
|
-
|
|
520
|
+
const totalItems = (remotes?.length || 0) + 1;
|
|
521
|
+
useInput3((input, key) => {
|
|
522
|
+
if (phase !== "list") {
|
|
523
|
+
if (key.escape) {
|
|
524
|
+
if (phase === "input-name") {
|
|
525
|
+
setPhase("input-url");
|
|
526
|
+
} else if (phase === "input-url") {
|
|
527
|
+
setPhase("list");
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
468
532
|
if (key.escape) {
|
|
469
|
-
|
|
533
|
+
onBack?.();
|
|
534
|
+
} else if (key.upArrow) {
|
|
535
|
+
setCursorIndex((prev) => Math.max(0, prev - 1));
|
|
536
|
+
} else if (key.downArrow) {
|
|
537
|
+
setCursorIndex((prev) => Math.min(totalItems - 1, prev + 1));
|
|
538
|
+
} else if (key.return) {
|
|
539
|
+
if (remotes && cursorIndex < remotes.length) {
|
|
540
|
+
onSelect(remotes[cursorIndex].name);
|
|
541
|
+
} else {
|
|
470
542
|
setPhase("input-url");
|
|
471
|
-
} else if (phase === "input-url") {
|
|
472
|
-
setPhase("list");
|
|
473
|
-
} else if (phase === "list") {
|
|
474
|
-
onBack?.();
|
|
475
543
|
}
|
|
476
544
|
}
|
|
477
545
|
});
|
|
@@ -480,7 +548,8 @@ function RemoteSelect({ onSelect, onBack }) {
|
|
|
480
548
|
}
|
|
481
549
|
if (error2) {
|
|
482
550
|
return /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
|
|
483
|
-
"\u2716
|
|
551
|
+
"\u2716 ",
|
|
552
|
+
"\u83B7\u53D6\u8FDC\u7A0B\u4ED3\u5E93\u5931\u8D25: ",
|
|
484
553
|
error2
|
|
485
554
|
] });
|
|
486
555
|
}
|
|
@@ -511,7 +580,10 @@ function RemoteSelect({ onSelect, onBack }) {
|
|
|
511
580
|
}
|
|
512
581
|
)
|
|
513
582
|
] }),
|
|
514
|
-
/* @__PURE__ */
|
|
583
|
+
/* @__PURE__ */ jsxs4(Text4, { color: "gray", dimColor: true, children: [
|
|
584
|
+
" ",
|
|
585
|
+
"\u652F\u6301 HTTPS / SSH \u5730\u5740"
|
|
586
|
+
] })
|
|
515
587
|
] });
|
|
516
588
|
}
|
|
517
589
|
if (phase === "input-name") {
|
|
@@ -555,99 +627,187 @@ function RemoteSelect({ onSelect, onBack }) {
|
|
|
555
627
|
] })
|
|
556
628
|
] });
|
|
557
629
|
}
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
label: `${r.name} ${r.fetchUrl}`,
|
|
561
|
-
value: r.name
|
|
562
|
-
})),
|
|
563
|
-
{
|
|
564
|
-
label: "+ \u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93...",
|
|
565
|
-
value: "__add_custom__"
|
|
566
|
-
}
|
|
567
|
-
];
|
|
568
|
-
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
|
|
630
|
+
const maxNameLen = Math.max(...(remotes || []).map((r) => r.name.length), 0);
|
|
631
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
569
632
|
/* @__PURE__ */ jsx4(SectionHeader, { title: "\u9009\u62E9\u8FDC\u7A0B\u4ED3\u5E93" }),
|
|
570
|
-
/* @__PURE__ */
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
633
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
|
|
634
|
+
(remotes || []).map((r, i) => {
|
|
635
|
+
const isCursor = i === cursorIndex;
|
|
636
|
+
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
637
|
+
/* @__PURE__ */ jsx4(Text4, { color: isCursor ? "cyan" : "gray", children: isCursor ? "\u203A" : " " }),
|
|
638
|
+
/* @__PURE__ */ jsx4(Text4, { children: " " }),
|
|
639
|
+
/* @__PURE__ */ jsx4(Text4, { color: isCursor ? "cyan" : "white", bold: isCursor, children: r.name.padEnd(maxNameLen + 2) }),
|
|
640
|
+
/* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, children: r.fetchUrl })
|
|
641
|
+
] }, r.name);
|
|
642
|
+
}),
|
|
643
|
+
/* @__PURE__ */ jsxs4(Box4, { children: [
|
|
644
|
+
/* @__PURE__ */ jsx4(Text4, { color: cursorIndex === (remotes?.length || 0) ? "cyan" : "gray", children: cursorIndex === (remotes?.length || 0) ? "\u203A" : " " }),
|
|
645
|
+
/* @__PURE__ */ jsx4(Text4, { children: " " }),
|
|
646
|
+
/* @__PURE__ */ jsx4(Text4, { color: "green", dimColor: cursorIndex !== (remotes?.length || 0), children: "+ \u6DFB\u52A0\u8FDC\u7A0B\u4ED3\u5E93..." })
|
|
647
|
+
] })
|
|
648
|
+
] })
|
|
583
649
|
] });
|
|
584
650
|
}
|
|
585
651
|
|
|
586
652
|
// src/components/branch-select.tsx
|
|
587
653
|
import { useState as useState4, useMemo } from "react";
|
|
588
654
|
import { Box as Box5, Text as Text5, useInput as useInput4 } from "ink";
|
|
589
|
-
import {
|
|
655
|
+
import { Spinner as Spinner3, TextInput as TextInput2 } from "@inkjs/ui";
|
|
590
656
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
591
657
|
function BranchSelect({ remote: remote2, onSelect, onBack }) {
|
|
592
658
|
const { data: branches, loading, error: error2 } = useBranches(remote2);
|
|
593
659
|
const [filter, setFilter] = useState4("");
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
});
|
|
597
|
-
const filteredOptions = useMemo(() => {
|
|
660
|
+
const [cursorIndex, setCursorIndex] = useState4(0);
|
|
661
|
+
const filteredBranches = useMemo(() => {
|
|
598
662
|
if (!branches) return [];
|
|
599
|
-
|
|
600
|
-
return filtered.map((b) => ({ label: b, value: b }));
|
|
663
|
+
return filter ? branches.filter((b) => b.toLowerCase().includes(filter.toLowerCase())) : branches;
|
|
601
664
|
}, [branches, filter]);
|
|
665
|
+
const visibleCount = 10;
|
|
666
|
+
const startIdx = Math.max(0, Math.min(cursorIndex - Math.floor(visibleCount / 2), filteredBranches.length - visibleCount));
|
|
667
|
+
const visibleBranches = filteredBranches.slice(startIdx, startIdx + visibleCount);
|
|
668
|
+
useInput4((input, key) => {
|
|
669
|
+
if (key.escape) {
|
|
670
|
+
onBack?.();
|
|
671
|
+
} else if (key.upArrow) {
|
|
672
|
+
setCursorIndex((prev) => Math.max(0, prev - 1));
|
|
673
|
+
} else if (key.downArrow) {
|
|
674
|
+
setCursorIndex((prev) => Math.min(filteredBranches.length - 1, prev + 1));
|
|
675
|
+
} else if (key.return) {
|
|
676
|
+
if (filteredBranches.length > 0) {
|
|
677
|
+
onSelect(filteredBranches[cursorIndex]);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
});
|
|
602
681
|
if (loading) {
|
|
603
682
|
return /* @__PURE__ */ jsx5(Spinner3, { label: `\u83B7\u53D6 ${remote2} \u7684\u5206\u652F\u5217\u8868...` });
|
|
604
683
|
}
|
|
605
684
|
if (error2) {
|
|
606
685
|
return /* @__PURE__ */ jsxs5(Text5, { color: "red", children: [
|
|
607
|
-
"\u2716
|
|
686
|
+
"\u2716 ",
|
|
687
|
+
"\u83B7\u53D6\u5206\u652F\u5217\u8868\u5931\u8D25: ",
|
|
608
688
|
error2
|
|
609
689
|
] });
|
|
610
690
|
}
|
|
611
691
|
if (!branches || branches.length === 0) {
|
|
612
|
-
return /* @__PURE__ */
|
|
692
|
+
return /* @__PURE__ */ jsxs5(Text5, { color: "red", children: [
|
|
693
|
+
"\u2716 ",
|
|
694
|
+
"\u672A\u627E\u5230\u8FDC\u7A0B\u5206\u652F"
|
|
695
|
+
] });
|
|
613
696
|
}
|
|
614
|
-
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column",
|
|
615
|
-
/* @__PURE__ */ jsx5(SectionHeader, { title:
|
|
616
|
-
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
617
|
-
/* @__PURE__ */ jsx5(Text5, { color: "
|
|
697
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
698
|
+
/* @__PURE__ */ jsx5(SectionHeader, { title: "\u9009\u62E9\u5206\u652F", subtitle: `${remote2} \xB7 ${branches.length} \u4E2A\u5206\u652F` }),
|
|
699
|
+
/* @__PURE__ */ jsxs5(Box5, { marginTop: 1, children: [
|
|
700
|
+
/* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "/ " }),
|
|
618
701
|
/* @__PURE__ */ jsx5(
|
|
619
702
|
TextInput2,
|
|
620
703
|
{
|
|
621
704
|
placeholder: "\u8F93\u5165\u5173\u952E\u5B57\u8FC7\u6EE4...",
|
|
622
|
-
onChange:
|
|
705
|
+
onChange: (val) => {
|
|
706
|
+
setFilter(val);
|
|
707
|
+
setCursorIndex(0);
|
|
708
|
+
}
|
|
623
709
|
}
|
|
624
710
|
),
|
|
625
711
|
filter && /* @__PURE__ */ jsxs5(Text5, { color: "gray", dimColor: true, children: [
|
|
626
712
|
" \xB7 \u5339\u914D ",
|
|
627
|
-
|
|
713
|
+
filteredBranches.length
|
|
628
714
|
] })
|
|
629
715
|
] }),
|
|
630
|
-
|
|
716
|
+
filteredBranches.length > 0 ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
|
|
717
|
+
startIdx > 0 && /* @__PURE__ */ jsxs5(Text5, { color: "gray", dimColor: true, children: [
|
|
718
|
+
" ",
|
|
719
|
+
"\u2191 ",
|
|
720
|
+
startIdx,
|
|
721
|
+
" more"
|
|
722
|
+
] }),
|
|
723
|
+
visibleBranches.map((b, i) => {
|
|
724
|
+
const actualIdx = startIdx + i;
|
|
725
|
+
const isCursor = actualIdx === cursorIndex;
|
|
726
|
+
return /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
727
|
+
/* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : "gray", children: isCursor ? "\u203A" : " " }),
|
|
728
|
+
/* @__PURE__ */ jsx5(Text5, { children: " " }),
|
|
729
|
+
/* @__PURE__ */ jsx5(Text5, { color: isCursor ? "cyan" : "white", bold: isCursor, children: b })
|
|
730
|
+
] }, b);
|
|
731
|
+
}),
|
|
732
|
+
startIdx + visibleCount < filteredBranches.length && /* @__PURE__ */ jsxs5(Text5, { color: "gray", dimColor: true, children: [
|
|
733
|
+
" ",
|
|
734
|
+
"\u2193 ",
|
|
735
|
+
filteredBranches.length - startIdx - visibleCount,
|
|
736
|
+
" more"
|
|
737
|
+
] })
|
|
738
|
+
] }) : /* @__PURE__ */ jsxs5(Text5, { color: "yellow", children: [
|
|
739
|
+
"\u25B2 ",
|
|
740
|
+
"\u65E0\u5339\u914D\u5206\u652F"
|
|
741
|
+
] })
|
|
631
742
|
] });
|
|
632
743
|
}
|
|
633
744
|
|
|
634
745
|
// src/components/commit-list.tsx
|
|
635
|
-
import { useState as useState5, useMemo as useMemo2, useRef } from "react";
|
|
746
|
+
import { useState as useState5, useMemo as useMemo2, useRef as useRef2, useEffect as useEffect3 } from "react";
|
|
636
747
|
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
637
748
|
import { Spinner as Spinner4 } from "@inkjs/ui";
|
|
638
749
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
750
|
+
function StatPanel({ stat, loading, count: count2 }) {
|
|
751
|
+
const STAT_HEIGHT = 8;
|
|
752
|
+
const [scrollOffset, setScrollOffset] = useState5(0);
|
|
753
|
+
const lines = useMemo2(() => stat ? stat.split("\n") : [], [stat]);
|
|
754
|
+
const canScroll = lines.length > STAT_HEIGHT;
|
|
755
|
+
useEffect3(() => {
|
|
756
|
+
setScrollOffset(0);
|
|
757
|
+
}, [stat]);
|
|
758
|
+
useInput5((input) => {
|
|
759
|
+
if (!canScroll) return;
|
|
760
|
+
if (input === "j") {
|
|
761
|
+
setScrollOffset((prev) => Math.min(prev + 1, lines.length - STAT_HEIGHT));
|
|
762
|
+
} else if (input === "k") {
|
|
763
|
+
setScrollOffset((prev) => Math.max(0, prev - 1));
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
const visibleLines = canScroll ? lines.slice(scrollOffset, scrollOffset + STAT_HEIGHT) : lines;
|
|
767
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
768
|
+
/* @__PURE__ */ jsxs6(Box6, { justifyContent: "space-between", children: [
|
|
769
|
+
/* @__PURE__ */ jsxs6(Text6, { bold: true, color: "cyan", children: [
|
|
770
|
+
"\u25C6 ",
|
|
771
|
+
"\u5DF2\u9009 ",
|
|
772
|
+
count2,
|
|
773
|
+
" \u4E2A commit \xB7 diff --stat"
|
|
774
|
+
] }),
|
|
775
|
+
canScroll && /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
|
|
776
|
+
scrollOffset + 1,
|
|
777
|
+
"-",
|
|
778
|
+
Math.min(scrollOffset + STAT_HEIGHT, lines.length),
|
|
779
|
+
"/",
|
|
780
|
+
lines.length,
|
|
781
|
+
" [j/k]"
|
|
782
|
+
] })
|
|
783
|
+
] }),
|
|
784
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", height: STAT_HEIGHT, children: loading ? /* @__PURE__ */ jsx6(Spinner4, { label: "\u52A0\u8F7D\u4E2D..." }) : visibleLines.length > 0 ? visibleLines.map((line, i) => /* @__PURE__ */ jsx6(Text6, { color: "gray", children: line }, scrollOffset + i)) : /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "(\u65E0\u53D8\u66F4)" }) })
|
|
785
|
+
] });
|
|
786
|
+
}
|
|
639
787
|
function CommitList({ remote: remote2, branch: branch2, onSelect, onBack }) {
|
|
640
|
-
const { data: commits2, loading, error: error2 } = useCommits(remote2, branch2,
|
|
788
|
+
const { data: commits2, loading, loadingMore, error: error2, hasMore, loadMore } = useCommits(remote2, branch2, 100);
|
|
641
789
|
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
642
790
|
const [selectedHashes, setSelectedHashes] = useState5(/* @__PURE__ */ new Set());
|
|
643
791
|
const [shiftMode, setShiftMode] = useState5(false);
|
|
644
|
-
const anchorIndexRef =
|
|
792
|
+
const anchorIndexRef = useRef2(null);
|
|
645
793
|
const selectedKey = useMemo2(() => Array.from(selectedHashes).sort().join(","), [selectedHashes]);
|
|
646
794
|
const selectedArray = useMemo2(() => Array.from(selectedHashes), [selectedKey]);
|
|
647
795
|
const { stat, loading: statLoading } = useCommitStat(selectedArray);
|
|
796
|
+
const syncedCount = useMemo2(() => {
|
|
797
|
+
if (!commits2) return 0;
|
|
798
|
+
return commits2.filter((c) => c.synced).length;
|
|
799
|
+
}, [commits2]);
|
|
800
|
+
useEffect3(() => {
|
|
801
|
+
if (!commits2 || !hasMore || loadingMore) return;
|
|
802
|
+
if (selectedIndex >= commits2.length - 5) {
|
|
803
|
+
loadMore();
|
|
804
|
+
}
|
|
805
|
+
}, [selectedIndex, commits2?.length, hasMore, loadingMore, loadMore]);
|
|
648
806
|
const toggleCurrent = () => {
|
|
649
807
|
if (!commits2 || commits2.length === 0) return;
|
|
650
|
-
const
|
|
808
|
+
const commit = commits2[selectedIndex];
|
|
809
|
+
if (commit.synced) return;
|
|
810
|
+
const hash = commit.hash;
|
|
651
811
|
setSelectedHashes((prev) => {
|
|
652
812
|
const next = new Set(prev);
|
|
653
813
|
if (next.has(hash)) {
|
|
@@ -667,19 +827,22 @@ function CommitList({ remote: remote2, branch: branch2, onSelect, onBack }) {
|
|
|
667
827
|
setSelectedHashes((prev) => {
|
|
668
828
|
const next = new Set(prev);
|
|
669
829
|
for (let i = start; i <= end; i++) {
|
|
670
|
-
|
|
830
|
+
if (!commits2[i].synced) {
|
|
831
|
+
next.add(commits2[i].hash);
|
|
832
|
+
}
|
|
671
833
|
}
|
|
672
834
|
return next;
|
|
673
835
|
});
|
|
674
836
|
};
|
|
675
837
|
const toggleAll = () => {
|
|
676
838
|
if (!commits2 || commits2.length === 0) return;
|
|
839
|
+
const unsyncedCommits = commits2.filter((c) => !c.synced);
|
|
677
840
|
setSelectedHashes((prev) => {
|
|
678
|
-
if (prev.size ===
|
|
841
|
+
if (prev.size === unsyncedCommits.length) {
|
|
679
842
|
anchorIndexRef.current = null;
|
|
680
843
|
return /* @__PURE__ */ new Set();
|
|
681
844
|
}
|
|
682
|
-
return new Set(
|
|
845
|
+
return new Set(unsyncedCommits.map((c) => c.hash));
|
|
683
846
|
});
|
|
684
847
|
};
|
|
685
848
|
const invertSelection = () => {
|
|
@@ -687,7 +850,7 @@ function CommitList({ remote: remote2, branch: branch2, onSelect, onBack }) {
|
|
|
687
850
|
setSelectedHashes((prev) => {
|
|
688
851
|
const next = /* @__PURE__ */ new Set();
|
|
689
852
|
for (const c of commits2) {
|
|
690
|
-
if (!prev.has(c.hash)) next.add(c.hash);
|
|
853
|
+
if (!c.synced && !prev.has(c.hash)) next.add(c.hash);
|
|
691
854
|
}
|
|
692
855
|
return next;
|
|
693
856
|
});
|
|
@@ -697,7 +860,9 @@ function CommitList({ remote: remote2, branch: branch2, onSelect, onBack }) {
|
|
|
697
860
|
setSelectedHashes((prev) => {
|
|
698
861
|
const next = new Set(prev);
|
|
699
862
|
for (let i = 0; i <= selectedIndex; i++) {
|
|
700
|
-
|
|
863
|
+
if (!commits2[i].synced) {
|
|
864
|
+
next.add(commits2[i].hash);
|
|
865
|
+
}
|
|
701
866
|
}
|
|
702
867
|
return next;
|
|
703
868
|
});
|
|
@@ -754,16 +919,21 @@ function CommitList({ remote: remote2, branch: branch2, onSelect, onBack }) {
|
|
|
754
919
|
}
|
|
755
920
|
if (error2) {
|
|
756
921
|
return /* @__PURE__ */ jsxs6(Text6, { color: "red", children: [
|
|
757
|
-
"\u2716
|
|
922
|
+
"\u2716 ",
|
|
923
|
+
"\u83B7\u53D6 commit \u5217\u8868\u5931\u8D25: ",
|
|
758
924
|
error2
|
|
759
925
|
] });
|
|
760
926
|
}
|
|
761
927
|
if (!commits2 || commits2.length === 0) {
|
|
762
|
-
return /* @__PURE__ */
|
|
928
|
+
return /* @__PURE__ */ jsxs6(Text6, { color: "yellow", children: [
|
|
929
|
+
"\u25B2 ",
|
|
930
|
+
"\u8BE5\u5206\u652F\u6CA1\u6709 commit"
|
|
931
|
+
] });
|
|
763
932
|
}
|
|
764
933
|
const visibleCount = 10;
|
|
765
934
|
const startIdx = Math.max(0, Math.min(selectedIndex - Math.floor(visibleCount / 2), commits2.length - visibleCount));
|
|
766
935
|
const visibleCommits = commits2.slice(startIdx, startIdx + visibleCount);
|
|
936
|
+
const unsyncedTotal = commits2.length - syncedCount;
|
|
767
937
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 1, children: [
|
|
768
938
|
/* @__PURE__ */ jsx6(SectionHeader, { title: "\u9009\u62E9\u8981\u540C\u6B65\u7684 commit" }),
|
|
769
939
|
/* @__PURE__ */ jsxs6(Box6, { gap: 2, children: [
|
|
@@ -774,17 +944,28 @@ function CommitList({ remote: remote2, branch: branch2, onSelect, onBack }) {
|
|
|
774
944
|
] }),
|
|
775
945
|
/* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
|
|
776
946
|
commits2.length,
|
|
777
|
-
" commits"
|
|
947
|
+
" commits",
|
|
948
|
+
hasMore ? "+" : ""
|
|
949
|
+
] }),
|
|
950
|
+
syncedCount > 0 && /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
|
|
951
|
+
syncedCount,
|
|
952
|
+
" \u5DF2\u540C\u6B65"
|
|
953
|
+
] }),
|
|
954
|
+
/* @__PURE__ */ jsxs6(Text6, { color: "green", children: [
|
|
955
|
+
unsyncedTotal,
|
|
956
|
+
" \u5F85\u540C\u6B65"
|
|
778
957
|
] }),
|
|
779
958
|
/* @__PURE__ */ jsxs6(Text6, { color: selectedHashes.size > 0 ? "cyan" : "gray", bold: selectedHashes.size > 0, children: [
|
|
780
959
|
"\u5DF2\u9009 ",
|
|
781
960
|
selectedHashes.size
|
|
782
961
|
] }),
|
|
783
|
-
shiftMode && /* @__PURE__ */ jsx6(Text6, { color: "yellow", bold: true, children: "SHIFT" })
|
|
962
|
+
shiftMode && /* @__PURE__ */ jsx6(Text6, { color: "yellow", bold: true, children: "SHIFT" }),
|
|
963
|
+
loadingMore && /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "\u52A0\u8F7D\u4E2D..." })
|
|
784
964
|
] }),
|
|
785
965
|
/* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
786
966
|
startIdx > 0 && /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
|
|
787
|
-
"
|
|
967
|
+
" ",
|
|
968
|
+
"\u2191 ",
|
|
788
969
|
startIdx,
|
|
789
970
|
" more"
|
|
790
971
|
] }),
|
|
@@ -793,30 +974,60 @@ function CommitList({ remote: remote2, branch: branch2, onSelect, onBack }) {
|
|
|
793
974
|
const isSelected = selectedHashes.has(c.hash);
|
|
794
975
|
const isCursor = actualIdx === selectedIndex;
|
|
795
976
|
const isAnchor = actualIdx === anchorIndexRef.current;
|
|
977
|
+
const isSynced = !!c.synced;
|
|
796
978
|
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
797
|
-
/* @__PURE__ */ jsxs6(
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
979
|
+
/* @__PURE__ */ jsxs6(
|
|
980
|
+
Text6,
|
|
981
|
+
{
|
|
982
|
+
backgroundColor: isCursor ? isSynced ? "gray" : "blue" : void 0,
|
|
983
|
+
color: isSynced ? "gray" : isSelected ? "green" : "white",
|
|
984
|
+
dimColor: isSynced,
|
|
985
|
+
children: [
|
|
986
|
+
isCursor ? "\u25B8 " : " ",
|
|
987
|
+
isSynced ? "\u2713" : isAnchor ? "\u2693" : isSelected ? "\u25CF" : "\u25CB",
|
|
988
|
+
" "
|
|
989
|
+
]
|
|
990
|
+
}
|
|
991
|
+
),
|
|
992
|
+
/* @__PURE__ */ jsx6(
|
|
993
|
+
Text6,
|
|
994
|
+
{
|
|
995
|
+
backgroundColor: isCursor ? isSynced ? "gray" : "blue" : void 0,
|
|
996
|
+
color: isSynced ? "gray" : "yellow",
|
|
997
|
+
dimColor: isSynced,
|
|
998
|
+
children: c.shortHash
|
|
999
|
+
}
|
|
1000
|
+
),
|
|
1001
|
+
/* @__PURE__ */ jsxs6(
|
|
1002
|
+
Text6,
|
|
1003
|
+
{
|
|
1004
|
+
backgroundColor: isCursor ? isSynced ? "gray" : "blue" : void 0,
|
|
1005
|
+
color: isSynced ? "gray" : isSelected ? "green" : "white",
|
|
1006
|
+
dimColor: isSynced,
|
|
1007
|
+
children: [
|
|
1008
|
+
" ",
|
|
1009
|
+
c.message
|
|
1010
|
+
]
|
|
1011
|
+
}
|
|
1012
|
+
),
|
|
807
1013
|
/* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
|
|
808
1014
|
" ",
|
|
809
1015
|
c.author,
|
|
810
1016
|
" \xB7 ",
|
|
811
1017
|
c.date
|
|
812
|
-
] })
|
|
1018
|
+
] }),
|
|
1019
|
+
isSynced && /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: " [\u5DF2\u540C\u6B65]" })
|
|
813
1020
|
] }, c.hash);
|
|
814
1021
|
}),
|
|
815
|
-
startIdx + visibleCount < commits2.length
|
|
816
|
-
"
|
|
1022
|
+
startIdx + visibleCount < commits2.length ? /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
|
|
1023
|
+
" ",
|
|
1024
|
+
"\u2193 ",
|
|
817
1025
|
commits2.length - startIdx - visibleCount,
|
|
818
1026
|
" more"
|
|
819
|
-
] })
|
|
1027
|
+
] }) : hasMore ? /* @__PURE__ */ jsxs6(Text6, { color: "gray", dimColor: true, children: [
|
|
1028
|
+
" ",
|
|
1029
|
+
"\u2193 \u6EDA\u52A8\u52A0\u8F7D\u66F4\u591A..."
|
|
1030
|
+
] }) : null
|
|
820
1031
|
] }),
|
|
821
1032
|
/* @__PURE__ */ jsx6(KeyHints, { hints: [
|
|
822
1033
|
{ key: "\u2191\u2193", label: "\u5BFC\u822A" },
|
|
@@ -828,7 +1039,7 @@ function CommitList({ remote: remote2, branch: branch2, onSelect, onBack }) {
|
|
|
828
1039
|
{ key: "Enter", label: "\u786E\u8BA4" },
|
|
829
1040
|
{ key: "Esc", label: "\u8FD4\u56DE" }
|
|
830
1041
|
] }),
|
|
831
|
-
selectedHashes.size > 0 && /* @__PURE__ */ jsx6(
|
|
1042
|
+
selectedHashes.size > 0 && /* @__PURE__ */ jsx6(StatPanel, { stat, loading: statLoading, count: selectedHashes.size })
|
|
832
1043
|
] });
|
|
833
1044
|
}
|
|
834
1045
|
|
|
@@ -890,7 +1101,7 @@ function ConfirmPanel({ commits: commits2, selectedHashes, hasMerge, useMainline
|
|
|
890
1101
|
}
|
|
891
1102
|
|
|
892
1103
|
// src/components/result-panel.tsx
|
|
893
|
-
import { useState as useState6, useEffect as
|
|
1104
|
+
import { useState as useState6, useEffect as useEffect4 } from "react";
|
|
894
1105
|
import { Box as Box8, Text as Text8 } from "ink";
|
|
895
1106
|
import { Spinner as Spinner5 } from "@inkjs/ui";
|
|
896
1107
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
@@ -907,7 +1118,7 @@ function ResultPanel({ selectedHashes, useMainline, stashed, onStashRestored, on
|
|
|
907
1118
|
if (ok) onStashRestored();
|
|
908
1119
|
return ok;
|
|
909
1120
|
};
|
|
910
|
-
|
|
1121
|
+
useEffect4(() => {
|
|
911
1122
|
async function run() {
|
|
912
1123
|
const res = await cherryPick(selectedHashes, useMainline);
|
|
913
1124
|
setResult(res);
|
|
@@ -994,10 +1205,10 @@ function App({ initialRemote, initialBranch }) {
|
|
|
994
1205
|
const [useMainline, setUseMainline] = useState7(false);
|
|
995
1206
|
const [stashed, setStashed] = useState7(false);
|
|
996
1207
|
const [guardTimestamp, setGuardTimestamp] = useState7();
|
|
997
|
-
const stashedRef =
|
|
998
|
-
const stashRestoredRef =
|
|
999
|
-
const mountedRef =
|
|
1000
|
-
const debounceTimer =
|
|
1208
|
+
const stashedRef = useRef3(false);
|
|
1209
|
+
const stashRestoredRef = useRef3(false);
|
|
1210
|
+
const mountedRef = useRef3(true);
|
|
1211
|
+
const debounceTimer = useRef3(null);
|
|
1001
1212
|
const setStep = useCallback2((newStep) => {
|
|
1002
1213
|
setInputReady(false);
|
|
1003
1214
|
setStepRaw(newStep);
|
|
@@ -1024,7 +1235,7 @@ function App({ initialRemote, initialBranch }) {
|
|
|
1024
1235
|
stashRestoredRef.current = true;
|
|
1025
1236
|
removeStashGuard();
|
|
1026
1237
|
}, []);
|
|
1027
|
-
|
|
1238
|
+
useEffect5(() => {
|
|
1028
1239
|
mountedRef.current = true;
|
|
1029
1240
|
async function check() {
|
|
1030
1241
|
const guard = await checkStashGuard();
|
|
@@ -1350,7 +1561,7 @@ var cli = meow(
|
|
|
1350
1561
|
-r, --remote <name> \u6307\u5B9A\u8FDC\u7A0B\u4ED3\u5E93\u540D\u79F0
|
|
1351
1562
|
-b, --branch <name> \u6307\u5B9A\u8FDC\u7A0B\u5206\u652F\u540D\u79F0
|
|
1352
1563
|
-c, --commits <hashes> \u6307\u5B9A commit hash\uFF08\u9017\u53F7\u5206\u9694\uFF09
|
|
1353
|
-
-n, --count <number> \u663E\u793A commit \u6570\u91CF\uFF08\u9ED8\u8BA4
|
|
1564
|
+
-n, --count <number> \u663E\u793A commit \u6570\u91CF\uFF08\u9ED8\u8BA4 100\uFF09
|
|
1354
1565
|
-m, --mainline \u5BF9 merge commit \u4F7F\u7528 -m 1
|
|
1355
1566
|
-y, --yes \u8DF3\u8FC7\u786E\u8BA4\u76F4\u63A5\u6267\u884C
|
|
1356
1567
|
--no-stash \u8DF3\u8FC7 stash \u63D0\u793A
|
|
@@ -1386,7 +1597,7 @@ var cli = meow(
|
|
|
1386
1597
|
remote: { type: "string", shortFlag: "r" },
|
|
1387
1598
|
branch: { type: "string", shortFlag: "b" },
|
|
1388
1599
|
commits: { type: "string", shortFlag: "c" },
|
|
1389
|
-
count: { type: "number", shortFlag: "n", default:
|
|
1600
|
+
count: { type: "number", shortFlag: "n", default: 100 },
|
|
1390
1601
|
mainline: { type: "boolean", shortFlag: "m", default: false },
|
|
1391
1602
|
yes: { type: "boolean", shortFlag: "y", default: false },
|
|
1392
1603
|
noStash: { type: "boolean", default: false },
|
package/package.json
CHANGED