@errhythm/gitmux 1.6.5 → 1.6.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@errhythm/gitmux",
3
- "version": "1.6.5",
3
+ "version": "1.6.6",
4
4
  "description": "Multi-repo Git & GitLab workflow CLI — switch branches, manage epics & issues, create MRs, all from the terminal",
5
5
  "type": "module",
6
6
  "bin": {
package/src/git/core.js CHANGED
@@ -1,30 +1,40 @@
1
- import { execSync } from "child_process";
2
- import { join, dirname } from "path";
1
+ import { readdirSync, statSync } from "fs";
2
+ import { join, dirname, sep } from "path";
3
3
 
4
4
  import { execAsync } from "../utils/exec.js";
5
5
 
6
6
  export function findRepos(cwd, depth) {
7
- try {
8
- const out = execSync(
9
- `find . -mindepth 1 -maxdepth ${depth} -type d -name '.git' 2>/dev/null`,
10
- { cwd, encoding: "utf8" },
11
- );
12
- const repos = out
13
- .trim()
14
- .split("\n")
15
- .filter(Boolean)
16
- .map((g) => join(cwd, dirname(g)));
7
+ const repos = [];
17
8
 
18
- // Filter out repos nested inside another found repo (submodule / monorepo protection).
19
- // A repo is nested if any other repo path is a strict path prefix of it.
20
- return repos.filter(
21
- (repo) => !repos.some(
22
- (other) => other !== repo && repo.startsWith(other + "/"),
23
- ),
24
- );
25
- } catch {
26
- return [];
9
+ function walk(dir, currentDepth) {
10
+ if (currentDepth > depth) return;
11
+ let entries;
12
+ try {
13
+ entries = readdirSync(dir, { withFileTypes: true });
14
+ } catch {
15
+ return; // permission denied or unreadable — skip
16
+ }
17
+ for (const entry of entries) {
18
+ if (!entry.isDirectory()) continue;
19
+ const full = join(dir, entry.name);
20
+ if (entry.name === ".git") {
21
+ repos.push(dirname(full));
22
+ return; // don't recurse into .git itself
23
+ }
24
+ // Skip hidden dirs (other than .git above) and node_modules
25
+ if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
26
+ walk(full, currentDepth + 1);
27
+ }
27
28
  }
29
+
30
+ walk(cwd, 1);
31
+
32
+ // Filter out repos nested inside another found repo (submodule / monorepo protection).
33
+ return repos.filter(
34
+ (repo) => !repos.some(
35
+ (other) => other !== repo && repo.startsWith(other + sep),
36
+ ),
37
+ );
28
38
  }
29
39
 
30
40
  export async function getCurrentBranch(repoPath) {
@@ -55,7 +65,7 @@ export async function getRepoStatus(repoPath) {
55
65
  export async function getAheadBehind(repoPath) {
56
66
  try {
57
67
  const { stdout } = await execAsync(
58
- "git rev-list --left-right --count @{upstream}...HEAD 2>/dev/null",
68
+ "git rev-list --left-right --count @{upstream}...HEAD",
59
69
  { cwd: repoPath, encoding: "utf8" },
60
70
  );
61
71
  if (!stdout.trim()) return { ahead: 0, behind: 0 };
@@ -65,3 +75,4 @@ export async function getAheadBehind(repoPath) {
65
75
  return { ahead: 0, behind: 0 };
66
76
  }
67
77
  }
78
+
@@ -25,7 +25,7 @@ export function isGitLabRemote(url) {
25
25
 
26
26
  export function getDefaultBranch(repoPath) {
27
27
  try {
28
- const out = execSync("git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null", {
28
+ const out = execSync("git symbolic-ref refs/remotes/origin/HEAD", {
29
29
  cwd: repoPath,
30
30
  encoding: "utf8",
31
31
  }).trim();