@ogpoyraz/wtx 0.8.0 → 0.8.2
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/README.md +1 -1
- package/dist/cli.mjs +305 -82
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -169,7 +169,7 @@ Config lives at `~/.config/wtx/config.json`.
|
|
|
169
169
|
| `agents.<name>.command` | – | Shell command template for `--agent`; `{wt}`, `{branch}`, `{repo}` expanded |
|
|
170
170
|
| `repos.<name>.main_branch` | `"auto"` | Auto-detects via `git symbolic-ref` |
|
|
171
171
|
| `repos.<name>.fetch_main_on_create` | `true` | Fetch before creating so branches start fresh |
|
|
172
|
-
| `repos.<name>.sync_files` | `[]` | Files copied from main checkout on create and sync |
|
|
172
|
+
| `repos.<name>.sync_files` | `[]` | Files or folders copied from main checkout on create and sync — directories are copied recursively (`build/`) |
|
|
173
173
|
| `repos.<name>.post_create` / `post_sync` | `[]` | Hook commands; failures fail the command with a rerun hint |
|
|
174
174
|
| `repos.<name>.install_script` | `null` | Command run inside a worktree (or the main checkout via `wtx deps --install`) for dependency installs (`{wt}`, `{branch}`, `{main}` expanded); when unset, the detected package manager performs a real install |
|
|
175
175
|
| `repos.<name>.deps.manager` | `"auto"` | Force a manager: `npm` `bun` `pnpm` `yarn` `go` `python` `cargo` |
|
package/dist/cli.mjs
CHANGED
|
@@ -15331,6 +15331,11 @@ function verbose(message, isVerbose) {
|
|
|
15331
15331
|
function indented(message) {
|
|
15332
15332
|
console.log(` ${message}`);
|
|
15333
15333
|
}
|
|
15334
|
+
function terminalLink(url2, text = url2, stream = process.stdout) {
|
|
15335
|
+
if (!stream.isTTY)
|
|
15336
|
+
return text;
|
|
15337
|
+
return `\x1B]8;;${url2}\x1B\\${text}\x1B]8;;\x1B\\`;
|
|
15338
|
+
}
|
|
15334
15339
|
var c, quietMode = false;
|
|
15335
15340
|
var init_log = __esm(() => {
|
|
15336
15341
|
init_source();
|
|
@@ -25410,6 +25415,28 @@ function sortRowsHierarchically(rows) {
|
|
|
25410
25415
|
function sortBlocks(blocks) {
|
|
25411
25416
|
return [...blocks].sort((a2, b) => a2.repoName.localeCompare(b.repoName));
|
|
25412
25417
|
}
|
|
25418
|
+
function wrapText(text, width) {
|
|
25419
|
+
const lines = [];
|
|
25420
|
+
for (const paragraph of text.split(`
|
|
25421
|
+
`)) {
|
|
25422
|
+
let current = "";
|
|
25423
|
+
for (const word of paragraph.split(/\s+/).filter(Boolean)) {
|
|
25424
|
+
if (!current) {
|
|
25425
|
+
current = word;
|
|
25426
|
+
} else if (current.length + 1 + word.length <= width) {
|
|
25427
|
+
current += ` ${word}`;
|
|
25428
|
+
} else {
|
|
25429
|
+
lines.push(current);
|
|
25430
|
+
current = word;
|
|
25431
|
+
}
|
|
25432
|
+
}
|
|
25433
|
+
lines.push(current);
|
|
25434
|
+
}
|
|
25435
|
+
return lines;
|
|
25436
|
+
}
|
|
25437
|
+
function isTapWithoutDrag(down, up) {
|
|
25438
|
+
return Math.abs(up.x - down.x) <= 1 && Math.abs(up.y - down.y) <= 1;
|
|
25439
|
+
}
|
|
25413
25440
|
function mergeBlocks(prev, next, scope) {
|
|
25414
25441
|
if (!scope)
|
|
25415
25442
|
return sortBlocks(next);
|
|
@@ -25568,9 +25595,91 @@ var init_theme = __esm(() => {
|
|
|
25568
25595
|
};
|
|
25569
25596
|
});
|
|
25570
25597
|
|
|
25598
|
+
// src/tui/hooks/use-tap.ts
|
|
25599
|
+
import { useRef as useRef2, useCallback as useCallback2 } from "react";
|
|
25600
|
+
function useTapHandler(onTap) {
|
|
25601
|
+
const down = useRef2(null);
|
|
25602
|
+
const onMouseDown = useCallback2((e) => {
|
|
25603
|
+
down.current = { x: e.x, y: e.y };
|
|
25604
|
+
}, []);
|
|
25605
|
+
const onMouseUp = useCallback2((e) => {
|
|
25606
|
+
const start = down.current;
|
|
25607
|
+
down.current = null;
|
|
25608
|
+
if (!start || !isTapWithoutDrag(start, e))
|
|
25609
|
+
return;
|
|
25610
|
+
onTap();
|
|
25611
|
+
}, [onTap]);
|
|
25612
|
+
return { onMouseDown, onMouseUp };
|
|
25613
|
+
}
|
|
25614
|
+
var init_use_tap = __esm(() => {
|
|
25615
|
+
init_utils();
|
|
25616
|
+
});
|
|
25617
|
+
|
|
25618
|
+
// src/tui/platform.ts
|
|
25619
|
+
function clipboardCandidatesFor(platform2, env2 = process.env) {
|
|
25620
|
+
if (platform2 === "darwin")
|
|
25621
|
+
return [{ cmd: "pbcopy", args: [] }];
|
|
25622
|
+
if (platform2 === "win32")
|
|
25623
|
+
return [{ cmd: "clip", args: [] }];
|
|
25624
|
+
const candidates = [];
|
|
25625
|
+
if (env2.WAYLAND_DISPLAY)
|
|
25626
|
+
candidates.push({ cmd: "wl-copy", args: [] });
|
|
25627
|
+
if (env2.DISPLAY) {
|
|
25628
|
+
candidates.push({ cmd: "xclip", args: ["-selection", "clipboard"] });
|
|
25629
|
+
candidates.push({ cmd: "xsel", args: ["--clipboard", "--input"] });
|
|
25630
|
+
}
|
|
25631
|
+
return candidates;
|
|
25632
|
+
}
|
|
25633
|
+
async function copyTextToClipboard(renderer, text) {
|
|
25634
|
+
if (!text)
|
|
25635
|
+
return false;
|
|
25636
|
+
const viaTerminal = renderer.copyToClipboardOSC52(text);
|
|
25637
|
+
let viaSystem = false;
|
|
25638
|
+
for (const candidate of clipboardCandidatesFor(process.platform)) {
|
|
25639
|
+
try {
|
|
25640
|
+
const proc = Bun.spawn([candidate.cmd, ...candidate.args], {
|
|
25641
|
+
stdin: "pipe",
|
|
25642
|
+
stdout: "ignore",
|
|
25643
|
+
stderr: "ignore"
|
|
25644
|
+
});
|
|
25645
|
+
proc.stdin.write(text);
|
|
25646
|
+
proc.stdin.end();
|
|
25647
|
+
if (await proc.exited === 0) {
|
|
25648
|
+
viaSystem = true;
|
|
25649
|
+
break;
|
|
25650
|
+
}
|
|
25651
|
+
} catch {}
|
|
25652
|
+
}
|
|
25653
|
+
return viaSystem || viaTerminal;
|
|
25654
|
+
}
|
|
25655
|
+
function browserCommandFor(platform2, url2) {
|
|
25656
|
+
if (!/^https?:\/\//.test(url2))
|
|
25657
|
+
return null;
|
|
25658
|
+
if (platform2 === "darwin")
|
|
25659
|
+
return { cmd: "open", args: [url2] };
|
|
25660
|
+
if (platform2 === "win32")
|
|
25661
|
+
return { cmd: "cmd", args: ["/c", "start", "", url2] };
|
|
25662
|
+
return { cmd: "xdg-open", args: [url2] };
|
|
25663
|
+
}
|
|
25664
|
+
async function openInBrowser(url2) {
|
|
25665
|
+
const command = browserCommandFor(process.platform, url2);
|
|
25666
|
+
if (!command)
|
|
25667
|
+
return false;
|
|
25668
|
+
try {
|
|
25669
|
+
const proc = Bun.spawn([command.cmd, ...command.args], {
|
|
25670
|
+
stdin: "ignore",
|
|
25671
|
+
stdout: "ignore",
|
|
25672
|
+
stderr: "ignore"
|
|
25673
|
+
});
|
|
25674
|
+
return await proc.exited === 0;
|
|
25675
|
+
} catch {
|
|
25676
|
+
return false;
|
|
25677
|
+
}
|
|
25678
|
+
}
|
|
25679
|
+
|
|
25571
25680
|
// src/tui/components/WorktreeTable.tsx
|
|
25572
|
-
import { useEffect as useEffect2, useRef as
|
|
25573
|
-
import { jsx, jsxs } from "@opentui/react/jsx-runtime";
|
|
25681
|
+
import { useEffect as useEffect2, useRef as useRef3 } from "react";
|
|
25682
|
+
import { jsx, jsxs, Fragment } from "@opentui/react/jsx-runtime";
|
|
25574
25683
|
function statusBadge(row) {
|
|
25575
25684
|
if (row.isMainCheckout)
|
|
25576
25685
|
return { text: "[main]", fg: tokens.accent };
|
|
@@ -25585,15 +25694,14 @@ function statusBadge(row) {
|
|
|
25585
25694
|
return { text: "clean", fg: tokens.dim };
|
|
25586
25695
|
}
|
|
25587
25696
|
function WorktreeItem({ row, isSelected, isMultiSelected, indicator, frame, id }) {
|
|
25697
|
+
const prTap = useTapHandler(() => {
|
|
25698
|
+
if (row.prUrl)
|
|
25699
|
+
openInBrowser(row.prUrl);
|
|
25700
|
+
});
|
|
25588
25701
|
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);
|
|
25589
25702
|
const disabled = indicator !== undefined || row.isPendingCreate === true;
|
|
25590
25703
|
const primary = isSelected ? tokens.bright : disabled ? tokens.dim : tokens.fg;
|
|
25591
25704
|
const divergence = row.ahead !== null && row.behind !== null && (row.ahead > 0 || row.behind > 0) ? ` · ↑${row.ahead} ↓${row.behind}` : "";
|
|
25592
|
-
const prSegment = row.prNumber ? [
|
|
25593
|
-
`· #${row.prNumber}`,
|
|
25594
|
-
row.prState ?? "",
|
|
25595
|
-
row.prChecks ? `(${row.prChecks})` : ""
|
|
25596
|
-
].filter(Boolean).join(" ") : "";
|
|
25597
25705
|
const ownerSegment = row.owner ? ` · by ${row.owner}` : "";
|
|
25598
25706
|
const baseSegment = row.base ? ` · base ${row.base}` : "";
|
|
25599
25707
|
const rebaseSegment = !row.isMainCheckout && row.rebaseStatus && !row.isPrunable ? ` · ${row.rebaseStatus}` : "";
|
|
@@ -25603,7 +25711,6 @@ function WorktreeItem({ row, isSelected, isMultiSelected, indicator, frame, id }
|
|
|
25603
25711
|
const secondary = [
|
|
25604
25712
|
`${secondaryIndent}${row.commitShort}`,
|
|
25605
25713
|
divergence,
|
|
25606
|
-
prSegment,
|
|
25607
25714
|
ownerSegment,
|
|
25608
25715
|
baseSegment
|
|
25609
25716
|
].filter(Boolean).join(" ").trimEnd();
|
|
@@ -25638,11 +25745,36 @@ function WorktreeItem({ row, isSelected, isMultiSelected, indicator, frame, id }
|
|
|
25638
25745
|
]
|
|
25639
25746
|
}),
|
|
25640
25747
|
/* @__PURE__ */ jsxs("text", {
|
|
25748
|
+
...row.prUrl ? prTap : {},
|
|
25641
25749
|
children: [
|
|
25642
25750
|
/* @__PURE__ */ jsx("span", {
|
|
25643
25751
|
fg: tokens.dim,
|
|
25644
25752
|
children: secondary
|
|
25645
25753
|
}),
|
|
25754
|
+
row.prNumber !== null && /* @__PURE__ */ jsxs(Fragment, {
|
|
25755
|
+
children: [
|
|
25756
|
+
/* @__PURE__ */ jsx("span", {
|
|
25757
|
+
fg: tokens.dim,
|
|
25758
|
+
children: secondary ? " · " : ""
|
|
25759
|
+
}),
|
|
25760
|
+
/* @__PURE__ */ jsx("span", {
|
|
25761
|
+
fg: tokens.accent,
|
|
25762
|
+
children: `#${row.prNumber}`
|
|
25763
|
+
}),
|
|
25764
|
+
row.prState && /* @__PURE__ */ jsx("span", {
|
|
25765
|
+
fg: tokens.dim,
|
|
25766
|
+
children: ` ${row.prState}`
|
|
25767
|
+
}),
|
|
25768
|
+
row.prChecks && /* @__PURE__ */ jsx("span", {
|
|
25769
|
+
fg: tokens.dim,
|
|
25770
|
+
children: ` (${row.prChecks})`
|
|
25771
|
+
}),
|
|
25772
|
+
row.prUrl && /* @__PURE__ */ jsx("span", {
|
|
25773
|
+
fg: tokens.dim,
|
|
25774
|
+
children: " ↗"
|
|
25775
|
+
})
|
|
25776
|
+
]
|
|
25777
|
+
}),
|
|
25646
25778
|
baseChangedSegment && /* @__PURE__ */ jsx("span", {
|
|
25647
25779
|
fg: tokens.warning,
|
|
25648
25780
|
children: baseChangedSegment
|
|
@@ -25657,7 +25789,7 @@ function WorktreeItem({ row, isSelected, isMultiSelected, indicator, frame, id }
|
|
|
25657
25789
|
});
|
|
25658
25790
|
}
|
|
25659
25791
|
function WorktreeTable({ blocks, selectedIndex, selection = new Set, frame, repoVerbs, rowVerbs }) {
|
|
25660
|
-
const scrollRef =
|
|
25792
|
+
const scrollRef = useRef3(null);
|
|
25661
25793
|
useEffect2(() => {
|
|
25662
25794
|
if (scrollRef.current?.scrollChildIntoView) {
|
|
25663
25795
|
scrollRef.current.scrollChildIntoView("selected-row");
|
|
@@ -25727,11 +25859,16 @@ function WorktreeTable({ blocks, selectedIndex, selection = new Set, frame, repo
|
|
|
25727
25859
|
var SECONDARY_INDENT = " ";
|
|
25728
25860
|
var init_WorktreeTable = __esm(() => {
|
|
25729
25861
|
init_theme();
|
|
25862
|
+
init_use_tap();
|
|
25730
25863
|
});
|
|
25731
25864
|
|
|
25732
25865
|
// src/tui/components/DetailPane.tsx
|
|
25733
|
-
import { jsx as jsx2, jsxs as jsxs2, Fragment } from "@opentui/react/jsx-runtime";
|
|
25866
|
+
import { jsx as jsx2, jsxs as jsxs2, Fragment as Fragment2 } from "@opentui/react/jsx-runtime";
|
|
25734
25867
|
function DetailPane({ selectedRow }) {
|
|
25868
|
+
const prTap = useTapHandler(() => {
|
|
25869
|
+
if (selectedRow?.prUrl)
|
|
25870
|
+
openInBrowser(selectedRow.prUrl);
|
|
25871
|
+
});
|
|
25735
25872
|
if (!selectedRow) {
|
|
25736
25873
|
return /* @__PURE__ */ jsx2("box", {
|
|
25737
25874
|
id: "detail-pane",
|
|
@@ -25946,7 +26083,7 @@ function DetailPane({ selectedRow }) {
|
|
|
25946
26083
|
})
|
|
25947
26084
|
]
|
|
25948
26085
|
}),
|
|
25949
|
-
prNumber !== null && /* @__PURE__ */ jsxs2(
|
|
26086
|
+
prNumber !== null && /* @__PURE__ */ jsxs2(Fragment2, {
|
|
25950
26087
|
children: [
|
|
25951
26088
|
/* @__PURE__ */ jsxs2("text", {
|
|
25952
26089
|
style: { marginTop: 1 },
|
|
@@ -25983,20 +26120,25 @@ function DetailPane({ selectedRow }) {
|
|
|
25983
26120
|
})
|
|
25984
26121
|
]
|
|
25985
26122
|
}),
|
|
25986
|
-
prUrl && /* @__PURE__ */
|
|
25987
|
-
|
|
25988
|
-
|
|
25989
|
-
|
|
25990
|
-
|
|
25991
|
-
|
|
25992
|
-
|
|
25993
|
-
|
|
25994
|
-
|
|
25995
|
-
|
|
25996
|
-
|
|
25997
|
-
|
|
25998
|
-
|
|
25999
|
-
|
|
26123
|
+
prUrl && /* @__PURE__ */ jsx2("box", {
|
|
26124
|
+
...prTap,
|
|
26125
|
+
children: /* @__PURE__ */ jsxs2("text", {
|
|
26126
|
+
selectable: false,
|
|
26127
|
+
children: [
|
|
26128
|
+
/* @__PURE__ */ jsx2("span", {
|
|
26129
|
+
fg: tokens.dim,
|
|
26130
|
+
children: "URL:"
|
|
26131
|
+
}),
|
|
26132
|
+
/* @__PURE__ */ jsx2("span", {
|
|
26133
|
+
fg: tokens.accent,
|
|
26134
|
+
children: ` ${prUrl}`
|
|
26135
|
+
}),
|
|
26136
|
+
/* @__PURE__ */ jsx2("span", {
|
|
26137
|
+
fg: tokens.dim,
|
|
26138
|
+
children: " ↗ click"
|
|
26139
|
+
})
|
|
26140
|
+
]
|
|
26141
|
+
})
|
|
26000
26142
|
})
|
|
26001
26143
|
]
|
|
26002
26144
|
}),
|
|
@@ -26037,7 +26179,7 @@ function DetailPane({ selectedRow }) {
|
|
|
26037
26179
|
fg: tokens.dim,
|
|
26038
26180
|
children: "Actions:"
|
|
26039
26181
|
}),
|
|
26040
|
-
!isMainCheckout && /* @__PURE__ */ jsxs2(
|
|
26182
|
+
!isMainCheckout && /* @__PURE__ */ jsxs2(Fragment2, {
|
|
26041
26183
|
children: [
|
|
26042
26184
|
/* @__PURE__ */ jsxs2("text", {
|
|
26043
26185
|
fg: tokens.dim,
|
|
@@ -26068,6 +26210,7 @@ function DetailPane({ selectedRow }) {
|
|
|
26068
26210
|
}
|
|
26069
26211
|
var init_DetailPane = __esm(() => {
|
|
26070
26212
|
init_theme();
|
|
26213
|
+
init_use_tap();
|
|
26071
26214
|
});
|
|
26072
26215
|
|
|
26073
26216
|
// src/tui/components/Footer.tsx
|
|
@@ -26114,11 +26257,15 @@ function Footer({ loading, lastRefreshed, errorCount, message, busyText, spinner
|
|
|
26114
26257
|
]
|
|
26115
26258
|
}) : null,
|
|
26116
26259
|
errorCount > 0 ? /* @__PURE__ */ jsxs3("text", {
|
|
26117
|
-
fg: tokens.error,
|
|
26118
26260
|
children: [
|
|
26119
|
-
|
|
26120
|
-
|
|
26121
|
-
|
|
26261
|
+
/* @__PURE__ */ jsx3("span", {
|
|
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
|
+
})
|
|
26122
26269
|
]
|
|
26123
26270
|
}) : null,
|
|
26124
26271
|
/* @__PURE__ */ jsx3("text", {
|
|
@@ -26238,8 +26385,12 @@ var init_HelpOverlay = __esm(() => {
|
|
|
26238
26385
|
["o", "Open selected in IDE"],
|
|
26239
26386
|
["a", "Spawn agent in selected"],
|
|
26240
26387
|
["d", "Remove selected worktree(s)"],
|
|
26388
|
+
["e", "View data warnings (when count > 0)"],
|
|
26241
26389
|
["r", "Refresh data"],
|
|
26242
26390
|
["H", "Action history"],
|
|
26391
|
+
["mouse drag", "Select text — copied to clipboard automatically"],
|
|
26392
|
+
["ctrl+shift+c", "Copy selection again (terminals reserve cmd+c)"],
|
|
26393
|
+
["click PR #/URL", "Open pull request in browser"],
|
|
26243
26394
|
["?", "Toggle help"],
|
|
26244
26395
|
["q/esc", "Quit"]
|
|
26245
26396
|
];
|
|
@@ -26588,8 +26739,8 @@ var init_HistoryOverlay = __esm(() => {
|
|
|
26588
26739
|
// src/tui/components/InputModal.tsx
|
|
26589
26740
|
import { useState as useState3 } from "react";
|
|
26590
26741
|
import { jsx as jsx9, jsxs as jsxs8 } from "@opentui/react/jsx-runtime";
|
|
26591
|
-
function InputModal({ title, placeholder, errorMessage, onSubmit }) {
|
|
26592
|
-
const [value, setValue] = useState3("");
|
|
26742
|
+
function InputModal({ title, placeholder, initialValue, errorMessage, onSubmit }) {
|
|
26743
|
+
const [value, setValue] = useState3(initialValue ?? "");
|
|
26593
26744
|
return /* @__PURE__ */ jsx9(Overlay, {
|
|
26594
26745
|
title,
|
|
26595
26746
|
borderColor: tokens.accent,
|
|
@@ -26598,6 +26749,7 @@ function InputModal({ title, placeholder, errorMessage, onSubmit }) {
|
|
|
26598
26749
|
children: [
|
|
26599
26750
|
/* @__PURE__ */ jsx9("input", {
|
|
26600
26751
|
focused: true,
|
|
26752
|
+
value: initialValue ?? "",
|
|
26601
26753
|
placeholder,
|
|
26602
26754
|
onInput: (val) => setValue(val),
|
|
26603
26755
|
onSubmit: () => onSubmit(value)
|
|
@@ -26695,7 +26847,7 @@ var init_ChoiceModal = __esm(() => {
|
|
|
26695
26847
|
// src/tui/components/ConfigOverlay.tsx
|
|
26696
26848
|
import { useState as useState5, useEffect as useEffect4 } from "react";
|
|
26697
26849
|
import { useKeyboard as useKeyboard2 } from "@opentui/react";
|
|
26698
|
-
import { jsx as jsx11, jsxs as jsxs10, Fragment as
|
|
26850
|
+
import { jsx as jsx11, jsxs as jsxs10, Fragment as Fragment3 } from "@opentui/react/jsx-runtime";
|
|
26699
26851
|
function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
26700
26852
|
const [config2, setConfig] = useState5(null);
|
|
26701
26853
|
const [viewState, setViewState] = useState5({ type: "main" });
|
|
@@ -26958,7 +27110,7 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
26958
27110
|
hint = "Remove this repository from config";
|
|
26959
27111
|
}
|
|
26960
27112
|
}
|
|
26961
|
-
return /* @__PURE__ */ jsxs10(
|
|
27113
|
+
return /* @__PURE__ */ jsxs10(Fragment3, {
|
|
26962
27114
|
children: [
|
|
26963
27115
|
/* @__PURE__ */ jsx11(Overlay, {
|
|
26964
27116
|
title: "Configuration",
|
|
@@ -27045,7 +27197,8 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27045
27197
|
}),
|
|
27046
27198
|
editState.type === "input" && /* @__PURE__ */ jsx11(InputModal, {
|
|
27047
27199
|
title: editState.title,
|
|
27048
|
-
|
|
27200
|
+
initialValue: editState.currentValue,
|
|
27201
|
+
placeholder: "Enter value...",
|
|
27049
27202
|
errorMessage: editState.error,
|
|
27050
27203
|
onSubmit: handleInputSubmit
|
|
27051
27204
|
}),
|
|
@@ -27065,6 +27218,47 @@ var init_ConfigOverlay = __esm(() => {
|
|
|
27065
27218
|
init_ConfirmModal();
|
|
27066
27219
|
});
|
|
27067
27220
|
|
|
27221
|
+
// src/tui/components/WarningsOverlay.tsx
|
|
27222
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "@opentui/react/jsx-runtime";
|
|
27223
|
+
function WarningsOverlay({ warnings }) {
|
|
27224
|
+
return /* @__PURE__ */ jsxs11(Overlay, {
|
|
27225
|
+
title: `Warnings (${warnings.length})`,
|
|
27226
|
+
borderColor: tokens.warning,
|
|
27227
|
+
children: [
|
|
27228
|
+
/* @__PURE__ */ jsx12("box", {
|
|
27229
|
+
flexDirection: "column",
|
|
27230
|
+
style: { maxHeight: 30 },
|
|
27231
|
+
children: /* @__PURE__ */ jsx12("scrollbox", {
|
|
27232
|
+
flexGrow: 1,
|
|
27233
|
+
children: warnings.map((warning, i2) => /* @__PURE__ */ jsxs11("box", {
|
|
27234
|
+
flexDirection: "column",
|
|
27235
|
+
style: { marginBottom: 1 },
|
|
27236
|
+
children: [
|
|
27237
|
+
/* @__PURE__ */ jsx12("text", {
|
|
27238
|
+
fg: tokens.warning,
|
|
27239
|
+
children: `⚠ ${warning.repoName}`
|
|
27240
|
+
}),
|
|
27241
|
+
wrapText(warning.message, 56).map((line, j) => /* @__PURE__ */ jsx12("text", {
|
|
27242
|
+
fg: tokens.fg,
|
|
27243
|
+
children: ` ${line}`
|
|
27244
|
+
}, j))
|
|
27245
|
+
]
|
|
27246
|
+
}, i2))
|
|
27247
|
+
})
|
|
27248
|
+
}),
|
|
27249
|
+
/* @__PURE__ */ jsx12("text", {
|
|
27250
|
+
style: { marginTop: 1, fg: tokens.dim },
|
|
27251
|
+
children: "Press any key to close"
|
|
27252
|
+
})
|
|
27253
|
+
]
|
|
27254
|
+
});
|
|
27255
|
+
}
|
|
27256
|
+
var init_WarningsOverlay = __esm(() => {
|
|
27257
|
+
init_Overlay();
|
|
27258
|
+
init_theme();
|
|
27259
|
+
init_utils();
|
|
27260
|
+
});
|
|
27261
|
+
|
|
27068
27262
|
// src/tui/hooks/useSpinnerFrame.ts
|
|
27069
27263
|
import { useEffect as useEffect5, useState as useState6 } from "react";
|
|
27070
27264
|
function useSpinnerFrame(active) {
|
|
@@ -27083,9 +27277,9 @@ var init_useSpinnerFrame = __esm(() => {
|
|
|
27083
27277
|
});
|
|
27084
27278
|
|
|
27085
27279
|
// src/tui/components/App.tsx
|
|
27086
|
-
import { useState as useState7, useEffect as useEffect6, useMemo, useRef as
|
|
27087
|
-
import { useKeyboard as useKeyboard3, useRenderer } from "@opentui/react";
|
|
27088
|
-
import { jsx as
|
|
27280
|
+
import { useState as useState7, useEffect as useEffect6, useMemo, useRef as useRef4, useCallback as useCallback3 } from "react";
|
|
27281
|
+
import { useKeyboard as useKeyboard3, useRenderer, useSelectionHandler } from "@opentui/react";
|
|
27282
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "@opentui/react/jsx-runtime";
|
|
27089
27283
|
function getWorktreePathFor(repoName, branch) {
|
|
27090
27284
|
try {
|
|
27091
27285
|
const config2 = loadConfig();
|
|
@@ -27101,10 +27295,10 @@ function App({ opts }) {
|
|
|
27101
27295
|
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
27102
27296
|
const [modal, setModal] = useState7({ type: "none" });
|
|
27103
27297
|
const [actionMessage, setActionMessage] = useState7();
|
|
27104
|
-
const messageTimer =
|
|
27298
|
+
const messageTimer = useRef4(null);
|
|
27105
27299
|
const [ops, setOps] = useState7([]);
|
|
27106
27300
|
const [failedLogs, setFailedLogs] = useState7([]);
|
|
27107
|
-
const nextOpId =
|
|
27301
|
+
const nextOpId = useRef4(1);
|
|
27108
27302
|
const [createModal, setCreateModal] = useState7(false);
|
|
27109
27303
|
const [createError, setCreateError] = useState7();
|
|
27110
27304
|
const [createBaseModal, setCreateBaseModal] = useState7(null);
|
|
@@ -27117,7 +27311,7 @@ function App({ opts }) {
|
|
|
27117
27311
|
const [filterText, setFilterText] = useState7("");
|
|
27118
27312
|
const [isFiltering, setIsFiltering] = useState7(false);
|
|
27119
27313
|
const [selection, setSelection] = useState7(new Set);
|
|
27120
|
-
const doRefresh =
|
|
27314
|
+
const doRefresh = useCallback3(async (scope) => {
|
|
27121
27315
|
const targets = scope ?? [
|
|
27122
27316
|
...new Set([...blocks.map((b) => b.repoName), ...pendingRepos])
|
|
27123
27317
|
];
|
|
@@ -27133,12 +27327,22 @@ function App({ opts }) {
|
|
|
27133
27327
|
setModal({ type: "error", message: error52 });
|
|
27134
27328
|
}
|
|
27135
27329
|
}, [error52]);
|
|
27136
|
-
const flash =
|
|
27330
|
+
const flash = useCallback3((message, ms = 3000) => {
|
|
27137
27331
|
if (messageTimer.current)
|
|
27138
27332
|
clearTimeout(messageTimer.current);
|
|
27139
27333
|
setActionMessage(message);
|
|
27140
27334
|
messageTimer.current = setTimeout(() => setActionMessage(undefined), ms);
|
|
27141
27335
|
}, []);
|
|
27336
|
+
const copySelectedText = useCallback3((warnOnEmpty) => {
|
|
27337
|
+
const text = renderer.getSelection()?.getSelectedText() ?? "";
|
|
27338
|
+
if (!text) {
|
|
27339
|
+
if (warnOnEmpty)
|
|
27340
|
+
flash("Nothing selected to copy");
|
|
27341
|
+
return;
|
|
27342
|
+
}
|
|
27343
|
+
copyTextToClipboard(renderer, text).then((ok) => flash(ok ? `Copied ${text.length} character${text.length !== 1 ? "s" : ""}` : "Copy failed"));
|
|
27344
|
+
}, [renderer, flash]);
|
|
27345
|
+
useSelectionHandler(() => copySelectedText(false));
|
|
27142
27346
|
const busyRepos = useMemo(() => new Set(ops.flatMap((o2) => o2.repoNames)), [ops]);
|
|
27143
27347
|
const busyRowPaths = useMemo(() => new Set(ops.map((o2) => o2.rowPath).filter((p) => p !== undefined)), [ops]);
|
|
27144
27348
|
const anyRunning = ops.some((o2) => o2.status === "running");
|
|
@@ -27324,7 +27528,7 @@ function App({ opts }) {
|
|
|
27324
27528
|
return;
|
|
27325
27529
|
}
|
|
27326
27530
|
if (modal.type !== "none") {
|
|
27327
|
-
if (modal.type === "error" || modal.type === "help" || modal.type === "history") {
|
|
27531
|
+
if (modal.type === "error" || modal.type === "help" || modal.type === "history" || modal.type === "warnings") {
|
|
27328
27532
|
setModal({ type: "none" });
|
|
27329
27533
|
if (modal.type === "error" && error52) {
|
|
27330
27534
|
renderer.destroy();
|
|
@@ -27372,6 +27576,10 @@ function App({ opts }) {
|
|
|
27372
27576
|
return;
|
|
27373
27577
|
}
|
|
27374
27578
|
}
|
|
27579
|
+
if ((key.super || key.meta || key.ctrl && key.shift) && key.name === "c") {
|
|
27580
|
+
copySelectedText(true);
|
|
27581
|
+
return;
|
|
27582
|
+
}
|
|
27375
27583
|
if (key.name === "q" || key.name === "escape" || key.name === "c" && key.ctrl) {
|
|
27376
27584
|
if (key.name === "escape" && selection.size > 0) {
|
|
27377
27585
|
setSelection(new Set);
|
|
@@ -27414,6 +27622,10 @@ function App({ opts }) {
|
|
|
27414
27622
|
}
|
|
27415
27623
|
return;
|
|
27416
27624
|
}
|
|
27625
|
+
if (key.name === "e" && warnings.length > 0) {
|
|
27626
|
+
setModal({ type: "warnings" });
|
|
27627
|
+
return;
|
|
27628
|
+
}
|
|
27417
27629
|
if (key.name === "n") {
|
|
27418
27630
|
if (!selectedRow)
|
|
27419
27631
|
return;
|
|
@@ -27591,17 +27803,17 @@ function App({ opts }) {
|
|
|
27591
27803
|
})();
|
|
27592
27804
|
}
|
|
27593
27805
|
});
|
|
27594
|
-
return /* @__PURE__ */
|
|
27806
|
+
return /* @__PURE__ */ jsxs12("box", {
|
|
27595
27807
|
flexDirection: "column",
|
|
27596
27808
|
width: "100%",
|
|
27597
27809
|
height: "100%",
|
|
27598
27810
|
children: [
|
|
27599
|
-
/* @__PURE__ */
|
|
27811
|
+
/* @__PURE__ */ jsxs12("box", {
|
|
27600
27812
|
flexDirection: "row",
|
|
27601
27813
|
width: "100%",
|
|
27602
27814
|
flexGrow: 1,
|
|
27603
27815
|
children: [
|
|
27604
|
-
/* @__PURE__ */
|
|
27816
|
+
/* @__PURE__ */ jsx13(WorktreeTable, {
|
|
27605
27817
|
blocks: displayBlocks,
|
|
27606
27818
|
selectedIndex,
|
|
27607
27819
|
selection,
|
|
@@ -27609,28 +27821,28 @@ function App({ opts }) {
|
|
|
27609
27821
|
repoVerbs,
|
|
27610
27822
|
rowVerbs
|
|
27611
27823
|
}),
|
|
27612
|
-
/* @__PURE__ */
|
|
27824
|
+
/* @__PURE__ */ jsx13(DetailPane, {
|
|
27613
27825
|
selectedRow
|
|
27614
27826
|
})
|
|
27615
27827
|
]
|
|
27616
27828
|
}),
|
|
27617
|
-
isFiltering && /* @__PURE__ */
|
|
27829
|
+
isFiltering && /* @__PURE__ */ jsxs12("box", {
|
|
27618
27830
|
flexDirection: "row",
|
|
27619
27831
|
paddingX: 1,
|
|
27620
27832
|
border: true,
|
|
27621
27833
|
borderColor: "magenta",
|
|
27622
27834
|
children: [
|
|
27623
|
-
/* @__PURE__ */
|
|
27835
|
+
/* @__PURE__ */ jsx13("text", {
|
|
27624
27836
|
children: "filter: "
|
|
27625
27837
|
}),
|
|
27626
|
-
/* @__PURE__ */
|
|
27838
|
+
/* @__PURE__ */ jsx13("input", {
|
|
27627
27839
|
focused: true,
|
|
27628
27840
|
placeholder: "Type to filter...",
|
|
27629
27841
|
onInput: (v) => setFilterText(v)
|
|
27630
27842
|
})
|
|
27631
27843
|
]
|
|
27632
27844
|
}),
|
|
27633
|
-
/* @__PURE__ */
|
|
27845
|
+
/* @__PURE__ */ jsx13(Footer, {
|
|
27634
27846
|
loading: loading || refreshing,
|
|
27635
27847
|
lastRefreshed,
|
|
27636
27848
|
errorCount: warnings.length,
|
|
@@ -27639,13 +27851,16 @@ function App({ opts }) {
|
|
|
27639
27851
|
spinnerFrame,
|
|
27640
27852
|
filter: filterText ? { term: filterText, matches: flatRows.length, total: totalRows } : undefined
|
|
27641
27853
|
}),
|
|
27642
|
-
modal.type === "help" && /* @__PURE__ */
|
|
27643
|
-
modal.type === "history" && /* @__PURE__ */
|
|
27644
|
-
modal.type === "
|
|
27854
|
+
modal.type === "help" && /* @__PURE__ */ jsx13(HelpOverlay, {}),
|
|
27855
|
+
modal.type === "history" && /* @__PURE__ */ jsx13(HistoryOverlay, {}),
|
|
27856
|
+
modal.type === "warnings" && /* @__PURE__ */ jsx13(WarningsOverlay, {
|
|
27857
|
+
warnings
|
|
27858
|
+
}),
|
|
27859
|
+
modal.type === "error" && /* @__PURE__ */ jsx13(ConfirmModal, {
|
|
27645
27860
|
title: "Error",
|
|
27646
27861
|
message: modal.message
|
|
27647
27862
|
}),
|
|
27648
|
-
modal.type === "confirm_remove" && /* @__PURE__ */
|
|
27863
|
+
modal.type === "confirm_remove" && /* @__PURE__ */ jsx13(ConfirmModal, {
|
|
27649
27864
|
title: `Remove ${modal.rows.length} Worktree(s)`,
|
|
27650
27865
|
message: (() => {
|
|
27651
27866
|
const count2 = modal.rows.length;
|
|
@@ -27662,15 +27877,15 @@ function App({ opts }) {
|
|
|
27662
27877
|
`);
|
|
27663
27878
|
})()
|
|
27664
27879
|
}),
|
|
27665
|
-
modal.type === "confirm_rebase" && /* @__PURE__ */
|
|
27880
|
+
modal.type === "confirm_rebase" && /* @__PURE__ */ jsx13(ConfirmModal, {
|
|
27666
27881
|
title: `Rebase ${modal.rows.length} Worktree(s)`,
|
|
27667
27882
|
message: `Are you sure you want to fetch and rebase ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}?`
|
|
27668
27883
|
}),
|
|
27669
|
-
modal.type === "confirm_sync" && /* @__PURE__ */
|
|
27884
|
+
modal.type === "confirm_sync" && /* @__PURE__ */ jsx13(ConfirmModal, {
|
|
27670
27885
|
title: `Sync ${modal.rows.length} Worktree(s)`,
|
|
27671
27886
|
message: `Are you sure you want to sync ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}?`
|
|
27672
27887
|
}),
|
|
27673
|
-
createModal && /* @__PURE__ */
|
|
27888
|
+
createModal && /* @__PURE__ */ jsx13(InputModal, {
|
|
27674
27889
|
title: `New worktree branch in ${selectedRow?.repoName ?? ""}`,
|
|
27675
27890
|
placeholder: "Branch name (empty to cancel)",
|
|
27676
27891
|
errorMessage: createError,
|
|
@@ -27697,7 +27912,7 @@ function App({ opts }) {
|
|
|
27697
27912
|
setCreateBaseModal({ branch, repoName });
|
|
27698
27913
|
}
|
|
27699
27914
|
}),
|
|
27700
|
-
createBaseModal && /* @__PURE__ */
|
|
27915
|
+
createBaseModal && /* @__PURE__ */ jsx13(InputModal, {
|
|
27701
27916
|
title: `Base ref for ${createBaseModal.branch}`,
|
|
27702
27917
|
placeholder: "origin/main (empty for default main)",
|
|
27703
27918
|
errorMessage: createBaseError,
|
|
@@ -27713,7 +27928,7 @@ function App({ opts }) {
|
|
|
27713
27928
|
setCreateDepsChoice({ branch, repoName, base: base2 || undefined });
|
|
27714
27929
|
}
|
|
27715
27930
|
}),
|
|
27716
|
-
createDepsChoice && /* @__PURE__ */
|
|
27931
|
+
createDepsChoice && /* @__PURE__ */ jsx13(ChoiceModal, {
|
|
27717
27932
|
title: `Dependencies for ${createDepsChoice.branch}`,
|
|
27718
27933
|
options: DEPS_CHOICES,
|
|
27719
27934
|
onSubmit: (choice) => {
|
|
@@ -27723,9 +27938,10 @@ function App({ opts }) {
|
|
|
27723
27938
|
},
|
|
27724
27939
|
onCancel: () => setCreateDepsChoice(null)
|
|
27725
27940
|
}),
|
|
27726
|
-
renameModal && selectedRow && /* @__PURE__ */
|
|
27941
|
+
renameModal && selectedRow && /* @__PURE__ */ jsx13(InputModal, {
|
|
27727
27942
|
title: `Rename branch ${selectedRow.branch}`,
|
|
27728
|
-
|
|
27943
|
+
initialValue: selectedRow.branch,
|
|
27944
|
+
placeholder: "New branch name",
|
|
27729
27945
|
errorMessage: renameError,
|
|
27730
27946
|
onSubmit: (value) => {
|
|
27731
27947
|
const target = selectedRow;
|
|
@@ -27747,7 +27963,7 @@ function App({ opts }) {
|
|
|
27747
27963
|
setModal({ type: "confirm_rename", row: target, to });
|
|
27748
27964
|
}
|
|
27749
27965
|
}),
|
|
27750
|
-
modal.type === "confirm_rename" && /* @__PURE__ */
|
|
27966
|
+
modal.type === "confirm_rename" && /* @__PURE__ */ jsx13(ConfirmModal, {
|
|
27751
27967
|
title: "Rename Worktree",
|
|
27752
27968
|
message: [
|
|
27753
27969
|
`${modal.row.branch} → ${modal.to}`,
|
|
@@ -27760,12 +27976,12 @@ function App({ opts }) {
|
|
|
27760
27976
|
].join(`
|
|
27761
27977
|
`)
|
|
27762
27978
|
}),
|
|
27763
|
-
configOpen && /* @__PURE__ */
|
|
27979
|
+
configOpen && /* @__PURE__ */ jsx13(ConfigOverlay, {
|
|
27764
27980
|
onClose: () => setConfigOpen(false),
|
|
27765
27981
|
onSaved: () => void doRefresh(),
|
|
27766
27982
|
onError: (msg) => setModal({ type: "error", message: msg })
|
|
27767
27983
|
}),
|
|
27768
|
-
failedLogs.length > 0 && /* @__PURE__ */
|
|
27984
|
+
failedLogs.length > 0 && /* @__PURE__ */ jsx13(ActionLogModal, {
|
|
27769
27985
|
title: failedLogs[0].title,
|
|
27770
27986
|
lines: failedLogs[0].lines,
|
|
27771
27987
|
done: true,
|
|
@@ -27789,6 +28005,7 @@ var init_App = __esm(() => {
|
|
|
27789
28005
|
init_InputModal();
|
|
27790
28006
|
init_ChoiceModal();
|
|
27791
28007
|
init_ConfigOverlay();
|
|
28008
|
+
init_WarningsOverlay();
|
|
27792
28009
|
init_utils();
|
|
27793
28010
|
init_agents();
|
|
27794
28011
|
init_config();
|
|
@@ -27819,14 +28036,14 @@ __export(exports_tui, {
|
|
|
27819
28036
|
});
|
|
27820
28037
|
import { createCliRenderer, TextTableRenderable } from "@opentui/core";
|
|
27821
28038
|
import { createRoot, extend as extend2 } from "@opentui/react";
|
|
27822
|
-
import { jsx as
|
|
28039
|
+
import { jsx as jsx14 } from "@opentui/react/jsx-runtime";
|
|
27823
28040
|
async function runTerminal(opts) {
|
|
27824
28041
|
const renderer = await createCliRenderer({
|
|
27825
28042
|
exitOnCtrlC: false
|
|
27826
28043
|
});
|
|
27827
28044
|
const root = createRoot(renderer);
|
|
27828
28045
|
try {
|
|
27829
|
-
root.render(/* @__PURE__ */
|
|
28046
|
+
root.render(/* @__PURE__ */ jsx14(App, {
|
|
27830
28047
|
opts
|
|
27831
28048
|
}));
|
|
27832
28049
|
} catch (err) {
|
|
@@ -30107,20 +30324,29 @@ async function getWorktreePort(repoName, branch, config2, currentWtPath) {
|
|
|
30107
30324
|
}
|
|
30108
30325
|
|
|
30109
30326
|
// src/lib/worktree-setup.ts
|
|
30327
|
+
function syncEntry(mainPath, wtPath, entry) {
|
|
30328
|
+
const src = path17.join(mainPath, entry);
|
|
30329
|
+
const dest = path17.join(wtPath, entry);
|
|
30330
|
+
if (!fs10.existsSync(src))
|
|
30331
|
+
return false;
|
|
30332
|
+
fs10.mkdirSync(path17.dirname(dest), { recursive: true });
|
|
30333
|
+
if (fs10.statSync(src).isDirectory()) {
|
|
30334
|
+
fs10.cpSync(src, dest, { recursive: true });
|
|
30335
|
+
} else {
|
|
30336
|
+
fs10.copyFileSync(src, dest);
|
|
30337
|
+
}
|
|
30338
|
+
return true;
|
|
30339
|
+
}
|
|
30110
30340
|
async function runPostCreateSetup(params) {
|
|
30111
30341
|
const { config: config2, repo, wtPath, branch, globalOpts } = params;
|
|
30112
30342
|
let copiedFiles = [];
|
|
30113
30343
|
let hooks = [];
|
|
30114
30344
|
if (repo.config.sync_files && repo.config.sync_files.length > 0) {
|
|
30115
30345
|
for (const file2 of repo.config.sync_files) {
|
|
30116
|
-
|
|
30117
|
-
|
|
30118
|
-
|
|
30119
|
-
|
|
30120
|
-
fs10.mkdirSync(path17.dirname(dest), { recursive: true });
|
|
30121
|
-
fs10.copyFileSync(src, dest);
|
|
30122
|
-
copiedFiles.push(file2);
|
|
30123
|
-
}
|
|
30346
|
+
if (!globalOpts.dryRun && syncEntry(repo.mainPath, wtPath, file2)) {
|
|
30347
|
+
copiedFiles.push(file2);
|
|
30348
|
+
}
|
|
30349
|
+
if (fs10.existsSync(path17.join(repo.mainPath, file2))) {
|
|
30124
30350
|
stepSuccess(`Synced ${file2}`);
|
|
30125
30351
|
} else {
|
|
30126
30352
|
stepWarning(`Could not sync ${file2}`, "file not found in main checkout");
|
|
@@ -31233,7 +31459,7 @@ function registerLsCommand(program2) {
|
|
|
31233
31459
|
const prInfo = prMap?.get(branch);
|
|
31234
31460
|
if (prInfo) {
|
|
31235
31461
|
const display = derivePrDisplay(prInfo);
|
|
31236
|
-
prSegment = ` #${prInfo.number} ${renderDisplayState(display)} ${source_default.dim(prInfo.url)}`;
|
|
31462
|
+
prSegment = ` #${prInfo.number} ${renderDisplayState(display)} ${source_default.dim(terminalLink(prInfo.url))}`;
|
|
31237
31463
|
}
|
|
31238
31464
|
let ownerSuffix = "";
|
|
31239
31465
|
const baseRef = wt.branch ? stackMetadata.branches[wt.branch]?.baseRef ?? prInfo?.baseRefName : prInfo?.baseRefName;
|
|
@@ -31501,12 +31727,9 @@ function registerSyncCommand(program2) {
|
|
|
31501
31727
|
try {
|
|
31502
31728
|
if (repo.config.sync_files) {
|
|
31503
31729
|
for (const file2 of repo.config.sync_files) {
|
|
31504
|
-
|
|
31505
|
-
const dest = path32.join(wtPath, file2);
|
|
31506
|
-
if (fs25.existsSync(src)) {
|
|
31730
|
+
if (fs25.existsSync(path32.join(repo.mainPath, file2))) {
|
|
31507
31731
|
if (!opts.dryRun) {
|
|
31508
|
-
|
|
31509
|
-
fs25.copyFileSync(src, dest);
|
|
31732
|
+
syncEntry(repo.mainPath, wtPath, file2);
|
|
31510
31733
|
}
|
|
31511
31734
|
stepSuccess(`Synced ${file2}`);
|
|
31512
31735
|
}
|
|
@@ -32163,7 +32386,7 @@ function renderTable(rows) {
|
|
|
32163
32386
|
const detailSuffix = details ? ` ${details}` : "";
|
|
32164
32387
|
const baseSuffix = row.baseRef ? ` → ${row.baseRef}` : "";
|
|
32165
32388
|
const authorTag = row.ownership && !row.ownership.mine && row.ownership.author ? ` ${source_default.dim(row.ownership.author)}` : "";
|
|
32166
|
-
info(` #${row.prNumber} ${paddedBranch} ${renderDisplayState(row.prDisplay)}${baseSuffix}${detailSuffix}${authorTag} ${formatRelativeTime(row.updatedAt)} ${source_default.dim(row.url)}`);
|
|
32389
|
+
info(` #${row.prNumber} ${paddedBranch} ${renderDisplayState(row.prDisplay)}${baseSuffix}${detailSuffix}${authorTag} ${formatRelativeTime(row.updatedAt)} ${source_default.dim(terminalLink(row.url))}`);
|
|
32167
32390
|
}
|
|
32168
32391
|
}
|
|
32169
32392
|
}
|