@ogpoyraz/wtx 0.8.6 → 0.8.7
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.mjs +691 -242
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -25437,6 +25437,13 @@ function wrapText(text, width) {
|
|
|
25437
25437
|
function isTapWithoutDrag(down, up) {
|
|
25438
25438
|
return Math.abs(up.x - down.x) <= 1 && Math.abs(up.y - down.y) <= 1;
|
|
25439
25439
|
}
|
|
25440
|
+
function clampSplitRatio(totalWidth, ratio, dividerWidth = DIVIDER_WIDTH) {
|
|
25441
|
+
if (totalWidth <= MIN_PANE_COLS * 2 + dividerWidth)
|
|
25442
|
+
return 0.5;
|
|
25443
|
+
const minRatio = MIN_PANE_COLS / totalWidth;
|
|
25444
|
+
const maxRatio = (totalWidth - MIN_PANE_COLS - dividerWidth) / totalWidth;
|
|
25445
|
+
return Math.max(minRatio, Math.min(maxRatio, ratio));
|
|
25446
|
+
}
|
|
25440
25447
|
function mergeBlocks(prev, next, scope) {
|
|
25441
25448
|
if (!scope)
|
|
25442
25449
|
return sortBlocks(next);
|
|
@@ -25492,6 +25499,7 @@ function withCreatePlaceholders(blocks, creating) {
|
|
|
25492
25499
|
return { ...block, rows: sortRowsHierarchically([...block.rows, ...placeholders]) };
|
|
25493
25500
|
});
|
|
25494
25501
|
}
|
|
25502
|
+
var MIN_PANE_COLS = 20, DIVIDER_WIDTH = 3;
|
|
25495
25503
|
var init_utils = __esm(() => {
|
|
25496
25504
|
init_stack();
|
|
25497
25505
|
});
|
|
@@ -25600,14 +25608,19 @@ import { useRef as useRef2, useCallback as useCallback2 } from "react";
|
|
|
25600
25608
|
function useTapHandler(onTap) {
|
|
25601
25609
|
const down = useRef2(null);
|
|
25602
25610
|
const onMouseDown = useCallback2((e) => {
|
|
25611
|
+
if (e.button !== 0)
|
|
25612
|
+
return;
|
|
25603
25613
|
down.current = { x: e.x, y: e.y };
|
|
25604
25614
|
}, []);
|
|
25605
25615
|
const onMouseUp = useCallback2((e) => {
|
|
25606
25616
|
const start = down.current;
|
|
25607
25617
|
down.current = null;
|
|
25618
|
+
if (e.button !== 0)
|
|
25619
|
+
return;
|
|
25608
25620
|
if (!start || !isTapWithoutDrag(start, e))
|
|
25609
25621
|
return;
|
|
25610
|
-
|
|
25622
|
+
e.stopPropagation();
|
|
25623
|
+
onTap(e);
|
|
25611
25624
|
}, [onTap]);
|
|
25612
25625
|
return { onMouseDown, onMouseUp };
|
|
25613
25626
|
}
|
|
@@ -25679,7 +25692,7 @@ async function openInBrowser(url2) {
|
|
|
25679
25692
|
|
|
25680
25693
|
// src/tui/components/WorktreeTable.tsx
|
|
25681
25694
|
import { useEffect as useEffect2, useRef as useRef3 } from "react";
|
|
25682
|
-
import { jsx, jsxs
|
|
25695
|
+
import { jsx, jsxs } from "@opentui/react/jsx-runtime";
|
|
25683
25696
|
function statusBadge(row) {
|
|
25684
25697
|
if (row.isMainCheckout)
|
|
25685
25698
|
return { text: "[main]", fg: tokens.accent };
|
|
@@ -25693,11 +25706,27 @@ function statusBadge(row) {
|
|
|
25693
25706
|
return { text: `dirty (${row.dirtyFiles.length})`, fg: tokens.warning };
|
|
25694
25707
|
return { text: "clean", fg: tokens.dim };
|
|
25695
25708
|
}
|
|
25696
|
-
function WorktreeItem({
|
|
25709
|
+
function WorktreeItem({
|
|
25710
|
+
row,
|
|
25711
|
+
isSelected,
|
|
25712
|
+
isMultiSelected,
|
|
25713
|
+
indicator,
|
|
25714
|
+
frame,
|
|
25715
|
+
id,
|
|
25716
|
+
onRowClick,
|
|
25717
|
+
onToggleSelect
|
|
25718
|
+
}) {
|
|
25697
25719
|
const prTap = useTapHandler(() => {
|
|
25698
25720
|
if (row.prUrl)
|
|
25699
25721
|
openInBrowser(row.prUrl);
|
|
25700
25722
|
});
|
|
25723
|
+
const rowTap = useTapHandler(() => {
|
|
25724
|
+
onRowClick?.();
|
|
25725
|
+
});
|
|
25726
|
+
const gutterTap = useTapHandler((e) => {
|
|
25727
|
+
e.stopPropagation();
|
|
25728
|
+
onToggleSelect?.();
|
|
25729
|
+
});
|
|
25701
25730
|
const badge = indicator ? indicator.running ? { text: `${frame} ${indicator.verb}…`, fg: tokens.accent } : { text: `◌ ${indicator.verb}`, fg: tokens.dim } : row.isPendingCreate ? { text: `${frame} creating…`, fg: tokens.accent } : statusBadge(row);
|
|
25702
25731
|
const disabled = indicator !== undefined || row.isPendingCreate === true;
|
|
25703
25732
|
const primary = isSelected ? tokens.bright : disabled ? tokens.dim : tokens.fg;
|
|
@@ -25714,98 +25743,134 @@ function WorktreeItem({ row, isSelected, isMultiSelected, indicator, frame, id }
|
|
|
25714
25743
|
ownerSegment,
|
|
25715
25744
|
baseSegment
|
|
25716
25745
|
].filter(Boolean).join(" ").trimEnd();
|
|
25746
|
+
const isClickable = !row.isPendingCreate && !indicator;
|
|
25717
25747
|
return /* @__PURE__ */ jsxs("box", {
|
|
25718
25748
|
id,
|
|
25719
25749
|
flexDirection: "column",
|
|
25720
25750
|
backgroundColor: isSelected ? tokens.selectionBg : undefined,
|
|
25721
25751
|
style: { paddingRight: 1 },
|
|
25752
|
+
...isClickable && onRowClick ? rowTap : {},
|
|
25722
25753
|
children: [
|
|
25723
|
-
/* @__PURE__ */ jsxs("
|
|
25754
|
+
/* @__PURE__ */ jsxs("box", {
|
|
25755
|
+
flexDirection: "row",
|
|
25724
25756
|
children: [
|
|
25725
|
-
/* @__PURE__ */ jsx("
|
|
25726
|
-
|
|
25727
|
-
|
|
25728
|
-
|
|
25729
|
-
|
|
25730
|
-
fg: tokens.accent,
|
|
25731
|
-
children: isMultiSelected ? "✓ " : " "
|
|
25732
|
-
}),
|
|
25733
|
-
/* @__PURE__ */ jsx("span", {
|
|
25734
|
-
fg: tokens.dim,
|
|
25735
|
-
children: hierarchyPrefix
|
|
25736
|
-
}),
|
|
25737
|
-
/* @__PURE__ */ jsx("span", {
|
|
25738
|
-
fg: primary,
|
|
25739
|
-
children: truncateBranch(row.branch)
|
|
25757
|
+
/* @__PURE__ */ jsx("text", {
|
|
25758
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
25759
|
+
fg: primary,
|
|
25760
|
+
children: isSelected ? "▸ " : " "
|
|
25761
|
+
})
|
|
25740
25762
|
}),
|
|
25741
|
-
/* @__PURE__ */ jsx("
|
|
25742
|
-
|
|
25743
|
-
|
|
25744
|
-
|
|
25745
|
-
|
|
25746
|
-
|
|
25747
|
-
|
|
25748
|
-
...row.prUrl ? prTap : {},
|
|
25749
|
-
children: [
|
|
25750
|
-
/* @__PURE__ */ jsx("span", {
|
|
25751
|
-
fg: tokens.dim,
|
|
25752
|
-
children: secondary
|
|
25763
|
+
/* @__PURE__ */ jsx("box", {
|
|
25764
|
+
width: 2,
|
|
25765
|
+
...onToggleSelect ? gutterTap : {},
|
|
25766
|
+
children: /* @__PURE__ */ jsx("text", {
|
|
25767
|
+
fg: tokens.accent,
|
|
25768
|
+
children: isMultiSelected ? "✓ " : " "
|
|
25769
|
+
})
|
|
25753
25770
|
}),
|
|
25754
|
-
|
|
25771
|
+
/* @__PURE__ */ jsxs("text", {
|
|
25755
25772
|
children: [
|
|
25756
25773
|
/* @__PURE__ */ jsx("span", {
|
|
25757
25774
|
fg: tokens.dim,
|
|
25758
|
-
children:
|
|
25775
|
+
children: hierarchyPrefix
|
|
25759
25776
|
}),
|
|
25760
25777
|
/* @__PURE__ */ jsx("span", {
|
|
25761
|
-
fg:
|
|
25762
|
-
children:
|
|
25763
|
-
}),
|
|
25764
|
-
row.prState && /* @__PURE__ */ jsx("span", {
|
|
25765
|
-
fg: tokens.dim,
|
|
25766
|
-
children: ` ${row.prState}`
|
|
25778
|
+
fg: primary,
|
|
25779
|
+
children: truncateBranch(row.branch)
|
|
25767
25780
|
}),
|
|
25768
|
-
|
|
25781
|
+
/* @__PURE__ */ jsx("span", {
|
|
25782
|
+
fg: badge.fg,
|
|
25783
|
+
children: ` ${badge.text}`
|
|
25784
|
+
})
|
|
25785
|
+
]
|
|
25786
|
+
})
|
|
25787
|
+
]
|
|
25788
|
+
}),
|
|
25789
|
+
/* @__PURE__ */ jsxs("box", {
|
|
25790
|
+
flexDirection: "row",
|
|
25791
|
+
children: [
|
|
25792
|
+
/* @__PURE__ */ jsxs("text", {
|
|
25793
|
+
children: [
|
|
25794
|
+
/* @__PURE__ */ jsx("span", {
|
|
25769
25795
|
fg: tokens.dim,
|
|
25770
|
-
children:
|
|
25796
|
+
children: secondary
|
|
25771
25797
|
}),
|
|
25772
|
-
row.
|
|
25798
|
+
row.prNumber !== null && secondary ? /* @__PURE__ */ jsx("span", {
|
|
25773
25799
|
fg: tokens.dim,
|
|
25774
|
-
children: "
|
|
25775
|
-
})
|
|
25800
|
+
children: " · "
|
|
25801
|
+
}) : null
|
|
25776
25802
|
]
|
|
25777
25803
|
}),
|
|
25778
|
-
|
|
25779
|
-
|
|
25780
|
-
children:
|
|
25804
|
+
row.prNumber !== null && /* @__PURE__ */ jsx("box", {
|
|
25805
|
+
...row.prUrl ? prTap : {},
|
|
25806
|
+
children: /* @__PURE__ */ jsxs("text", {
|
|
25807
|
+
children: [
|
|
25808
|
+
/* @__PURE__ */ jsx("span", {
|
|
25809
|
+
fg: tokens.accent,
|
|
25810
|
+
children: `#${row.prNumber}`
|
|
25811
|
+
}),
|
|
25812
|
+
row.prState && /* @__PURE__ */ jsx("span", {
|
|
25813
|
+
fg: tokens.dim,
|
|
25814
|
+
children: ` ${row.prState}`
|
|
25815
|
+
}),
|
|
25816
|
+
row.prChecks && /* @__PURE__ */ jsx("span", {
|
|
25817
|
+
fg: tokens.dim,
|
|
25818
|
+
children: ` (${row.prChecks})`
|
|
25819
|
+
}),
|
|
25820
|
+
row.prUrl && /* @__PURE__ */ jsx("span", {
|
|
25821
|
+
fg: tokens.dim,
|
|
25822
|
+
children: " ↗"
|
|
25823
|
+
})
|
|
25824
|
+
]
|
|
25825
|
+
})
|
|
25781
25826
|
}),
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25827
|
+
/* @__PURE__ */ jsxs("text", {
|
|
25828
|
+
children: [
|
|
25829
|
+
baseChangedSegment && /* @__PURE__ */ jsx("span", {
|
|
25830
|
+
fg: tokens.warning,
|
|
25831
|
+
children: baseChangedSegment
|
|
25832
|
+
}),
|
|
25833
|
+
rebaseSegment && /* @__PURE__ */ jsx("span", {
|
|
25834
|
+
fg: tokens.error,
|
|
25835
|
+
children: rebaseSegment
|
|
25836
|
+
})
|
|
25837
|
+
]
|
|
25785
25838
|
})
|
|
25786
25839
|
]
|
|
25787
25840
|
})
|
|
25788
25841
|
]
|
|
25789
25842
|
});
|
|
25790
25843
|
}
|
|
25791
|
-
function WorktreeTable({ blocks, selectedIndex, selection = new Set, frame, repoVerbs, rowVerbs }) {
|
|
25844
|
+
function WorktreeTable({ blocks, selectedIndex, selection = new Set, frame, repoVerbs, rowVerbs, onRowClick, onToggleSelect }) {
|
|
25792
25845
|
const scrollRef = useRef3(null);
|
|
25793
25846
|
useEffect2(() => {
|
|
25794
25847
|
if (scrollRef.current?.scrollChildIntoView) {
|
|
25795
25848
|
scrollRef.current.scrollChildIntoView("selected-row");
|
|
25796
25849
|
}
|
|
25797
25850
|
}, [selectedIndex]);
|
|
25798
|
-
|
|
25851
|
+
const flatIndexMap = new Map;
|
|
25852
|
+
let idx = 0;
|
|
25853
|
+
for (const b of blocks) {
|
|
25854
|
+
for (const r of b.rows) {
|
|
25855
|
+
if (!r.isPendingCreate)
|
|
25856
|
+
flatIndexMap.set(r.path, idx++);
|
|
25857
|
+
}
|
|
25858
|
+
}
|
|
25859
|
+
let headerSeen = 0;
|
|
25799
25860
|
return /* @__PURE__ */ jsx("scrollbox", {
|
|
25800
25861
|
ref: scrollRef,
|
|
25801
25862
|
id: "worktree-table",
|
|
25802
|
-
flexGrow:
|
|
25863
|
+
flexGrow: 1,
|
|
25864
|
+
width: "100%",
|
|
25803
25865
|
height: "100%",
|
|
25804
25866
|
border: true,
|
|
25805
25867
|
borderColor: tokens.border,
|
|
25806
25868
|
title: "Worktrees",
|
|
25807
25869
|
paddingX: 1,
|
|
25808
25870
|
focused: false,
|
|
25871
|
+
onMouseScroll: (e) => {
|
|
25872
|
+
e.stopPropagation();
|
|
25873
|
+
},
|
|
25809
25874
|
children: blocks.length === 0 ? /* @__PURE__ */ jsx("text", {
|
|
25810
25875
|
fg: tokens.dim,
|
|
25811
25876
|
children: "No repositories configured."
|
|
@@ -25816,7 +25881,7 @@ function WorktreeTable({ blocks, selectedIndex, selection = new Set, frame, repo
|
|
|
25816
25881
|
style: { marginBottom: 1 },
|
|
25817
25882
|
children: [
|
|
25818
25883
|
/* @__PURE__ */ jsx("box", {
|
|
25819
|
-
style: { marginTop:
|
|
25884
|
+
style: { marginTop: headerSeen === 0 ? 0 : 1 },
|
|
25820
25885
|
children: /* @__PURE__ */ jsxs("text", {
|
|
25821
25886
|
children: [
|
|
25822
25887
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -25837,18 +25902,23 @@ function WorktreeTable({ blocks, selectedIndex, selection = new Set, frame, repo
|
|
|
25837
25902
|
]
|
|
25838
25903
|
})
|
|
25839
25904
|
}),
|
|
25905
|
+
(() => {
|
|
25906
|
+
headerSeen++;
|
|
25907
|
+
return null;
|
|
25908
|
+
})(),
|
|
25840
25909
|
block.rows.map((row) => {
|
|
25841
25910
|
const navigable = !row.isPendingCreate;
|
|
25842
|
-
const
|
|
25843
|
-
|
|
25844
|
-
flatIndex++;
|
|
25911
|
+
const flatIdx = flatIndexMap.get(row.path);
|
|
25912
|
+
const isSelected = navigable && flatIdx === selectedIndex;
|
|
25845
25913
|
return /* @__PURE__ */ jsx(WorktreeItem, {
|
|
25846
25914
|
row,
|
|
25847
25915
|
isSelected,
|
|
25848
25916
|
isMultiSelected: selection.has(row.path),
|
|
25849
25917
|
indicator: rowVerbs.get(row.path),
|
|
25850
25918
|
frame,
|
|
25851
|
-
id: isSelected ? "selected-row" : undefined
|
|
25919
|
+
id: isSelected ? "selected-row" : undefined,
|
|
25920
|
+
onRowClick: navigable && flatIdx !== undefined && onRowClick ? () => onRowClick(flatIdx) : undefined,
|
|
25921
|
+
onToggleSelect: onToggleSelect ? () => onToggleSelect(row.path) : undefined
|
|
25852
25922
|
}, row.path);
|
|
25853
25923
|
})
|
|
25854
25924
|
]
|
|
@@ -25863,7 +25933,7 @@ var init_WorktreeTable = __esm(() => {
|
|
|
25863
25933
|
});
|
|
25864
25934
|
|
|
25865
25935
|
// src/tui/components/DetailPane.tsx
|
|
25866
|
-
import { jsx as jsx2, jsxs as jsxs2, Fragment
|
|
25936
|
+
import { jsx as jsx2, jsxs as jsxs2, Fragment } from "@opentui/react/jsx-runtime";
|
|
25867
25937
|
function DetailPane({ selectedRow }) {
|
|
25868
25938
|
const prTap = useTapHandler(() => {
|
|
25869
25939
|
if (selectedRow?.prUrl)
|
|
@@ -25873,6 +25943,7 @@ function DetailPane({ selectedRow }) {
|
|
|
25873
25943
|
return /* @__PURE__ */ jsx2("box", {
|
|
25874
25944
|
id: "detail-pane",
|
|
25875
25945
|
flexGrow: 1,
|
|
25946
|
+
width: "100%",
|
|
25876
25947
|
height: "100%",
|
|
25877
25948
|
border: true,
|
|
25878
25949
|
borderColor: tokens.border,
|
|
@@ -25911,6 +25982,7 @@ function DetailPane({ selectedRow }) {
|
|
|
25911
25982
|
return /* @__PURE__ */ jsxs2("scrollbox", {
|
|
25912
25983
|
id: "detail-pane",
|
|
25913
25984
|
flexGrow: 1,
|
|
25985
|
+
width: "100%",
|
|
25914
25986
|
height: "100%",
|
|
25915
25987
|
border: true,
|
|
25916
25988
|
borderColor: tokens.border,
|
|
@@ -26083,7 +26155,7 @@ function DetailPane({ selectedRow }) {
|
|
|
26083
26155
|
})
|
|
26084
26156
|
]
|
|
26085
26157
|
}),
|
|
26086
|
-
prNumber !== null && /* @__PURE__ */ jsxs2(
|
|
26158
|
+
prNumber !== null && /* @__PURE__ */ jsxs2(Fragment, {
|
|
26087
26159
|
children: [
|
|
26088
26160
|
/* @__PURE__ */ jsxs2("text", {
|
|
26089
26161
|
style: { marginTop: 1 },
|
|
@@ -26179,7 +26251,7 @@ function DetailPane({ selectedRow }) {
|
|
|
26179
26251
|
fg: tokens.dim,
|
|
26180
26252
|
children: "Actions:"
|
|
26181
26253
|
}),
|
|
26182
|
-
!isMainCheckout && /* @__PURE__ */ jsxs2(
|
|
26254
|
+
!isMainCheckout && /* @__PURE__ */ jsxs2(Fragment, {
|
|
26183
26255
|
children: [
|
|
26184
26256
|
/* @__PURE__ */ jsxs2("text", {
|
|
26185
26257
|
fg: tokens.dim,
|
|
@@ -26215,8 +26287,44 @@ var init_DetailPane = __esm(() => {
|
|
|
26215
26287
|
|
|
26216
26288
|
// src/tui/components/Footer.tsx
|
|
26217
26289
|
import { jsx as jsx3, jsxs as jsxs3 } from "@opentui/react/jsx-runtime";
|
|
26218
|
-
function
|
|
26219
|
-
const
|
|
26290
|
+
function HintItem({ hintKey, label, isFirst, onClick }) {
|
|
26291
|
+
const tap = useTapHandler(() => onClick?.(hintKey));
|
|
26292
|
+
return /* @__PURE__ */ jsx3("box", {
|
|
26293
|
+
flexDirection: "row",
|
|
26294
|
+
...onClick ? tap : {},
|
|
26295
|
+
children: /* @__PURE__ */ jsxs3("text", {
|
|
26296
|
+
children: [
|
|
26297
|
+
/* @__PURE__ */ jsx3("span", {
|
|
26298
|
+
fg: tokens.dim,
|
|
26299
|
+
children: isFirst ? "" : " · "
|
|
26300
|
+
}),
|
|
26301
|
+
/* @__PURE__ */ jsx3("span", {
|
|
26302
|
+
fg: tokens.dim,
|
|
26303
|
+
children: `${hintKey} ${label}`
|
|
26304
|
+
})
|
|
26305
|
+
]
|
|
26306
|
+
})
|
|
26307
|
+
});
|
|
26308
|
+
}
|
|
26309
|
+
function ErrorBadge({ count: count2, onClick }) {
|
|
26310
|
+
const tap = useTapHandler(() => onClick?.());
|
|
26311
|
+
return /* @__PURE__ */ jsx3("box", {
|
|
26312
|
+
...onClick ? tap : {},
|
|
26313
|
+
children: /* @__PURE__ */ jsxs3("text", {
|
|
26314
|
+
children: [
|
|
26315
|
+
/* @__PURE__ */ jsx3("span", {
|
|
26316
|
+
fg: tokens.error,
|
|
26317
|
+
children: `${count2} error${count2 !== 1 ? "s" : ""}`
|
|
26318
|
+
}),
|
|
26319
|
+
/* @__PURE__ */ jsx3("span", {
|
|
26320
|
+
fg: tokens.dim,
|
|
26321
|
+
children: " · e view"
|
|
26322
|
+
})
|
|
26323
|
+
]
|
|
26324
|
+
})
|
|
26325
|
+
});
|
|
26326
|
+
}
|
|
26327
|
+
function Footer({ loading, lastRefreshed, errorCount, message, busyText, spinnerFrame, filter, onHintClick, onErrorClick }) {
|
|
26220
26328
|
const frame = spinnerFrame ?? "◌";
|
|
26221
26329
|
return /* @__PURE__ */ jsxs3("box", {
|
|
26222
26330
|
id: "footer",
|
|
@@ -26232,9 +26340,15 @@ function Footer({ loading, lastRefreshed, errorCount, message, busyText, spinner
|
|
|
26232
26340
|
busyText ? /* @__PURE__ */ jsx3("text", {
|
|
26233
26341
|
fg: tokens.accent,
|
|
26234
26342
|
children: `${frame} ${busyText}`
|
|
26235
|
-
}) : /* @__PURE__ */ jsx3("
|
|
26236
|
-
|
|
26237
|
-
|
|
26343
|
+
}) : /* @__PURE__ */ jsx3("box", {
|
|
26344
|
+
flexDirection: "row",
|
|
26345
|
+
gap: 1,
|
|
26346
|
+
children: HINTS.map(([key, label], idx) => /* @__PURE__ */ jsx3(HintItem, {
|
|
26347
|
+
hintKey: key,
|
|
26348
|
+
label,
|
|
26349
|
+
isFirst: idx === 0,
|
|
26350
|
+
onClick: onHintClick
|
|
26351
|
+
}, key))
|
|
26238
26352
|
}),
|
|
26239
26353
|
/* @__PURE__ */ jsxs3("box", {
|
|
26240
26354
|
flexDirection: "row",
|
|
@@ -26256,17 +26370,9 @@ function Footer({ loading, lastRefreshed, errorCount, message, busyText, spinner
|
|
|
26256
26370
|
")"
|
|
26257
26371
|
]
|
|
26258
26372
|
}) : null,
|
|
26259
|
-
errorCount > 0 ? /* @__PURE__ */
|
|
26260
|
-
|
|
26261
|
-
|
|
26262
|
-
fg: tokens.error,
|
|
26263
|
-
children: `${errorCount} error${errorCount !== 1 ? "s" : ""}`
|
|
26264
|
-
}),
|
|
26265
|
-
/* @__PURE__ */ jsx3("span", {
|
|
26266
|
-
fg: tokens.dim,
|
|
26267
|
-
children: " · e view"
|
|
26268
|
-
})
|
|
26269
|
-
]
|
|
26373
|
+
errorCount > 0 ? /* @__PURE__ */ jsx3(ErrorBadge, {
|
|
26374
|
+
count: errorCount,
|
|
26375
|
+
onClick: onErrorClick
|
|
26270
26376
|
}) : null,
|
|
26271
26377
|
/* @__PURE__ */ jsx3("text", {
|
|
26272
26378
|
fg: tokens.dim,
|
|
@@ -26280,6 +26386,7 @@ function Footer({ loading, lastRefreshed, errorCount, message, busyText, spinner
|
|
|
26280
26386
|
var HINTS;
|
|
26281
26387
|
var init_Footer = __esm(() => {
|
|
26282
26388
|
init_theme();
|
|
26389
|
+
init_use_tap();
|
|
26283
26390
|
HINTS = [
|
|
26284
26391
|
["c", "config"],
|
|
26285
26392
|
["n", "create"],
|
|
@@ -26297,10 +26404,76 @@ var init_Footer = __esm(() => {
|
|
|
26297
26404
|
];
|
|
26298
26405
|
});
|
|
26299
26406
|
|
|
26300
|
-
// src/tui/components/
|
|
26407
|
+
// src/tui/components/Divider.tsx
|
|
26408
|
+
import { useState as useState2, useRef as useRef4, useCallback as useCallback3 } from "react";
|
|
26409
|
+
import { useRenderer } from "@opentui/react";
|
|
26301
26410
|
import { jsx as jsx4 } from "@opentui/react/jsx-runtime";
|
|
26302
|
-
function
|
|
26411
|
+
function Divider({ splitRatio, totalWidth, onChange, onDraggingChange }) {
|
|
26412
|
+
const renderer = useRenderer();
|
|
26413
|
+
const [hovered, setHovered] = useState2(false);
|
|
26414
|
+
const [dragging, setDragging] = useState2(false);
|
|
26415
|
+
const startXRef = useRef4(null);
|
|
26416
|
+
const startRatioRef = useRef4(splitRatio);
|
|
26417
|
+
const handleMouseDown = useCallback3((e) => {
|
|
26418
|
+
if (e.button !== 0)
|
|
26419
|
+
return;
|
|
26420
|
+
startXRef.current = e.x;
|
|
26421
|
+
startRatioRef.current = splitRatio;
|
|
26422
|
+
setDragging(true);
|
|
26423
|
+
onDraggingChange?.(true);
|
|
26424
|
+
renderer.clearSelection();
|
|
26425
|
+
e.stopPropagation();
|
|
26426
|
+
}, [splitRatio, onDraggingChange, renderer]);
|
|
26427
|
+
const handleMouseUp = useCallback3((e) => {
|
|
26428
|
+
if (e.button !== 0)
|
|
26429
|
+
return;
|
|
26430
|
+
startXRef.current = null;
|
|
26431
|
+
setDragging(false);
|
|
26432
|
+
onDraggingChange?.(false);
|
|
26433
|
+
e.stopPropagation();
|
|
26434
|
+
}, [onDraggingChange]);
|
|
26435
|
+
const handleMouseDrag = useCallback3((e) => {
|
|
26436
|
+
if (startXRef.current === null)
|
|
26437
|
+
return;
|
|
26438
|
+
renderer.clearSelection();
|
|
26439
|
+
const dx = e.x - startXRef.current;
|
|
26440
|
+
const next = clampSplitRatio(totalWidth, startRatioRef.current + dx / totalWidth);
|
|
26441
|
+
onChange(next);
|
|
26442
|
+
e.stopPropagation();
|
|
26443
|
+
}, [totalWidth, onChange, renderer]);
|
|
26444
|
+
const dragHandlers = {
|
|
26445
|
+
onMouseDown: handleMouseDown,
|
|
26446
|
+
onMouseUp: handleMouseUp,
|
|
26447
|
+
onMouseDrag: handleMouseDrag,
|
|
26448
|
+
onMouseMove: handleMouseDrag
|
|
26449
|
+
};
|
|
26303
26450
|
return /* @__PURE__ */ jsx4("box", {
|
|
26451
|
+
width: 3,
|
|
26452
|
+
height: "100%",
|
|
26453
|
+
backgroundColor: dragging ? tokens.selectionBg : hovered ? tokens.panelBg : undefined,
|
|
26454
|
+
...dragHandlers,
|
|
26455
|
+
onMouseOver: () => setHovered(true),
|
|
26456
|
+
onMouseOut: () => setHovered(false),
|
|
26457
|
+
alignItems: "center",
|
|
26458
|
+
justifyContent: "center",
|
|
26459
|
+
children: /* @__PURE__ */ jsx4("text", {
|
|
26460
|
+
fg: dragging ? tokens.accent : hovered ? tokens.borderActive : tokens.border,
|
|
26461
|
+
...dragHandlers,
|
|
26462
|
+
onMouseOver: () => setHovered(true),
|
|
26463
|
+
onMouseOut: () => setHovered(false),
|
|
26464
|
+
children: " │ "
|
|
26465
|
+
})
|
|
26466
|
+
});
|
|
26467
|
+
}
|
|
26468
|
+
var init_Divider = __esm(() => {
|
|
26469
|
+
init_theme();
|
|
26470
|
+
init_utils();
|
|
26471
|
+
});
|
|
26472
|
+
|
|
26473
|
+
// src/tui/components/Overlay.tsx
|
|
26474
|
+
import { jsx as jsx5 } from "@opentui/react/jsx-runtime";
|
|
26475
|
+
function Overlay({ title, borderColor = tokens.border, width = 64, children }) {
|
|
26476
|
+
return /* @__PURE__ */ jsx5("box", {
|
|
26304
26477
|
id: "overlay-scrim",
|
|
26305
26478
|
position: "absolute",
|
|
26306
26479
|
width: "100%",
|
|
@@ -26312,7 +26485,7 @@ function Overlay({ title, borderColor = tokens.border, width = 64, children }) {
|
|
|
26312
26485
|
flexDirection: "row",
|
|
26313
26486
|
justifyContent: "center",
|
|
26314
26487
|
alignItems: "center",
|
|
26315
|
-
children: /* @__PURE__ */
|
|
26488
|
+
children: /* @__PURE__ */ jsx5("box", {
|
|
26316
26489
|
id: "overlay-panel",
|
|
26317
26490
|
width,
|
|
26318
26491
|
border: true,
|
|
@@ -26332,34 +26505,34 @@ var init_Overlay = __esm(() => {
|
|
|
26332
26505
|
});
|
|
26333
26506
|
|
|
26334
26507
|
// src/tui/components/HelpOverlay.tsx
|
|
26335
|
-
import { jsx as
|
|
26508
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "@opentui/react/jsx-runtime";
|
|
26336
26509
|
function HelpOverlay() {
|
|
26337
26510
|
return /* @__PURE__ */ jsxs4(Overlay, {
|
|
26338
26511
|
title: "Help",
|
|
26339
26512
|
borderColor: tokens.border,
|
|
26340
26513
|
children: [
|
|
26341
|
-
/* @__PURE__ */
|
|
26514
|
+
/* @__PURE__ */ jsx6("box", {
|
|
26342
26515
|
flexDirection: "column",
|
|
26343
26516
|
style: { maxHeight: 40 },
|
|
26344
|
-
children: /* @__PURE__ */
|
|
26517
|
+
children: /* @__PURE__ */ jsx6("scrollbox", {
|
|
26345
26518
|
flexGrow: 1,
|
|
26346
26519
|
children: HELP_ENTRIES.map(([key, desc]) => /* @__PURE__ */ jsxs4("text", {
|
|
26347
26520
|
children: [
|
|
26348
|
-
/* @__PURE__ */
|
|
26521
|
+
/* @__PURE__ */ jsx6("span", {
|
|
26349
26522
|
fg: tokens.accent,
|
|
26350
26523
|
children: key.padEnd(10)
|
|
26351
26524
|
}),
|
|
26352
|
-
/* @__PURE__ */
|
|
26525
|
+
/* @__PURE__ */ jsx6("span", {
|
|
26353
26526
|
children: " - "
|
|
26354
26527
|
}),
|
|
26355
|
-
/* @__PURE__ */
|
|
26528
|
+
/* @__PURE__ */ jsx6("span", {
|
|
26356
26529
|
children: desc
|
|
26357
26530
|
})
|
|
26358
26531
|
]
|
|
26359
26532
|
}, key))
|
|
26360
26533
|
})
|
|
26361
26534
|
}),
|
|
26362
|
-
/* @__PURE__ */
|
|
26535
|
+
/* @__PURE__ */ jsx6("text", {
|
|
26363
26536
|
style: { marginTop: 1, fg: tokens.dim },
|
|
26364
26537
|
children: "Press any key to close"
|
|
26365
26538
|
})
|
|
@@ -26398,9 +26571,11 @@ var init_HelpOverlay = __esm(() => {
|
|
|
26398
26571
|
});
|
|
26399
26572
|
|
|
26400
26573
|
// src/tui/components/ConfirmModal.tsx
|
|
26401
|
-
import { jsx as
|
|
26402
|
-
function ConfirmModal({ title, message }) {
|
|
26403
|
-
|
|
26574
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "@opentui/react/jsx-runtime";
|
|
26575
|
+
function ConfirmModal({ title, message, onConfirm, onCancel }) {
|
|
26576
|
+
const yesTap = useTapHandler(() => onConfirm?.());
|
|
26577
|
+
const noTap = useTapHandler(() => onCancel?.());
|
|
26578
|
+
return /* @__PURE__ */ jsx7(Overlay, {
|
|
26404
26579
|
title,
|
|
26405
26580
|
borderColor: tokens.warning,
|
|
26406
26581
|
children: /* @__PURE__ */ jsxs5("box", {
|
|
@@ -26408,25 +26583,42 @@ function ConfirmModal({ title, message }) {
|
|
|
26408
26583
|
justifyContent: "center",
|
|
26409
26584
|
alignItems: "center",
|
|
26410
26585
|
children: [
|
|
26411
|
-
/* @__PURE__ */
|
|
26586
|
+
/* @__PURE__ */ jsx7("text", {
|
|
26412
26587
|
children: message
|
|
26413
26588
|
}),
|
|
26414
|
-
/* @__PURE__ */ jsxs5("
|
|
26589
|
+
/* @__PURE__ */ jsxs5("box", {
|
|
26590
|
+
flexDirection: "row",
|
|
26591
|
+
gap: 2,
|
|
26415
26592
|
style: { marginTop: 2 },
|
|
26416
26593
|
children: [
|
|
26417
|
-
/* @__PURE__ */
|
|
26418
|
-
|
|
26419
|
-
children: "
|
|
26420
|
-
|
|
26421
|
-
|
|
26422
|
-
|
|
26423
|
-
|
|
26424
|
-
|
|
26425
|
-
|
|
26426
|
-
|
|
26594
|
+
/* @__PURE__ */ jsx7("box", {
|
|
26595
|
+
...onConfirm ? yesTap : {},
|
|
26596
|
+
children: /* @__PURE__ */ jsxs5("text", {
|
|
26597
|
+
children: [
|
|
26598
|
+
/* @__PURE__ */ jsx7("span", {
|
|
26599
|
+
fg: tokens.dim,
|
|
26600
|
+
children: "[y] "
|
|
26601
|
+
}),
|
|
26602
|
+
/* @__PURE__ */ jsx7("span", {
|
|
26603
|
+
fg: tokens.success,
|
|
26604
|
+
children: "Yes"
|
|
26605
|
+
})
|
|
26606
|
+
]
|
|
26607
|
+
})
|
|
26427
26608
|
}),
|
|
26428
|
-
/* @__PURE__ */
|
|
26429
|
-
|
|
26609
|
+
/* @__PURE__ */ jsx7("box", {
|
|
26610
|
+
...onCancel ? noTap : {},
|
|
26611
|
+
children: /* @__PURE__ */ jsxs5("text", {
|
|
26612
|
+
children: [
|
|
26613
|
+
/* @__PURE__ */ jsx7("span", {
|
|
26614
|
+
fg: tokens.dim,
|
|
26615
|
+
children: "[n/esc] "
|
|
26616
|
+
}),
|
|
26617
|
+
/* @__PURE__ */ jsx7("span", {
|
|
26618
|
+
children: "Cancel"
|
|
26619
|
+
})
|
|
26620
|
+
]
|
|
26621
|
+
})
|
|
26430
26622
|
})
|
|
26431
26623
|
]
|
|
26432
26624
|
})
|
|
@@ -26437,6 +26629,7 @@ function ConfirmModal({ title, message }) {
|
|
|
26437
26629
|
var init_ConfirmModal = __esm(() => {
|
|
26438
26630
|
init_Overlay();
|
|
26439
26631
|
init_theme();
|
|
26632
|
+
init_use_tap();
|
|
26440
26633
|
});
|
|
26441
26634
|
|
|
26442
26635
|
// src/tui/actions.ts
|
|
@@ -26497,20 +26690,20 @@ async function runWtxAction(args, onLine) {
|
|
|
26497
26690
|
}
|
|
26498
26691
|
|
|
26499
26692
|
// src/tui/components/ActionLogModal.tsx
|
|
26500
|
-
import { jsx as
|
|
26693
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "@opentui/react/jsx-runtime";
|
|
26501
26694
|
function ActionLogModal({ title, lines, done, exitCode, remaining }) {
|
|
26502
26695
|
return /* @__PURE__ */ jsxs6(Overlay, {
|
|
26503
26696
|
title,
|
|
26504
26697
|
borderColor: tokens.border,
|
|
26505
26698
|
children: [
|
|
26506
|
-
/* @__PURE__ */
|
|
26699
|
+
/* @__PURE__ */ jsx8("box", {
|
|
26507
26700
|
flexGrow: 1,
|
|
26508
26701
|
flexDirection: "column",
|
|
26509
26702
|
style: { minHeight: 10, maxHeight: 20 },
|
|
26510
|
-
children: /* @__PURE__ */
|
|
26703
|
+
children: /* @__PURE__ */ jsx8("scrollbox", {
|
|
26511
26704
|
flexGrow: 1,
|
|
26512
26705
|
stickyScroll: true,
|
|
26513
|
-
children: lines.map((line, i2) => /* @__PURE__ */
|
|
26706
|
+
children: lines.map((line, i2) => /* @__PURE__ */ jsx8("text", {
|
|
26514
26707
|
fg: line.type === "err" ? tokens.error : tokens.fg,
|
|
26515
26708
|
children: line.text
|
|
26516
26709
|
}, i2))
|
|
@@ -26521,11 +26714,11 @@ function ActionLogModal({ title, lines, done, exitCode, remaining }) {
|
|
|
26521
26714
|
flexDirection: "row",
|
|
26522
26715
|
justifyContent: "center",
|
|
26523
26716
|
children: [
|
|
26524
|
-
!done && /* @__PURE__ */
|
|
26717
|
+
!done && /* @__PURE__ */ jsx8("text", {
|
|
26525
26718
|
fg: tokens.warning,
|
|
26526
26719
|
children: "Running..."
|
|
26527
26720
|
}),
|
|
26528
|
-
done && exitCode === 0 && /* @__PURE__ */
|
|
26721
|
+
done && exitCode === 0 && /* @__PURE__ */ jsx8("text", {
|
|
26529
26722
|
fg: tokens.success,
|
|
26530
26723
|
children: "✓ Done (exit 0)"
|
|
26531
26724
|
}),
|
|
@@ -26538,11 +26731,11 @@ function ActionLogModal({ title, lines, done, exitCode, remaining }) {
|
|
|
26538
26731
|
exitCode
|
|
26539
26732
|
]
|
|
26540
26733
|
}),
|
|
26541
|
-
remaining !== undefined && remaining > 0 && /* @__PURE__ */
|
|
26734
|
+
remaining !== undefined && remaining > 0 && /* @__PURE__ */ jsx8("span", {
|
|
26542
26735
|
fg: tokens.warning,
|
|
26543
26736
|
children: ` · ${remaining} more failure${remaining > 1 ? "s" : ""}`
|
|
26544
26737
|
}),
|
|
26545
|
-
/* @__PURE__ */
|
|
26738
|
+
/* @__PURE__ */ jsx8("span", {
|
|
26546
26739
|
fg: tokens.dim,
|
|
26547
26740
|
children: " - press any key to close"
|
|
26548
26741
|
})
|
|
@@ -26629,8 +26822,8 @@ var init_history = __esm(() => {
|
|
|
26629
26822
|
});
|
|
26630
26823
|
|
|
26631
26824
|
// src/tui/components/HistoryOverlay.tsx
|
|
26632
|
-
import { useEffect as useEffect3, useState as
|
|
26633
|
-
import { jsx as
|
|
26825
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
26826
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "@opentui/react/jsx-runtime";
|
|
26634
26827
|
function formatShortTime(iso) {
|
|
26635
26828
|
const d = new Date(iso);
|
|
26636
26829
|
if (Number.isNaN(d.getTime()))
|
|
@@ -26652,7 +26845,7 @@ function HistoryEntryLine({ entry }) {
|
|
|
26652
26845
|
prefix
|
|
26653
26846
|
]
|
|
26654
26847
|
}),
|
|
26655
|
-
duration3 && /* @__PURE__ */
|
|
26848
|
+
duration3 && /* @__PURE__ */ jsx9("span", {
|
|
26656
26849
|
fg: tokens.dim,
|
|
26657
26850
|
children: duration3
|
|
26658
26851
|
})
|
|
@@ -26669,7 +26862,7 @@ function HistoryEntryLine({ entry }) {
|
|
|
26669
26862
|
prefix
|
|
26670
26863
|
]
|
|
26671
26864
|
}),
|
|
26672
|
-
duration3 && /* @__PURE__ */
|
|
26865
|
+
duration3 && /* @__PURE__ */ jsx9("span", {
|
|
26673
26866
|
fg: tokens.dim,
|
|
26674
26867
|
children: duration3
|
|
26675
26868
|
})
|
|
@@ -26678,11 +26871,11 @@ function HistoryEntryLine({ entry }) {
|
|
|
26678
26871
|
}
|
|
26679
26872
|
return /* @__PURE__ */ jsxs7("text", {
|
|
26680
26873
|
children: [
|
|
26681
|
-
/* @__PURE__ */
|
|
26874
|
+
/* @__PURE__ */ jsx9("span", {
|
|
26682
26875
|
fg: tokens.error,
|
|
26683
26876
|
children: "✗ "
|
|
26684
26877
|
}),
|
|
26685
|
-
/* @__PURE__ */
|
|
26878
|
+
/* @__PURE__ */ jsx9("span", {
|
|
26686
26879
|
children: prefix
|
|
26687
26880
|
}),
|
|
26688
26881
|
/* @__PURE__ */ jsxs7("span", {
|
|
@@ -26698,7 +26891,7 @@ function HistoryEntryLine({ entry }) {
|
|
|
26698
26891
|
});
|
|
26699
26892
|
}
|
|
26700
26893
|
function HistoryOverlay() {
|
|
26701
|
-
const [entries, setEntries] =
|
|
26894
|
+
const [entries, setEntries] = useState3([]);
|
|
26702
26895
|
useEffect3(() => {
|
|
26703
26896
|
setEntries(readRecentHistory(500));
|
|
26704
26897
|
}, []);
|
|
@@ -26707,23 +26900,23 @@ function HistoryOverlay() {
|
|
|
26707
26900
|
borderColor: tokens.border,
|
|
26708
26901
|
width: 110,
|
|
26709
26902
|
children: [
|
|
26710
|
-
/* @__PURE__ */
|
|
26903
|
+
/* @__PURE__ */ jsx9("box", {
|
|
26711
26904
|
flexGrow: 1,
|
|
26712
26905
|
flexDirection: "column",
|
|
26713
26906
|
style: { minHeight: 30, maxHeight: 46 },
|
|
26714
|
-
children: entries.length === 0 ? /* @__PURE__ */
|
|
26907
|
+
children: entries.length === 0 ? /* @__PURE__ */ jsx9("text", {
|
|
26715
26908
|
fg: tokens.dim,
|
|
26716
26909
|
children: "No actions recorded yet."
|
|
26717
|
-
}) : /* @__PURE__ */
|
|
26910
|
+
}) : /* @__PURE__ */ jsx9("scrollbox", {
|
|
26718
26911
|
flexGrow: 1,
|
|
26719
|
-
children: entries.map((entry, i2) => /* @__PURE__ */
|
|
26912
|
+
children: entries.map((entry, i2) => /* @__PURE__ */ jsx9(HistoryEntryLine, {
|
|
26720
26913
|
entry
|
|
26721
26914
|
}, i2))
|
|
26722
26915
|
})
|
|
26723
26916
|
}),
|
|
26724
|
-
/* @__PURE__ */
|
|
26917
|
+
/* @__PURE__ */ jsx9("box", {
|
|
26725
26918
|
marginTop: 1,
|
|
26726
|
-
children: /* @__PURE__ */
|
|
26919
|
+
children: /* @__PURE__ */ jsx9("text", {
|
|
26727
26920
|
fg: tokens.dim,
|
|
26728
26921
|
children: "Press any key to close · newest first"
|
|
26729
26922
|
})
|
|
@@ -26738,28 +26931,28 @@ var init_HistoryOverlay = __esm(() => {
|
|
|
26738
26931
|
});
|
|
26739
26932
|
|
|
26740
26933
|
// src/tui/components/InputModal.tsx
|
|
26741
|
-
import { useState as
|
|
26742
|
-
import { jsx as
|
|
26934
|
+
import { useState as useState4 } from "react";
|
|
26935
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "@opentui/react/jsx-runtime";
|
|
26743
26936
|
function InputModal({ title, placeholder, initialValue, errorMessage: errorMessage2, onSubmit }) {
|
|
26744
|
-
const [value, setValue] =
|
|
26745
|
-
return /* @__PURE__ */
|
|
26937
|
+
const [value, setValue] = useState4(initialValue ?? "");
|
|
26938
|
+
return /* @__PURE__ */ jsx10(Overlay, {
|
|
26746
26939
|
title,
|
|
26747
26940
|
borderColor: tokens.accent,
|
|
26748
26941
|
children: /* @__PURE__ */ jsxs8("box", {
|
|
26749
26942
|
flexDirection: "column",
|
|
26750
26943
|
children: [
|
|
26751
|
-
/* @__PURE__ */
|
|
26944
|
+
/* @__PURE__ */ jsx10("input", {
|
|
26752
26945
|
focused: true,
|
|
26753
26946
|
value: initialValue ?? "",
|
|
26754
26947
|
placeholder,
|
|
26755
26948
|
onInput: (val) => setValue(val),
|
|
26756
26949
|
onSubmit: () => onSubmit(value)
|
|
26757
26950
|
}),
|
|
26758
|
-
errorMessage2 ? /* @__PURE__ */
|
|
26951
|
+
errorMessage2 ? /* @__PURE__ */ jsx10("text", {
|
|
26759
26952
|
fg: tokens.error,
|
|
26760
26953
|
style: { marginTop: 1 },
|
|
26761
26954
|
children: errorMessage2
|
|
26762
|
-
}) : /* @__PURE__ */
|
|
26955
|
+
}) : /* @__PURE__ */ jsx10("text", {
|
|
26763
26956
|
fg: tokens.dim,
|
|
26764
26957
|
style: { marginTop: 1 },
|
|
26765
26958
|
children: "Press Enter to submit, empty to cancel"
|
|
@@ -26774,11 +26967,31 @@ var init_InputModal = __esm(() => {
|
|
|
26774
26967
|
});
|
|
26775
26968
|
|
|
26776
26969
|
// src/tui/components/ChoiceModal.tsx
|
|
26777
|
-
import { useState as
|
|
26970
|
+
import { useState as useState5 } from "react";
|
|
26778
26971
|
import { useKeyboard } from "@opentui/react";
|
|
26779
|
-
import { jsx as
|
|
26972
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "@opentui/react/jsx-runtime";
|
|
26973
|
+
function ChoiceOptionRow({ option, index, isSelected, onSelect }) {
|
|
26974
|
+
const tap = useTapHandler(() => onSelect(option.value));
|
|
26975
|
+
return /* @__PURE__ */ jsxs9("box", {
|
|
26976
|
+
flexDirection: "column",
|
|
26977
|
+
backgroundColor: isSelected ? tokens.selectionBg : undefined,
|
|
26978
|
+
...tap,
|
|
26979
|
+
children: [
|
|
26980
|
+
/* @__PURE__ */ jsx11("text", {
|
|
26981
|
+
children: /* @__PURE__ */ jsx11("span", {
|
|
26982
|
+
fg: isSelected ? tokens.bright : tokens.fg,
|
|
26983
|
+
children: `${index + 1}. ${option.label}`
|
|
26984
|
+
})
|
|
26985
|
+
}),
|
|
26986
|
+
option.desc && /* @__PURE__ */ jsx11("text", {
|
|
26987
|
+
fg: tokens.dim,
|
|
26988
|
+
children: ` ${option.desc}`
|
|
26989
|
+
})
|
|
26990
|
+
]
|
|
26991
|
+
});
|
|
26992
|
+
}
|
|
26780
26993
|
function ChoiceModal({ title, options, initialIndex = 0, onSubmit, onCancel }) {
|
|
26781
|
-
const [index, setIndex] =
|
|
26994
|
+
const [index, setIndex] = useState5(Math.min(Math.max(initialIndex, 0), options.length - 1));
|
|
26782
26995
|
useKeyboard((key) => {
|
|
26783
26996
|
if (key.name === "escape") {
|
|
26784
26997
|
onCancel();
|
|
@@ -26805,27 +27018,17 @@ function ChoiceModal({ title, options, initialIndex = 0, onSubmit, onCancel }) {
|
|
|
26805
27018
|
onSubmit(option.value);
|
|
26806
27019
|
}
|
|
26807
27020
|
});
|
|
26808
|
-
return /* @__PURE__ */
|
|
27021
|
+
return /* @__PURE__ */ jsx11(Overlay, {
|
|
26809
27022
|
title,
|
|
26810
27023
|
borderColor: tokens.accent,
|
|
26811
27024
|
children: /* @__PURE__ */ jsxs9("box", {
|
|
26812
27025
|
flexDirection: "column",
|
|
26813
27026
|
children: [
|
|
26814
|
-
options.map((option, i2) => /* @__PURE__ */
|
|
26815
|
-
|
|
26816
|
-
|
|
26817
|
-
|
|
26818
|
-
|
|
26819
|
-
children: /* @__PURE__ */ jsx10("span", {
|
|
26820
|
-
fg: i2 === index ? tokens.bright : tokens.fg,
|
|
26821
|
-
children: `${i2 + 1}. ${option.label}`
|
|
26822
|
-
})
|
|
26823
|
-
}),
|
|
26824
|
-
option.desc && /* @__PURE__ */ jsx10("text", {
|
|
26825
|
-
fg: tokens.dim,
|
|
26826
|
-
children: ` ${option.desc}`
|
|
26827
|
-
})
|
|
26828
|
-
]
|
|
27027
|
+
options.map((option, i2) => /* @__PURE__ */ jsx11(ChoiceOptionRow, {
|
|
27028
|
+
option,
|
|
27029
|
+
index: i2,
|
|
27030
|
+
isSelected: i2 === index,
|
|
27031
|
+
onSelect: onSubmit
|
|
26829
27032
|
}, option.value)),
|
|
26830
27033
|
/* @__PURE__ */ jsxs9("text", {
|
|
26831
27034
|
fg: tokens.dim,
|
|
@@ -26833,7 +27036,7 @@ function ChoiceModal({ title, options, initialIndex = 0, onSubmit, onCancel }) {
|
|
|
26833
27036
|
children: [
|
|
26834
27037
|
"↑/↓ to choose · Enter to confirm · 1-",
|
|
26835
27038
|
options.length,
|
|
26836
|
-
" quick pick · Esc to cancel"
|
|
27039
|
+
" quick pick · Esc to cancel · click to select"
|
|
26837
27040
|
]
|
|
26838
27041
|
})
|
|
26839
27042
|
]
|
|
@@ -26843,18 +27046,19 @@ function ChoiceModal({ title, options, initialIndex = 0, onSubmit, onCancel }) {
|
|
|
26843
27046
|
var init_ChoiceModal = __esm(() => {
|
|
26844
27047
|
init_Overlay();
|
|
26845
27048
|
init_theme();
|
|
27049
|
+
init_use_tap();
|
|
26846
27050
|
});
|
|
26847
27051
|
|
|
26848
27052
|
// src/tui/components/ConfigOverlay.tsx
|
|
26849
|
-
import { useState as
|
|
27053
|
+
import { useState as useState6, useEffect as useEffect4 } from "react";
|
|
26850
27054
|
import { useKeyboard as useKeyboard2 } from "@opentui/react";
|
|
26851
|
-
import { jsx as
|
|
27055
|
+
import { jsx as jsx12, jsxs as jsxs10, Fragment as Fragment2 } from "@opentui/react/jsx-runtime";
|
|
26852
27056
|
function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
26853
|
-
const [config2, setConfig] =
|
|
26854
|
-
const [viewState, setViewState] =
|
|
26855
|
-
const [selectedIndex, setSelectedIndex] =
|
|
26856
|
-
const [windowStart, setWindowStart] =
|
|
26857
|
-
const [editState, setEditState] =
|
|
27057
|
+
const [config2, setConfig] = useState6(null);
|
|
27058
|
+
const [viewState, setViewState] = useState6({ type: "main" });
|
|
27059
|
+
const [selectedIndex, setSelectedIndex] = useState6(1);
|
|
27060
|
+
const [windowStart, setWindowStart] = useState6(0);
|
|
27061
|
+
const [editState, setEditState] = useState6({ type: "none" });
|
|
26858
27062
|
useEffect4(() => {
|
|
26859
27063
|
try {
|
|
26860
27064
|
setConfig(loadConfig());
|
|
@@ -27111,9 +27315,9 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27111
27315
|
hint = "Remove this repository from config";
|
|
27112
27316
|
}
|
|
27113
27317
|
}
|
|
27114
|
-
return /* @__PURE__ */ jsxs10(
|
|
27318
|
+
return /* @__PURE__ */ jsxs10(Fragment2, {
|
|
27115
27319
|
children: [
|
|
27116
|
-
/* @__PURE__ */
|
|
27320
|
+
/* @__PURE__ */ jsx12(Overlay, {
|
|
27117
27321
|
title: "Configuration",
|
|
27118
27322
|
borderColor: tokens.border,
|
|
27119
27323
|
children: /* @__PURE__ */ jsxs10("box", {
|
|
@@ -27121,7 +27325,7 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27121
27325
|
width: "100%",
|
|
27122
27326
|
height: 24,
|
|
27123
27327
|
children: [
|
|
27124
|
-
/* @__PURE__ */
|
|
27328
|
+
/* @__PURE__ */ jsx12("box", {
|
|
27125
27329
|
flexDirection: "column",
|
|
27126
27330
|
flexGrow: 1,
|
|
27127
27331
|
overflow: "hidden",
|
|
@@ -27129,7 +27333,7 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27129
27333
|
const i2 = windowStart + idx;
|
|
27130
27334
|
const isSelected = i2 === selectedIndex;
|
|
27131
27335
|
if (row.type === "header") {
|
|
27132
|
-
return /* @__PURE__ */
|
|
27336
|
+
return /* @__PURE__ */ jsx12("text", {
|
|
27133
27337
|
fg: tokens.dim,
|
|
27134
27338
|
style: { marginTop: i2 === 0 ? 0 : 1 },
|
|
27135
27339
|
children: row.label
|
|
@@ -27171,7 +27375,7 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27171
27375
|
labelText
|
|
27172
27376
|
]
|
|
27173
27377
|
}),
|
|
27174
|
-
valText && /* @__PURE__ */
|
|
27378
|
+
valText && /* @__PURE__ */ jsx12("text", {
|
|
27175
27379
|
fg: isSelected ? tokens.accent : tokens.dim,
|
|
27176
27380
|
bg: isSelected ? tokens.selectionBg : undefined,
|
|
27177
27381
|
flexShrink: 1,
|
|
@@ -27181,14 +27385,14 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27181
27385
|
}, i2);
|
|
27182
27386
|
})
|
|
27183
27387
|
}),
|
|
27184
|
-
/* @__PURE__ */
|
|
27388
|
+
/* @__PURE__ */ jsx12("box", {
|
|
27185
27389
|
flexDirection: "row",
|
|
27186
27390
|
border: true,
|
|
27187
27391
|
borderColor: tokens.border,
|
|
27188
27392
|
paddingTop: 1,
|
|
27189
27393
|
marginTop: 1,
|
|
27190
27394
|
minHeight: 3,
|
|
27191
|
-
children: /* @__PURE__ */
|
|
27395
|
+
children: /* @__PURE__ */ jsx12("text", {
|
|
27192
27396
|
fg: tokens.dim,
|
|
27193
27397
|
children: hint
|
|
27194
27398
|
})
|
|
@@ -27196,14 +27400,14 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27196
27400
|
]
|
|
27197
27401
|
})
|
|
27198
27402
|
}),
|
|
27199
|
-
editState.type === "input" && /* @__PURE__ */
|
|
27403
|
+
editState.type === "input" && /* @__PURE__ */ jsx12(InputModal, {
|
|
27200
27404
|
title: editState.title,
|
|
27201
27405
|
initialValue: editState.currentValue,
|
|
27202
27406
|
placeholder: "Enter value...",
|
|
27203
27407
|
errorMessage: editState.error,
|
|
27204
27408
|
onSubmit: handleInputSubmit
|
|
27205
27409
|
}),
|
|
27206
|
-
editState.type === "confirm_remove" && /* @__PURE__ */
|
|
27410
|
+
editState.type === "confirm_remove" && /* @__PURE__ */ jsx12(ConfirmModal, {
|
|
27207
27411
|
title: "Remove Repo",
|
|
27208
27412
|
message: `Remove repo ${editState.repo} from config?`
|
|
27209
27413
|
})
|
|
@@ -27220,26 +27424,26 @@ var init_ConfigOverlay = __esm(() => {
|
|
|
27220
27424
|
});
|
|
27221
27425
|
|
|
27222
27426
|
// src/tui/components/WarningsOverlay.tsx
|
|
27223
|
-
import { jsx as
|
|
27427
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "@opentui/react/jsx-runtime";
|
|
27224
27428
|
function WarningsOverlay({ warnings }) {
|
|
27225
27429
|
return /* @__PURE__ */ jsxs11(Overlay, {
|
|
27226
27430
|
title: `Warnings (${warnings.length})`,
|
|
27227
27431
|
borderColor: tokens.warning,
|
|
27228
27432
|
children: [
|
|
27229
|
-
/* @__PURE__ */
|
|
27433
|
+
/* @__PURE__ */ jsx13("box", {
|
|
27230
27434
|
flexDirection: "column",
|
|
27231
27435
|
style: { maxHeight: 30 },
|
|
27232
|
-
children: /* @__PURE__ */
|
|
27436
|
+
children: /* @__PURE__ */ jsx13("scrollbox", {
|
|
27233
27437
|
flexGrow: 1,
|
|
27234
27438
|
children: warnings.map((warning, i2) => /* @__PURE__ */ jsxs11("box", {
|
|
27235
27439
|
flexDirection: "column",
|
|
27236
27440
|
style: { marginBottom: 1 },
|
|
27237
27441
|
children: [
|
|
27238
|
-
/* @__PURE__ */
|
|
27442
|
+
/* @__PURE__ */ jsx13("text", {
|
|
27239
27443
|
fg: tokens.warning,
|
|
27240
27444
|
children: `⚠ ${warning.repoName}`
|
|
27241
27445
|
}),
|
|
27242
|
-
wrapText(warning.message, 56).map((line, j) => /* @__PURE__ */
|
|
27446
|
+
wrapText(warning.message, 56).map((line, j) => /* @__PURE__ */ jsx13("text", {
|
|
27243
27447
|
fg: tokens.fg,
|
|
27244
27448
|
children: ` ${line}`
|
|
27245
27449
|
}, j))
|
|
@@ -27247,7 +27451,7 @@ function WarningsOverlay({ warnings }) {
|
|
|
27247
27451
|
}, i2))
|
|
27248
27452
|
})
|
|
27249
27453
|
}),
|
|
27250
|
-
/* @__PURE__ */
|
|
27454
|
+
/* @__PURE__ */ jsx13("text", {
|
|
27251
27455
|
style: { marginTop: 1, fg: tokens.dim },
|
|
27252
27456
|
children: "Press any key to close"
|
|
27253
27457
|
})
|
|
@@ -27261,9 +27465,9 @@ var init_WarningsOverlay = __esm(() => {
|
|
|
27261
27465
|
});
|
|
27262
27466
|
|
|
27263
27467
|
// src/tui/hooks/useSpinnerFrame.ts
|
|
27264
|
-
import { useEffect as useEffect5, useState as
|
|
27468
|
+
import { useEffect as useEffect5, useState as useState7 } from "react";
|
|
27265
27469
|
function useSpinnerFrame(active) {
|
|
27266
|
-
const [index, setIndex] =
|
|
27470
|
+
const [index, setIndex] = useState7(0);
|
|
27267
27471
|
useEffect5(() => {
|
|
27268
27472
|
if (!active)
|
|
27269
27473
|
return;
|
|
@@ -27278,10 +27482,10 @@ var init_useSpinnerFrame = __esm(() => {
|
|
|
27278
27482
|
});
|
|
27279
27483
|
|
|
27280
27484
|
// src/tui/components/App.tsx
|
|
27281
|
-
import { useState as
|
|
27485
|
+
import { useState as useState8, useEffect as useEffect6, useMemo, useRef as useRef5, useCallback as useCallback4 } from "react";
|
|
27282
27486
|
import { existsSync as existsSync4 } from "node:fs";
|
|
27283
|
-
import { useKeyboard as useKeyboard3, useRenderer, useSelectionHandler } from "@opentui/react";
|
|
27284
|
-
import { jsx as
|
|
27487
|
+
import { useKeyboard as useKeyboard3, useRenderer as useRenderer2, useSelectionHandler, useTerminalDimensions } from "@opentui/react";
|
|
27488
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "@opentui/react/jsx-runtime";
|
|
27285
27489
|
function getWorktreePathFor(repoName, branch) {
|
|
27286
27490
|
try {
|
|
27287
27491
|
const config2 = loadConfig();
|
|
@@ -27292,31 +27496,39 @@ function getWorktreePathFor(repoName, branch) {
|
|
|
27292
27496
|
}
|
|
27293
27497
|
}
|
|
27294
27498
|
function App({ opts }) {
|
|
27295
|
-
const renderer =
|
|
27499
|
+
const renderer = useRenderer2();
|
|
27296
27500
|
const { blocks, loading, refreshing, error: error52, warnings, lastRefreshed, pendingRepos, refresh } = useWorktrees(opts);
|
|
27297
|
-
const [selectedIndex, setSelectedIndex] =
|
|
27298
|
-
const [modal, setModal] =
|
|
27299
|
-
const [actionMessage, setActionMessage] =
|
|
27300
|
-
const messageTimer =
|
|
27301
|
-
const [ops, setOps] =
|
|
27302
|
-
const [failedLogs, setFailedLogs] =
|
|
27303
|
-
const nextOpId =
|
|
27304
|
-
const [createModal, setCreateModal] =
|
|
27305
|
-
const [createError, setCreateError] =
|
|
27306
|
-
const [createBaseModal, setCreateBaseModal] =
|
|
27307
|
-
const [createBaseError, setCreateBaseError] =
|
|
27308
|
-
const [createDepsChoice, setCreateDepsChoice] =
|
|
27309
|
-
const [pullPrModal, setPullPrModal] =
|
|
27310
|
-
const [pullPrError, setPullPrError] =
|
|
27311
|
-
const [pullForceChoice, setPullForceChoice] =
|
|
27312
|
-
const [renameModal, setRenameModal] =
|
|
27313
|
-
const [renameError, setRenameError] =
|
|
27314
|
-
const [configOpen, setConfigOpen] =
|
|
27315
|
-
const [refreshScopes, setRefreshScopes] =
|
|
27316
|
-
const [filterText, setFilterText] =
|
|
27317
|
-
const [isFiltering, setIsFiltering] =
|
|
27318
|
-
const [selection, setSelection] =
|
|
27319
|
-
const
|
|
27501
|
+
const [selectedIndex, setSelectedIndex] = useState8(0);
|
|
27502
|
+
const [modal, setModal] = useState8({ type: "none" });
|
|
27503
|
+
const [actionMessage, setActionMessage] = useState8();
|
|
27504
|
+
const messageTimer = useRef5(null);
|
|
27505
|
+
const [ops, setOps] = useState8([]);
|
|
27506
|
+
const [failedLogs, setFailedLogs] = useState8([]);
|
|
27507
|
+
const nextOpId = useRef5(1);
|
|
27508
|
+
const [createModal, setCreateModal] = useState8(false);
|
|
27509
|
+
const [createError, setCreateError] = useState8();
|
|
27510
|
+
const [createBaseModal, setCreateBaseModal] = useState8(null);
|
|
27511
|
+
const [createBaseError, setCreateBaseError] = useState8();
|
|
27512
|
+
const [createDepsChoice, setCreateDepsChoice] = useState8(null);
|
|
27513
|
+
const [pullPrModal, setPullPrModal] = useState8(false);
|
|
27514
|
+
const [pullPrError, setPullPrError] = useState8();
|
|
27515
|
+
const [pullForceChoice, setPullForceChoice] = useState8(null);
|
|
27516
|
+
const [renameModal, setRenameModal] = useState8(false);
|
|
27517
|
+
const [renameError, setRenameError] = useState8();
|
|
27518
|
+
const [configOpen, setConfigOpen] = useState8(false);
|
|
27519
|
+
const [refreshScopes, setRefreshScopes] = useState8([]);
|
|
27520
|
+
const [filterText, setFilterText] = useState8("");
|
|
27521
|
+
const [isFiltering, setIsFiltering] = useState8(false);
|
|
27522
|
+
const [selection, setSelection] = useState8(new Set);
|
|
27523
|
+
const [splitRatio, setSplitRatio] = useState8(0.6);
|
|
27524
|
+
const [isResizing, setIsResizing] = useState8(false);
|
|
27525
|
+
const { width: termWidth } = useTerminalDimensions();
|
|
27526
|
+
const totalWidth = termWidth || renderer.width || 80;
|
|
27527
|
+
useEffect6(() => {
|
|
27528
|
+
if (termWidth)
|
|
27529
|
+
setSplitRatio((prev) => clampSplitRatio(termWidth, prev));
|
|
27530
|
+
}, [termWidth]);
|
|
27531
|
+
const doRefresh = useCallback4(async (scope) => {
|
|
27320
27532
|
const targets = scope ?? [
|
|
27321
27533
|
...new Set([...blocks.map((b) => b.repoName), ...pendingRepos])
|
|
27322
27534
|
];
|
|
@@ -27332,13 +27544,17 @@ function App({ opts }) {
|
|
|
27332
27544
|
setModal({ type: "error", message: error52 });
|
|
27333
27545
|
}
|
|
27334
27546
|
}, [error52]);
|
|
27335
|
-
const flash =
|
|
27547
|
+
const flash = useCallback4((message, ms = 3000) => {
|
|
27336
27548
|
if (messageTimer.current)
|
|
27337
27549
|
clearTimeout(messageTimer.current);
|
|
27338
27550
|
setActionMessage(message);
|
|
27339
27551
|
messageTimer.current = setTimeout(() => setActionMessage(undefined), ms);
|
|
27340
27552
|
}, []);
|
|
27341
|
-
const copySelectedText =
|
|
27553
|
+
const copySelectedText = useCallback4((warnOnEmpty) => {
|
|
27554
|
+
if (isResizing) {
|
|
27555
|
+
renderer.clearSelection();
|
|
27556
|
+
return;
|
|
27557
|
+
}
|
|
27342
27558
|
const text = renderer.getSelection()?.getSelectedText() ?? "";
|
|
27343
27559
|
if (!text) {
|
|
27344
27560
|
if (warnOnEmpty)
|
|
@@ -27346,7 +27562,7 @@ function App({ opts }) {
|
|
|
27346
27562
|
return;
|
|
27347
27563
|
}
|
|
27348
27564
|
copyTextToClipboard(renderer, text).then((ok) => flash(ok ? `Copied ${text.length} character${text.length !== 1 ? "s" : ""}` : "Copy failed"));
|
|
27349
|
-
}, [renderer, flash]);
|
|
27565
|
+
}, [renderer, flash, isResizing]);
|
|
27350
27566
|
useSelectionHandler(() => copySelectedText(false));
|
|
27351
27567
|
const busyRepos = useMemo(() => new Set(ops.flatMap((o2) => o2.repoNames)), [ops]);
|
|
27352
27568
|
const busyRowPaths = useMemo(() => new Set(ops.map((o2) => o2.rowPath).filter((p) => p !== undefined)), [ops]);
|
|
@@ -27508,6 +27724,159 @@ function App({ opts }) {
|
|
|
27508
27724
|
args.push("--force");
|
|
27509
27725
|
executeOp(op, args, [repoName]);
|
|
27510
27726
|
};
|
|
27727
|
+
const handleHintClick = useCallback4((key) => {
|
|
27728
|
+
if (key === "c") {
|
|
27729
|
+
setConfigOpen(true);
|
|
27730
|
+
return;
|
|
27731
|
+
}
|
|
27732
|
+
if (key === "?") {
|
|
27733
|
+
setModal({ type: "help" });
|
|
27734
|
+
return;
|
|
27735
|
+
}
|
|
27736
|
+
if (key === "H") {
|
|
27737
|
+
setModal({ type: "history" });
|
|
27738
|
+
return;
|
|
27739
|
+
}
|
|
27740
|
+
if (key === "r") {
|
|
27741
|
+
doRefresh();
|
|
27742
|
+
return;
|
|
27743
|
+
}
|
|
27744
|
+
if (key === "e" && warnings.length > 0) {
|
|
27745
|
+
setModal({ type: "warnings" });
|
|
27746
|
+
return;
|
|
27747
|
+
}
|
|
27748
|
+
if (key === "n") {
|
|
27749
|
+
if (!selectedRow)
|
|
27750
|
+
return;
|
|
27751
|
+
setCreateModal(true);
|
|
27752
|
+
setCreateError(undefined);
|
|
27753
|
+
return;
|
|
27754
|
+
}
|
|
27755
|
+
if (key === "m") {
|
|
27756
|
+
const target = selectedRow;
|
|
27757
|
+
if (!target || target.isMainCheckout || !target.branch || target.branch === "(detached)") {
|
|
27758
|
+
if (target?.isMainCheckout)
|
|
27759
|
+
flash("Cannot rename main checkout");
|
|
27760
|
+
else if (target && (!target.branch || target.branch === "(detached)"))
|
|
27761
|
+
flash("Cannot rename detached worktree");
|
|
27762
|
+
return;
|
|
27763
|
+
}
|
|
27764
|
+
const conflict = findConflict([target]);
|
|
27765
|
+
if (conflict) {
|
|
27766
|
+
flash(conflict);
|
|
27767
|
+
return;
|
|
27768
|
+
}
|
|
27769
|
+
setRenameModal(true);
|
|
27770
|
+
setRenameError(undefined);
|
|
27771
|
+
return;
|
|
27772
|
+
}
|
|
27773
|
+
if (key === "f") {
|
|
27774
|
+
const targets = getSelectedRows();
|
|
27775
|
+
if (targets.length > 0)
|
|
27776
|
+
startFetch(targets);
|
|
27777
|
+
return;
|
|
27778
|
+
}
|
|
27779
|
+
if (key === "o") {
|
|
27780
|
+
const targets = getSelectedRows();
|
|
27781
|
+
if (targets.length === 0)
|
|
27782
|
+
return;
|
|
27783
|
+
if (targets.length > 1) {
|
|
27784
|
+
flash("Cannot open multiple worktrees");
|
|
27785
|
+
return;
|
|
27786
|
+
}
|
|
27787
|
+
const target = targets[0];
|
|
27788
|
+
const conflict = findConflict(targets);
|
|
27789
|
+
if (conflict) {
|
|
27790
|
+
flash(conflict);
|
|
27791
|
+
return;
|
|
27792
|
+
}
|
|
27793
|
+
const op = {
|
|
27794
|
+
id: nextOpId.current++,
|
|
27795
|
+
kind: "open",
|
|
27796
|
+
repoNames: [target.repoName],
|
|
27797
|
+
rowPath: target.path,
|
|
27798
|
+
label: target.branch,
|
|
27799
|
+
title: `Open ${target.branch}`,
|
|
27800
|
+
status: "queued",
|
|
27801
|
+
lines: []
|
|
27802
|
+
};
|
|
27803
|
+
setOps((prev) => [...prev, op]);
|
|
27804
|
+
executeOp(op, ["open", target.branch, "--repo", target.repoName], null);
|
|
27805
|
+
return;
|
|
27806
|
+
}
|
|
27807
|
+
if (key === "i") {
|
|
27808
|
+
const targets = getSelectedRows();
|
|
27809
|
+
if (targets.length === 0)
|
|
27810
|
+
return;
|
|
27811
|
+
const conflict = findConflict(targets);
|
|
27812
|
+
if (conflict) {
|
|
27813
|
+
flash(conflict);
|
|
27814
|
+
return;
|
|
27815
|
+
}
|
|
27816
|
+
startBatchActions("install", targets, (r) => r.isMainCheckout ? ["deps", "--repo", r.repoName, "--install"] : ["deps", r.branch, "--repo", r.repoName, "--install"]);
|
|
27817
|
+
return;
|
|
27818
|
+
}
|
|
27819
|
+
if (key === "p") {
|
|
27820
|
+
const targets = getSelectedRows();
|
|
27821
|
+
if (targets.length === 0)
|
|
27822
|
+
return;
|
|
27823
|
+
const conflict = findConflict(targets);
|
|
27824
|
+
if (conflict) {
|
|
27825
|
+
flash(conflict);
|
|
27826
|
+
return;
|
|
27827
|
+
}
|
|
27828
|
+
startBatchActions("pull", targets, (r) => ["pull-branch", r.branch, "--repo", r.repoName]);
|
|
27829
|
+
return;
|
|
27830
|
+
}
|
|
27831
|
+
if (key === "b") {
|
|
27832
|
+
const targets = getSelectedRows();
|
|
27833
|
+
if (targets.length === 0)
|
|
27834
|
+
return;
|
|
27835
|
+
if (targets.some((r) => r.isMainCheckout)) {
|
|
27836
|
+
flash("Cannot rebase main checkout");
|
|
27837
|
+
return;
|
|
27838
|
+
}
|
|
27839
|
+
const conflict = findConflict(targets);
|
|
27840
|
+
if (conflict) {
|
|
27841
|
+
flash(conflict);
|
|
27842
|
+
return;
|
|
27843
|
+
}
|
|
27844
|
+
setModal({ type: "confirm_rebase", rows: targets });
|
|
27845
|
+
return;
|
|
27846
|
+
}
|
|
27847
|
+
if (key === "d") {
|
|
27848
|
+
const targets = getSelectedRows();
|
|
27849
|
+
if (targets.length === 0)
|
|
27850
|
+
return;
|
|
27851
|
+
if (targets.some((r) => r.isMainCheckout)) {
|
|
27852
|
+
flash("Cannot remove main checkout");
|
|
27853
|
+
return;
|
|
27854
|
+
}
|
|
27855
|
+
const conflict = findConflict(targets);
|
|
27856
|
+
if (conflict) {
|
|
27857
|
+
flash(conflict);
|
|
27858
|
+
return;
|
|
27859
|
+
}
|
|
27860
|
+
setModal({ type: "confirm_remove", rows: targets });
|
|
27861
|
+
return;
|
|
27862
|
+
}
|
|
27863
|
+
if (key === "s") {
|
|
27864
|
+
const targets = getSelectedRows();
|
|
27865
|
+
if (targets.length === 0)
|
|
27866
|
+
return;
|
|
27867
|
+
if (targets.some((r) => r.isMainCheckout)) {
|
|
27868
|
+
flash("Cannot sync main checkout");
|
|
27869
|
+
return;
|
|
27870
|
+
}
|
|
27871
|
+
const conflict = findConflict(targets);
|
|
27872
|
+
if (conflict) {
|
|
27873
|
+
flash(conflict);
|
|
27874
|
+
return;
|
|
27875
|
+
}
|
|
27876
|
+
setModal({ type: "confirm_sync", rows: targets });
|
|
27877
|
+
return;
|
|
27878
|
+
}
|
|
27879
|
+
}, [selectedRow, selection, warnings, busyRepos, busyRowPaths, doRefresh, flash, blocks]);
|
|
27511
27880
|
useKeyboard3((key) => {
|
|
27512
27881
|
if (isFiltering) {
|
|
27513
27882
|
if (key.name === "escape") {
|
|
@@ -27848,6 +28217,9 @@ function App({ opts }) {
|
|
|
27848
28217
|
})();
|
|
27849
28218
|
}
|
|
27850
28219
|
});
|
|
28220
|
+
const rawLeft = Math.floor(totalWidth * splitRatio);
|
|
28221
|
+
const leftCols = Math.max(20, Math.min(totalWidth - 20 - DIVIDER_WIDTH, rawLeft));
|
|
28222
|
+
const rightCols = Math.max(20, totalWidth - leftCols - DIVIDER_WIDTH);
|
|
27851
28223
|
return /* @__PURE__ */ jsxs12("box", {
|
|
27852
28224
|
flexDirection: "column",
|
|
27853
28225
|
width: "100%",
|
|
@@ -27858,16 +28230,34 @@ function App({ opts }) {
|
|
|
27858
28230
|
width: "100%",
|
|
27859
28231
|
flexGrow: 1,
|
|
27860
28232
|
children: [
|
|
27861
|
-
/* @__PURE__ */
|
|
27862
|
-
|
|
27863
|
-
|
|
27864
|
-
|
|
27865
|
-
|
|
27866
|
-
|
|
27867
|
-
|
|
28233
|
+
/* @__PURE__ */ jsx14("box", {
|
|
28234
|
+
width: leftCols,
|
|
28235
|
+
height: "100%",
|
|
28236
|
+
flexDirection: "column",
|
|
28237
|
+
children: /* @__PURE__ */ jsx14(WorktreeTable, {
|
|
28238
|
+
blocks: displayBlocks,
|
|
28239
|
+
selectedIndex,
|
|
28240
|
+
selection,
|
|
28241
|
+
frame: spinnerFrame,
|
|
28242
|
+
repoVerbs,
|
|
28243
|
+
rowVerbs,
|
|
28244
|
+
onRowClick: (idx) => setSelectedIndex(idx),
|
|
28245
|
+
onToggleSelect: (path37) => setSelection((prev) => toggleSelection(prev, path37))
|
|
28246
|
+
})
|
|
27868
28247
|
}),
|
|
27869
|
-
/* @__PURE__ */
|
|
27870
|
-
|
|
28248
|
+
/* @__PURE__ */ jsx14(Divider, {
|
|
28249
|
+
splitRatio,
|
|
28250
|
+
totalWidth,
|
|
28251
|
+
onChange: setSplitRatio,
|
|
28252
|
+
onDraggingChange: setIsResizing
|
|
28253
|
+
}),
|
|
28254
|
+
/* @__PURE__ */ jsx14("box", {
|
|
28255
|
+
width: rightCols,
|
|
28256
|
+
height: "100%",
|
|
28257
|
+
flexDirection: "column",
|
|
28258
|
+
children: /* @__PURE__ */ jsx14(DetailPane, {
|
|
28259
|
+
selectedRow
|
|
28260
|
+
})
|
|
27871
28261
|
})
|
|
27872
28262
|
]
|
|
27873
28263
|
}),
|
|
@@ -27877,35 +28267,51 @@ function App({ opts }) {
|
|
|
27877
28267
|
border: true,
|
|
27878
28268
|
borderColor: "magenta",
|
|
27879
28269
|
children: [
|
|
27880
|
-
/* @__PURE__ */
|
|
28270
|
+
/* @__PURE__ */ jsx14("text", {
|
|
27881
28271
|
children: "filter: "
|
|
27882
28272
|
}),
|
|
27883
|
-
/* @__PURE__ */
|
|
28273
|
+
/* @__PURE__ */ jsx14("input", {
|
|
27884
28274
|
focused: true,
|
|
27885
28275
|
placeholder: "Type to filter...",
|
|
27886
28276
|
onInput: (v) => setFilterText(v)
|
|
27887
28277
|
})
|
|
27888
28278
|
]
|
|
27889
28279
|
}),
|
|
27890
|
-
/* @__PURE__ */
|
|
28280
|
+
/* @__PURE__ */ jsx14(Footer, {
|
|
27891
28281
|
loading: loading || refreshing,
|
|
27892
28282
|
lastRefreshed,
|
|
27893
28283
|
errorCount: warnings.length,
|
|
27894
28284
|
message: actionMessage,
|
|
27895
28285
|
busyText: latestOp ? `${capitalize(VERBS[latestOp.kind])} ${latestOp.label}…${runningOps.length > 1 ? ` (+${runningOps.length - 1})` : ""}` : undefined,
|
|
27896
28286
|
spinnerFrame,
|
|
27897
|
-
filter: filterText ? { term: filterText, matches: flatRows.length, total: totalRows } : undefined
|
|
28287
|
+
filter: filterText ? { term: filterText, matches: flatRows.length, total: totalRows } : undefined,
|
|
28288
|
+
onHintClick: handleHintClick,
|
|
28289
|
+
onErrorClick: () => setModal({ type: "warnings" })
|
|
27898
28290
|
}),
|
|
27899
|
-
modal.type === "help" && /* @__PURE__ */
|
|
27900
|
-
modal.type === "history" && /* @__PURE__ */
|
|
27901
|
-
modal.type === "warnings" && /* @__PURE__ */
|
|
28291
|
+
modal.type === "help" && /* @__PURE__ */ jsx14(HelpOverlay, {}),
|
|
28292
|
+
modal.type === "history" && /* @__PURE__ */ jsx14(HistoryOverlay, {}),
|
|
28293
|
+
modal.type === "warnings" && /* @__PURE__ */ jsx14(WarningsOverlay, {
|
|
27902
28294
|
warnings
|
|
27903
28295
|
}),
|
|
27904
|
-
modal.type === "error" && /* @__PURE__ */
|
|
28296
|
+
modal.type === "error" && /* @__PURE__ */ jsx14(ConfirmModal, {
|
|
27905
28297
|
title: "Error",
|
|
27906
|
-
message: modal.message
|
|
28298
|
+
message: modal.message,
|
|
28299
|
+
onConfirm: () => {
|
|
28300
|
+
setModal({ type: "none" });
|
|
28301
|
+
if (error52) {
|
|
28302
|
+
renderer.destroy();
|
|
28303
|
+
process.exit(1);
|
|
28304
|
+
}
|
|
28305
|
+
},
|
|
28306
|
+
onCancel: () => {
|
|
28307
|
+
setModal({ type: "none" });
|
|
28308
|
+
if (error52) {
|
|
28309
|
+
renderer.destroy();
|
|
28310
|
+
process.exit(1);
|
|
28311
|
+
}
|
|
28312
|
+
}
|
|
27907
28313
|
}),
|
|
27908
|
-
modal.type === "confirm_remove" && /* @__PURE__ */
|
|
28314
|
+
modal.type === "confirm_remove" && /* @__PURE__ */ jsx14(ConfirmModal, {
|
|
27909
28315
|
title: `Remove ${modal.rows.length} Worktree(s)`,
|
|
27910
28316
|
message: (() => {
|
|
27911
28317
|
const count2 = modal.rows.length;
|
|
@@ -27920,17 +28326,41 @@ function App({ opts }) {
|
|
|
27920
28326
|
}
|
|
27921
28327
|
return lines.join(`
|
|
27922
28328
|
`);
|
|
27923
|
-
})()
|
|
28329
|
+
})(),
|
|
28330
|
+
onConfirm: () => {
|
|
28331
|
+
const rows = modal.rows;
|
|
28332
|
+
setModal({ type: "none" });
|
|
28333
|
+
startBatchActions("remove", rows, (r) => {
|
|
28334
|
+
const args = ["remove", r.branch, "--repo", r.repoName, "--yes"];
|
|
28335
|
+
const needsForce = r.dirtyFiles.length > 0 || !existsSync4(r.path);
|
|
28336
|
+
if (needsForce)
|
|
28337
|
+
args.push("--force");
|
|
28338
|
+
return args;
|
|
28339
|
+
});
|
|
28340
|
+
},
|
|
28341
|
+
onCancel: () => setModal({ type: "none" })
|
|
27924
28342
|
}),
|
|
27925
|
-
modal.type === "confirm_rebase" && /* @__PURE__ */
|
|
28343
|
+
modal.type === "confirm_rebase" && /* @__PURE__ */ jsx14(ConfirmModal, {
|
|
27926
28344
|
title: `Rebase ${modal.rows.length} Worktree(s)`,
|
|
27927
|
-
message: `Are you sure you want to fetch and rebase ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}
|
|
28345
|
+
message: `Are you sure you want to fetch and rebase ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}?`,
|
|
28346
|
+
onConfirm: () => {
|
|
28347
|
+
const rows = modal.rows;
|
|
28348
|
+
setModal({ type: "none" });
|
|
28349
|
+
startBatchActions("rebase", rows, (r) => ["rebase", r.branch, "--repo", r.repoName]);
|
|
28350
|
+
},
|
|
28351
|
+
onCancel: () => setModal({ type: "none" })
|
|
27928
28352
|
}),
|
|
27929
|
-
modal.type === "confirm_sync" && /* @__PURE__ */
|
|
28353
|
+
modal.type === "confirm_sync" && /* @__PURE__ */ jsx14(ConfirmModal, {
|
|
27930
28354
|
title: `Sync ${modal.rows.length} Worktree(s)`,
|
|
27931
|
-
message: `Are you sure you want to sync ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}
|
|
28355
|
+
message: `Are you sure you want to sync ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}?`,
|
|
28356
|
+
onConfirm: () => {
|
|
28357
|
+
const rows = modal.rows;
|
|
28358
|
+
setModal({ type: "none" });
|
|
28359
|
+
startBatchActions("sync", rows, (r) => ["sync", r.branch, "--repo", r.repoName]);
|
|
28360
|
+
},
|
|
28361
|
+
onCancel: () => setModal({ type: "none" })
|
|
27932
28362
|
}),
|
|
27933
|
-
createModal && /* @__PURE__ */
|
|
28363
|
+
createModal && /* @__PURE__ */ jsx14(InputModal, {
|
|
27934
28364
|
title: `New worktree branch in ${selectedRow?.repoName ?? ""}`,
|
|
27935
28365
|
placeholder: "Branch name (empty to cancel)",
|
|
27936
28366
|
errorMessage: createError,
|
|
@@ -27957,7 +28387,7 @@ function App({ opts }) {
|
|
|
27957
28387
|
setCreateBaseModal({ branch, repoName });
|
|
27958
28388
|
}
|
|
27959
28389
|
}),
|
|
27960
|
-
createBaseModal && /* @__PURE__ */
|
|
28390
|
+
createBaseModal && /* @__PURE__ */ jsx14(InputModal, {
|
|
27961
28391
|
title: `Base ref for ${createBaseModal.branch}`,
|
|
27962
28392
|
placeholder: "origin/main (empty for default main)",
|
|
27963
28393
|
errorMessage: createBaseError,
|
|
@@ -27973,7 +28403,7 @@ function App({ opts }) {
|
|
|
27973
28403
|
setCreateDepsChoice({ branch, repoName, base: base2 || undefined });
|
|
27974
28404
|
}
|
|
27975
28405
|
}),
|
|
27976
|
-
createDepsChoice && /* @__PURE__ */
|
|
28406
|
+
createDepsChoice && /* @__PURE__ */ jsx14(ChoiceModal, {
|
|
27977
28407
|
title: `Dependencies for ${createDepsChoice.branch}`,
|
|
27978
28408
|
options: DEPS_CHOICES,
|
|
27979
28409
|
onSubmit: (choice) => {
|
|
@@ -27983,7 +28413,7 @@ function App({ opts }) {
|
|
|
27983
28413
|
},
|
|
27984
28414
|
onCancel: () => setCreateDepsChoice(null)
|
|
27985
28415
|
}),
|
|
27986
|
-
pullPrModal && /* @__PURE__ */
|
|
28416
|
+
pullPrModal && /* @__PURE__ */ jsx14(InputModal, {
|
|
27987
28417
|
title: `Pull PR into ${selectedRow?.repoName ?? ""}`,
|
|
27988
28418
|
placeholder: "https://github.com/owner/repo/pull/123",
|
|
27989
28419
|
errorMessage: pullPrError,
|
|
@@ -28011,7 +28441,7 @@ function App({ opts }) {
|
|
|
28011
28441
|
setPullForceChoice({ link, repoName });
|
|
28012
28442
|
}
|
|
28013
28443
|
}),
|
|
28014
|
-
pullForceChoice && /* @__PURE__ */
|
|
28444
|
+
pullForceChoice && /* @__PURE__ */ jsx14(ChoiceModal, {
|
|
28015
28445
|
title: `Pull ${pullForceChoice.link.split("/").pop()}?`,
|
|
28016
28446
|
options: [
|
|
28017
28447
|
{ value: "normal", label: "Pull (skip if exists)", desc: "Fails if branch already exists" },
|
|
@@ -28024,7 +28454,7 @@ function App({ opts }) {
|
|
|
28024
28454
|
},
|
|
28025
28455
|
onCancel: () => setPullForceChoice(null)
|
|
28026
28456
|
}),
|
|
28027
|
-
renameModal && selectedRow && /* @__PURE__ */
|
|
28457
|
+
renameModal && selectedRow && /* @__PURE__ */ jsx14(InputModal, {
|
|
28028
28458
|
title: `Rename branch ${selectedRow.branch}`,
|
|
28029
28459
|
initialValue: selectedRow.branch,
|
|
28030
28460
|
placeholder: "New branch name",
|
|
@@ -28049,7 +28479,7 @@ function App({ opts }) {
|
|
|
28049
28479
|
setModal({ type: "confirm_rename", row: target, to });
|
|
28050
28480
|
}
|
|
28051
28481
|
}),
|
|
28052
|
-
modal.type === "confirm_rename" && /* @__PURE__ */
|
|
28482
|
+
modal.type === "confirm_rename" && /* @__PURE__ */ jsx14(ConfirmModal, {
|
|
28053
28483
|
title: "Rename Worktree",
|
|
28054
28484
|
message: [
|
|
28055
28485
|
`${modal.row.branch} → ${modal.to}`,
|
|
@@ -28060,14 +28490,32 @@ function App({ opts }) {
|
|
|
28060
28490
|
"Uncommitted changes and synced files move with it.",
|
|
28061
28491
|
"Proceed?"
|
|
28062
28492
|
].join(`
|
|
28063
|
-
`)
|
|
28493
|
+
`),
|
|
28494
|
+
onConfirm: () => {
|
|
28495
|
+
const { row, to } = modal;
|
|
28496
|
+
setModal({ type: "none" });
|
|
28497
|
+
const op = {
|
|
28498
|
+
id: nextOpId.current++,
|
|
28499
|
+
kind: "rename",
|
|
28500
|
+
repoNames: [row.repoName],
|
|
28501
|
+
rowPath: row.path,
|
|
28502
|
+
branch: row.branch,
|
|
28503
|
+
label: `${row.branch} → ${to}`,
|
|
28504
|
+
title: `Rename ${row.branch} → ${to}`,
|
|
28505
|
+
status: "queued",
|
|
28506
|
+
lines: []
|
|
28507
|
+
};
|
|
28508
|
+
setOps((prev) => [...prev, op]);
|
|
28509
|
+
executeOp(op, ["rename", row.branch, to, "--repo", row.repoName], [row.repoName]);
|
|
28510
|
+
},
|
|
28511
|
+
onCancel: () => setModal({ type: "none" })
|
|
28064
28512
|
}),
|
|
28065
|
-
configOpen && /* @__PURE__ */
|
|
28513
|
+
configOpen && /* @__PURE__ */ jsx14(ConfigOverlay, {
|
|
28066
28514
|
onClose: () => setConfigOpen(false),
|
|
28067
28515
|
onSaved: () => void doRefresh(),
|
|
28068
28516
|
onError: (msg) => setModal({ type: "error", message: msg })
|
|
28069
28517
|
}),
|
|
28070
|
-
failedLogs.length > 0 && /* @__PURE__ */
|
|
28518
|
+
failedLogs.length > 0 && /* @__PURE__ */ jsx14(ActionLogModal, {
|
|
28071
28519
|
title: failedLogs[0].title,
|
|
28072
28520
|
lines: failedLogs[0].lines,
|
|
28073
28521
|
done: true,
|
|
@@ -28083,6 +28531,7 @@ var init_App = __esm(() => {
|
|
|
28083
28531
|
init_WorktreeTable();
|
|
28084
28532
|
init_DetailPane();
|
|
28085
28533
|
init_Footer();
|
|
28534
|
+
init_Divider();
|
|
28086
28535
|
init_HelpOverlay();
|
|
28087
28536
|
init_ConfirmModal();
|
|
28088
28537
|
init_git();
|
|
@@ -28122,14 +28571,14 @@ __export(exports_tui, {
|
|
|
28122
28571
|
});
|
|
28123
28572
|
import { createCliRenderer, TextTableRenderable } from "@opentui/core";
|
|
28124
28573
|
import { createRoot, extend as extend2 } from "@opentui/react";
|
|
28125
|
-
import { jsx as
|
|
28574
|
+
import { jsx as jsx15 } from "@opentui/react/jsx-runtime";
|
|
28126
28575
|
async function runTerminal(opts) {
|
|
28127
28576
|
const renderer = await createCliRenderer({
|
|
28128
28577
|
exitOnCtrlC: false
|
|
28129
28578
|
});
|
|
28130
28579
|
const root = createRoot(renderer);
|
|
28131
28580
|
try {
|
|
28132
|
-
root.render(/* @__PURE__ */
|
|
28581
|
+
root.render(/* @__PURE__ */ jsx15(App, {
|
|
28133
28582
|
opts
|
|
28134
28583
|
}));
|
|
28135
28584
|
} catch (err) {
|