workon 3.5.2 → 3.7.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/dist/cli.js CHANGED
@@ -283,6 +283,13 @@ var init_project = __esm({
283
283
  }
284
284
  return this._path;
285
285
  }
286
+ /**
287
+ * Override the project path with an absolute path.
288
+ * Used when targeting a worktree instead of the main project directory.
289
+ */
290
+ overridePath(absolutePath) {
291
+ this._path = File.from(absolutePath).absolutify();
292
+ }
286
293
  set branch(branch) {
287
294
  this._branch = branch;
288
295
  }
@@ -1421,24 +1428,6 @@ var init_tmux = __esm({
1421
1428
  }
1422
1429
  });
1423
1430
 
1424
- // src/types/constants.ts
1425
- var IDE_CHOICES;
1426
- var init_constants = __esm({
1427
- "src/types/constants.ts"() {
1428
- "use strict";
1429
- IDE_CHOICES = [
1430
- { name: "Cursor", value: "cursor" },
1431
- { name: "Visual Studio Code", value: "vscode" },
1432
- { name: "Visual Studio Code (code)", value: "code" },
1433
- { name: "IntelliJ IDEA", value: "idea" },
1434
- { name: "Atom", value: "atom" },
1435
- { name: "Sublime Text", value: "subl" },
1436
- { name: "Vim", value: "vim" },
1437
- { name: "Emacs", value: "emacs" }
1438
- ];
1439
- }
1440
- });
1441
-
1442
1431
  // src/lib/worktree.ts
1443
1432
  import { exec as execCallback2 } from "child_process";
1444
1433
  import { promisify as promisify2 } from "util";
@@ -1458,7 +1447,7 @@ function deriveProjectIdentifier(projectPath) {
1458
1447
  function getWorktreesDirForProject(projectIdentifier) {
1459
1448
  return join(homedir(), WORKON_DIR, WORKTREES_SUBDIR, projectIdentifier);
1460
1449
  }
1461
- var exec2, WORKON_DIR, WORKTREES_SUBDIR, HOOK_DIR, SETUP_HOOK, WorktreeManager;
1450
+ var exec2, WORKON_DIR, WORKTREES_SUBDIR, HOOK_DIR, SETUP_HOOK, TEARDOWN_HOOK, WorktreeManager;
1462
1451
  var init_worktree = __esm({
1463
1452
  "src/lib/worktree.ts"() {
1464
1453
  "use strict";
@@ -1467,6 +1456,7 @@ var init_worktree = __esm({
1467
1456
  WORKTREES_SUBDIR = "worktrees";
1468
1457
  HOOK_DIR = ".workon";
1469
1458
  SETUP_HOOK = "worktree-setup.sh";
1459
+ TEARDOWN_HOOK = "worktree-teardown.sh";
1470
1460
  WorktreeManager = class {
1471
1461
  projectPath;
1472
1462
  projectIdentifier;
@@ -1684,6 +1674,42 @@ var init_worktree = __esm({
1684
1674
  });
1685
1675
  return { stdout, stderr };
1686
1676
  }
1677
+ /**
1678
+ * Check if a pre-teardown hook exists
1679
+ */
1680
+ hasTeardownHook() {
1681
+ const hookPath = this.getTeardownHookPath();
1682
+ return existsSync2(hookPath);
1683
+ }
1684
+ /**
1685
+ * Get the path to the teardown hook
1686
+ */
1687
+ getTeardownHookPath() {
1688
+ return join(this.projectPath, HOOK_DIR, TEARDOWN_HOOK);
1689
+ }
1690
+ /**
1691
+ * Run the pre-teardown hook for a worktree
1692
+ */
1693
+ async runPreTeardownHook(worktreePath) {
1694
+ const hookPath = this.getTeardownHookPath();
1695
+ if (!existsSync2(hookPath)) {
1696
+ throw new Error("Teardown hook not found");
1697
+ }
1698
+ try {
1699
+ chmodSync(hookPath, "755");
1700
+ } catch {
1701
+ }
1702
+ const env = {
1703
+ ...process.env,
1704
+ WORKTREE_PATH: worktreePath,
1705
+ PROJECT_PATH: this.projectPath
1706
+ };
1707
+ const { stdout, stderr } = await exec2(hookPath, {
1708
+ cwd: worktreePath,
1709
+ env
1710
+ });
1711
+ return { stdout, stderr };
1712
+ }
1687
1713
  /**
1688
1714
  * Parse the porcelain output of git worktree list
1689
1715
  */
@@ -1734,6 +1760,24 @@ var init_worktree = __esm({
1734
1760
  }
1735
1761
  });
1736
1762
 
1763
+ // src/types/constants.ts
1764
+ var IDE_CHOICES;
1765
+ var init_constants = __esm({
1766
+ "src/types/constants.ts"() {
1767
+ "use strict";
1768
+ IDE_CHOICES = [
1769
+ { name: "Cursor", value: "cursor" },
1770
+ { name: "Visual Studio Code", value: "vscode" },
1771
+ { name: "Visual Studio Code (code)", value: "code" },
1772
+ { name: "IntelliJ IDEA", value: "idea" },
1773
+ { name: "Atom", value: "atom" },
1774
+ { name: "Sublime Text", value: "subl" },
1775
+ { name: "Vim", value: "vim" },
1776
+ { name: "Emacs", value: "emacs" }
1777
+ ];
1778
+ }
1779
+ });
1780
+
1737
1781
  // src/commands/worktrees/utils.ts
1738
1782
  import File3 from "phylo";
1739
1783
  import path from "path";
@@ -1998,7 +2042,7 @@ import ora from "ora";
1998
2042
  import { select as select2, confirm as confirm4 } from "@inquirer/prompts";
1999
2043
  function createAddCommand(ctx) {
2000
2044
  const { config, log } = ctx;
2001
- return new Command2("add").description("Create a new worktree for a branch").argument("<branch>", "Branch name for the worktree").option("-b, --base <branch>", "Base branch to create new branch from").option("-f, --force", "Overwrite existing worktree").option("-o, --open", "Open the worktree after creation").option("--no-hook", "Skip running the post-setup hook").action(async (branch, options) => {
2045
+ return new Command2("add").description("Create a new worktree for a branch").argument("<branch>", "Branch name for the worktree").option("-b, --base <branch>", "Base branch to create new branch from").option("-f, --force", "Overwrite existing worktree").option("-o, --open", "Open the worktree after creation").option("--no-hook", "Skip running the post-setup hook").option("-y, --yes", "Skip all confirmation prompts (non-interactive mode)").action(async (branch, options) => {
2002
2046
  const projectCtx = await resolveProjectFromCwd(config, log);
2003
2047
  if (!projectCtx) {
2004
2048
  log.error("Not in a git repository. Run this command from within a git project.");
@@ -2008,11 +2052,15 @@ function createAddCommand(ctx) {
2008
2052
  process.exit(1);
2009
2053
  }
2010
2054
  if (!projectCtx.isRegistered) {
2011
- const result = await promptToRegisterProject(projectCtx.projectPath, config, log);
2012
- if (result) {
2013
- projectCtx.projectName = result.projectName;
2014
- projectCtx.projectConfig = result.projectConfig;
2015
- projectCtx.isRegistered = true;
2055
+ if (options.yes) {
2056
+ log.info("Project is not registered. Proceeding without registration.");
2057
+ } else {
2058
+ const result = await promptToRegisterProject(projectCtx.projectPath, config, log);
2059
+ if (result) {
2060
+ projectCtx.projectName = result.projectName;
2061
+ projectCtx.projectConfig = result.projectConfig;
2062
+ projectCtx.isRegistered = true;
2063
+ }
2016
2064
  }
2017
2065
  }
2018
2066
  const { projectPath, projectName } = projectCtx;
@@ -2020,16 +2068,21 @@ function createAddCommand(ctx) {
2020
2068
  const branchExists = await manager.branchExists(branch);
2021
2069
  let baseBranch = options.base;
2022
2070
  if (!branchExists && !baseBranch) {
2023
- const branches = await manager.getBranches();
2024
- const currentBranch = await manager.getCurrentBranch();
2025
- baseBranch = await select2({
2026
- message: `Branch '${branch}' doesn't exist. Create from which branch?`,
2027
- choices: branches.map((b) => ({
2028
- name: b === currentBranch ? `${b} (current)` : b,
2029
- value: b
2030
- })),
2031
- default: currentBranch
2032
- });
2071
+ if (options.yes) {
2072
+ baseBranch = await manager.getCurrentBranch();
2073
+ log.info(`Branch '${branch}' doesn't exist. Creating from '${baseBranch}'.`);
2074
+ } else {
2075
+ const branches = await manager.getBranches();
2076
+ const currentBranch = await manager.getCurrentBranch();
2077
+ baseBranch = await select2({
2078
+ message: `Branch '${branch}' doesn't exist. Create from which branch?`,
2079
+ choices: branches.map((b) => ({
2080
+ name: b === currentBranch ? `${b} (current)` : b,
2081
+ value: b
2082
+ })),
2083
+ default: currentBranch
2084
+ });
2085
+ }
2033
2086
  }
2034
2087
  const spinner = ora(`Creating worktree for branch '${branch}'...`).start();
2035
2088
  try {
@@ -2062,6 +2115,9 @@ ${chalk2.bold("Worktree details:")}`);
2062
2115
  if (projectCtx.isRegistered && projectName) {
2063
2116
  if (options.open) {
2064
2117
  await openWorktreeSession(projectCtx, worktree.name, config, log);
2118
+ } else if (options.yes) {
2119
+ console.log(`
2120
+ To open later: ${chalk2.cyan(`workon worktrees open ${worktree.name}`)}`);
2065
2121
  } else {
2066
2122
  const shouldOpen = await confirm4({
2067
2123
  message: "Open workon session in this worktree?",
@@ -2115,7 +2171,7 @@ import { existsSync as existsSync4 } from "fs";
2115
2171
  import { confirm as confirm5 } from "@inquirer/prompts";
2116
2172
  function createRemoveCommand(ctx) {
2117
2173
  const { config, log } = ctx;
2118
- return new Command3("remove").description("Remove a worktree").argument("<name>", "Worktree name").option("-f, --force", "Force removal even with uncommitted changes").option("-y, --yes", "Skip confirmation prompt").action(async (name, options) => {
2174
+ return new Command3("remove").description("Remove a worktree").argument("<name>", "Worktree name").option("-f, --force", "Force removal even with uncommitted changes").option("-y, --yes", "Skip confirmation prompt").option("--no-hook", "Skip running the pre-teardown hook").action(async (name, options) => {
2119
2175
  const projectCtx = await resolveProjectFromCwd(config, log);
2120
2176
  if (!projectCtx) {
2121
2177
  log.error("Not in a git repository. Run this command from within a git project.");
@@ -2188,6 +2244,21 @@ ${chalk3.bold("Worktree to remove:")}`);
2188
2244
  log.debug(`Killing tmux session: ${sessionName}`);
2189
2245
  await tmux.killSession(sessionName);
2190
2246
  }
2247
+ if (options.hook !== false && !pathMissing && manager.hasTeardownHook()) {
2248
+ const hookSpinner = ora2("Running pre-teardown hook...").start();
2249
+ try {
2250
+ const { stdout, stderr } = await manager.runPreTeardownHook(worktree.path);
2251
+ hookSpinner.succeed("Pre-teardown hook completed");
2252
+ if (stdout.trim()) {
2253
+ console.log(chalk3.gray(stdout.trim()));
2254
+ }
2255
+ if (stderr.trim()) {
2256
+ console.log(chalk3.yellow(stderr.trim()));
2257
+ }
2258
+ } catch (error) {
2259
+ hookSpinner.warn(`Pre-teardown hook failed: ${error.message}`);
2260
+ }
2261
+ }
2191
2262
  const spinner = ora2(`Removing worktree '${name}'...`).start();
2192
2263
  try {
2193
2264
  await manager.remove(name, options.force);
@@ -2216,7 +2287,7 @@ import path4 from "path";
2216
2287
  import { select as select3, confirm as confirm6 } from "@inquirer/prompts";
2217
2288
  function createMergeCommand(ctx) {
2218
2289
  const { config, log } = ctx;
2219
- return new Command4("merge").description("Merge a worktree branch and optionally remove the worktree").argument("<name>", "Worktree name").option("-i, --into <branch>", "Target branch to merge into").option("-s, --squash", "Use squash merge").option("-k, --keep", "Keep the worktree after merging").option("-y, --yes", "Skip confirmation prompts").action(async (name, options) => {
2290
+ return new Command4("merge").description("Merge a worktree branch and optionally remove the worktree").argument("<name>", "Worktree name").option("-i, --into <branch>", "Target branch to merge into").option("-s, --squash", "Use squash merge").option("-k, --keep", "Keep the worktree after merging").option("-y, --yes", "Skip confirmation prompts").option("--delete-branch", "Delete the merged branch after merge").action(async (name, options) => {
2220
2291
  const projectCtx = await resolveProjectFromCwd(config, log);
2221
2292
  if (!projectCtx) {
2222
2293
  log.error("Not in a git repository. Run this command from within a git project.");
@@ -2258,14 +2329,19 @@ function createMergeCommand(ctx) {
2258
2329
  }
2259
2330
  const commonTargets = ["main", "master", "develop", "dev"];
2260
2331
  const defaultTarget = commonTargets.find((t) => targetBranches.includes(t)) || targetBranches[0];
2261
- targetBranch = await select3({
2262
- message: `Merge '${worktree.branch}' into which branch?`,
2263
- choices: targetBranches.map((b) => ({
2264
- name: b,
2265
- value: b
2266
- })),
2267
- default: defaultTarget
2268
- });
2332
+ if (options.yes) {
2333
+ targetBranch = defaultTarget;
2334
+ log.info(`Auto-selected target branch: '${targetBranch}'`);
2335
+ } else {
2336
+ targetBranch = await select3({
2337
+ message: `Merge '${worktree.branch}' into which branch?`,
2338
+ choices: targetBranches.map((b) => ({
2339
+ name: b,
2340
+ value: b
2341
+ })),
2342
+ default: defaultTarget
2343
+ });
2344
+ }
2269
2345
  }
2270
2346
  if (!await manager.branchExists(targetBranch)) {
2271
2347
  log.error(`Target branch '${targetBranch}' does not exist.`);
@@ -2307,6 +2383,11 @@ ${chalk4.bold("Merge operation:")}`);
2307
2383
  log.info("You may need to resolve conflicts manually.");
2308
2384
  process.exit(1);
2309
2385
  }
2386
+ if (options.keep && options.deleteBranch) {
2387
+ log.warn(
2388
+ "--delete-branch is ignored when --keep is set (branch is needed by the worktree)."
2389
+ );
2390
+ }
2310
2391
  if (!options.keep) {
2311
2392
  const tmux = new TmuxManager();
2312
2393
  const sessionName = tmux.getWorktreeSessionName(displayName, name);
@@ -2322,21 +2403,22 @@ ${chalk4.bold("Merge operation:")}`);
2322
2403
  removeSpinner.warn(`Failed to remove worktree: ${error.message}`);
2323
2404
  log.info(`You can remove it manually with: workon worktrees remove ${name}`);
2324
2405
  }
2325
- if (!options.yes) {
2326
- const shouldDeleteBranch = await confirm6({
2406
+ let shouldDeleteBranch = options.deleteBranch || false;
2407
+ if (!shouldDeleteBranch && !options.yes) {
2408
+ shouldDeleteBranch = await confirm6({
2327
2409
  message: `Delete the merged branch '${worktree.branch}'?`,
2328
2410
  default: false
2329
2411
  });
2330
- if (shouldDeleteBranch) {
2331
- const deleteSpinner = ora3(`Deleting branch '${worktree.branch}'...`).start();
2332
- try {
2333
- const { simpleGit: simpleGit6 } = await import("simple-git");
2334
- const git = simpleGit6(projectPath);
2335
- await git.deleteLocalBranch(worktree.branch, true);
2336
- deleteSpinner.succeed(`Branch '${worktree.branch}' deleted`);
2337
- } catch (error) {
2338
- deleteSpinner.warn(`Failed to delete branch: ${error.message}`);
2339
- }
2412
+ }
2413
+ if (shouldDeleteBranch) {
2414
+ const deleteSpinner = ora3(`Deleting branch '${worktree.branch}'...`).start();
2415
+ try {
2416
+ const { simpleGit: simpleGit6 } = await import("simple-git");
2417
+ const git = simpleGit6(projectPath);
2418
+ await git.deleteLocalBranch(worktree.branch, true);
2419
+ deleteSpinner.succeed(`Branch '${worktree.branch}' deleted`);
2420
+ } catch (error) {
2421
+ deleteSpinner.warn(`Failed to delete branch: ${error.message}`);
2340
2422
  }
2341
2423
  }
2342
2424
  }
@@ -2362,7 +2444,7 @@ import { confirm as confirm7 } from "@inquirer/prompts";
2362
2444
  import { simpleGit as simpleGit4 } from "simple-git";
2363
2445
  function createBranchCommand(ctx) {
2364
2446
  const { config, log } = ctx;
2365
- return new Command5("branch").description("Create a branch from a worktree (useful for detached HEAD state)").argument("<worktree>", "Worktree name").argument("<branch>", "New branch name to create").option("-p, --push", "Push the branch to origin after creating").option("-f, --force", "Overwrite existing branch").action(async (worktreeName, branchName, options) => {
2447
+ return new Command5("branch").description("Create a branch from a worktree (useful for detached HEAD state)").argument("<worktree>", "Worktree name").argument("<branch>", "New branch name to create").option("-p, --push", "Push the branch to origin after creating").option("-f, --force", "Overwrite existing branch").option("-y, --yes", "Skip all confirmation prompts (non-interactive mode)").action(async (worktreeName, branchName, options) => {
2366
2448
  const projectCtx = await resolveProjectFromCwd(config, log);
2367
2449
  if (!projectCtx) {
2368
2450
  log.error("Not in a git repository. Run this command from within a git project.");
@@ -2425,6 +2507,8 @@ ${chalk5.bold("Action:")}`);
2425
2507
  pushSpinner.fail(`Failed to push: ${error.message}`);
2426
2508
  log.info(`You can push manually with: git push -u origin ${branchName}`);
2427
2509
  }
2510
+ } else if (options.yes) {
2511
+ log.info(`You can push manually with: git push -u origin ${branchName}`);
2428
2512
  } else {
2429
2513
  const shouldPush = await confirm7({
2430
2514
  message: "Push branch to origin for PR?",
@@ -2527,13 +2611,12 @@ __export(open_exports, {
2527
2611
  });
2528
2612
  import { Command as Command7 } from "commander";
2529
2613
  import chalk6 from "chalk";
2530
- import File4 from "phylo";
2531
2614
  import path6 from "path";
2532
2615
  import { exec as execCallback3 } from "child_process";
2533
2616
  import { promisify as promisify3 } from "util";
2534
2617
  function createOpenCommand(ctx) {
2535
2618
  const { config, log } = ctx;
2536
- return new Command7("open").description("Open a workon session in a worktree").argument("<name>", "Worktree name").option("-d, --debug", "Enable debug logging").option("--shell", "Output shell commands instead of spawning processes").action(async (name, options) => {
2619
+ return new Command7("open").description("Open a workon session in a worktree").argument("<name>", "Worktree name").option("-d, --debug", "Enable debug logging").option("--shell", "Output shell commands instead of spawning processes").option("-y, --yes", "Skip all confirmation prompts (non-interactive mode)").action(async (name, options) => {
2537
2620
  if (options.debug) {
2538
2621
  log.setLogLevel("debug");
2539
2622
  }
@@ -2546,12 +2629,16 @@ function createOpenCommand(ctx) {
2546
2629
  process.exit(1);
2547
2630
  }
2548
2631
  if (!projectCtx.isRegistered) {
2549
- log.warn("Project is not registered. Opening with basic shell layout.");
2550
- const shouldRegister = await promptToRegisterProject(projectCtx.projectPath, config, log);
2551
- if (shouldRegister) {
2552
- projectCtx.projectName = shouldRegister.projectName;
2553
- projectCtx.projectConfig = shouldRegister.projectConfig;
2554
- projectCtx.isRegistered = true;
2632
+ if (options.yes) {
2633
+ log.info("Project is not registered. Opening with basic shell layout.");
2634
+ } else {
2635
+ log.warn("Project is not registered. Opening with basic shell layout.");
2636
+ const shouldRegister = await promptToRegisterProject(projectCtx.projectPath, config, log);
2637
+ if (shouldRegister) {
2638
+ projectCtx.projectName = shouldRegister.projectName;
2639
+ projectCtx.projectConfig = shouldRegister.projectConfig;
2640
+ projectCtx.isRegistered = true;
2641
+ }
2555
2642
  }
2556
2643
  }
2557
2644
  await runWorktreeOpen(projectCtx, name, options, { config, log });
@@ -2584,7 +2671,7 @@ async function runWorktreeOpen(projectCtx, worktreeName, options, ctx) {
2584
2671
  let hasNpmEvent = false;
2585
2672
  if (isRegistered && projectName && projectConfig) {
2586
2673
  project = new Project(projectName, projectConfig, defaults);
2587
- project._path = File4.from(worktree.path).absolutify();
2674
+ project.overridePath(worktree.path);
2588
2675
  const events = project.events || {};
2589
2676
  hasClaudeEvent = !!events.claude;
2590
2677
  hasNpmEvent = !!events.npm;
@@ -2802,7 +2889,8 @@ __export(interactive_exports, {
2802
2889
  runInteractive: () => runInteractive
2803
2890
  });
2804
2891
  import { select as select4, input as input5, checkbox as checkbox2, confirm as confirm8 } from "@inquirer/prompts";
2805
- import File5 from "phylo";
2892
+ import { existsSync as existsSync5 } from "fs";
2893
+ import File4 from "phylo";
2806
2894
  import path7 from "path";
2807
2895
  import deepAssign2 from "deep-assign";
2808
2896
  import chalk7 from "chalk";
@@ -2810,7 +2898,7 @@ async function runInteractive(ctx) {
2810
2898
  const { config, log, environment, suggestedName } = ctx;
2811
2899
  showLogo(config);
2812
2900
  log.log("");
2813
- const defaultName = suggestedName ?? (environment.$isProjectEnvironment ? environment.project.name : File5.cwd().name);
2901
+ const defaultName = suggestedName ?? (environment.$isProjectEnvironment ? environment.project.name : File4.cwd().name);
2814
2902
  const fromUser = !!suggestedName;
2815
2903
  await startInteractive(defaultName, fromUser, ctx);
2816
2904
  }
@@ -2911,15 +2999,15 @@ async function initProject(defaultName, fromUser, ctx) {
2911
2999
  let basePath;
2912
3000
  if (isBranch) {
2913
3001
  const projectName = name.substring(0, name.indexOf("#"));
2914
- basePath = defaults?.base ? File5.from(defaults.base).join(projects[projectName].path).absolutePath() : projects[projectName].path;
3002
+ basePath = defaults?.base ? File4.from(defaults.base).join(projects[projectName].path).absolutePath() : projects[projectName].path;
2915
3003
  log.log(`Project path: ${basePath}`);
2916
3004
  } else {
2917
3005
  const pathAnswer = await input5({
2918
3006
  message: "What is the path to the project?",
2919
- default: defaults?.base ? File5.from(defaults.base).join(name).path : name
3007
+ default: defaults?.base ? File4.from(defaults.base).join(name).path : name
2920
3008
  });
2921
- let answerFile = File5.from(pathAnswer);
2922
- const defaultBase = defaults?.base ? File5.from(defaults.base).absolutify() : File5.cwd();
3009
+ let answerFile = File4.from(pathAnswer);
3010
+ const defaultBase = defaults?.base ? File4.from(defaults.base).absolutify() : File4.cwd();
2923
3011
  if (!answerFile.isAbsolute()) {
2924
3012
  answerFile = defaultBase.join(answerFile.path);
2925
3013
  }
@@ -3127,15 +3215,15 @@ async function createProjectManage(ctx) {
3127
3215
  return true;
3128
3216
  }
3129
3217
  });
3130
- const defaultPath = defaults?.base ? File5.from(defaults.base).absolutify().join(name).path : name;
3218
+ const defaultPath = defaults?.base ? File4.from(defaults.base).absolutify().join(name).path : name;
3131
3219
  const pathInput = await input5({
3132
3220
  message: "Project path:",
3133
3221
  default: defaultPath
3134
3222
  });
3135
3223
  let relativePath = pathInput;
3136
3224
  if (defaults?.base) {
3137
- const baseDir = File5.from(defaults.base).absolutify();
3138
- const pathFile = File5.from(pathInput);
3225
+ const baseDir = File4.from(defaults.base).absolutify();
3226
+ const pathFile = File4.from(pathInput);
3139
3227
  try {
3140
3228
  if (pathFile.isAbsolute()) {
3141
3229
  const relPath = pathFile.relativize(baseDir.path);
@@ -3202,8 +3290,8 @@ async function editProjectManage(ctx) {
3202
3290
  });
3203
3291
  let relativePath = pathInput;
3204
3292
  if (defaults?.base) {
3205
- const baseDir = File5.from(defaults.base).absolutify();
3206
- const pathFile = File5.from(pathInput);
3293
+ const baseDir = File4.from(defaults.base).absolutify();
3294
+ const pathFile = File4.from(pathInput);
3207
3295
  try {
3208
3296
  if (pathFile.isAbsolute()) {
3209
3297
  const relPath = pathFile.relativize(baseDir.path);
@@ -3306,7 +3394,7 @@ function listProjectsManage(ctx) {
3306
3394
  const baseProjects = Object.keys(projects).filter((name) => !name.includes("#"));
3307
3395
  for (const name of baseProjects) {
3308
3396
  const project = projects[name];
3309
- const fullPath = defaults?.base ? File5.from(defaults.base).join(project.path).path : project.path;
3397
+ const fullPath = defaults?.base ? File4.from(defaults.base).join(project.path).path : project.path;
3310
3398
  console.log(` ${name}`);
3311
3399
  console.log(` Path: ${fullPath}`);
3312
3400
  console.log(` IDE: ${project.ide || "not set"}`);
@@ -3430,11 +3518,11 @@ async function manageWorktrees(projectName, ctx) {
3430
3518
  const projectConfig = projects[projectName];
3431
3519
  const basePath = defaults?.base || "";
3432
3520
  let projectPath;
3433
- const configPath = File5.from(projectConfig.path);
3521
+ const configPath = File4.from(projectConfig.path);
3434
3522
  if (configPath.path.startsWith("/") || configPath.path.startsWith("~")) {
3435
3523
  projectPath = configPath.absolutify().path;
3436
3524
  } else if (basePath) {
3437
- projectPath = File5.from(basePath).absolutify().join(projectConfig.path).path;
3525
+ projectPath = File4.from(basePath).absolutify().join(projectConfig.path).path;
3438
3526
  } else {
3439
3527
  projectPath = configPath.absolutify().path;
3440
3528
  }
@@ -3565,11 +3653,11 @@ async function openWorktreeManage(projectName, manager, config, log) {
3565
3653
  const projectConfig = projects[projectName];
3566
3654
  const basePath = defaults?.base || "";
3567
3655
  let projectPath;
3568
- const configPath = File5.from(projectConfig.path);
3656
+ const configPath = File4.from(projectConfig.path);
3569
3657
  if (configPath.path.startsWith("/") || configPath.path.startsWith("~")) {
3570
3658
  projectPath = configPath.absolutify().path;
3571
3659
  } else if (basePath) {
3572
- projectPath = File5.from(basePath).absolutify().join(projectConfig.path).path;
3660
+ projectPath = File4.from(basePath).absolutify().join(projectConfig.path).path;
3573
3661
  } else {
3574
3662
  projectPath = configPath.absolutify().path;
3575
3663
  }
@@ -3621,6 +3709,18 @@ async function removeWorktreeManage(projectName, manager, log) {
3621
3709
  });
3622
3710
  if (confirmed) {
3623
3711
  try {
3712
+ if (manager.hasTeardownHook()) {
3713
+ const worktree = await manager.get(worktreeName);
3714
+ if (worktree && existsSync5(worktree.path)) {
3715
+ log.info("Running pre-teardown hook...");
3716
+ try {
3717
+ await manager.runPreTeardownHook(worktree.path);
3718
+ log.info("Pre-teardown hook completed.");
3719
+ } catch (error) {
3720
+ log.warn(`Pre-teardown hook failed: ${error.message}`);
3721
+ }
3722
+ }
3723
+ }
3624
3724
  await manager.remove(worktreeName, true);
3625
3725
  log.info(`Worktree '${worktreeName}' removed.`);
3626
3726
  } catch (error) {
@@ -3670,6 +3770,15 @@ async function mergeWorktreeManage(projectName, manager, log) {
3670
3770
  await manager.merge(worktreeName, { targetBranch, squash });
3671
3771
  log.info(`Merged '${worktree.branch}' into '${targetBranch}'`);
3672
3772
  if (removeAfter) {
3773
+ if (manager.hasTeardownHook() && existsSync5(worktree.path)) {
3774
+ log.info("Running pre-teardown hook...");
3775
+ try {
3776
+ await manager.runPreTeardownHook(worktree.path);
3777
+ log.info("Pre-teardown hook completed.");
3778
+ } catch (error) {
3779
+ log.warn(`Pre-teardown hook failed: ${error.message}`);
3780
+ }
3781
+ }
3673
3782
  await manager.remove(worktreeName, true);
3674
3783
  log.info(`Worktree '${worktreeName}' removed.`);
3675
3784
  }
@@ -3791,7 +3900,7 @@ __export(open_exports2, {
3791
3900
  runOpen: () => runOpen
3792
3901
  });
3793
3902
  import { Command as Command8 } from "commander";
3794
- import File6 from "phylo";
3903
+ import File5 from "phylo";
3795
3904
  async function runOpen(projectArg, options, ctx) {
3796
3905
  const { log } = ctx;
3797
3906
  if (options.debug) {
@@ -3810,7 +3919,7 @@ function createOpenCommand2(ctx) {
3810
3919
  } else {
3811
3920
  log.debug("No project name provided, starting interactive mode");
3812
3921
  const { runInteractive: runInteractive2 } = await Promise.resolve().then(() => (init_interactive(), interactive_exports));
3813
- const environment = await EnvironmentRecognizer.recognize(File6.cwd());
3922
+ const environment = await EnvironmentRecognizer.recognize(File5.cwd());
3814
3923
  await runInteractive2({ config, log, environment });
3815
3924
  }
3816
3925
  });
@@ -3818,17 +3927,20 @@ function createOpenCommand2(ctx) {
3818
3927
  }
3819
3928
  async function processProject(projectParam, options, ctx) {
3820
3929
  const { config, log } = ctx;
3821
- const [projectName, commandsString] = projectParam.split(":");
3822
- const requestedCommands = commandsString ? commandsString.split(",").map((cmd) => cmd.trim()) : null;
3930
+ const parts = projectParam.split(":");
3931
+ const projectName = parts[0];
3932
+ const commandsString = parts[1] || null;
3933
+ const worktreeName = parts[2] || null;
3934
+ const requestedCommands = commandsString && commandsString !== "help" ? commandsString.split(",").map((cmd) => cmd.trim()) : null;
3823
3935
  if (commandsString === "help") {
3824
3936
  await showProjectHelp(projectName, ctx);
3825
3937
  return;
3826
3938
  }
3827
3939
  log.debug(
3828
- `Project: ${projectName}, Commands: ${requestedCommands ? requestedCommands.join(", ") : "all"}`
3940
+ `Project: ${projectName}, Commands: ${requestedCommands ? requestedCommands.join(", ") : "all"}` + (worktreeName ? `, Worktree: ${worktreeName}` : "")
3829
3941
  );
3830
3942
  const projects = config.getProjects();
3831
- const environment = await EnvironmentRecognizer.recognize(File6.cwd());
3943
+ const environment = await EnvironmentRecognizer.recognize(File5.cwd());
3832
3944
  if (environment.$isProjectEnvironment && (projectName === "this" || projectName === ".")) {
3833
3945
  log.info(`Opening current project: ${environment.project.name}`);
3834
3946
  await switchTo(environment, requestedCommands, options, ctx);
@@ -3841,6 +3953,22 @@ async function processProject(projectParam, options, ctx) {
3841
3953
  validateRequestedCommands(requestedCommands, projectCfg, projectName);
3842
3954
  }
3843
3955
  const projectEnv = ProjectEnvironment.load(projectCfg, config.getDefaults());
3956
+ if (worktreeName) {
3957
+ const projectPath = projectEnv.project.path.path;
3958
+ const manager = new WorktreeManager(projectPath, projectName);
3959
+ const worktree = await manager.get(worktreeName);
3960
+ if (!worktree) {
3961
+ log.error(`Worktree '${worktreeName}' not found for project '${projectName}'.`);
3962
+ const worktrees = await manager.listManagedWorktrees();
3963
+ if (worktrees.length > 0) {
3964
+ log.info("Available worktrees:");
3965
+ worktrees.forEach((wt) => log.info(` - ${wt.name}`));
3966
+ }
3967
+ process.exit(1);
3968
+ }
3969
+ log.debug(`Using worktree path: ${worktree.path}`);
3970
+ projectEnv.project.overridePath(worktree.path);
3971
+ }
3844
3972
  await switchTo(projectEnv, requestedCommands, options, ctx);
3845
3973
  } else {
3846
3974
  log.error(`Project '${projectName}' not found.`);
@@ -4101,7 +4229,9 @@ Available commands for '${projectName}':`);
4101
4229
  const twoCommands = configuredEvents.slice(0, 2).join(",");
4102
4230
  console.log(` workon ${projectName}:${twoCommands.padEnd(12)} # Multiple commands`);
4103
4231
  }
4104
- console.log(` workon ${projectName}:cwd --shell # Output shell commands
4232
+ console.log(` workon ${projectName}:cwd --shell # Output shell commands`);
4233
+ console.log(` workon ${projectName}:cwd:my-worktree # Run in a worktree`);
4234
+ console.log(` workon ${projectName}::my-worktree # All commands in a worktree
4105
4235
  `);
4106
4236
  }
4107
4237
  var init_open2 = __esm({
@@ -4110,6 +4240,7 @@ var init_open2 = __esm({
4110
4240
  init_environment();
4111
4241
  init_tmux();
4112
4242
  init_registry();
4243
+ init_worktree();
4113
4244
  }
4114
4245
  });
4115
4246
 
@@ -4119,12 +4250,12 @@ init_environment();
4119
4250
  init_registry();
4120
4251
  init_open2();
4121
4252
  import { Command as Command16 } from "commander";
4122
- import { readFileSync as readFileSync2, existsSync as existsSync6 } from "fs";
4253
+ import { readFileSync as readFileSync2, existsSync as existsSync7 } from "fs";
4123
4254
  import { join as join2, dirname as dirname2 } from "path";
4124
4255
  import { fileURLToPath } from "url";
4125
4256
  import loog from "loog";
4126
4257
  import omelette from "omelette";
4127
- import File9 from "phylo";
4258
+ import File8 from "phylo";
4128
4259
 
4129
4260
  // src/commands/config/index.ts
4130
4261
  import { Command as Command12 } from "commander";
@@ -4221,7 +4352,7 @@ init_registry();
4221
4352
  init_constants();
4222
4353
  import { Command as Command13 } from "commander";
4223
4354
  import { select as select5, input as input6, confirm as confirm9, checkbox as checkbox3 } from "@inquirer/prompts";
4224
- import File7 from "phylo";
4355
+ import File6 from "phylo";
4225
4356
  function createManageCommand(ctx) {
4226
4357
  const { log } = ctx;
4227
4358
  return new Command13("manage").description("Interactive project management").option("-d, --debug", "Enable debug logging").action(async (options) => {
@@ -4280,12 +4411,12 @@ async function createProject(ctx) {
4280
4411
  return true;
4281
4412
  }
4282
4413
  });
4283
- const defaultPath = defaults?.base ? File7.from(defaults.base).join(name).path : name;
4414
+ const defaultPath = defaults?.base ? File6.from(defaults.base).join(name).path : name;
4284
4415
  const pathInput = await input6({
4285
4416
  message: "Project path:",
4286
4417
  default: defaultPath,
4287
4418
  validate: (value) => {
4288
- const path8 = File7.from(value);
4419
+ const path8 = File6.from(value);
4289
4420
  try {
4290
4421
  const exists = path8.exists();
4291
4422
  if (!exists) return `Path does not exist: ${value}`;
@@ -4299,8 +4430,8 @@ async function createProject(ctx) {
4299
4430
  });
4300
4431
  let relativePath = pathInput;
4301
4432
  if (defaults?.base) {
4302
- const baseDir = File7.from(defaults.base).absolutify();
4303
- const pathFile = File7.from(pathInput);
4433
+ const baseDir = File6.from(defaults.base).absolutify();
4434
+ const pathFile = File6.from(pathInput);
4304
4435
  try {
4305
4436
  const relPath = pathFile.relativize(baseDir.path);
4306
4437
  if (relPath && !relPath.path.startsWith("..")) {
@@ -4377,8 +4508,8 @@ async function editProject(ctx) {
4377
4508
  });
4378
4509
  let relativePath = pathInput;
4379
4510
  if (defaults?.base) {
4380
- const baseDir = File7.from(defaults.base).absolutify();
4381
- const pathFile = File7.from(pathInput);
4511
+ const baseDir = File6.from(defaults.base).absolutify();
4512
+ const pathFile = File6.from(pathInput);
4382
4513
  try {
4383
4514
  if (pathFile.isAbsolute()) {
4384
4515
  const relPath = pathFile.relativize(baseDir.path);
@@ -4478,7 +4609,7 @@ async function listProjects(ctx) {
4478
4609
  const defaults = config.getDefaults();
4479
4610
  console.log("\nConfigured projects:\n");
4480
4611
  for (const [name, project] of Object.entries(projects)) {
4481
- const fullPath = defaults?.base ? File7.from(defaults.base).join(project.path).path : project.path;
4612
+ const fullPath = defaults?.base ? File6.from(defaults.base).join(project.path).path : project.path;
4482
4613
  console.log(` ${name}`);
4483
4614
  console.log(` Path: ${fullPath}`);
4484
4615
  console.log(` IDE: ${project.ide || "not set"}`);
@@ -4492,9 +4623,9 @@ async function listProjects(ctx) {
4492
4623
 
4493
4624
  // src/commands/add.ts
4494
4625
  import { Command as Command14 } from "commander";
4495
- import { existsSync as existsSync5, readFileSync } from "fs";
4626
+ import { existsSync as existsSync6, readFileSync } from "fs";
4496
4627
  import { basename as basename2, resolve } from "path";
4497
- import File8 from "phylo";
4628
+ import File7 from "phylo";
4498
4629
  import { confirm as confirm10 } from "@inquirer/prompts";
4499
4630
  function createAddCommand2(ctx) {
4500
4631
  const { log } = ctx;
@@ -4514,11 +4645,11 @@ async function addProject(pathArg, options, ctx) {
4514
4645
  const projects = config.getProjects();
4515
4646
  const targetPath = resolve(pathArg);
4516
4647
  log.debug(`Resolved path: ${targetPath}`);
4517
- if (!existsSync5(targetPath)) {
4648
+ if (!existsSync6(targetPath)) {
4518
4649
  log.error(`Path does not exist: ${targetPath}`);
4519
4650
  process.exit(1);
4520
4651
  }
4521
- const pathFile = File8.from(targetPath);
4652
+ const pathFile = File7.from(targetPath);
4522
4653
  try {
4523
4654
  const stat = pathFile.stat();
4524
4655
  if (!stat.isDirectory()) {
@@ -4552,7 +4683,7 @@ async function addProject(pathArg, options, ctx) {
4552
4683
  log.debug(`IDE: ${ide}`);
4553
4684
  let relativePath = targetPath;
4554
4685
  if (defaults?.base) {
4555
- const baseDir = File8.from(defaults.base).absolutify();
4686
+ const baseDir = File7.from(defaults.base).absolutify();
4556
4687
  try {
4557
4688
  const relPath = pathFile.relativize(baseDir.path);
4558
4689
  if (relPath && !relPath.path.startsWith("..")) {
@@ -4598,7 +4729,7 @@ function discoverProject(targetPath, log) {
4598
4729
  packageJson: null
4599
4730
  };
4600
4731
  const packageJsonPath = resolve(targetPath, "package.json");
4601
- if (existsSync5(packageJsonPath)) {
4732
+ if (existsSync6(packageJsonPath)) {
4602
4733
  discovery.isNode = true;
4603
4734
  log.debug("Detected Node project (package.json found)");
4604
4735
  try {
@@ -4614,25 +4745,25 @@ function discoverProject(targetPath, log) {
4614
4745
  }
4615
4746
  }
4616
4747
  const bunLockPath = resolve(targetPath, "bun.lockb");
4617
- if (existsSync5(bunLockPath)) {
4748
+ if (existsSync6(bunLockPath)) {
4618
4749
  discovery.isBun = true;
4619
4750
  log.debug("Detected Bun project (bun.lockb found)");
4620
4751
  }
4621
4752
  const vscodeDir = resolve(targetPath, ".vscode");
4622
4753
  const cursorDir = resolve(targetPath, ".cursor");
4623
4754
  const ideaDir = resolve(targetPath, ".idea");
4624
- if (existsSync5(cursorDir)) {
4755
+ if (existsSync6(cursorDir)) {
4625
4756
  discovery.detectedIde = "cursor";
4626
4757
  log.debug("Detected Cursor (.cursor directory found)");
4627
- } else if (existsSync5(vscodeDir)) {
4758
+ } else if (existsSync6(vscodeDir)) {
4628
4759
  discovery.detectedIde = "code";
4629
4760
  log.debug("Detected VS Code (.vscode directory found)");
4630
- } else if (existsSync5(ideaDir)) {
4761
+ } else if (existsSync6(ideaDir)) {
4631
4762
  discovery.detectedIde = "idea";
4632
4763
  log.debug("Detected IntelliJ IDEA (.idea directory found)");
4633
4764
  }
4634
4765
  const claudeMdPath = resolve(targetPath, "CLAUDE.md");
4635
- if (existsSync5(claudeMdPath)) {
4766
+ if (existsSync6(claudeMdPath)) {
4636
4767
  discovery.hasClaude = true;
4637
4768
  log.debug("Detected Claude Code project (CLAUDE.md found)");
4638
4769
  }
@@ -4681,19 +4812,21 @@ function createWorktreeCommand(ctx) {
4681
4812
  }
4682
4813
  await showWorktreeStatus(worktreeInfo, log);
4683
4814
  });
4684
- command.command("merge").description("Merge this worktree branch into a target branch").option("-i, --into <branch>", "Target branch to merge into").option("-s, --squash", "Use squash merge").option("-k, --keep", "Keep the worktree after merging").option("-y, --yes", "Skip confirmation prompts").action(async (options) => {
4685
- const worktreeInfo = await detectWorktreeContext();
4686
- if (!worktreeInfo) {
4687
- log.error("Not in a git repository.");
4688
- process.exit(1);
4689
- }
4690
- if (!worktreeInfo.isWorktree) {
4691
- log.error("You're in the main repository, not a worktree.");
4692
- log.info(`Use 'workon worktrees merge <name>' from the main repository.`);
4693
- process.exit(1);
4815
+ command.command("merge").description("Merge this worktree branch into a target branch").option("-i, --into <branch>", "Target branch to merge into").option("-s, --squash", "Use squash merge").option("-k, --keep", "Keep the worktree after merging").option("-y, --yes", "Skip confirmation prompts").option("--delete-branch", "Delete the merged branch after merge").action(
4816
+ async (options) => {
4817
+ const worktreeInfo = await detectWorktreeContext();
4818
+ if (!worktreeInfo) {
4819
+ log.error("Not in a git repository.");
4820
+ process.exit(1);
4821
+ }
4822
+ if (!worktreeInfo.isWorktree) {
4823
+ log.error("You're in the main repository, not a worktree.");
4824
+ log.info(`Use 'workon worktrees merge <name>' from the main repository.`);
4825
+ process.exit(1);
4826
+ }
4827
+ await mergeCurrentWorktree(worktreeInfo, options, ctx);
4694
4828
  }
4695
- await mergeCurrentWorktree(worktreeInfo, options, ctx);
4696
- });
4829
+ );
4697
4830
  command.command("remove").description("Remove the current worktree").option("-f, --force", "Force removal even with uncommitted changes").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
4698
4831
  const worktreeInfo = await detectWorktreeContext();
4699
4832
  if (!worktreeInfo) {
@@ -4778,11 +4911,16 @@ async function mergeCurrentWorktree(worktreeInfo, options, ctx) {
4778
4911
  }
4779
4912
  const commonTargets = ["main", "master", "develop", "dev"];
4780
4913
  const defaultTarget = commonTargets.find((t) => targetBranches.includes(t)) || targetBranches[0];
4781
- targetBranch = await select6({
4782
- message: `Merge '${worktreeInfo.branch}' into which branch?`,
4783
- choices: targetBranches.map((b) => ({ name: b, value: b })),
4784
- default: defaultTarget
4785
- });
4914
+ if (options.yes) {
4915
+ targetBranch = defaultTarget;
4916
+ log.info(`Auto-selected target branch: '${targetBranch}'`);
4917
+ } else {
4918
+ targetBranch = await select6({
4919
+ message: `Merge '${worktreeInfo.branch}' into which branch?`,
4920
+ choices: targetBranches.map((b) => ({ name: b, value: b })),
4921
+ default: defaultTarget
4922
+ });
4923
+ }
4786
4924
  }
4787
4925
  if (!await manager.branchExists(targetBranch)) {
4788
4926
  log.error(`Target branch '${targetBranch}' does not exist.`);
@@ -4824,12 +4962,18 @@ ${chalk8.bold("Merge operation:")}`);
4824
4962
  log.info("You may need to resolve conflicts manually.");
4825
4963
  process.exit(1);
4826
4964
  }
4965
+ if (options.keep && options.deleteBranch) {
4966
+ log.warn("--delete-branch is ignored when --keep is set (branch is needed by the worktree).");
4967
+ }
4827
4968
  if (!options.keep) {
4828
- log.warn("You need to exit this worktree directory before it can be removed.");
4829
- const shouldContinue = await confirm11({
4830
- message: `Remove worktree '${worktreeInfo.worktreeName}'? (You'll need to cd out first)`,
4831
- default: true
4832
- });
4969
+ let shouldContinue = true;
4970
+ if (!options.yes) {
4971
+ log.warn("You need to exit this worktree directory before it can be removed.");
4972
+ shouldContinue = await confirm11({
4973
+ message: `Remove worktree '${worktreeInfo.worktreeName}'? (You'll need to cd out first)`,
4974
+ default: true
4975
+ });
4976
+ }
4833
4977
  if (shouldContinue) {
4834
4978
  const tmux = new TmuxManager();
4835
4979
  const sessionName = tmux.getWorktreeSessionName(
@@ -4845,20 +4989,21 @@ To complete removal, run from the main project directory:`);
4845
4989
  console.log(chalk8.cyan(` cd ${worktreeInfo.mainRepoPath}`));
4846
4990
  console.log(chalk8.cyan(` workon worktrees remove ${worktreeInfo.worktreeName}`));
4847
4991
  }
4848
- if (!options.yes) {
4849
- const shouldDeleteBranch = await confirm11({
4992
+ let shouldDeleteBranch = options.deleteBranch || false;
4993
+ if (!shouldDeleteBranch && !options.yes) {
4994
+ shouldDeleteBranch = await confirm11({
4850
4995
  message: `Delete the merged branch '${worktreeInfo.branch}'?`,
4851
4996
  default: false
4852
4997
  });
4853
- if (shouldDeleteBranch) {
4854
- const deleteSpinner = ora5(`Deleting branch '${worktreeInfo.branch}'...`).start();
4855
- try {
4856
- const git = simpleGit5(worktreeInfo.mainRepoPath);
4857
- await git.deleteLocalBranch(worktreeInfo.branch, true);
4858
- deleteSpinner.succeed(`Branch '${worktreeInfo.branch}' deleted`);
4859
- } catch (error) {
4860
- deleteSpinner.warn(`Failed to delete branch: ${error.message}`);
4861
- }
4998
+ }
4999
+ if (shouldDeleteBranch) {
5000
+ const deleteSpinner = ora5(`Deleting branch '${worktreeInfo.branch}'...`).start();
5001
+ try {
5002
+ const git = simpleGit5(worktreeInfo.mainRepoPath);
5003
+ await git.deleteLocalBranch(worktreeInfo.branch, true);
5004
+ deleteSpinner.succeed(`Branch '${worktreeInfo.branch}' deleted`);
5005
+ } catch (error) {
5006
+ deleteSpinner.warn(`Failed to delete branch: ${error.message}`);
4862
5007
  }
4863
5008
  }
4864
5009
  }
@@ -4928,7 +5073,7 @@ function findPackageJson() {
4928
5073
  join2(process.cwd(), "package.json")
4929
5074
  ];
4930
5075
  for (const p of paths) {
4931
- if (existsSync6(p)) {
5076
+ if (existsSync7(p)) {
4932
5077
  return p;
4933
5078
  }
4934
5079
  }
@@ -4972,7 +5117,7 @@ function createCli() {
4972
5117
  await runOpen2(project, { debug: options.debug, shell: options.shell }, { config, log });
4973
5118
  return;
4974
5119
  }
4975
- const environment = await EnvironmentRecognizer.recognize(File9.cwd());
5120
+ const environment = await EnvironmentRecognizer.recognize(File8.cwd());
4976
5121
  program2.setOptionValue("_environment", environment);
4977
5122
  program2.setOptionValue("_config", config);
4978
5123
  program2.setOptionValue("_log", log);