vde-worktree 0.0.14 → 0.0.15

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/index.mjs CHANGED
@@ -1440,9 +1440,9 @@ const colorizeListTableLine = ({ line, theme }) => {
1440
1440
  const segments = line.split("│");
1441
1441
  if (segments.length < 3) return line;
1442
1442
  const cells = segments.slice(1, -1);
1443
- if (cells.length !== 5) return line;
1443
+ if (cells.length !== 7) return line;
1444
1444
  const headers = cells.map((cell) => cell.trim());
1445
- if (headers[0] === "branch" && headers[1] === "dirty" && headers[2] === "merged" && headers[3] === "locked" && headers[4] === "path") {
1445
+ if (headers[0] === "branch" && headers[1] === "dirty" && headers[2] === "merged" && headers[3] === "locked" && headers[4] === "ahead" && headers[5] === "behind" && headers[6] === "path") {
1446
1446
  const nextCells = cells.map((cell) => colorizeCellContent({
1447
1447
  cell,
1448
1448
  color: theme.header
@@ -1457,13 +1457,21 @@ const colorizeListTableLine = ({ line, theme }) => {
1457
1457
  const dirtyCell = cells[1];
1458
1458
  const mergedCell = cells[2];
1459
1459
  const lockedCell = cells[3];
1460
- const pathCell = cells[4];
1460
+ const aheadCell = cells[4];
1461
+ const behindCell = cells[5];
1462
+ const pathCell = cells[6];
1461
1463
  const branchColor = branchCell.includes("(detached)") === true ? theme.branchDetached : branchCell.trimStart().startsWith("*") ? theme.branchCurrent : theme.branch;
1462
1464
  const dirtyTrimmed = dirtyCell.trim();
1463
1465
  const dirtyColor = dirtyTrimmed === "dirty" ? theme.dirty : dirtyTrimmed === "clean" ? theme.clean : theme.value;
1464
1466
  const mergedTrimmed = mergedCell.trim();
1465
1467
  const mergedColor = mergedTrimmed === "merged" ? theme.merged : mergedTrimmed === "unmerged" ? theme.unmerged : mergedTrimmed === "-" ? theme.base : theme.unknown;
1466
1468
  const lockedColor = lockedCell.trim() === "locked" ? theme.locked : theme.muted;
1469
+ const aheadTrimmed = aheadCell.trim();
1470
+ const aheadValue = Number.parseInt(aheadTrimmed, 10);
1471
+ const aheadColor = aheadTrimmed === "-" ? theme.muted : Number.isNaN(aheadValue) ? theme.value : aheadValue > 0 ? theme.unmerged : aheadValue === 0 ? theme.merged : theme.unknown;
1472
+ const behindTrimmed = behindCell.trim();
1473
+ const behindValue = Number.parseInt(behindTrimmed, 10);
1474
+ const behindColor = behindTrimmed === "-" ? theme.muted : Number.isNaN(behindValue) ? theme.value : behindValue > 0 ? theme.unknown : behindValue === 0 ? theme.merged : theme.unknown;
1467
1475
  const nextCells = [
1468
1476
  colorizeCellContent({
1469
1477
  cell: branchCell,
@@ -1481,6 +1489,14 @@ const colorizeListTableLine = ({ line, theme }) => {
1481
1489
  cell: lockedCell,
1482
1490
  color: lockedColor
1483
1491
  }),
1492
+ colorizeCellContent({
1493
+ cell: aheadCell,
1494
+ color: aheadColor
1495
+ }),
1496
+ colorizeCellContent({
1497
+ cell: behindCell,
1498
+ color: behindColor
1499
+ }),
1484
1500
  colorizeCellContent({
1485
1501
  cell: pathCell,
1486
1502
  color: theme.path
@@ -1509,7 +1525,7 @@ const commandHelpEntries = [
1509
1525
  name: "list",
1510
1526
  usage: "vw list [--json]",
1511
1527
  summary: "List worktrees with status metadata.",
1512
- details: ["Includes branch, path, dirty, lock, merged, and upstream fields."]
1528
+ details: ["Table output includes branch, path, dirty, lock, merged, and ahead/behind vs base branch.", "JSON output includes upstream metadata fields."]
1513
1529
  },
1514
1530
  {
1515
1531
  name: "status",
@@ -2342,6 +2358,37 @@ const formatMergedColor = ({ mergedState, theme }) => {
2342
2358
  if (normalized === "base") return theme.base(mergedState);
2343
2359
  return theme.unknown(mergedState);
2344
2360
  };
2361
+ const formatListUpstreamCount = (value) => {
2362
+ if (value === null) return "-";
2363
+ return String(value);
2364
+ };
2365
+ const resolveAheadBehindAgainstBaseBranch = async ({ repoRoot, baseBranch, worktree }) => {
2366
+ if (baseBranch === null) return {
2367
+ ahead: null,
2368
+ behind: null
2369
+ };
2370
+ const distance = await runGitCommand({
2371
+ cwd: repoRoot,
2372
+ args: [
2373
+ "rev-list",
2374
+ "--left-right",
2375
+ "--count",
2376
+ `${baseBranch}...${worktree.branch ?? worktree.head}`
2377
+ ],
2378
+ reject: false
2379
+ });
2380
+ if (distance.exitCode !== 0) return {
2381
+ ahead: null,
2382
+ behind: null
2383
+ };
2384
+ const [behindRaw, aheadRaw] = distance.stdout.trim().split(/\s+/);
2385
+ const behind = Number.parseInt(behindRaw ?? "", 10);
2386
+ const ahead = Number.parseInt(aheadRaw ?? "", 10);
2387
+ return {
2388
+ ahead: Number.isNaN(ahead) ? null : ahead,
2389
+ behind: Number.isNaN(behind) ? null : behind
2390
+ };
2391
+ };
2345
2392
  const padToDisplayWidth = ({ value, width }) => {
2346
2393
  const visibleLength = stringWidth(value);
2347
2394
  if (visibleLength >= width) return value;
@@ -2910,17 +2957,26 @@ const createCli = (options = {}) => {
2910
2957
  "dirty",
2911
2958
  "merged",
2912
2959
  "locked",
2960
+ "ahead",
2961
+ "behind",
2913
2962
  "path"
2914
- ], ...snapshot.worktrees.map((worktree) => {
2963
+ ], ...await Promise.all(snapshot.worktrees.map(async (worktree) => {
2964
+ const distanceFromBase = await resolveAheadBehindAgainstBaseBranch({
2965
+ repoRoot,
2966
+ baseBranch: snapshot.baseBranch,
2967
+ worktree
2968
+ });
2915
2969
  const mergedState = (worktree.branch !== null && snapshot.baseBranch !== null && worktree.branch === snapshot.baseBranch) === true ? "-" : worktree.merged.overall === true ? "merged" : worktree.merged.overall === false ? "unmerged" : "unknown";
2916
2970
  return [
2917
2971
  `${worktree.path === repoContext.currentWorktreeRoot ? "*" : " "} ${worktree.branch ?? "(detached)"}`,
2918
2972
  worktree.dirty ? "dirty" : "clean",
2919
2973
  mergedState,
2920
2974
  worktree.locked.value ? "locked" : "-",
2975
+ formatListUpstreamCount(distanceFromBase.ahead),
2976
+ formatListUpstreamCount(distanceFromBase.behind),
2921
2977
  formatDisplayPath(worktree.path)
2922
2978
  ];
2923
- })], {
2979
+ }))], {
2924
2980
  border: getBorderCharacters("norc"),
2925
2981
  drawHorizontalLine: (lineIndex, rowCount) => {
2926
2982
  return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount;