@ogpoyraz/wtx 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.mjs +272 -64
  2. package/package.json +1 -1
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 useRef2 } from "react";
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 = useRef2(null);
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(Fragment, {
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__ */ jsxs2("text", {
25987
- children: [
25988
- /* @__PURE__ */ jsx2("span", {
25989
- fg: tokens.dim,
25990
- children: "URL:"
25991
- }),
25992
- /* @__PURE__ */ jsxs2("span", {
25993
- fg: tokens.fg,
25994
- children: [
25995
- " ",
25996
- prUrl
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(Fragment, {
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
- errorCount,
26120
- " error",
26121
- errorCount !== 1 ? "s" : ""
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,11 @@ 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
+ ["cmd+c / ctrl+shift+c", "Copy selected text to clipboard"],
26392
+ ["click PR #/URL", "Open pull request in browser"],
26243
26393
  ["?", "Toggle help"],
26244
26394
  ["q/esc", "Quit"]
26245
26395
  ];
@@ -26695,7 +26845,7 @@ var init_ChoiceModal = __esm(() => {
26695
26845
  // src/tui/components/ConfigOverlay.tsx
26696
26846
  import { useState as useState5, useEffect as useEffect4 } from "react";
26697
26847
  import { useKeyboard as useKeyboard2 } from "@opentui/react";
26698
- import { jsx as jsx11, jsxs as jsxs10, Fragment as Fragment2 } from "@opentui/react/jsx-runtime";
26848
+ import { jsx as jsx11, jsxs as jsxs10, Fragment as Fragment3 } from "@opentui/react/jsx-runtime";
26699
26849
  function ConfigOverlay({ onClose, onSaved, onError }) {
26700
26850
  const [config2, setConfig] = useState5(null);
26701
26851
  const [viewState, setViewState] = useState5({ type: "main" });
@@ -26958,7 +27108,7 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
26958
27108
  hint = "Remove this repository from config";
26959
27109
  }
26960
27110
  }
26961
- return /* @__PURE__ */ jsxs10(Fragment2, {
27111
+ return /* @__PURE__ */ jsxs10(Fragment3, {
26962
27112
  children: [
26963
27113
  /* @__PURE__ */ jsx11(Overlay, {
26964
27114
  title: "Configuration",
@@ -27065,6 +27215,47 @@ var init_ConfigOverlay = __esm(() => {
27065
27215
  init_ConfirmModal();
27066
27216
  });
27067
27217
 
27218
+ // src/tui/components/WarningsOverlay.tsx
27219
+ import { jsx as jsx12, jsxs as jsxs11 } from "@opentui/react/jsx-runtime";
27220
+ function WarningsOverlay({ warnings }) {
27221
+ return /* @__PURE__ */ jsxs11(Overlay, {
27222
+ title: `Warnings (${warnings.length})`,
27223
+ borderColor: tokens.warning,
27224
+ children: [
27225
+ /* @__PURE__ */ jsx12("box", {
27226
+ flexDirection: "column",
27227
+ style: { maxHeight: 30 },
27228
+ children: /* @__PURE__ */ jsx12("scrollbox", {
27229
+ flexGrow: 1,
27230
+ children: warnings.map((warning, i2) => /* @__PURE__ */ jsxs11("box", {
27231
+ flexDirection: "column",
27232
+ style: { marginBottom: 1 },
27233
+ children: [
27234
+ /* @__PURE__ */ jsx12("text", {
27235
+ fg: tokens.warning,
27236
+ children: `⚠ ${warning.repoName}`
27237
+ }),
27238
+ wrapText(warning.message, 56).map((line, j) => /* @__PURE__ */ jsx12("text", {
27239
+ fg: tokens.fg,
27240
+ children: ` ${line}`
27241
+ }, j))
27242
+ ]
27243
+ }, i2))
27244
+ })
27245
+ }),
27246
+ /* @__PURE__ */ jsx12("text", {
27247
+ style: { marginTop: 1, fg: tokens.dim },
27248
+ children: "Press any key to close"
27249
+ })
27250
+ ]
27251
+ });
27252
+ }
27253
+ var init_WarningsOverlay = __esm(() => {
27254
+ init_Overlay();
27255
+ init_theme();
27256
+ init_utils();
27257
+ });
27258
+
27068
27259
  // src/tui/hooks/useSpinnerFrame.ts
27069
27260
  import { useEffect as useEffect5, useState as useState6 } from "react";
27070
27261
  function useSpinnerFrame(active) {
@@ -27083,9 +27274,9 @@ var init_useSpinnerFrame = __esm(() => {
27083
27274
  });
27084
27275
 
27085
27276
  // src/tui/components/App.tsx
27086
- import { useState as useState7, useEffect as useEffect6, useMemo, useRef as useRef3, useCallback as useCallback2 } from "react";
27277
+ import { useState as useState7, useEffect as useEffect6, useMemo, useRef as useRef4, useCallback as useCallback3 } from "react";
27087
27278
  import { useKeyboard as useKeyboard3, useRenderer } from "@opentui/react";
27088
- import { jsx as jsx12, jsxs as jsxs11 } from "@opentui/react/jsx-runtime";
27279
+ import { jsx as jsx13, jsxs as jsxs12 } from "@opentui/react/jsx-runtime";
27089
27280
  function getWorktreePathFor(repoName, branch) {
27090
27281
  try {
27091
27282
  const config2 = loadConfig();
@@ -27101,10 +27292,10 @@ function App({ opts }) {
27101
27292
  const [selectedIndex, setSelectedIndex] = useState7(0);
27102
27293
  const [modal, setModal] = useState7({ type: "none" });
27103
27294
  const [actionMessage, setActionMessage] = useState7();
27104
- const messageTimer = useRef3(null);
27295
+ const messageTimer = useRef4(null);
27105
27296
  const [ops, setOps] = useState7([]);
27106
27297
  const [failedLogs, setFailedLogs] = useState7([]);
27107
- const nextOpId = useRef3(1);
27298
+ const nextOpId = useRef4(1);
27108
27299
  const [createModal, setCreateModal] = useState7(false);
27109
27300
  const [createError, setCreateError] = useState7();
27110
27301
  const [createBaseModal, setCreateBaseModal] = useState7(null);
@@ -27117,7 +27308,7 @@ function App({ opts }) {
27117
27308
  const [filterText, setFilterText] = useState7("");
27118
27309
  const [isFiltering, setIsFiltering] = useState7(false);
27119
27310
  const [selection, setSelection] = useState7(new Set);
27120
- const doRefresh = useCallback2(async (scope) => {
27311
+ const doRefresh = useCallback3(async (scope) => {
27121
27312
  const targets = scope ?? [
27122
27313
  ...new Set([...blocks.map((b) => b.repoName), ...pendingRepos])
27123
27314
  ];
@@ -27133,7 +27324,7 @@ function App({ opts }) {
27133
27324
  setModal({ type: "error", message: error52 });
27134
27325
  }
27135
27326
  }, [error52]);
27136
- const flash = useCallback2((message, ms = 3000) => {
27327
+ const flash = useCallback3((message, ms = 3000) => {
27137
27328
  if (messageTimer.current)
27138
27329
  clearTimeout(messageTimer.current);
27139
27330
  setActionMessage(message);
@@ -27324,7 +27515,7 @@ function App({ opts }) {
27324
27515
  return;
27325
27516
  }
27326
27517
  if (modal.type !== "none") {
27327
- if (modal.type === "error" || modal.type === "help" || modal.type === "history") {
27518
+ if (modal.type === "error" || modal.type === "help" || modal.type === "history" || modal.type === "warnings") {
27328
27519
  setModal({ type: "none" });
27329
27520
  if (modal.type === "error" && error52) {
27330
27521
  renderer.destroy();
@@ -27372,6 +27563,15 @@ function App({ opts }) {
27372
27563
  return;
27373
27564
  }
27374
27565
  }
27566
+ if ((key.super || key.meta || key.ctrl && key.shift) && key.name === "c") {
27567
+ const text = renderer.getSelection()?.getSelectedText() ?? "";
27568
+ if (!text) {
27569
+ flash("Nothing selected to copy");
27570
+ return;
27571
+ }
27572
+ copyTextToClipboard(renderer, text).then((ok) => flash(ok ? `Copied ${text.length} character${text.length !== 1 ? "s" : ""}` : "Copy failed"));
27573
+ return;
27574
+ }
27375
27575
  if (key.name === "q" || key.name === "escape" || key.name === "c" && key.ctrl) {
27376
27576
  if (key.name === "escape" && selection.size > 0) {
27377
27577
  setSelection(new Set);
@@ -27414,6 +27614,10 @@ function App({ opts }) {
27414
27614
  }
27415
27615
  return;
27416
27616
  }
27617
+ if (key.name === "e" && warnings.length > 0) {
27618
+ setModal({ type: "warnings" });
27619
+ return;
27620
+ }
27417
27621
  if (key.name === "n") {
27418
27622
  if (!selectedRow)
27419
27623
  return;
@@ -27591,17 +27795,17 @@ function App({ opts }) {
27591
27795
  })();
27592
27796
  }
27593
27797
  });
27594
- return /* @__PURE__ */ jsxs11("box", {
27798
+ return /* @__PURE__ */ jsxs12("box", {
27595
27799
  flexDirection: "column",
27596
27800
  width: "100%",
27597
27801
  height: "100%",
27598
27802
  children: [
27599
- /* @__PURE__ */ jsxs11("box", {
27803
+ /* @__PURE__ */ jsxs12("box", {
27600
27804
  flexDirection: "row",
27601
27805
  width: "100%",
27602
27806
  flexGrow: 1,
27603
27807
  children: [
27604
- /* @__PURE__ */ jsx12(WorktreeTable, {
27808
+ /* @__PURE__ */ jsx13(WorktreeTable, {
27605
27809
  blocks: displayBlocks,
27606
27810
  selectedIndex,
27607
27811
  selection,
@@ -27609,28 +27813,28 @@ function App({ opts }) {
27609
27813
  repoVerbs,
27610
27814
  rowVerbs
27611
27815
  }),
27612
- /* @__PURE__ */ jsx12(DetailPane, {
27816
+ /* @__PURE__ */ jsx13(DetailPane, {
27613
27817
  selectedRow
27614
27818
  })
27615
27819
  ]
27616
27820
  }),
27617
- isFiltering && /* @__PURE__ */ jsxs11("box", {
27821
+ isFiltering && /* @__PURE__ */ jsxs12("box", {
27618
27822
  flexDirection: "row",
27619
27823
  paddingX: 1,
27620
27824
  border: true,
27621
27825
  borderColor: "magenta",
27622
27826
  children: [
27623
- /* @__PURE__ */ jsx12("text", {
27827
+ /* @__PURE__ */ jsx13("text", {
27624
27828
  children: "filter: "
27625
27829
  }),
27626
- /* @__PURE__ */ jsx12("input", {
27830
+ /* @__PURE__ */ jsx13("input", {
27627
27831
  focused: true,
27628
27832
  placeholder: "Type to filter...",
27629
27833
  onInput: (v) => setFilterText(v)
27630
27834
  })
27631
27835
  ]
27632
27836
  }),
27633
- /* @__PURE__ */ jsx12(Footer, {
27837
+ /* @__PURE__ */ jsx13(Footer, {
27634
27838
  loading: loading || refreshing,
27635
27839
  lastRefreshed,
27636
27840
  errorCount: warnings.length,
@@ -27639,13 +27843,16 @@ function App({ opts }) {
27639
27843
  spinnerFrame,
27640
27844
  filter: filterText ? { term: filterText, matches: flatRows.length, total: totalRows } : undefined
27641
27845
  }),
27642
- modal.type === "help" && /* @__PURE__ */ jsx12(HelpOverlay, {}),
27643
- modal.type === "history" && /* @__PURE__ */ jsx12(HistoryOverlay, {}),
27644
- modal.type === "error" && /* @__PURE__ */ jsx12(ConfirmModal, {
27846
+ modal.type === "help" && /* @__PURE__ */ jsx13(HelpOverlay, {}),
27847
+ modal.type === "history" && /* @__PURE__ */ jsx13(HistoryOverlay, {}),
27848
+ modal.type === "warnings" && /* @__PURE__ */ jsx13(WarningsOverlay, {
27849
+ warnings
27850
+ }),
27851
+ modal.type === "error" && /* @__PURE__ */ jsx13(ConfirmModal, {
27645
27852
  title: "Error",
27646
27853
  message: modal.message
27647
27854
  }),
27648
- modal.type === "confirm_remove" && /* @__PURE__ */ jsx12(ConfirmModal, {
27855
+ modal.type === "confirm_remove" && /* @__PURE__ */ jsx13(ConfirmModal, {
27649
27856
  title: `Remove ${modal.rows.length} Worktree(s)`,
27650
27857
  message: (() => {
27651
27858
  const count2 = modal.rows.length;
@@ -27662,15 +27869,15 @@ function App({ opts }) {
27662
27869
  `);
27663
27870
  })()
27664
27871
  }),
27665
- modal.type === "confirm_rebase" && /* @__PURE__ */ jsx12(ConfirmModal, {
27872
+ modal.type === "confirm_rebase" && /* @__PURE__ */ jsx13(ConfirmModal, {
27666
27873
  title: `Rebase ${modal.rows.length} Worktree(s)`,
27667
27874
  message: `Are you sure you want to fetch and rebase ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}?`
27668
27875
  }),
27669
- modal.type === "confirm_sync" && /* @__PURE__ */ jsx12(ConfirmModal, {
27876
+ modal.type === "confirm_sync" && /* @__PURE__ */ jsx13(ConfirmModal, {
27670
27877
  title: `Sync ${modal.rows.length} Worktree(s)`,
27671
27878
  message: `Are you sure you want to sync ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}?`
27672
27879
  }),
27673
- createModal && /* @__PURE__ */ jsx12(InputModal, {
27880
+ createModal && /* @__PURE__ */ jsx13(InputModal, {
27674
27881
  title: `New worktree branch in ${selectedRow?.repoName ?? ""}`,
27675
27882
  placeholder: "Branch name (empty to cancel)",
27676
27883
  errorMessage: createError,
@@ -27697,7 +27904,7 @@ function App({ opts }) {
27697
27904
  setCreateBaseModal({ branch, repoName });
27698
27905
  }
27699
27906
  }),
27700
- createBaseModal && /* @__PURE__ */ jsx12(InputModal, {
27907
+ createBaseModal && /* @__PURE__ */ jsx13(InputModal, {
27701
27908
  title: `Base ref for ${createBaseModal.branch}`,
27702
27909
  placeholder: "origin/main (empty for default main)",
27703
27910
  errorMessage: createBaseError,
@@ -27713,7 +27920,7 @@ function App({ opts }) {
27713
27920
  setCreateDepsChoice({ branch, repoName, base: base2 || undefined });
27714
27921
  }
27715
27922
  }),
27716
- createDepsChoice && /* @__PURE__ */ jsx12(ChoiceModal, {
27923
+ createDepsChoice && /* @__PURE__ */ jsx13(ChoiceModal, {
27717
27924
  title: `Dependencies for ${createDepsChoice.branch}`,
27718
27925
  options: DEPS_CHOICES,
27719
27926
  onSubmit: (choice) => {
@@ -27723,7 +27930,7 @@ function App({ opts }) {
27723
27930
  },
27724
27931
  onCancel: () => setCreateDepsChoice(null)
27725
27932
  }),
27726
- renameModal && selectedRow && /* @__PURE__ */ jsx12(InputModal, {
27933
+ renameModal && selectedRow && /* @__PURE__ */ jsx13(InputModal, {
27727
27934
  title: `Rename branch ${selectedRow.branch}`,
27728
27935
  placeholder: `New branch name (${selectedRow.branch})`,
27729
27936
  errorMessage: renameError,
@@ -27747,7 +27954,7 @@ function App({ opts }) {
27747
27954
  setModal({ type: "confirm_rename", row: target, to });
27748
27955
  }
27749
27956
  }),
27750
- modal.type === "confirm_rename" && /* @__PURE__ */ jsx12(ConfirmModal, {
27957
+ modal.type === "confirm_rename" && /* @__PURE__ */ jsx13(ConfirmModal, {
27751
27958
  title: "Rename Worktree",
27752
27959
  message: [
27753
27960
  `${modal.row.branch} → ${modal.to}`,
@@ -27760,12 +27967,12 @@ function App({ opts }) {
27760
27967
  ].join(`
27761
27968
  `)
27762
27969
  }),
27763
- configOpen && /* @__PURE__ */ jsx12(ConfigOverlay, {
27970
+ configOpen && /* @__PURE__ */ jsx13(ConfigOverlay, {
27764
27971
  onClose: () => setConfigOpen(false),
27765
27972
  onSaved: () => void doRefresh(),
27766
27973
  onError: (msg) => setModal({ type: "error", message: msg })
27767
27974
  }),
27768
- failedLogs.length > 0 && /* @__PURE__ */ jsx12(ActionLogModal, {
27975
+ failedLogs.length > 0 && /* @__PURE__ */ jsx13(ActionLogModal, {
27769
27976
  title: failedLogs[0].title,
27770
27977
  lines: failedLogs[0].lines,
27771
27978
  done: true,
@@ -27789,6 +27996,7 @@ var init_App = __esm(() => {
27789
27996
  init_InputModal();
27790
27997
  init_ChoiceModal();
27791
27998
  init_ConfigOverlay();
27999
+ init_WarningsOverlay();
27792
28000
  init_utils();
27793
28001
  init_agents();
27794
28002
  init_config();
@@ -27819,14 +28027,14 @@ __export(exports_tui, {
27819
28027
  });
27820
28028
  import { createCliRenderer, TextTableRenderable } from "@opentui/core";
27821
28029
  import { createRoot, extend as extend2 } from "@opentui/react";
27822
- import { jsx as jsx13 } from "@opentui/react/jsx-runtime";
28030
+ import { jsx as jsx14 } from "@opentui/react/jsx-runtime";
27823
28031
  async function runTerminal(opts) {
27824
28032
  const renderer = await createCliRenderer({
27825
28033
  exitOnCtrlC: false
27826
28034
  });
27827
28035
  const root = createRoot(renderer);
27828
28036
  try {
27829
- root.render(/* @__PURE__ */ jsx13(App, {
28037
+ root.render(/* @__PURE__ */ jsx14(App, {
27830
28038
  opts
27831
28039
  }));
27832
28040
  } catch (err) {
@@ -31233,7 +31441,7 @@ function registerLsCommand(program2) {
31233
31441
  const prInfo = prMap?.get(branch);
31234
31442
  if (prInfo) {
31235
31443
  const display = derivePrDisplay(prInfo);
31236
- prSegment = ` #${prInfo.number} ${renderDisplayState(display)} ${source_default.dim(prInfo.url)}`;
31444
+ prSegment = ` #${prInfo.number} ${renderDisplayState(display)} ${source_default.dim(terminalLink(prInfo.url))}`;
31237
31445
  }
31238
31446
  let ownerSuffix = "";
31239
31447
  const baseRef = wt.branch ? stackMetadata.branches[wt.branch]?.baseRef ?? prInfo?.baseRefName : prInfo?.baseRefName;
@@ -32163,7 +32371,7 @@ function renderTable(rows) {
32163
32371
  const detailSuffix = details ? ` ${details}` : "";
32164
32372
  const baseSuffix = row.baseRef ? ` → ${row.baseRef}` : "";
32165
32373
  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)}`);
32374
+ info(` #${row.prNumber} ${paddedBranch} ${renderDisplayState(row.prDisplay)}${baseSuffix}${detailSuffix}${authorTag} ${formatRelativeTime(row.updatedAt)} ${source_default.dim(terminalLink(row.url))}`);
32167
32375
  }
32168
32376
  }
32169
32377
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ogpoyraz/wtx",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Multi-repo git worktree manager",
5
5
  "type": "module",
6
6
  "bin": {