webmux 0.12.0 → 0.13.0

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/bin/webmux.js CHANGED
@@ -164,6 +164,11 @@ function listGitWorktrees(cwd) {
164
164
  const output = runGit(["worktree", "list", "--porcelain"], cwd);
165
165
  return parseGitWorktreePorcelain(output);
166
166
  }
167
+ function listLocalGitBranches(cwd) {
168
+ const output = runGit(["for-each-ref", "--format=%(refname:short)", "refs/heads"], cwd);
169
+ return output.split(`
170
+ `).map((line) => line.trim()).filter((line) => line.length > 0);
171
+ }
167
172
  function readGitWorktreeStatus(cwd) {
168
173
  const dirtyOutput = runGit(["status", "--porcelain"], cwd);
169
174
  const commit = tryRunGit(["rev-parse", "HEAD"], cwd);
@@ -205,13 +210,21 @@ class BunGitGateway {
205
210
  listWorktrees(cwd) {
206
211
  return listGitWorktrees(cwd);
207
212
  }
213
+ listLocalBranches(cwd) {
214
+ return listLocalGitBranches(cwd);
215
+ }
208
216
  readWorktreeStatus(cwd) {
209
217
  return readGitWorktreeStatus(cwd);
210
218
  }
211
219
  createWorktree(opts) {
212
- const args = ["worktree", "add", "-b", opts.branch, opts.worktreePath];
213
- if (opts.baseBranch)
214
- args.push(opts.baseBranch);
220
+ const args = ["worktree", "add"];
221
+ if (opts.mode === "new") {
222
+ args.push("-b", opts.branch, opts.worktreePath);
223
+ if (opts.baseBranch)
224
+ args.push(opts.baseBranch);
225
+ } else {
226
+ args.push(opts.worktreePath, opts.branch);
227
+ }
215
228
  runGit(args, opts.repoRoot);
216
229
  }
217
230
  removeWorktree(opts) {
@@ -350,6 +363,7 @@ _webmux() {
350
363
  'close:Close a worktree session'
351
364
  'remove:Remove a worktree'
352
365
  'merge:Merge a worktree into main'
366
+ 'prune:Remove all worktrees in the current project'
353
367
  'completion:Generate shell completion script'
354
368
  )
355
369
 
@@ -397,7 +411,7 @@ compdef _webmux webmux`, BASH_SCRIPT = `_webmux() {
397
411
  prev="\${COMP_WORDS[COMP_CWORD-1]}"
398
412
 
399
413
  if [[ \${COMP_CWORD} -eq 1 ]]; then
400
- COMPREPLY=($(compgen -W "serve init service update add list open close remove merge completion" -- "\${cur}"))
414
+ COMPREPLY=($(compgen -W "serve init service update add list open close remove merge prune completion" -- "\${cur}"))
401
415
  return
402
416
  fi
403
417
 
@@ -2625,7 +2639,6 @@ class BunTmuxGateway {
2625
2639
  if (check.exitCode !== 0) {
2626
2640
  assertTmuxOk(["new-session", "-d", "-s", sessionName, "-c", cwd], `create tmux session ${sessionName}`);
2627
2641
  }
2628
- assertTmuxOk(["set-option", "-t", sessionName, "pane-base-index", "0"], `set pane-base-index on ${sessionName}`);
2629
2642
  }
2630
2643
  hasWindow(sessionName, windowName) {
2631
2644
  const result = runTmux(["list-windows", "-t", sessionName, "-F", "#{window_name}"]);
@@ -10730,15 +10743,22 @@ function buildRuntimeBootstrap(runtimeEnvPath) {
10730
10743
  return `set -a; . ${quoteShell(runtimeEnvPath)}; set +a`;
10731
10744
  }
10732
10745
  function buildAgentInvocation(input) {
10733
- const promptSuffix = input.prompt ? ` ${quoteShell(input.prompt)}` : "";
10734
10746
  if (input.agent === "codex") {
10735
10747
  const yoloFlag2 = input.yolo ? " --yolo" : "";
10748
+ if (input.launchMode === "resume") {
10749
+ return `codex${yoloFlag2} resume --last`;
10750
+ }
10751
+ const promptSuffix2 = input.prompt ? ` ${quoteShell(input.prompt)}` : "";
10736
10752
  if (input.systemPrompt) {
10737
- return `codex${yoloFlag2} -c ${quoteShell(`developer_instructions=${input.systemPrompt}`)}${promptSuffix}`;
10753
+ return `codex${yoloFlag2} -c ${quoteShell(`developer_instructions=${input.systemPrompt}`)}${promptSuffix2}`;
10738
10754
  }
10739
- return `codex${yoloFlag2}${promptSuffix}`;
10755
+ return `codex${yoloFlag2}${promptSuffix2}`;
10740
10756
  }
10741
10757
  const yoloFlag = input.yolo ? " --dangerously-skip-permissions" : "";
10758
+ if (input.launchMode === "resume") {
10759
+ return `claude${yoloFlag} --continue`;
10760
+ }
10761
+ const promptSuffix = input.prompt ? ` ${quoteShell(input.prompt)}` : "";
10742
10762
  if (input.systemPrompt) {
10743
10763
  return `claude${yoloFlag} --append-system-prompt ${quoteShell(input.systemPrompt)}${promptSuffix}`;
10744
10764
  }
@@ -10821,6 +10841,7 @@ function ensureSessionLayout(tmux, plan) {
10821
10841
  cwd: rootPane.cwd,
10822
10842
  command: plan.shellCommand
10823
10843
  });
10844
+ tmux.setWindowOption(plan.sessionName, plan.windowName, "pane-base-index", "0");
10824
10845
  tmux.setWindowOption(plan.sessionName, plan.windowName, "automatic-rename", "off");
10825
10846
  tmux.setWindowOption(plan.sessionName, plan.windowName, "allow-rename", "off");
10826
10847
  for (const pane of plan.panes.slice(1)) {
@@ -10879,10 +10900,12 @@ function rollbackManagedWorktreeCreation(opts, sessionLayoutPlan, git, deps2) {
10879
10900
  } catch (error) {
10880
10901
  cleanupErrors.push(`worktree rollback failed: ${toErrorMessage(error)}`);
10881
10902
  }
10882
- try {
10883
- git.deleteBranch(opts.repoRoot, opts.branch, true);
10884
- } catch (error) {
10885
- cleanupErrors.push(`branch rollback failed: ${toErrorMessage(error)}`);
10903
+ if (opts.deleteBranchOnRollback ?? true) {
10904
+ try {
10905
+ git.deleteBranch(opts.repoRoot, opts.branch, true);
10906
+ } catch (error) {
10907
+ cleanupErrors.push(`branch rollback failed: ${toErrorMessage(error)}`);
10908
+ }
10886
10909
  }
10887
10910
  return cleanupErrors.length > 0 ? joinErrorMessages(cleanupErrors) : null;
10888
10911
  }
@@ -10932,6 +10955,7 @@ async function createManagedWorktree(opts, deps2 = {}) {
10932
10955
  repoRoot: opts.repoRoot,
10933
10956
  worktreePath: opts.worktreePath,
10934
10957
  branch: opts.branch,
10958
+ mode: opts.mode,
10935
10959
  baseBranch: opts.baseBranch
10936
10960
  });
10937
10961
  worktreeCreated = true;
@@ -11011,11 +11035,13 @@ class LifecycleService {
11011
11035
  this.deps = deps2;
11012
11036
  }
11013
11037
  async createWorktree(input) {
11014
- const branch = await this.resolveBranch(input.branch, input.prompt);
11015
- this.ensureBranchAvailable(branch);
11038
+ const mode = input.mode ?? "new";
11039
+ const branch = await this.resolveBranch(input.branch, input.prompt, mode);
11040
+ this.ensureBranchAvailable(branch, mode);
11016
11041
  const { profileName, profile } = this.resolveProfile(input.profile);
11017
11042
  const agent = this.resolveAgent(input.agent);
11018
11043
  const worktreePath = this.resolveWorktreePath(branch);
11044
+ const deleteBranchOnRollback = mode === "new";
11019
11045
  let initialized = null;
11020
11046
  try {
11021
11047
  await this.reportCreateProgress({
@@ -11030,7 +11056,8 @@ class LifecycleService {
11030
11056
  repoRoot: this.deps.projectRoot,
11031
11057
  worktreePath,
11032
11058
  branch,
11033
- baseBranch: this.deps.config.workspace.mainBranch,
11059
+ mode,
11060
+ ...mode === "new" ? { baseBranch: this.deps.config.workspace.mainBranch } : {},
11034
11061
  profile: profileName,
11035
11062
  agent,
11036
11063
  runtime: profile.runtime,
@@ -11038,7 +11065,8 @@ class LifecycleService {
11038
11065
  allocatedPorts: await this.allocatePorts(),
11039
11066
  runtimeEnvExtras: { WEBMUX_WORKTREE_PATH: worktreePath },
11040
11067
  controlUrl: this.controlUrl(),
11041
- controlToken: await this.deps.getControlToken()
11068
+ controlToken: await this.deps.getControlToken(),
11069
+ deleteBranchOnRollback
11042
11070
  }, {
11043
11071
  git: this.deps.git
11044
11072
  });
@@ -11084,7 +11112,8 @@ class LifecycleService {
11084
11112
  agent,
11085
11113
  initialized,
11086
11114
  worktreePath,
11087
- prompt: input.prompt
11115
+ prompt: input.prompt,
11116
+ launchMode: "fresh"
11088
11117
  });
11089
11118
  await this.reportCreateProgress({
11090
11119
  branch,
@@ -11100,7 +11129,7 @@ class LifecycleService {
11100
11129
  };
11101
11130
  } catch (error) {
11102
11131
  if (initialized) {
11103
- const cleanupError = await this.cleanupFailedCreate(branch, worktreePath, profile.runtime);
11132
+ const cleanupError = await this.cleanupFailedCreate(branch, worktreePath, profile.runtime, deleteBranchOnRollback);
11104
11133
  if (cleanupError) {
11105
11134
  throw this.wrapOperationError(new Error(`${toErrorMessage2(error)}; ${cleanupError}`));
11106
11135
  }
@@ -11113,6 +11142,7 @@ class LifecycleService {
11113
11142
  async openWorktree(branch) {
11114
11143
  try {
11115
11144
  const resolved = await this.resolveExistingWorktree(branch);
11145
+ const launchMode = resolved.meta ? "resume" : "fresh";
11116
11146
  const initialized = resolved.meta ? await this.refreshManagedArtifacts(resolved) : await this.initializeUnmanagedWorktree(resolved);
11117
11147
  const { profile } = this.resolveProfile(initialized.meta.profile);
11118
11148
  await ensureAgentRuntimeArtifacts({
@@ -11124,7 +11154,8 @@ class LifecycleService {
11124
11154
  profile,
11125
11155
  agent: initialized.meta.agent,
11126
11156
  initialized,
11127
- worktreePath: resolved.entry.path
11157
+ worktreePath: resolved.entry.path,
11158
+ launchMode
11128
11159
  });
11129
11160
  await this.deps.reconciliation.reconcile(this.deps.projectRoot);
11130
11161
  return {
@@ -11152,6 +11183,20 @@ class LifecycleService {
11152
11183
  throw this.wrapOperationError(error);
11153
11184
  }
11154
11185
  }
11186
+ async pruneWorktrees() {
11187
+ try {
11188
+ const resolvedWorktrees = await this.resolveAllWorktrees();
11189
+ const removedBranches = [];
11190
+ for (const resolved of resolvedWorktrees) {
11191
+ const branch = resolved.entry.branch ?? resolved.entry.path;
11192
+ await this.removeResolvedWorktree(resolved);
11193
+ removedBranches.push(branch);
11194
+ }
11195
+ return { removedBranches };
11196
+ } catch (error) {
11197
+ throw this.wrapOperationError(error);
11198
+ }
11199
+ }
11155
11200
  async mergeWorktree(branch) {
11156
11201
  try {
11157
11202
  const resolved = await this.resolveExistingWorktree(branch);
@@ -11170,9 +11215,17 @@ class LifecycleService {
11170
11215
  throw this.wrapOperationError(error);
11171
11216
  }
11172
11217
  }
11173
- async resolveBranch(rawBranch, prompt) {
11218
+ listAvailableBranches() {
11219
+ const localBranches = this.listLocalBranches().filter((branch) => isValidBranchName(branch));
11220
+ const checkedOutBranches = this.listCheckedOutBranches();
11221
+ return localBranches.filter((branch) => !checkedOutBranches.has(branch)).sort((left, right) => left.localeCompare(right)).map((name) => ({ name }));
11222
+ }
11223
+ async resolveBranch(rawBranch, prompt, mode) {
11174
11224
  const explicitBranch = rawBranch?.trim();
11175
- const branch = explicitBranch || await this.generateAutoName(prompt) || generateBranchName();
11225
+ const branch = mode === "existing" ? explicitBranch : explicitBranch || await this.generateAutoName(prompt) || generateBranchName();
11226
+ if (!branch) {
11227
+ throw new LifecycleError("Existing branch is required", 400);
11228
+ }
11176
11229
  if (!isValidBranchName(branch)) {
11177
11230
  throw new LifecycleError(`Invalid branch name: ${branch}`, 400);
11178
11231
  }
@@ -11184,10 +11237,19 @@ class LifecycleService {
11184
11237
  }
11185
11238
  return await this.deps.autoName.generateBranchName(this.deps.config.autoName, prompt);
11186
11239
  }
11187
- ensureBranchAvailable(branch) {
11188
- const exists = this.listProjectWorktrees().some((entry) => entry.branch === branch);
11189
- if (exists) {
11190
- throw new LifecycleError(`Worktree already exists: ${branch}`, 409);
11240
+ ensureBranchAvailable(branch, mode) {
11241
+ const localBranches = new Set(this.listLocalBranches());
11242
+ if (mode === "new") {
11243
+ if (localBranches.has(branch)) {
11244
+ throw new LifecycleError(`Branch already exists: ${branch}`, 409);
11245
+ }
11246
+ return;
11247
+ }
11248
+ if (!localBranches.has(branch)) {
11249
+ throw new LifecycleError(`Branch not found: ${branch}`, 404);
11250
+ }
11251
+ if (this.listCheckedOutBranches().has(branch)) {
11252
+ throw new LifecycleError(`Branch already has a worktree: ${branch}`, 409);
11191
11253
  }
11192
11254
  }
11193
11255
  resolveProfile(profileName) {
@@ -11226,6 +11288,12 @@ class LifecycleService {
11226
11288
  resolveWorktreePath(branch) {
11227
11289
  return resolve4(this.deps.projectRoot, this.deps.config.workspace.worktreeRoot, branch);
11228
11290
  }
11291
+ listLocalBranches() {
11292
+ return this.deps.git.listLocalBranches(resolve4(this.deps.projectRoot));
11293
+ }
11294
+ listCheckedOutBranches() {
11295
+ return new Set(this.deps.git.listWorktrees(resolve4(this.deps.projectRoot)).filter((entry) => !entry.bare && entry.branch !== null).map((entry) => entry.branch));
11296
+ }
11229
11297
  listProjectWorktrees() {
11230
11298
  const projectRoot = resolve4(this.deps.projectRoot);
11231
11299
  return this.deps.git.listWorktrees(projectRoot).filter((entry) => !entry.bare && resolve4(entry.path) !== projectRoot);
@@ -11246,6 +11314,14 @@ class LifecycleService {
11246
11314
  const meta = await readWorktreeMeta(gitDir);
11247
11315
  return { entry, gitDir, meta };
11248
11316
  }
11317
+ async resolveAllWorktrees() {
11318
+ const entries = this.listProjectWorktrees().sort((left, right) => (left.branch ?? left.path).localeCompare(right.branch ?? right.path));
11319
+ return await Promise.all(entries.map(async (entry) => {
11320
+ const gitDir = this.deps.git.resolveWorktreeGitDir(entry.path);
11321
+ const meta = await readWorktreeMeta(gitDir);
11322
+ return { entry, gitDir, meta };
11323
+ }));
11324
+ }
11249
11325
  async initializeUnmanagedWorktree(resolved) {
11250
11326
  const { profileName, profile } = this.resolveProfile(undefined);
11251
11327
  const dotenvValues = await loadDotenvLocal(resolved.entry.path);
@@ -11311,6 +11387,7 @@ class LifecycleService {
11311
11387
  initialized: input.initialized,
11312
11388
  worktreePath: input.worktreePath,
11313
11389
  prompt: input.prompt,
11390
+ launchMode: input.launchMode,
11314
11391
  containerName: containerName2
11315
11392
  }));
11316
11393
  return;
@@ -11321,11 +11398,12 @@ class LifecycleService {
11321
11398
  agent: input.agent,
11322
11399
  initialized: input.initialized,
11323
11400
  worktreePath: input.worktreePath,
11324
- prompt: input.prompt
11401
+ prompt: input.prompt,
11402
+ launchMode: input.launchMode
11325
11403
  }));
11326
11404
  }
11327
11405
  buildSessionLayout(input) {
11328
- const systemPrompt = input.profile.systemPrompt ? expandTemplate(input.profile.systemPrompt, input.initialized.runtimeEnv) : undefined;
11406
+ const systemPrompt = input.launchMode === "fresh" && input.profile.systemPrompt ? expandTemplate(input.profile.systemPrompt, input.initialized.runtimeEnv) : undefined;
11329
11407
  const containerName2 = input.containerName;
11330
11408
  return planSessionLayout(this.deps.projectRoot, input.branch, input.profile.panes, {
11331
11409
  repoRoot: this.deps.projectRoot,
@@ -11338,7 +11416,8 @@ class LifecycleService {
11338
11416
  runtimeEnvPath: input.initialized.paths.runtimeEnvPath,
11339
11417
  yolo: input.profile.yolo === true,
11340
11418
  systemPrompt,
11341
- prompt: input.prompt
11419
+ prompt: input.launchMode === "fresh" ? input.prompt : undefined,
11420
+ launchMode: input.launchMode
11342
11421
  }),
11343
11422
  shell: buildDockerShellCommand(containerName2, input.worktreePath, input.initialized.paths.runtimeEnvPath)
11344
11423
  } : {
@@ -11347,7 +11426,8 @@ class LifecycleService {
11347
11426
  runtimeEnvPath: input.initialized.paths.runtimeEnvPath,
11348
11427
  yolo: input.profile.yolo === true,
11349
11428
  systemPrompt,
11350
- prompt: input.prompt
11429
+ prompt: input.launchMode === "fresh" ? input.prompt : undefined,
11430
+ launchMode: input.launchMode
11351
11431
  }),
11352
11432
  shell: buildManagedShellCommand(input.initialized.paths.runtimeEnvPath)
11353
11433
  }
@@ -11359,7 +11439,7 @@ class LifecycleService {
11359
11439
  }
11360
11440
  return profile;
11361
11441
  }
11362
- async cleanupFailedCreate(branch, worktreePath, runtime) {
11442
+ async cleanupFailedCreate(branch, worktreePath, runtime, deleteBranch) {
11363
11443
  const cleanupErrors = [];
11364
11444
  if (runtime === "docker") {
11365
11445
  try {
@@ -11379,8 +11459,8 @@ class LifecycleService {
11379
11459
  worktreePath,
11380
11460
  branch,
11381
11461
  force: true,
11382
- deleteBranch: true,
11383
- deleteBranchForce: true
11462
+ deleteBranch,
11463
+ deleteBranchForce: deleteBranch
11384
11464
  }, this.deps.git);
11385
11465
  } catch (error) {
11386
11466
  cleanupErrors.push(`worktree cleanup failed: ${toErrorMessage2(error)}`);
@@ -11986,6 +12066,9 @@ function getWorktreeCommandUsage(command) {
11986
12066
  case "merge":
11987
12067
  return `Usage:
11988
12068
  webmux merge <branch>`;
12069
+ case "prune":
12070
+ return `Usage:
12071
+ webmux prune`;
11989
12072
  }
11990
12073
  }
11991
12074
  function readOptionValue(args, index, flag) {
@@ -12088,6 +12171,29 @@ function parseBranchCommandArgs(args) {
12088
12171
  }
12089
12172
  return branch;
12090
12173
  }
12174
+ function parsePruneCommandArgs(args) {
12175
+ for (const arg of args) {
12176
+ if (arg === "--help" || arg === "-h") {
12177
+ return false;
12178
+ }
12179
+ if (arg.startsWith("-")) {
12180
+ throw new CommandUsageError(`Unknown option: ${arg}`);
12181
+ }
12182
+ throw new CommandUsageError(`Unexpected argument: ${arg}`);
12183
+ }
12184
+ return true;
12185
+ }
12186
+ function listProjectWorktrees(runtime) {
12187
+ const projectDir = resolve6(runtime.projectDir);
12188
+ return runtime.git.listWorktrees(projectDir).filter((entry) => !entry.bare && resolve6(entry.path) !== projectDir);
12189
+ }
12190
+ async function defaultConfirmPrune(worktreeCount) {
12191
+ const response = await Rt({
12192
+ message: `Prune all ${worktreeCount} worktree${worktreeCount === 1 ? "" : "s"}? This action cannot be undone.`,
12193
+ initialValue: false
12194
+ });
12195
+ return !Ct(response) && response;
12196
+ }
12091
12197
  function defaultSwitchToTmuxWindow(projectDir, branch) {
12092
12198
  const sessionName = buildProjectSessionName(resolve6(projectDir));
12093
12199
  const windowName = buildWorktreeWindowName(branch);
@@ -12119,7 +12225,7 @@ function defaultSwitchToTmuxWindow(projectDir, branch) {
12119
12225
  }
12120
12226
  async function listWorktrees(runtime, stdout) {
12121
12227
  const projectDir = resolve6(runtime.projectDir);
12122
- const entries = runtime.git.listWorktrees(projectDir).filter((entry) => !entry.bare && resolve6(entry.path) !== projectDir);
12228
+ const entries = listProjectWorktrees(runtime);
12123
12229
  if (entries.length === 0) {
12124
12230
  stdout("No worktrees found.");
12125
12231
  return;
@@ -12152,6 +12258,7 @@ async function runWorktreeCommand(context, deps2 = {}) {
12152
12258
  const stdout = deps2.stdout ?? ((message) => console.log(message));
12153
12259
  const stderr = deps2.stderr ?? ((message) => console.error(message));
12154
12260
  const switchToTmuxWindow = deps2.switchToTmuxWindow ?? defaultSwitchToTmuxWindow;
12261
+ const confirmPrune = deps2.confirmPrune ?? defaultConfirmPrune;
12155
12262
  try {
12156
12263
  if (context.command === "add") {
12157
12264
  const input = parseAddCommandArgs(context.args);
@@ -12180,6 +12287,32 @@ async function runWorktreeCommand(context, deps2 = {}) {
12180
12287
  await listWorktrees(runtime2, stdout);
12181
12288
  return 0;
12182
12289
  }
12290
+ if (context.command === "prune") {
12291
+ if (!parsePruneCommandArgs(context.args)) {
12292
+ stdout(getWorktreeCommandUsage("prune"));
12293
+ return 0;
12294
+ }
12295
+ const runtime2 = createRuntime({
12296
+ projectDir: context.projectDir,
12297
+ port: context.port
12298
+ });
12299
+ const worktrees = listProjectWorktrees(runtime2);
12300
+ if (worktrees.length === 0) {
12301
+ stdout("No worktrees found.");
12302
+ return 0;
12303
+ }
12304
+ if (!await confirmPrune(worktrees.length)) {
12305
+ stdout("Aborted.");
12306
+ return 0;
12307
+ }
12308
+ const result = await runtime2.lifecycleService.pruneWorktrees();
12309
+ if (result.removedBranches.length === 0) {
12310
+ stdout("No worktrees found.");
12311
+ return 0;
12312
+ }
12313
+ stdout(`Pruned ${result.removedBranches.length} worktree${result.removedBranches.length === 1 ? "" : "s"}: ${result.removedBranches.join(", ")}`);
12314
+ return 0;
12315
+ }
12183
12316
  const command = context.command;
12184
12317
  const branch = parseBranchCommandArgs(context.args);
12185
12318
  if (!branch) {
@@ -12215,6 +12348,7 @@ async function runWorktreeCommand(context, deps2 = {}) {
12215
12348
  }
12216
12349
  var CommandUsageError;
12217
12350
  var init_worktree_commands = __esm(() => {
12351
+ init_dist2();
12218
12352
  init_fs();
12219
12353
  init_tmux();
12220
12354
  init_policies();
@@ -12230,7 +12364,7 @@ import { fileURLToPath } from "url";
12230
12364
  // package.json
12231
12365
  var package_default = {
12232
12366
  name: "webmux",
12233
- version: "0.12.0",
12367
+ version: "0.13.0",
12234
12368
  description: "Web dashboard for workmux \u2014 browser UI with embedded terminals, PR monitoring, and CI integration",
12235
12369
  type: "module",
12236
12370
  repository: {
@@ -12300,6 +12434,7 @@ Usage:
12300
12434
  webmux close Close a worktree session without removing it
12301
12435
  webmux remove Remove a worktree
12302
12436
  webmux merge Merge a worktree into the main branch and remove it
12437
+ webmux prune Remove all worktrees in the current project
12303
12438
  webmux completion Generate shell completion script (bash, zsh)
12304
12439
 
12305
12440
  Options:
@@ -12313,7 +12448,7 @@ Environment:
12313
12448
  `);
12314
12449
  }
12315
12450
  function isRootCommand(value) {
12316
- return value === "serve" || value === "init" || value === "service" || value === "update" || value === "add" || value === "list" || value === "open" || value === "close" || value === "remove" || value === "merge" || value === "completion";
12451
+ return value === "serve" || value === "init" || value === "service" || value === "update" || value === "add" || value === "list" || value === "open" || value === "close" || value === "remove" || value === "merge" || value === "prune" || value === "completion";
12317
12452
  }
12318
12453
  function isServeRootOption(value) {
12319
12454
  return value === "--port" || value === "--debug" || value === "--help" || value === "-h" || value === "--version" || value === "-V";
@@ -12372,7 +12507,7 @@ Run webmux --help for usage.`);
12372
12507
  };
12373
12508
  }
12374
12509
  function isWorktreeCommand(command) {
12375
- return command === "add" || command === "list" || command === "open" || command === "close" || command === "remove" || command === "merge";
12510
+ return command === "add" || command === "list" || command === "open" || command === "close" || command === "remove" || command === "merge" || command === "prune";
12376
12511
  }
12377
12512
  async function loadEnvFile(path) {
12378
12513
  if (!existsSync5(path))