@aku11i/phantom 1.2.0 → 1.3.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/phantom.js +499 -293
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aku11i/phantom",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "A powerful CLI tool for managing Git worktrees for parallel development",
5
5
  "keywords": [
6
6
  "git",
package/phantom.js CHANGED
@@ -131,19 +131,6 @@ import { argv, exit as exit2 } from "node:process";
131
131
  // src/handlers/attach.ts
132
132
  import { parseArgs } from "node:util";
133
133
 
134
- // ../core/src/paths.ts
135
- import { join } from "node:path";
136
- function getPhantomDirectory(gitRoot) {
137
- return join(gitRoot, ".git", "phantom", "worktrees");
138
- }
139
- function getWorktreePath(gitRoot, name) {
140
- return join(getPhantomDirectory(gitRoot), name);
141
- }
142
-
143
- // ../core/src/config/loader.ts
144
- import fs from "node:fs/promises";
145
- import path from "node:path";
146
-
147
134
  // ../shared/src/types/result.ts
148
135
  var ok = (value) => ({
149
136
  ok: true,
@@ -164,6 +151,10 @@ var exitCodes = {
164
151
  validationError: 3
165
152
  };
166
153
 
154
+ // ../core/src/config/loader.ts
155
+ import fs from "node:fs/promises";
156
+ import path from "node:path";
157
+
167
158
  // ../../node_modules/.pnpm/zod@3.25.64/node_modules/zod/dist/esm/v3/external.js
168
159
  var external_exports = {};
169
160
  __export(external_exports, {
@@ -4211,7 +4202,8 @@ var phantomConfigSchema = external_exports.object({
4211
4202
  postCreate: external_exports.object({
4212
4203
  copyFiles: external_exports.array(external_exports.string()).optional(),
4213
4204
  commands: external_exports.array(external_exports.string()).optional()
4214
- }).passthrough().optional()
4205
+ }).passthrough().optional(),
4206
+ worktreesDirectory: external_exports.string().optional()
4215
4207
  }).passthrough();
4216
4208
  function validateConfig(config) {
4217
4209
  const result = phantomConfigSchema.safeParse(config);
@@ -4265,6 +4257,30 @@ async function loadConfig(gitRoot) {
4265
4257
  }
4266
4258
  }
4267
4259
 
4260
+ // ../core/src/paths.ts
4261
+ import { isAbsolute, join } from "node:path";
4262
+ function getWorktreesDirectory(gitRoot, worktreesDirectory) {
4263
+ if (worktreesDirectory) {
4264
+ return isAbsolute(worktreesDirectory) ? worktreesDirectory : join(gitRoot, worktreesDirectory);
4265
+ }
4266
+ return join(gitRoot, ".git", "phantom", "worktrees");
4267
+ }
4268
+ function getWorktreePathFromDirectory(worktreeDirectory, name) {
4269
+ return join(worktreeDirectory, name);
4270
+ }
4271
+
4272
+ // ../core/src/context.ts
4273
+ async function createContext(gitRoot) {
4274
+ const configResult = await loadConfig(gitRoot);
4275
+ const config = isOk(configResult) ? configResult.value : null;
4276
+ const worktreesDirectory = config?.worktreesDirectory;
4277
+ return {
4278
+ gitRoot,
4279
+ worktreesDirectory: getWorktreesDirectory(gitRoot, worktreesDirectory),
4280
+ config
4281
+ };
4282
+ }
4283
+
4268
4284
  // ../core/src/worktree/errors.ts
4269
4285
  var WorktreeError = class extends Error {
4270
4286
  constructor(message) {
@@ -4517,10 +4533,170 @@ async function copyFiles(sourceDir, targetDir, files) {
4517
4533
  return ok({ copiedFiles, skippedFiles });
4518
4534
  }
4519
4535
 
4536
+ // ../process/src/errors.ts
4537
+ var ProcessError = class extends Error {
4538
+ exitCode;
4539
+ constructor(message, exitCode) {
4540
+ super(message);
4541
+ this.name = this.constructor.name;
4542
+ this.exitCode = exitCode;
4543
+ }
4544
+ };
4545
+ var ProcessExecutionError = class extends ProcessError {
4546
+ constructor(command2, exitCode) {
4547
+ super(`Command '${command2}' failed with exit code ${exitCode}`, exitCode);
4548
+ this.name = "ProcessExecutionError";
4549
+ }
4550
+ };
4551
+ var ProcessSignalError = class extends ProcessError {
4552
+ constructor(signal) {
4553
+ const exitCode = 128 + (signal === "SIGTERM" ? 15 : 1);
4554
+ super(`Command terminated by signal: ${signal}`, exitCode);
4555
+ this.name = "ProcessSignalError";
4556
+ }
4557
+ };
4558
+ var ProcessSpawnError = class extends ProcessError {
4559
+ constructor(command2, details) {
4560
+ super(`Error executing command '${command2}': ${details}`);
4561
+ this.name = "ProcessSpawnError";
4562
+ }
4563
+ };
4564
+
4565
+ // ../process/src/spawn.ts
4566
+ import {
4567
+ spawn as nodeSpawn
4568
+ } from "node:child_process";
4569
+ async function spawnProcess(config) {
4570
+ return new Promise((resolve2) => {
4571
+ const { command: command2, args: args2 = [], options = {} } = config;
4572
+ const childProcess = nodeSpawn(command2, args2, {
4573
+ stdio: "inherit",
4574
+ ...options
4575
+ });
4576
+ childProcess.on("error", (error) => {
4577
+ resolve2(err(new ProcessSpawnError(command2, error.message)));
4578
+ });
4579
+ childProcess.on("exit", (code, signal) => {
4580
+ if (signal) {
4581
+ resolve2(err(new ProcessSignalError(signal)));
4582
+ } else {
4583
+ const exitCode = code ?? 0;
4584
+ if (exitCode === 0) {
4585
+ resolve2(ok({ exitCode }));
4586
+ } else {
4587
+ resolve2(err(new ProcessExecutionError(command2, exitCode)));
4588
+ }
4589
+ }
4590
+ });
4591
+ });
4592
+ }
4593
+
4594
+ // ../process/src/tmux.ts
4595
+ async function isInsideTmux() {
4596
+ return process.env.TMUX !== void 0;
4597
+ }
4598
+ async function executeTmuxCommand(options) {
4599
+ const { direction, command: command2, args: args2, cwd, env, windowName } = options;
4600
+ const tmuxArgs = [];
4601
+ switch (direction) {
4602
+ case "new":
4603
+ tmuxArgs.push("new-window");
4604
+ if (windowName) {
4605
+ tmuxArgs.push("-n", windowName);
4606
+ }
4607
+ break;
4608
+ case "vertical":
4609
+ tmuxArgs.push("split-window", "-v");
4610
+ break;
4611
+ case "horizontal":
4612
+ tmuxArgs.push("split-window", "-h");
4613
+ break;
4614
+ }
4615
+ if (cwd) {
4616
+ tmuxArgs.push("-c", cwd);
4617
+ }
4618
+ if (env) {
4619
+ for (const [key, value] of Object.entries(env)) {
4620
+ tmuxArgs.push("-e", `${key}=${value}`);
4621
+ }
4622
+ }
4623
+ tmuxArgs.push(command2);
4624
+ if (args2 && args2.length > 0) {
4625
+ tmuxArgs.push(...args2);
4626
+ }
4627
+ const result = await spawnProcess({
4628
+ command: "tmux",
4629
+ args: tmuxArgs
4630
+ });
4631
+ return result;
4632
+ }
4633
+
4634
+ // ../process/src/env.ts
4635
+ function getPhantomEnv(worktreeName, worktreePath) {
4636
+ return {
4637
+ PHANTOM: "1",
4638
+ PHANTOM_NAME: worktreeName,
4639
+ PHANTOM_PATH: worktreePath
4640
+ };
4641
+ }
4642
+
4643
+ // ../process/src/fzf.ts
4644
+ import { spawn } from "node:child_process";
4645
+ async function selectWithFzf(items, options = {}) {
4646
+ return new Promise((resolve2) => {
4647
+ const args2 = [];
4648
+ if (options.prompt) {
4649
+ args2.push("--prompt", options.prompt);
4650
+ }
4651
+ if (options.header) {
4652
+ args2.push("--header", options.header);
4653
+ }
4654
+ if (options.previewCommand) {
4655
+ args2.push("--preview", options.previewCommand);
4656
+ }
4657
+ const fzf = spawn("fzf", args2, {
4658
+ stdio: ["pipe", "pipe", "pipe"]
4659
+ });
4660
+ let result = "";
4661
+ let errorOutput = "";
4662
+ fzf.stdout.on("data", (data) => {
4663
+ result += data.toString();
4664
+ });
4665
+ if (fzf.stderr) {
4666
+ fzf.stderr.on("data", (data) => {
4667
+ errorOutput += data.toString();
4668
+ });
4669
+ }
4670
+ fzf.on("error", (error) => {
4671
+ if (error.message.includes("ENOENT")) {
4672
+ resolve2(
4673
+ err(new Error("fzf command not found. Please install fzf first."))
4674
+ );
4675
+ } else {
4676
+ resolve2(err(error));
4677
+ }
4678
+ });
4679
+ fzf.on("close", (code) => {
4680
+ if (code === 0) {
4681
+ const selected = result.trim();
4682
+ resolve2(ok(selected || null));
4683
+ } else if (code === 1) {
4684
+ resolve2(ok(null));
4685
+ } else if (code === 130) {
4686
+ resolve2(ok(null));
4687
+ } else {
4688
+ resolve2(err(new Error(`fzf exited with code ${code}: ${errorOutput}`)));
4689
+ }
4690
+ });
4691
+ fzf.stdin.write(items.join("\n"));
4692
+ fzf.stdin.end();
4693
+ });
4694
+ }
4695
+
4520
4696
  // ../core/src/worktree/validate.ts
4521
4697
  import fs2 from "node:fs/promises";
4522
- async function validateWorktreeExists(gitRoot, name) {
4523
- const worktreePath = getWorktreePath(gitRoot, name);
4698
+ async function validateWorktreeExists(gitRoot, worktreeDirectory, name) {
4699
+ const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
4524
4700
  try {
4525
4701
  await fs2.access(worktreePath);
4526
4702
  return ok({ path: worktreePath });
@@ -4528,8 +4704,8 @@ async function validateWorktreeExists(gitRoot, name) {
4528
4704
  return err(new WorktreeNotFoundError(name));
4529
4705
  }
4530
4706
  }
4531
- async function validateWorktreeDoesNotExist(gitRoot, name) {
4532
- const worktreePath = getWorktreePath(gitRoot, name);
4707
+ async function validateWorktreeDoesNotExist(gitRoot, worktreeDirectory, name) {
4708
+ const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
4533
4709
  try {
4534
4710
  await fs2.access(worktreePath);
4535
4711
  return err(new WorktreeAlreadyExistsError(name));
@@ -4555,21 +4731,91 @@ function validateWorktreeName(name) {
4555
4731
  return ok(void 0);
4556
4732
  }
4557
4733
 
4734
+ // ../core/src/exec.ts
4735
+ async function execInWorktree(gitRoot, worktreeDirectory, worktreeName, command2, options) {
4736
+ const validation = await validateWorktreeExists(
4737
+ gitRoot,
4738
+ worktreeDirectory,
4739
+ worktreeName
4740
+ );
4741
+ if (isErr(validation)) {
4742
+ return err(validation.error);
4743
+ }
4744
+ const worktreePath = validation.value.path;
4745
+ const [cmd, ...args2] = command2;
4746
+ const stdio = options?.interactive ? "inherit" : ["ignore", "inherit", "inherit"];
4747
+ return spawnProcess({
4748
+ command: cmd,
4749
+ args: args2,
4750
+ options: {
4751
+ cwd: worktreePath,
4752
+ stdio
4753
+ }
4754
+ });
4755
+ }
4756
+
4757
+ // ../core/src/worktree/post-create.ts
4758
+ async function executePostCreateCommands(options) {
4759
+ const { gitRoot, worktreesDirectory, worktreeName, commands: commands2 } = options;
4760
+ const executedCommands = [];
4761
+ for (const command2 of commands2) {
4762
+ console.log(`Executing: ${command2}`);
4763
+ const shell = process.env.SHELL || "/bin/sh";
4764
+ const cmdResult = await execInWorktree(
4765
+ gitRoot,
4766
+ worktreesDirectory,
4767
+ worktreeName,
4768
+ [shell, "-c", command2]
4769
+ );
4770
+ if (isErr(cmdResult)) {
4771
+ const errorMessage = cmdResult.error instanceof Error ? cmdResult.error.message : String(cmdResult.error);
4772
+ return err(
4773
+ new Error(
4774
+ `Failed to execute post-create command "${command2}": ${errorMessage}`
4775
+ )
4776
+ );
4777
+ }
4778
+ if (cmdResult.value.exitCode !== 0) {
4779
+ return err(
4780
+ new Error(
4781
+ `Post-create command failed with exit code ${cmdResult.value.exitCode}: ${command2}`
4782
+ )
4783
+ );
4784
+ }
4785
+ executedCommands.push(command2);
4786
+ }
4787
+ return ok({ executedCommands });
4788
+ }
4789
+ async function copyFilesToWorktree(gitRoot, worktreesDirectory, worktreeName, filesToCopy) {
4790
+ const worktreePath = getWorktreePathFromDirectory(
4791
+ worktreesDirectory,
4792
+ worktreeName
4793
+ );
4794
+ const copyResult = await copyFiles(gitRoot, worktreePath, filesToCopy);
4795
+ if (isErr(copyResult)) {
4796
+ return err(copyResult.error);
4797
+ }
4798
+ return ok(void 0);
4799
+ }
4800
+
4558
4801
  // ../core/src/worktree/create.ts
4559
- async function createWorktree(gitRoot, name, options = {}) {
4802
+ async function createWorktree(gitRoot, worktreeDirectory, name, options, postCreateCopyFiles, postCreateCommands) {
4560
4803
  const nameValidation = validateWorktreeName(name);
4561
4804
  if (isErr(nameValidation)) {
4562
4805
  return nameValidation;
4563
4806
  }
4564
4807
  const { branch = name, base = "HEAD" } = options;
4565
- const worktreesPath = getPhantomDirectory(gitRoot);
4566
- const worktreePath = getWorktreePath(gitRoot, name);
4808
+ const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
4567
4809
  try {
4568
- await fs3.access(worktreesPath);
4810
+ await fs3.access(worktreeDirectory);
4569
4811
  } catch {
4570
- await fs3.mkdir(worktreesPath, { recursive: true });
4812
+ await fs3.mkdir(worktreeDirectory, { recursive: true });
4571
4813
  }
4572
- const validation = await validateWorktreeDoesNotExist(gitRoot, name);
4814
+ const validation = await validateWorktreeDoesNotExist(
4815
+ gitRoot,
4816
+ worktreeDirectory,
4817
+ name
4818
+ );
4573
4819
  if (isErr(validation)) {
4574
4820
  return err(validation.error);
4575
4821
  }
@@ -4595,6 +4841,31 @@ async function createWorktree(gitRoot, name, options = {}) {
4595
4841
  copyError = copyResult.error.message;
4596
4842
  }
4597
4843
  }
4844
+ if (postCreateCopyFiles && postCreateCopyFiles.length > 0) {
4845
+ const copyResult = await copyFilesToWorktree(
4846
+ gitRoot,
4847
+ worktreeDirectory,
4848
+ name,
4849
+ postCreateCopyFiles
4850
+ );
4851
+ if (isErr(copyResult)) {
4852
+ if (!copyError) {
4853
+ copyError = copyResult.error.message;
4854
+ }
4855
+ }
4856
+ }
4857
+ if (postCreateCommands && postCreateCommands.length > 0) {
4858
+ console.log("\nRunning post-create commands...");
4859
+ const commandsResult = await executePostCreateCommands({
4860
+ gitRoot,
4861
+ worktreesDirectory: worktreeDirectory,
4862
+ worktreeName: name,
4863
+ commands: postCreateCommands
4864
+ });
4865
+ if (isErr(commandsResult)) {
4866
+ return err(new WorktreeError(commandsResult.error.message));
4867
+ }
4868
+ }
4598
4869
  return ok({
4599
4870
  message: `Created worktree '${name}' at ${worktreePath}`,
4600
4871
  path: worktreePath,
@@ -4652,9 +4923,13 @@ async function deleteBranch(gitRoot, branchName) {
4652
4923
  return err(new WorktreeError(`branch delete failed: ${errorMessage}`));
4653
4924
  }
4654
4925
  }
4655
- async function deleteWorktree(gitRoot, name, options = {}) {
4656
- const { force = false } = options;
4657
- const validation = await validateWorktreeExists(gitRoot, name);
4926
+ async function deleteWorktree(gitRoot, worktreeDirectory, name, options) {
4927
+ const { force = false } = options || {};
4928
+ const validation = await validateWorktreeExists(
4929
+ gitRoot,
4930
+ worktreeDirectory,
4931
+ name
4932
+ );
4658
4933
  if (isErr(validation)) {
4659
4934
  return err(validation.error);
4660
4935
  }
@@ -4706,12 +4981,11 @@ async function getWorktreeStatus(worktreePath) {
4706
4981
  return true;
4707
4982
  }
4708
4983
  }
4709
- async function listWorktrees2(gitRoot) {
4984
+ async function listWorktrees2(gitRoot, worktreeDirectory) {
4710
4985
  try {
4711
4986
  const gitWorktrees = await listWorktrees(gitRoot);
4712
- const phantomDir = getPhantomDirectory(gitRoot);
4713
4987
  const phantomWorktrees = gitWorktrees.filter(
4714
- (worktree) => worktree.path.startsWith(phantomDir)
4988
+ (worktree) => worktree.path.startsWith(worktreeDirectory)
4715
4989
  );
4716
4990
  if (phantomWorktrees.length === 0) {
4717
4991
  return ok({
@@ -4721,7 +4995,7 @@ async function listWorktrees2(gitRoot) {
4721
4995
  }
4722
4996
  const worktrees = await Promise.all(
4723
4997
  phantomWorktrees.map(async (gitWorktree) => {
4724
- const name = gitWorktree.path.substring(phantomDir.length + 1);
4998
+ const name = gitWorktree.path.substring(worktreeDirectory.length + 1);
4725
4999
  const isClean = await getWorktreeStatus(gitWorktree.path);
4726
5000
  return {
4727
5001
  name,
@@ -4742,12 +5016,12 @@ async function listWorktrees2(gitRoot) {
4742
5016
 
4743
5017
  // ../core/src/worktree/attach.ts
4744
5018
  import { existsSync } from "node:fs";
4745
- async function attachWorktreeCore(gitRoot, name) {
5019
+ async function attachWorktreeCore(gitRoot, worktreeDirectory, name, postCreateCopyFiles, postCreateCommands) {
4746
5020
  const validation = validateWorktreeName(name);
4747
5021
  if (isErr(validation)) {
4748
5022
  return validation;
4749
5023
  }
4750
- const worktreePath = getWorktreePath(gitRoot, name);
5024
+ const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
4751
5025
  if (existsSync(worktreePath)) {
4752
5026
  return err(new WorktreeAlreadyExistsError(name));
4753
5027
  }
@@ -4762,12 +5036,41 @@ async function attachWorktreeCore(gitRoot, name) {
4762
5036
  if (isErr(attachResult)) {
4763
5037
  return err(attachResult.error);
4764
5038
  }
5039
+ if (postCreateCopyFiles && postCreateCopyFiles.length > 0) {
5040
+ const copyResult = await copyFilesToWorktree(
5041
+ gitRoot,
5042
+ worktreeDirectory,
5043
+ name,
5044
+ postCreateCopyFiles
5045
+ );
5046
+ if (isErr(copyResult)) {
5047
+ console.warn(
5048
+ `Warning: Failed to copy some files: ${copyResult.error.message}`
5049
+ );
5050
+ }
5051
+ }
5052
+ if (postCreateCommands && postCreateCommands.length > 0) {
5053
+ console.log("\nRunning post-create commands...");
5054
+ const commandsResult = await executePostCreateCommands({
5055
+ gitRoot,
5056
+ worktreesDirectory: worktreeDirectory,
5057
+ worktreeName: name,
5058
+ commands: postCreateCommands
5059
+ });
5060
+ if (isErr(commandsResult)) {
5061
+ return err(new WorktreeError(commandsResult.error.message));
5062
+ }
5063
+ }
4765
5064
  return ok(worktreePath);
4766
5065
  }
4767
5066
 
4768
5067
  // ../core/src/worktree/where.ts
4769
- async function whereWorktree(gitRoot, name) {
4770
- const validation = await validateWorktreeExists(gitRoot, name);
5068
+ async function whereWorktree(gitRoot, worktreeDirectory, name) {
5069
+ const validation = await validateWorktreeExists(
5070
+ gitRoot,
5071
+ worktreeDirectory,
5072
+ name
5073
+ );
4771
5074
  if (isErr(validation)) {
4772
5075
  return err(validation.error);
4773
5076
  }
@@ -4776,169 +5079,9 @@ async function whereWorktree(gitRoot, name) {
4776
5079
  });
4777
5080
  }
4778
5081
 
4779
- // ../process/src/errors.ts
4780
- var ProcessError = class extends Error {
4781
- exitCode;
4782
- constructor(message, exitCode) {
4783
- super(message);
4784
- this.name = this.constructor.name;
4785
- this.exitCode = exitCode;
4786
- }
4787
- };
4788
- var ProcessExecutionError = class extends ProcessError {
4789
- constructor(command2, exitCode) {
4790
- super(`Command '${command2}' failed with exit code ${exitCode}`, exitCode);
4791
- this.name = "ProcessExecutionError";
4792
- }
4793
- };
4794
- var ProcessSignalError = class extends ProcessError {
4795
- constructor(signal) {
4796
- const exitCode = 128 + (signal === "SIGTERM" ? 15 : 1);
4797
- super(`Command terminated by signal: ${signal}`, exitCode);
4798
- this.name = "ProcessSignalError";
4799
- }
4800
- };
4801
- var ProcessSpawnError = class extends ProcessError {
4802
- constructor(command2, details) {
4803
- super(`Error executing command '${command2}': ${details}`);
4804
- this.name = "ProcessSpawnError";
4805
- }
4806
- };
4807
-
4808
- // ../process/src/spawn.ts
4809
- import {
4810
- spawn as nodeSpawn
4811
- } from "node:child_process";
4812
- async function spawnProcess(config) {
4813
- return new Promise((resolve2) => {
4814
- const { command: command2, args: args2 = [], options = {} } = config;
4815
- const childProcess = nodeSpawn(command2, args2, {
4816
- stdio: "inherit",
4817
- ...options
4818
- });
4819
- childProcess.on("error", (error) => {
4820
- resolve2(err(new ProcessSpawnError(command2, error.message)));
4821
- });
4822
- childProcess.on("exit", (code, signal) => {
4823
- if (signal) {
4824
- resolve2(err(new ProcessSignalError(signal)));
4825
- } else {
4826
- const exitCode = code ?? 0;
4827
- if (exitCode === 0) {
4828
- resolve2(ok({ exitCode }));
4829
- } else {
4830
- resolve2(err(new ProcessExecutionError(command2, exitCode)));
4831
- }
4832
- }
4833
- });
4834
- });
4835
- }
4836
-
4837
- // ../process/src/tmux.ts
4838
- async function isInsideTmux() {
4839
- return process.env.TMUX !== void 0;
4840
- }
4841
- async function executeTmuxCommand(options) {
4842
- const { direction, command: command2, args: args2, cwd, env, windowName } = options;
4843
- const tmuxArgs = [];
4844
- switch (direction) {
4845
- case "new":
4846
- tmuxArgs.push("new-window");
4847
- if (windowName) {
4848
- tmuxArgs.push("-n", windowName);
4849
- }
4850
- break;
4851
- case "vertical":
4852
- tmuxArgs.push("split-window", "-v");
4853
- break;
4854
- case "horizontal":
4855
- tmuxArgs.push("split-window", "-h");
4856
- break;
4857
- }
4858
- if (cwd) {
4859
- tmuxArgs.push("-c", cwd);
4860
- }
4861
- if (env) {
4862
- for (const [key, value] of Object.entries(env)) {
4863
- tmuxArgs.push("-e", `${key}=${value}`);
4864
- }
4865
- }
4866
- tmuxArgs.push(command2);
4867
- if (args2 && args2.length > 0) {
4868
- tmuxArgs.push(...args2);
4869
- }
4870
- const result = await spawnProcess({
4871
- command: "tmux",
4872
- args: tmuxArgs
4873
- });
4874
- return result;
4875
- }
4876
-
4877
- // ../process/src/env.ts
4878
- function getPhantomEnv(worktreeName, worktreePath) {
4879
- return {
4880
- PHANTOM: "1",
4881
- PHANTOM_NAME: worktreeName,
4882
- PHANTOM_PATH: worktreePath
4883
- };
4884
- }
4885
-
4886
- // ../process/src/fzf.ts
4887
- import { spawn } from "node:child_process";
4888
- async function selectWithFzf(items, options = {}) {
4889
- return new Promise((resolve2) => {
4890
- const args2 = [];
4891
- if (options.prompt) {
4892
- args2.push("--prompt", options.prompt);
4893
- }
4894
- if (options.header) {
4895
- args2.push("--header", options.header);
4896
- }
4897
- if (options.previewCommand) {
4898
- args2.push("--preview", options.previewCommand);
4899
- }
4900
- const fzf = spawn("fzf", args2, {
4901
- stdio: ["pipe", "pipe", "pipe"]
4902
- });
4903
- let result = "";
4904
- let errorOutput = "";
4905
- fzf.stdout.on("data", (data) => {
4906
- result += data.toString();
4907
- });
4908
- if (fzf.stderr) {
4909
- fzf.stderr.on("data", (data) => {
4910
- errorOutput += data.toString();
4911
- });
4912
- }
4913
- fzf.on("error", (error) => {
4914
- if (error.message.includes("ENOENT")) {
4915
- resolve2(
4916
- err(new Error("fzf command not found. Please install fzf first."))
4917
- );
4918
- } else {
4919
- resolve2(err(error));
4920
- }
4921
- });
4922
- fzf.on("close", (code) => {
4923
- if (code === 0) {
4924
- const selected = result.trim();
4925
- resolve2(ok(selected || null));
4926
- } else if (code === 1) {
4927
- resolve2(ok(null));
4928
- } else if (code === 130) {
4929
- resolve2(ok(null));
4930
- } else {
4931
- resolve2(err(new Error(`fzf exited with code ${code}: ${errorOutput}`)));
4932
- }
4933
- });
4934
- fzf.stdin.write(items.join("\n"));
4935
- fzf.stdin.end();
4936
- });
4937
- }
4938
-
4939
5082
  // ../core/src/worktree/select.ts
4940
- async function selectWorktreeWithFzf(gitRoot) {
4941
- const listResult = await listWorktrees2(gitRoot);
5083
+ async function selectWorktreeWithFzf(gitRoot, worktreeDirectory) {
5084
+ const listResult = await listWorktrees2(gitRoot, worktreeDirectory);
4942
5085
  if (isErr(listResult)) {
4943
5086
  return listResult;
4944
5087
  }
@@ -4985,28 +5128,13 @@ async function selectWorktreeWithFzf(gitRoot) {
4985
5128
  };
4986
5129
  }
4987
5130
 
4988
- // ../core/src/exec.ts
4989
- async function execInWorktree(gitRoot, worktreeName, command2, options = {}) {
4990
- const validation = await validateWorktreeExists(gitRoot, worktreeName);
4991
- if (isErr(validation)) {
4992
- return err(validation.error);
4993
- }
4994
- const worktreePath = validation.value.path;
4995
- const [cmd, ...args2] = command2;
4996
- const stdio = options.interactive ? "inherit" : ["ignore", "inherit", "inherit"];
4997
- return spawnProcess({
4998
- command: cmd,
4999
- args: args2,
5000
- options: {
5001
- cwd: worktreePath,
5002
- stdio
5003
- }
5004
- });
5005
- }
5006
-
5007
5131
  // ../core/src/shell.ts
5008
- async function shellInWorktree(gitRoot, worktreeName) {
5009
- const validation = await validateWorktreeExists(gitRoot, worktreeName);
5132
+ async function shellInWorktree(gitRoot, worktreeDirectory, worktreeName) {
5133
+ const validation = await validateWorktreeExists(
5134
+ gitRoot,
5135
+ worktreeDirectory,
5136
+ worktreeName
5137
+ );
5010
5138
  if (isErr(validation)) {
5011
5139
  return err(validation.error);
5012
5140
  }
@@ -5085,7 +5213,14 @@ async function attachHandler(args2) {
5085
5213
  );
5086
5214
  }
5087
5215
  const gitRoot = await getGitRoot();
5088
- const result = await attachWorktreeCore(gitRoot, branchName);
5216
+ const context = await createContext(gitRoot);
5217
+ const result = await attachWorktreeCore(
5218
+ context.gitRoot,
5219
+ context.worktreesDirectory,
5220
+ branchName,
5221
+ context.config?.postCreate?.copyFiles,
5222
+ context.config?.postCreate?.commands
5223
+ );
5089
5224
  if (isErr(result)) {
5090
5225
  const error = result.error;
5091
5226
  if (error instanceof WorktreeAlreadyExistsError) {
@@ -5099,14 +5234,19 @@ async function attachHandler(args2) {
5099
5234
  const worktreePath = result.value;
5100
5235
  output.log(`Attached phantom: ${branchName}`);
5101
5236
  if (values.shell) {
5102
- const shellResult = await shellInWorktree(gitRoot, branchName);
5237
+ const shellResult = await shellInWorktree(
5238
+ context.gitRoot,
5239
+ context.worktreesDirectory,
5240
+ branchName
5241
+ );
5103
5242
  if (isErr(shellResult)) {
5104
5243
  exitWithError(shellResult.error.message, exitCodes.generalError);
5105
5244
  }
5106
5245
  } else if (values.exec) {
5107
5246
  const shell = process.env.SHELL || "/bin/sh";
5108
5247
  const execResult = await execInWorktree(
5109
- gitRoot,
5248
+ context.gitRoot,
5249
+ context.worktreesDirectory,
5110
5250
  branchName,
5111
5251
  [shell, "-c", values.exec],
5112
5252
  { interactive: true }
@@ -5618,27 +5758,26 @@ async function createHandler(args2) {
5618
5758
  }
5619
5759
  try {
5620
5760
  const gitRoot = await getGitRoot();
5761
+ const context = await createContext(gitRoot);
5621
5762
  let filesToCopy = [];
5622
- const configResult = await loadConfig(gitRoot);
5623
- if (isOk(configResult)) {
5624
- if (configResult.value.postCreate?.copyFiles) {
5625
- filesToCopy = [...configResult.value.postCreate.copyFiles];
5626
- }
5627
- } else {
5628
- if (configResult.error instanceof ConfigValidationError) {
5629
- output.warn(`Configuration warning: ${configResult.error.message}`);
5630
- } else if (configResult.error instanceof ConfigParseError) {
5631
- output.warn(`Configuration warning: ${configResult.error.message}`);
5632
- }
5763
+ if (context.config?.postCreate?.copyFiles) {
5764
+ filesToCopy = [...context.config.postCreate.copyFiles];
5633
5765
  }
5634
5766
  if (copyFileOptions && copyFileOptions.length > 0) {
5635
5767
  const cliFiles = Array.isArray(copyFileOptions) ? copyFileOptions : [copyFileOptions];
5636
5768
  filesToCopy = [.../* @__PURE__ */ new Set([...filesToCopy, ...cliFiles])];
5637
5769
  }
5638
- const result = await createWorktree(gitRoot, worktreeName, {
5639
- copyFiles: filesToCopy.length > 0 ? filesToCopy : void 0,
5640
- base: baseOption
5641
- });
5770
+ const result = await createWorktree(
5771
+ context.gitRoot,
5772
+ context.worktreesDirectory,
5773
+ worktreeName,
5774
+ {
5775
+ copyFiles: filesToCopy.length > 0 ? filesToCopy : void 0,
5776
+ base: baseOption
5777
+ },
5778
+ filesToCopy.length > 0 ? filesToCopy : void 0,
5779
+ context.config?.postCreate?.commands
5780
+ );
5642
5781
  if (isErr(result)) {
5643
5782
  const exitCode = result.error instanceof WorktreeAlreadyExistsError ? exitCodes.validationError : exitCodes.generalError;
5644
5783
  exitWithError(result.error.message, exitCode);
@@ -5650,30 +5789,6 @@ async function createHandler(args2) {
5650
5789
  Warning: Failed to copy some files: ${result.value.copyError}`
5651
5790
  );
5652
5791
  }
5653
- if (isOk(configResult) && configResult.value.postCreate?.commands) {
5654
- const commands2 = configResult.value.postCreate.commands;
5655
- output.log("\nRunning post-create commands...");
5656
- for (const command2 of commands2) {
5657
- output.log(`Executing: ${command2}`);
5658
- const shell = process.env.SHELL || "/bin/sh";
5659
- const cmdResult = await execInWorktree(gitRoot, worktreeName, [
5660
- shell,
5661
- "-c",
5662
- command2
5663
- ]);
5664
- if (isErr(cmdResult)) {
5665
- output.error(`Failed to execute command: ${cmdResult.error.message}`);
5666
- const exitCode = "exitCode" in cmdResult.error ? cmdResult.error.exitCode ?? exitCodes.generalError : exitCodes.generalError;
5667
- exitWithError(`Post-create command failed: ${command2}`, exitCode);
5668
- }
5669
- if (cmdResult.value.exitCode !== 0) {
5670
- exitWithError(
5671
- `Post-create command failed: ${command2}`,
5672
- cmdResult.value.exitCode
5673
- );
5674
- }
5675
- }
5676
- }
5677
5792
  if (execCommand && isOk(result)) {
5678
5793
  output.log(
5679
5794
  `
@@ -5681,7 +5796,8 @@ Executing command in worktree '${worktreeName}': ${execCommand}`
5681
5796
  );
5682
5797
  const shell = process.env.SHELL || "/bin/sh";
5683
5798
  const execResult = await execInWorktree(
5684
- gitRoot,
5799
+ context.gitRoot,
5800
+ context.worktreesDirectory,
5685
5801
  worktreeName,
5686
5802
  [shell, "-c", execCommand],
5687
5803
  { interactive: true }
@@ -5699,7 +5815,11 @@ Executing command in worktree '${worktreeName}': ${execCommand}`
5699
5815
  Entering worktree '${worktreeName}' at ${result.value.path}`
5700
5816
  );
5701
5817
  output.log("Type 'exit' to return to your original directory\n");
5702
- const shellResult = await shellInWorktree(gitRoot, worktreeName);
5818
+ const shellResult = await shellInWorktree(
5819
+ context.gitRoot,
5820
+ context.worktreesDirectory,
5821
+ worktreeName
5822
+ );
5703
5823
  if (isErr(shellResult)) {
5704
5824
  output.error(shellResult.error.message);
5705
5825
  const exitCode = "exitCode" in shellResult.error ? shellResult.error.exitCode ?? exitCodes.generalError : exitCodes.generalError;
@@ -5779,6 +5899,7 @@ async function deleteHandler(args2) {
5779
5899
  const forceDelete = values.force ?? false;
5780
5900
  try {
5781
5901
  const gitRoot = await getGitRoot();
5902
+ const context = await createContext(gitRoot);
5782
5903
  let worktreeName;
5783
5904
  if (deleteCurrent) {
5784
5905
  const currentWorktree = await getCurrentWorktree(gitRoot);
@@ -5790,7 +5911,10 @@ async function deleteHandler(args2) {
5790
5911
  }
5791
5912
  worktreeName = currentWorktree;
5792
5913
  } else if (useFzf) {
5793
- const selectResult = await selectWorktreeWithFzf(gitRoot);
5914
+ const selectResult = await selectWorktreeWithFzf(
5915
+ context.gitRoot,
5916
+ context.worktreesDirectory
5917
+ );
5794
5918
  if (isErr(selectResult)) {
5795
5919
  exitWithError(selectResult.error.message, exitCodes.generalError);
5796
5920
  }
@@ -5801,9 +5925,14 @@ async function deleteHandler(args2) {
5801
5925
  } else {
5802
5926
  worktreeName = positionals[0];
5803
5927
  }
5804
- const result = await deleteWorktree(gitRoot, worktreeName, {
5805
- force: forceDelete
5806
- });
5928
+ const result = await deleteWorktree(
5929
+ context.gitRoot,
5930
+ context.worktreesDirectory,
5931
+ worktreeName,
5932
+ {
5933
+ force: forceDelete
5934
+ }
5935
+ );
5807
5936
  if (isErr(result)) {
5808
5937
  const exitCode = result.error instanceof WorktreeNotFoundError ? exitCodes.validationError : result.error instanceof WorktreeError && result.error.message.includes("uncommitted changes") ? exitCodes.validationError : exitCodes.generalError;
5809
5938
  exitWithError(result.error.message, exitCode);
@@ -5878,6 +6007,7 @@ async function execHandler(args2) {
5878
6007
  }
5879
6008
  try {
5880
6009
  const gitRoot = await getGitRoot();
6010
+ const context = await createContext(gitRoot);
5881
6011
  if (tmuxOption && !await isInsideTmux()) {
5882
6012
  exitWithError(
5883
6013
  "The --tmux option can only be used inside a tmux session",
@@ -5886,7 +6016,10 @@ async function execHandler(args2) {
5886
6016
  }
5887
6017
  let worktreeName;
5888
6018
  if (useFzf) {
5889
- const selectResult = await selectWorktreeWithFzf(gitRoot);
6019
+ const selectResult = await selectWorktreeWithFzf(
6020
+ context.gitRoot,
6021
+ context.worktreesDirectory
6022
+ );
5890
6023
  if (isErr(selectResult)) {
5891
6024
  exitWithError(selectResult.error.message, exitCodes.generalError);
5892
6025
  }
@@ -5897,7 +6030,11 @@ async function execHandler(args2) {
5897
6030
  } else {
5898
6031
  worktreeName = positionals[0];
5899
6032
  }
5900
- const validation = await validateWorktreeExists(gitRoot, worktreeName);
6033
+ const validation = await validateWorktreeExists(
6034
+ context.gitRoot,
6035
+ context.worktreesDirectory,
6036
+ worktreeName
6037
+ );
5901
6038
  if (isErr(validation)) {
5902
6039
  exitWithError(validation.error.message, exitCodes.generalError);
5903
6040
  }
@@ -5922,7 +6059,8 @@ async function execHandler(args2) {
5922
6059
  exitWithSuccess();
5923
6060
  }
5924
6061
  const result = await execInWorktree(
5925
- gitRoot,
6062
+ context.gitRoot,
6063
+ context.worktreesDirectory,
5926
6064
  worktreeName,
5927
6065
  commandArgs,
5928
6066
  { interactive: true }
@@ -9387,15 +9525,26 @@ async function checkoutIssue(issue, base) {
9387
9525
  );
9388
9526
  }
9389
9527
  const gitRoot = await getGitRoot();
9528
+ const context = await createContext(gitRoot);
9390
9529
  const worktreeName = `issue-${issue.number}`;
9391
9530
  const branchName = `issue-${issue.number}`;
9392
- const worktreePath = getWorktreePath(gitRoot, worktreeName);
9393
- const result = await createWorktree(gitRoot, worktreeName, {
9394
- branch: branchName,
9395
- base
9396
- });
9531
+ const result = await createWorktree(
9532
+ context.gitRoot,
9533
+ context.worktreesDirectory,
9534
+ worktreeName,
9535
+ {
9536
+ branch: branchName,
9537
+ base
9538
+ },
9539
+ context.config?.postCreate?.copyFiles,
9540
+ context.config?.postCreate?.commands
9541
+ );
9397
9542
  if (isErr(result)) {
9398
9543
  if (result.error instanceof WorktreeAlreadyExistsError) {
9544
+ const worktreePath = getWorktreePathFromDirectory(
9545
+ context.worktreesDirectory,
9546
+ worktreeName
9547
+ );
9399
9548
  return ok({
9400
9549
  message: `Worktree for issue #${issue.number} is already checked out`,
9401
9550
  worktree: worktreeName,
@@ -9408,13 +9557,14 @@ async function checkoutIssue(issue, base) {
9408
9557
  return ok({
9409
9558
  message: result.value.message,
9410
9559
  worktree: worktreeName,
9411
- path: worktreePath
9560
+ path: result.value.path
9412
9561
  });
9413
9562
  }
9414
9563
 
9415
9564
  // ../github/src/checkout/pr.ts
9416
9565
  async function checkoutPullRequest(pullRequest) {
9417
9566
  const gitRoot = await getGitRoot();
9567
+ const context = await createContext(gitRoot);
9418
9568
  const worktreeName = `pr-${pullRequest.number}`;
9419
9569
  const localBranch = `pr-${pullRequest.number}`;
9420
9570
  const upstream = pullRequest.isFromFork ? `origin/pull/${pullRequest.number}/head` : `origin/${pullRequest.head.ref}`;
@@ -9437,10 +9587,19 @@ async function checkoutPullRequest(pullRequest) {
9437
9587
  `Warning: Could not set upstream branch: ${setUpstreamResult.error.message}`
9438
9588
  );
9439
9589
  }
9440
- const attachResult = await attachWorktreeCore(gitRoot, worktreeName);
9441
- const worktreePath = getWorktreePath(gitRoot, worktreeName);
9590
+ const attachResult = await attachWorktreeCore(
9591
+ context.gitRoot,
9592
+ context.worktreesDirectory,
9593
+ worktreeName,
9594
+ context.config?.postCreate?.copyFiles,
9595
+ context.config?.postCreate?.commands
9596
+ );
9442
9597
  if (isErr(attachResult)) {
9443
9598
  if (attachResult.error instanceof WorktreeAlreadyExistsError) {
9599
+ const worktreePath = getWorktreePathFromDirectory(
9600
+ context.worktreesDirectory,
9601
+ worktreeName
9602
+ );
9444
9603
  return ok({
9445
9604
  message: `Worktree for PR #${pullRequest.number} is already checked out`,
9446
9605
  worktree: worktreeName,
@@ -9454,7 +9613,7 @@ async function checkoutPullRequest(pullRequest) {
9454
9613
  return ok({
9455
9614
  message,
9456
9615
  worktree: worktreeName,
9457
- path: worktreePath
9616
+ path: attachResult.value
9458
9617
  });
9459
9618
  }
9460
9619
 
@@ -9745,8 +9904,12 @@ async function listHandler(args2 = []) {
9745
9904
  });
9746
9905
  try {
9747
9906
  const gitRoot = await getGitRoot();
9907
+ const context = await createContext(gitRoot);
9748
9908
  if (values.fzf) {
9749
- const selectResult = await selectWorktreeWithFzf(gitRoot);
9909
+ const selectResult = await selectWorktreeWithFzf(
9910
+ context.gitRoot,
9911
+ context.worktreesDirectory
9912
+ );
9750
9913
  if (isErr(selectResult)) {
9751
9914
  exitWithError(selectResult.error.message, exitCodes.generalError);
9752
9915
  }
@@ -9754,7 +9917,10 @@ async function listHandler(args2 = []) {
9754
9917
  output.log(selectResult.value.name);
9755
9918
  }
9756
9919
  } else {
9757
- const result = await listWorktrees2(gitRoot);
9920
+ const result = await listWorktrees2(
9921
+ context.gitRoot,
9922
+ context.worktreesDirectory
9923
+ );
9758
9924
  if (isErr(result)) {
9759
9925
  exitWithError("Failed to list worktrees", exitCodes.generalError);
9760
9926
  }
@@ -13057,7 +13223,7 @@ var StdioServerTransport = class {
13057
13223
  // ../mcp/package.json
13058
13224
  var package_default = {
13059
13225
  name: "@aku11i/phantom-mcp",
13060
- version: "1.2.0",
13226
+ version: "1.3.0",
13061
13227
  private: true,
13062
13228
  type: "module",
13063
13229
  main: "./src/index.ts",
@@ -13092,10 +13258,18 @@ var createWorktreeTool = {
13092
13258
  inputSchema: schema,
13093
13259
  handler: async ({ name, baseBranch }) => {
13094
13260
  const gitRoot = await getGitRoot();
13095
- const result = await createWorktree(gitRoot, name, {
13096
- branch: name,
13097
- base: baseBranch
13098
- });
13261
+ const context = await createContext(gitRoot);
13262
+ const result = await createWorktree(
13263
+ context.gitRoot,
13264
+ context.worktreesDirectory,
13265
+ name,
13266
+ {
13267
+ branch: name,
13268
+ base: baseBranch
13269
+ },
13270
+ context.config?.postCreate?.copyFiles,
13271
+ context.config?.postCreate?.commands
13272
+ );
13099
13273
  if (!isOk(result)) {
13100
13274
  throw new Error(result.error.message);
13101
13275
  }
@@ -13130,7 +13304,15 @@ var deleteWorktreeTool = {
13130
13304
  inputSchema: schema2,
13131
13305
  handler: async ({ name, force }) => {
13132
13306
  const gitRoot = await getGitRoot();
13133
- const result = await deleteWorktree(gitRoot, name, { force });
13307
+ const context = await createContext(gitRoot);
13308
+ const result = await deleteWorktree(
13309
+ context.gitRoot,
13310
+ context.worktreesDirectory,
13311
+ name,
13312
+ {
13313
+ force
13314
+ }
13315
+ );
13134
13316
  if (!isOk(result)) {
13135
13317
  throw new Error(result.error.message);
13136
13318
  }
@@ -13195,7 +13377,11 @@ var listWorktreesTool = {
13195
13377
  inputSchema: schema4,
13196
13378
  handler: async () => {
13197
13379
  const gitRoot = await getGitRoot();
13198
- const result = await listWorktrees2(gitRoot);
13380
+ const context = await createContext(gitRoot);
13381
+ const result = await listWorktrees2(
13382
+ context.gitRoot,
13383
+ context.worktreesDirectory
13384
+ );
13199
13385
  if (!isOk(result)) {
13200
13386
  throw new Error("Failed to list worktrees");
13201
13387
  }
@@ -13370,6 +13556,7 @@ async function shellHandler(args2) {
13370
13556
  let worktreeName;
13371
13557
  try {
13372
13558
  const gitRoot = await getGitRoot();
13559
+ const context = await createContext(gitRoot);
13373
13560
  if (tmuxOption && !await isInsideTmux()) {
13374
13561
  exitWithError(
13375
13562
  "The --tmux option can only be used inside a tmux session",
@@ -13377,7 +13564,10 @@ async function shellHandler(args2) {
13377
13564
  );
13378
13565
  }
13379
13566
  if (useFzf) {
13380
- const selectResult = await selectWorktreeWithFzf(gitRoot);
13567
+ const selectResult = await selectWorktreeWithFzf(
13568
+ context.gitRoot,
13569
+ context.worktreesDirectory
13570
+ );
13381
13571
  if (isErr(selectResult)) {
13382
13572
  exitWithError(selectResult.error.message, exitCodes.generalError);
13383
13573
  }
@@ -13388,7 +13578,11 @@ async function shellHandler(args2) {
13388
13578
  } else {
13389
13579
  worktreeName = positionals[0];
13390
13580
  }
13391
- const validation = await validateWorktreeExists(gitRoot, worktreeName);
13581
+ const validation = await validateWorktreeExists(
13582
+ context.gitRoot,
13583
+ context.worktreesDirectory,
13584
+ worktreeName
13585
+ );
13392
13586
  if (isErr(validation)) {
13393
13587
  exitWithError(validation.error.message, exitCodes.generalError);
13394
13588
  }
@@ -13415,7 +13609,11 @@ async function shellHandler(args2) {
13415
13609
  `Entering worktree '${worktreeName}' at ${validation.value.path}`
13416
13610
  );
13417
13611
  output.log("Type 'exit' to return to your original directory\n");
13418
- const result = await shellInWorktree(gitRoot, worktreeName);
13612
+ const result = await shellInWorktree(
13613
+ context.gitRoot,
13614
+ context.worktreesDirectory,
13615
+ worktreeName
13616
+ );
13419
13617
  if (isErr(result)) {
13420
13618
  const exitCode = result.error instanceof WorktreeNotFoundError ? exitCodes.notFound : result.error.exitCode || exitCodes.generalError;
13421
13619
  exitWithError(result.error.message, exitCode);
@@ -13435,7 +13633,7 @@ import { parseArgs as parseArgs9 } from "node:util";
13435
13633
  // package.json
13436
13634
  var package_default2 = {
13437
13635
  name: "@aku11i/phantom-cli",
13438
- version: "1.2.0",
13636
+ version: "1.3.0",
13439
13637
  private: true,
13440
13638
  type: "module",
13441
13639
  scripts: {
@@ -13511,8 +13709,12 @@ async function whereHandler(args2) {
13511
13709
  exitCodes.generalError
13512
13710
  );
13513
13711
  }
13712
+ const context = await createContext(gitRoot);
13514
13713
  if (useFzf) {
13515
- const selectResult = await selectWorktreeWithFzf(gitRoot);
13714
+ const selectResult = await selectWorktreeWithFzf(
13715
+ context.gitRoot,
13716
+ context.worktreesDirectory
13717
+ );
13516
13718
  if (isErr(selectResult)) {
13517
13719
  exitWithError(selectResult.error.message, exitCodes.generalError);
13518
13720
  }
@@ -13523,7 +13725,11 @@ async function whereHandler(args2) {
13523
13725
  } else {
13524
13726
  worktreeName = positionals[0];
13525
13727
  }
13526
- const result = await whereWorktree(gitRoot, worktreeName);
13728
+ const result = await whereWorktree(
13729
+ context.gitRoot,
13730
+ context.worktreesDirectory,
13731
+ worktreeName
13732
+ );
13527
13733
  if (isErr(result)) {
13528
13734
  exitWithError(result.error.message, exitCodes.notFound);
13529
13735
  }