webmux 0.31.1 → 0.31.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.
@@ -14975,12 +14975,26 @@ import { randomUUID } from "crypto";
14975
14975
  // backend/src/adapters/git.ts
14976
14976
  import { readdirSync, rmSync, statSync } from "fs";
14977
14977
  import { resolve as resolve6, join as join5 } from "path";
14978
+ function spawnGit(args, cwd) {
14979
+ try {
14980
+ return {
14981
+ ok: true,
14982
+ result: Bun.spawnSync(["git", ...args], {
14983
+ cwd,
14984
+ stdout: "pipe",
14985
+ stderr: "pipe"
14986
+ })
14987
+ };
14988
+ } catch (error) {
14989
+ return { ok: false, stderr: `spawn error (cwd=${cwd}): ${errorMessage(error)}` };
14990
+ }
14991
+ }
14978
14992
  function runGit(args, cwd) {
14979
- const result = Bun.spawnSync(["git", ...args], {
14980
- cwd,
14981
- stdout: "pipe",
14982
- stderr: "pipe"
14983
- });
14993
+ const spawned = spawnGit(args, cwd);
14994
+ if (!spawned.ok) {
14995
+ throw new Error(`git ${args.join(" ")} failed: ${spawned.stderr}`);
14996
+ }
14997
+ const { result } = spawned;
14984
14998
  if (result.exitCode !== 0) {
14985
14999
  const stderr = new TextDecoder().decode(result.stderr).trim();
14986
15000
  throw new Error(`git ${args.join(" ")} failed: ${stderr || `exit ${result.exitCode}`}`);
@@ -14988,11 +15002,11 @@ function runGit(args, cwd) {
14988
15002
  return new TextDecoder().decode(result.stdout).trim();
14989
15003
  }
14990
15004
  function tryRunGit(args, cwd) {
14991
- const result = Bun.spawnSync(["git", ...args], {
14992
- cwd,
14993
- stdout: "pipe",
14994
- stderr: "pipe"
14995
- });
15005
+ const spawned = spawnGit(args, cwd);
15006
+ if (!spawned.ok) {
15007
+ return { ok: false, stderr: spawned.stderr };
15008
+ }
15009
+ const { result } = spawned;
14996
15010
  if (result.exitCode !== 0) {
14997
15011
  return {
14998
15012
  ok: false,
@@ -15113,6 +15127,16 @@ function listGitWorktrees(cwd) {
15113
15127
  const output = runGit(["worktree", "list", "--porcelain"], cwd);
15114
15128
  return parseGitWorktreePorcelain(output);
15115
15129
  }
15130
+ function worktreeEntryPathExists(entry) {
15131
+ try {
15132
+ return statSync(entry.path).isDirectory();
15133
+ } catch {
15134
+ return false;
15135
+ }
15136
+ }
15137
+ function filterLiveWorktreeEntries(entries) {
15138
+ return entries.filter(worktreeEntryPathExists);
15139
+ }
15116
15140
  function listLocalGitBranches(cwd) {
15117
15141
  const output = runGit(["for-each-ref", "--format=%(refname:short)", "refs/heads"], cwd);
15118
15142
  return output.split(`
@@ -15173,6 +15197,9 @@ class BunGitGateway {
15173
15197
  listWorktrees(cwd) {
15174
15198
  return listGitWorktrees(cwd);
15175
15199
  }
15200
+ listLiveWorktrees(cwd) {
15201
+ return filterLiveWorktreeEntries(listGitWorktrees(cwd));
15202
+ }
15176
15203
  listLocalBranches(cwd) {
15177
15204
  return listLocalGitBranches(cwd);
15178
15205
  }
@@ -15736,7 +15763,7 @@ class LifecycleService {
15736
15763
  }
15737
15764
  listProjectWorktrees() {
15738
15765
  const projectRoot2 = resolve7(this.deps.projectRoot);
15739
- return this.deps.git.listWorktrees(projectRoot2).filter((entry) => !entry.bare && resolve7(entry.path) !== projectRoot2);
15766
+ return this.deps.git.listLiveWorktrees(projectRoot2).filter((entry) => !entry.bare && resolve7(entry.path) !== projectRoot2);
15740
15767
  }
15741
15768
  async readManagedMetas() {
15742
15769
  const metas = await Promise.all(this.listProjectWorktrees().map(async (entry) => {
@@ -16623,7 +16650,7 @@ function resetProcessedIssues() {
16623
16650
 
16624
16651
  // backend/src/services/auto-remove-service.ts
16625
16652
  async function runAutoRemove(deps) {
16626
- const worktrees = deps.git.listWorktrees(deps.projectRoot).filter((e) => !e.bare && e.branch !== null && e.path !== deps.projectRoot);
16653
+ const worktrees = deps.git.listLiveWorktrees(deps.projectRoot).filter((e) => !e.bare && e.branch !== null && e.path !== deps.projectRoot);
16627
16654
  for (const entry of worktrees) {
16628
16655
  const branch = entry.branch;
16629
16656
  if (deps.isRemoving(branch))
@@ -18205,7 +18232,7 @@ class ReconciliationService {
18205
18232
  return await this.inFlight;
18206
18233
  }
18207
18234
  async runReconcile(normalizedRepoRoot) {
18208
- const worktrees = this.deps.git.listWorktrees(normalizedRepoRoot);
18235
+ const worktrees = this.deps.git.listLiveWorktrees(normalizedRepoRoot);
18209
18236
  const sessionName = buildProjectSessionName(normalizedRepoRoot);
18210
18237
  let windows = [];
18211
18238
  try {
@@ -18610,7 +18637,7 @@ async function hasValidControlToken(req) {
18610
18637
  async function getWorktreeGitDirs() {
18611
18638
  const gitDirs = new Map;
18612
18639
  const projectRoot2 = resolve9(PROJECT_DIR);
18613
- for (const entry of git.listWorktrees(projectRoot2)) {
18640
+ for (const entry of git.listLiveWorktrees(projectRoot2)) {
18614
18641
  if (entry.bare || resolve9(entry.path) === projectRoot2 || !entry.branch)
18615
18642
  continue;
18616
18643
  gitDirs.set(entry.branch, git.resolveWorktreeGitDir(entry.path));
package/bin/webmux.js CHANGED
@@ -50,12 +50,26 @@ var __require = import.meta.require;
50
50
  // backend/src/adapters/git.ts
51
51
  import { readdirSync, rmSync, statSync } from "fs";
52
52
  import { resolve, join } from "path";
53
+ function spawnGit(args, cwd) {
54
+ try {
55
+ return {
56
+ ok: true,
57
+ result: Bun.spawnSync(["git", ...args], {
58
+ cwd,
59
+ stdout: "pipe",
60
+ stderr: "pipe"
61
+ })
62
+ };
63
+ } catch (error) {
64
+ return { ok: false, stderr: `spawn error (cwd=${cwd}): ${errorMessage(error)}` };
65
+ }
66
+ }
53
67
  function runGit(args, cwd) {
54
- const result = Bun.spawnSync(["git", ...args], {
55
- cwd,
56
- stdout: "pipe",
57
- stderr: "pipe"
58
- });
68
+ const spawned = spawnGit(args, cwd);
69
+ if (!spawned.ok) {
70
+ throw new Error(`git ${args.join(" ")} failed: ${spawned.stderr}`);
71
+ }
72
+ const { result } = spawned;
59
73
  if (result.exitCode !== 0) {
60
74
  const stderr = new TextDecoder().decode(result.stderr).trim();
61
75
  throw new Error(`git ${args.join(" ")} failed: ${stderr || `exit ${result.exitCode}`}`);
@@ -63,11 +77,11 @@ function runGit(args, cwd) {
63
77
  return new TextDecoder().decode(result.stdout).trim();
64
78
  }
65
79
  function tryRunGit(args, cwd) {
66
- const result = Bun.spawnSync(["git", ...args], {
67
- cwd,
68
- stdout: "pipe",
69
- stderr: "pipe"
70
- });
80
+ const spawned = spawnGit(args, cwd);
81
+ if (!spawned.ok) {
82
+ return { ok: false, stderr: spawned.stderr };
83
+ }
84
+ const { result } = spawned;
71
85
  if (result.exitCode !== 0) {
72
86
  return {
73
87
  ok: false,
@@ -188,6 +202,16 @@ function listGitWorktrees(cwd) {
188
202
  const output = runGit(["worktree", "list", "--porcelain"], cwd);
189
203
  return parseGitWorktreePorcelain(output);
190
204
  }
205
+ function worktreeEntryPathExists(entry) {
206
+ try {
207
+ return statSync(entry.path).isDirectory();
208
+ } catch {
209
+ return false;
210
+ }
211
+ }
212
+ function filterLiveWorktreeEntries(entries) {
213
+ return entries.filter(worktreeEntryPathExists);
214
+ }
191
215
  function listLocalGitBranches(cwd) {
192
216
  const output = runGit(["for-each-ref", "--format=%(refname:short)", "refs/heads"], cwd);
193
217
  return output.split(`
@@ -248,6 +272,9 @@ class BunGitGateway {
248
272
  listWorktrees(cwd) {
249
273
  return listGitWorktrees(cwd);
250
274
  }
275
+ listLiveWorktrees(cwd) {
276
+ return filterLiveWorktreeEntries(listGitWorktrees(cwd));
277
+ }
251
278
  listLocalBranches(cwd) {
252
279
  return listLocalGitBranches(cwd);
253
280
  }
@@ -17754,7 +17781,7 @@ class LifecycleService {
17754
17781
  }
17755
17782
  listProjectWorktrees() {
17756
17783
  const projectRoot2 = resolve8(this.deps.projectRoot);
17757
- return this.deps.git.listWorktrees(projectRoot2).filter((entry) => !entry.bare && resolve8(entry.path) !== projectRoot2);
17784
+ return this.deps.git.listLiveWorktrees(projectRoot2).filter((entry) => !entry.bare && resolve8(entry.path) !== projectRoot2);
17758
17785
  }
17759
17786
  async readManagedMetas() {
17760
17787
  const metas = await Promise.all(this.listProjectWorktrees().map(async (entry) => {
@@ -18507,7 +18534,7 @@ class ReconciliationService {
18507
18534
  return await this.inFlight;
18508
18535
  }
18509
18536
  async runReconcile(normalizedRepoRoot) {
18510
- const worktrees = this.deps.git.listWorktrees(normalizedRepoRoot);
18537
+ const worktrees = this.deps.git.listLiveWorktrees(normalizedRepoRoot);
18511
18538
  const sessionName = buildProjectSessionName(normalizedRepoRoot);
18512
18539
  let windows = [];
18513
18540
  try {
@@ -19351,7 +19378,7 @@ import { fileURLToPath } from "url";
19351
19378
  // package.json
19352
19379
  var package_default = {
19353
19380
  name: "webmux",
19354
- version: "0.31.1",
19381
+ version: "0.31.2",
19355
19382
  description: "Web dashboard for workmux \u2014 browser UI with embedded terminals, PR monitoring, and CI integration",
19356
19383
  type: "module",
19357
19384
  repository: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webmux",
3
- "version": "0.31.1",
3
+ "version": "0.31.2",
4
4
  "description": "Web dashboard for workmux — browser UI with embedded terminals, PR monitoring, and CI integration",
5
5
  "type": "module",
6
6
  "repository": {