@aku11i/phantom 3.0.1 → 3.1.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 +799 -810
package/phantom.js CHANGED
@@ -3684,49 +3684,49 @@ var require_fast_uri = __commonJS({
3684
3684
  schemelessOptions.skipEscape = true;
3685
3685
  return serialize(resolved, schemelessOptions);
3686
3686
  }
3687
- function resolveComponent(base, relative, options, skipNormalization) {
3687
+ function resolveComponent(base, relative2, options, skipNormalization) {
3688
3688
  const target = {};
3689
3689
  if (!skipNormalization) {
3690
3690
  base = parse4(serialize(base, options), options);
3691
- relative = parse4(serialize(relative, options), options);
3691
+ relative2 = parse4(serialize(relative2, options), options);
3692
3692
  }
3693
3693
  options = options || {};
3694
- if (!options.tolerant && relative.scheme) {
3695
- target.scheme = relative.scheme;
3696
- target.userinfo = relative.userinfo;
3697
- target.host = relative.host;
3698
- target.port = relative.port;
3699
- target.path = removeDotSegments(relative.path || "");
3700
- target.query = relative.query;
3694
+ if (!options.tolerant && relative2.scheme) {
3695
+ target.scheme = relative2.scheme;
3696
+ target.userinfo = relative2.userinfo;
3697
+ target.host = relative2.host;
3698
+ target.port = relative2.port;
3699
+ target.path = removeDotSegments(relative2.path || "");
3700
+ target.query = relative2.query;
3701
3701
  } else {
3702
- if (relative.userinfo !== void 0 || relative.host !== void 0 || relative.port !== void 0) {
3703
- target.userinfo = relative.userinfo;
3704
- target.host = relative.host;
3705
- target.port = relative.port;
3706
- target.path = removeDotSegments(relative.path || "");
3707
- target.query = relative.query;
3702
+ if (relative2.userinfo !== void 0 || relative2.host !== void 0 || relative2.port !== void 0) {
3703
+ target.userinfo = relative2.userinfo;
3704
+ target.host = relative2.host;
3705
+ target.port = relative2.port;
3706
+ target.path = removeDotSegments(relative2.path || "");
3707
+ target.query = relative2.query;
3708
3708
  } else {
3709
- if (!relative.path) {
3709
+ if (!relative2.path) {
3710
3710
  target.path = base.path;
3711
- if (relative.query !== void 0) {
3712
- target.query = relative.query;
3711
+ if (relative2.query !== void 0) {
3712
+ target.query = relative2.query;
3713
3713
  } else {
3714
3714
  target.query = base.query;
3715
3715
  }
3716
3716
  } else {
3717
- if (relative.path[0] === "/") {
3718
- target.path = removeDotSegments(relative.path);
3717
+ if (relative2.path[0] === "/") {
3718
+ target.path = removeDotSegments(relative2.path);
3719
3719
  } else {
3720
3720
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
3721
- target.path = "/" + relative.path;
3721
+ target.path = "/" + relative2.path;
3722
3722
  } else if (!base.path) {
3723
- target.path = relative.path;
3723
+ target.path = relative2.path;
3724
3724
  } else {
3725
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
3725
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative2.path;
3726
3726
  }
3727
3727
  target.path = removeDotSegments(target.path);
3728
3728
  }
3729
- target.query = relative.query;
3729
+ target.query = relative2.query;
3730
3730
  }
3731
3731
  target.userinfo = base.userinfo;
3732
3732
  target.host = base.host;
@@ -3734,7 +3734,7 @@ var require_fast_uri = __commonJS({
3734
3734
  }
3735
3735
  target.scheme = base.scheme;
3736
3736
  }
3737
- target.fragment = relative.fragment;
3737
+ target.fragment = relative2.fragment;
3738
3738
  return target;
3739
3739
  }
3740
3740
  function equal(uriA, uriB, options) {
@@ -6891,6 +6891,18 @@ import { argv, exit as exit2 } from "node:process";
6891
6891
  // src/handlers/attach.ts
6892
6892
  import { parseArgs } from "node:util";
6893
6893
 
6894
+ // ../core/src/config/loader.ts
6895
+ import fs from "node:fs/promises";
6896
+ import path from "node:path";
6897
+
6898
+ // ../shared/src/constants/exit-codes.ts
6899
+ var exitCodes = {
6900
+ success: 0,
6901
+ generalError: 1,
6902
+ notFound: 2,
6903
+ validationError: 3
6904
+ };
6905
+
6894
6906
  // ../shared/src/types/result.ts
6895
6907
  var ok = (value) => ({
6896
6908
  ok: true,
@@ -6903,18 +6915,6 @@ var err = (error2) => ({
6903
6915
  var isOk = (result) => result.ok;
6904
6916
  var isErr = (result) => !result.ok;
6905
6917
 
6906
- // ../shared/src/constants/exit-codes.ts
6907
- var exitCodes = {
6908
- success: 0,
6909
- generalError: 1,
6910
- notFound: 2,
6911
- validationError: 3
6912
- };
6913
-
6914
- // ../core/src/config/loader.ts
6915
- import fs from "node:fs/promises";
6916
- import path from "node:path";
6917
-
6918
6918
  // ../../node_modules/.pnpm/zod@3.25.64/node_modules/zod/dist/esm/v3/external.js
6919
6919
  var external_exports = {};
6920
6920
  __export(external_exports, {
@@ -11043,6 +11043,169 @@ async function createContext(gitRoot) {
11043
11043
  };
11044
11044
  }
11045
11045
 
11046
+ // ../process/src/env.ts
11047
+ function getPhantomEnv(worktreeName, worktreePath) {
11048
+ return {
11049
+ PHANTOM: "1",
11050
+ PHANTOM_NAME: worktreeName,
11051
+ PHANTOM_PATH: worktreePath
11052
+ };
11053
+ }
11054
+
11055
+ // ../process/src/errors.ts
11056
+ var ProcessError = class extends Error {
11057
+ exitCode;
11058
+ constructor(message, exitCode) {
11059
+ super(message);
11060
+ this.name = this.constructor.name;
11061
+ this.exitCode = exitCode;
11062
+ }
11063
+ };
11064
+ var ProcessExecutionError = class extends ProcessError {
11065
+ constructor(command2, exitCode) {
11066
+ super(`Command '${command2}' failed with exit code ${exitCode}`, exitCode);
11067
+ this.name = "ProcessExecutionError";
11068
+ }
11069
+ };
11070
+ var ProcessSignalError = class extends ProcessError {
11071
+ constructor(signal) {
11072
+ const exitCode = 128 + (signal === "SIGTERM" ? 15 : 1);
11073
+ super(`Command terminated by signal: ${signal}`, exitCode);
11074
+ this.name = "ProcessSignalError";
11075
+ }
11076
+ };
11077
+ var ProcessSpawnError = class extends ProcessError {
11078
+ constructor(command2, details) {
11079
+ super(`Error executing command '${command2}': ${details}`);
11080
+ this.name = "ProcessSpawnError";
11081
+ }
11082
+ };
11083
+
11084
+ // ../process/src/fzf.ts
11085
+ import { spawn } from "node:child_process";
11086
+ async function selectWithFzf(items, options = {}) {
11087
+ return new Promise((resolve2) => {
11088
+ const args2 = [];
11089
+ if (options.prompt) {
11090
+ args2.push("--prompt", options.prompt);
11091
+ }
11092
+ if (options.header) {
11093
+ args2.push("--header", options.header);
11094
+ }
11095
+ if (options.previewCommand) {
11096
+ args2.push("--preview", options.previewCommand);
11097
+ }
11098
+ const fzf = spawn("fzf", args2, {
11099
+ stdio: ["pipe", "pipe", "pipe"]
11100
+ });
11101
+ let result = "";
11102
+ let errorOutput = "";
11103
+ fzf.stdout.on("data", (data) => {
11104
+ result += data.toString();
11105
+ });
11106
+ if (fzf.stderr) {
11107
+ fzf.stderr.on("data", (data) => {
11108
+ errorOutput += data.toString();
11109
+ });
11110
+ }
11111
+ fzf.on("error", (error2) => {
11112
+ if (error2.message.includes("ENOENT")) {
11113
+ resolve2(
11114
+ err(new Error("fzf command not found. Please install fzf first."))
11115
+ );
11116
+ } else {
11117
+ resolve2(err(error2));
11118
+ }
11119
+ });
11120
+ fzf.on("close", (code) => {
11121
+ if (code === 0) {
11122
+ const selected = result.trim();
11123
+ resolve2(ok(selected || null));
11124
+ } else if (code === 1) {
11125
+ resolve2(ok(null));
11126
+ } else if (code === 130) {
11127
+ resolve2(ok(null));
11128
+ } else {
11129
+ resolve2(err(new Error(`fzf exited with code ${code}: ${errorOutput}`)));
11130
+ }
11131
+ });
11132
+ fzf.stdin.write(items.join("\n"));
11133
+ fzf.stdin.end();
11134
+ });
11135
+ }
11136
+
11137
+ // ../process/src/spawn.ts
11138
+ import {
11139
+ spawn as nodeSpawn
11140
+ } from "node:child_process";
11141
+ async function spawnProcess(config2) {
11142
+ return new Promise((resolve2) => {
11143
+ const { command: command2, args: args2 = [], options = {} } = config2;
11144
+ const childProcess = nodeSpawn(command2, args2, {
11145
+ stdio: "inherit",
11146
+ ...options
11147
+ });
11148
+ childProcess.on("error", (error2) => {
11149
+ resolve2(err(new ProcessSpawnError(command2, error2.message)));
11150
+ });
11151
+ childProcess.on("exit", (code, signal) => {
11152
+ if (signal) {
11153
+ resolve2(err(new ProcessSignalError(signal)));
11154
+ } else {
11155
+ const exitCode = code ?? 0;
11156
+ if (exitCode === 0) {
11157
+ resolve2(ok({ exitCode }));
11158
+ } else {
11159
+ resolve2(err(new ProcessExecutionError(command2, exitCode)));
11160
+ }
11161
+ }
11162
+ });
11163
+ });
11164
+ }
11165
+
11166
+ // ../process/src/tmux.ts
11167
+ async function isInsideTmux() {
11168
+ return process.env.TMUX !== void 0;
11169
+ }
11170
+ async function executeTmuxCommand(options) {
11171
+ const { direction, command: command2, args: args2, cwd, env, windowName } = options;
11172
+ const tmuxArgs = [];
11173
+ switch (direction) {
11174
+ case "new":
11175
+ tmuxArgs.push("new-window");
11176
+ if (windowName) {
11177
+ tmuxArgs.push("-n", windowName);
11178
+ }
11179
+ break;
11180
+ case "vertical":
11181
+ tmuxArgs.push("split-window", "-v");
11182
+ break;
11183
+ case "horizontal":
11184
+ tmuxArgs.push("split-window", "-h");
11185
+ break;
11186
+ }
11187
+ if (cwd) {
11188
+ tmuxArgs.push("-c", cwd);
11189
+ }
11190
+ if (env) {
11191
+ for (const [key, value] of Object.entries(env)) {
11192
+ tmuxArgs.push("-e", `${key}=${value}`);
11193
+ }
11194
+ }
11195
+ tmuxArgs.push(command2);
11196
+ if (args2 && args2.length > 0) {
11197
+ tmuxArgs.push(...args2);
11198
+ }
11199
+ const result = await spawnProcess({
11200
+ command: "tmux",
11201
+ args: tmuxArgs
11202
+ });
11203
+ return result;
11204
+ }
11205
+
11206
+ // ../core/src/worktree/validate.ts
11207
+ import fs2 from "node:fs/promises";
11208
+
11046
11209
  // ../core/src/worktree/errors.ts
11047
11210
  var WorktreeError = class extends Error {
11048
11211
  constructor(message) {
@@ -11069,8 +11232,8 @@ var BranchNotFoundError = class extends WorktreeError {
11069
11232
  }
11070
11233
  };
11071
11234
 
11072
- // ../core/src/worktree/create.ts
11073
- import fs3 from "node:fs/promises";
11235
+ // ../core/src/worktree/list.ts
11236
+ import { relative } from "node:path";
11074
11237
 
11075
11238
  // ../git/src/executor.ts
11076
11239
  import { execFile as execFileCallback } from "node:child_process";
@@ -11252,234 +11415,86 @@ async function setUpstreamBranch(gitRoot, branch, upstream) {
11252
11415
  }
11253
11416
  }
11254
11417
 
11255
- // ../core/src/worktree/file-copier.ts
11256
- import { copyFile, mkdir, stat } from "node:fs/promises";
11257
- import path2 from "node:path";
11258
- var FileCopyError = class extends Error {
11259
- file;
11260
- constructor(file, message) {
11261
- super(`Failed to copy ${file}: ${message}`);
11262
- this.name = "FileCopyError";
11263
- this.file = file;
11264
- }
11265
- };
11266
- async function copyFiles(sourceDir, targetDir, files) {
11267
- const copiedFiles = [];
11268
- const skippedFiles = [];
11269
- for (const file of files) {
11270
- const sourcePath = path2.join(sourceDir, file);
11271
- const targetPath = path2.join(targetDir, file);
11272
- try {
11273
- const stats = await stat(sourcePath);
11274
- if (!stats.isFile()) {
11275
- skippedFiles.push(file);
11276
- continue;
11277
- }
11278
- const targetDirPath = path2.dirname(targetPath);
11279
- await mkdir(targetDirPath, { recursive: true });
11280
- await copyFile(sourcePath, targetPath);
11281
- copiedFiles.push(file);
11282
- } catch (error2) {
11283
- if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT") {
11284
- skippedFiles.push(file);
11285
- } else {
11286
- return err(
11287
- new FileCopyError(
11288
- file,
11289
- error2 instanceof Error ? error2.message : String(error2)
11290
- )
11291
- );
11292
- }
11293
- }
11418
+ // ../core/src/worktree/list.ts
11419
+ async function getWorktreeStatus(worktreePath) {
11420
+ try {
11421
+ const { stdout: stdout2 } = await executeGitCommandInDirectory(worktreePath, [
11422
+ "status",
11423
+ "--porcelain"
11424
+ ]);
11425
+ return !stdout2;
11426
+ } catch {
11427
+ return true;
11294
11428
  }
11295
- return ok({ copiedFiles, skippedFiles });
11296
11429
  }
11297
-
11298
- // ../process/src/errors.ts
11299
- var ProcessError = class extends Error {
11300
- exitCode;
11301
- constructor(message, exitCode) {
11302
- super(message);
11303
- this.name = this.constructor.name;
11304
- this.exitCode = exitCode;
11305
- }
11306
- };
11307
- var ProcessExecutionError = class extends ProcessError {
11308
- constructor(command2, exitCode) {
11309
- super(`Command '${command2}' failed with exit code ${exitCode}`, exitCode);
11310
- this.name = "ProcessExecutionError";
11311
- }
11312
- };
11313
- var ProcessSignalError = class extends ProcessError {
11314
- constructor(signal) {
11315
- const exitCode = 128 + (signal === "SIGTERM" ? 15 : 1);
11316
- super(`Command terminated by signal: ${signal}`, exitCode);
11317
- this.name = "ProcessSignalError";
11318
- }
11319
- };
11320
- var ProcessSpawnError = class extends ProcessError {
11321
- constructor(command2, details) {
11322
- super(`Error executing command '${command2}': ${details}`);
11323
- this.name = "ProcessSpawnError";
11324
- }
11325
- };
11326
-
11327
- // ../process/src/spawn.ts
11328
- import {
11329
- spawn as nodeSpawn
11330
- } from "node:child_process";
11331
- async function spawnProcess(config2) {
11332
- return new Promise((resolve2) => {
11333
- const { command: command2, args: args2 = [], options = {} } = config2;
11334
- const childProcess = nodeSpawn(command2, args2, {
11335
- stdio: "inherit",
11336
- ...options
11337
- });
11338
- childProcess.on("error", (error2) => {
11339
- resolve2(err(new ProcessSpawnError(command2, error2.message)));
11340
- });
11341
- childProcess.on("exit", (code, signal) => {
11342
- if (signal) {
11343
- resolve2(err(new ProcessSignalError(signal)));
11344
- } else {
11345
- const exitCode = code ?? 0;
11346
- if (exitCode === 0) {
11347
- resolve2(ok({ exitCode }));
11348
- } else {
11349
- resolve2(err(new ProcessExecutionError(command2, exitCode)));
11350
- }
11351
- }
11352
- });
11353
- });
11354
- }
11355
-
11356
- // ../process/src/tmux.ts
11357
- async function isInsideTmux() {
11358
- return process.env.TMUX !== void 0;
11359
- }
11360
- async function executeTmuxCommand(options) {
11361
- const { direction, command: command2, args: args2, cwd, env, windowName } = options;
11362
- const tmuxArgs = [];
11363
- switch (direction) {
11364
- case "new":
11365
- tmuxArgs.push("new-window");
11366
- if (windowName) {
11367
- tmuxArgs.push("-n", windowName);
11368
- }
11369
- break;
11370
- case "vertical":
11371
- tmuxArgs.push("split-window", "-v");
11372
- break;
11373
- case "horizontal":
11374
- tmuxArgs.push("split-window", "-h");
11375
- break;
11376
- }
11377
- if (cwd) {
11378
- tmuxArgs.push("-c", cwd);
11379
- }
11380
- if (env) {
11381
- for (const [key, value] of Object.entries(env)) {
11382
- tmuxArgs.push("-e", `${key}=${value}`);
11383
- }
11384
- }
11385
- tmuxArgs.push(command2);
11386
- if (args2 && args2.length > 0) {
11387
- tmuxArgs.push(...args2);
11388
- }
11389
- const result = await spawnProcess({
11390
- command: "tmux",
11391
- args: tmuxArgs
11392
- });
11393
- return result;
11394
- }
11395
-
11396
- // ../process/src/env.ts
11397
- function getPhantomEnv(worktreeName, worktreePath) {
11398
- return {
11399
- PHANTOM: "1",
11400
- PHANTOM_NAME: worktreeName,
11401
- PHANTOM_PATH: worktreePath
11402
- };
11403
- }
11404
-
11405
- // ../process/src/fzf.ts
11406
- import { spawn } from "node:child_process";
11407
- async function selectWithFzf(items, options = {}) {
11408
- return new Promise((resolve2) => {
11409
- const args2 = [];
11410
- if (options.prompt) {
11411
- args2.push("--prompt", options.prompt);
11412
- }
11413
- if (options.header) {
11414
- args2.push("--header", options.header);
11415
- }
11416
- if (options.previewCommand) {
11417
- args2.push("--preview", options.previewCommand);
11418
- }
11419
- const fzf = spawn("fzf", args2, {
11420
- stdio: ["pipe", "pipe", "pipe"]
11421
- });
11422
- let result = "";
11423
- let errorOutput = "";
11424
- fzf.stdout.on("data", (data) => {
11425
- result += data.toString();
11426
- });
11427
- if (fzf.stderr) {
11428
- fzf.stderr.on("data", (data) => {
11429
- errorOutput += data.toString();
11430
+ async function listWorktrees2(gitRoot) {
11431
+ try {
11432
+ const gitWorktrees = await listWorktrees(gitRoot);
11433
+ const filteredWorktrees = gitWorktrees.filter(
11434
+ (worktree) => Boolean(relative(gitRoot, worktree.path))
11435
+ );
11436
+ if (filteredWorktrees.length === 0) {
11437
+ return ok({
11438
+ worktrees: [],
11439
+ message: "No worktrees found"
11430
11440
  });
11431
11441
  }
11432
- fzf.on("error", (error2) => {
11433
- if (error2.message.includes("ENOENT")) {
11434
- resolve2(
11435
- err(new Error("fzf command not found. Please install fzf first."))
11436
- );
11437
- } else {
11438
- resolve2(err(error2));
11439
- }
11440
- });
11441
- fzf.on("close", (code) => {
11442
- if (code === 0) {
11443
- const selected = result.trim();
11444
- resolve2(ok(selected || null));
11445
- } else if (code === 1) {
11446
- resolve2(ok(null));
11447
- } else if (code === 130) {
11448
- resolve2(ok(null));
11449
- } else {
11450
- resolve2(err(new Error(`fzf exited with code ${code}: ${errorOutput}`)));
11451
- }
11442
+ const worktrees = await Promise.all(
11443
+ filteredWorktrees.map(async (gitWorktree) => {
11444
+ const shortHead = gitWorktree.head?.slice(0, 7) ?? "HEAD";
11445
+ const branchName = gitWorktree.branch && gitWorktree.branch !== "(detached HEAD)" ? gitWorktree.branch : shortHead;
11446
+ const isClean = await getWorktreeStatus(gitWorktree.path);
11447
+ const pathToDisplay = relative(process.cwd(), gitWorktree.path) || ".";
11448
+ return {
11449
+ name: branchName,
11450
+ path: gitWorktree.path,
11451
+ pathToDisplay,
11452
+ branch: branchName,
11453
+ isClean
11454
+ };
11455
+ })
11456
+ );
11457
+ return ok({
11458
+ worktrees
11452
11459
  });
11453
- fzf.stdin.write(items.join("\n"));
11454
- fzf.stdin.end();
11455
- });
11460
+ } catch (error2) {
11461
+ const errorMessage = error2 instanceof Error ? error2.message : String(error2);
11462
+ throw new Error(`Failed to list worktrees: ${errorMessage}`);
11463
+ }
11456
11464
  }
11457
11465
 
11458
11466
  // ../core/src/worktree/validate.ts
11459
- import fs2 from "node:fs/promises";
11460
- async function validateWorktreeExists(_gitRoot, worktreeDirectory, name) {
11461
- const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
11462
- try {
11463
- await fs2.access(worktreePath);
11464
- return ok({ path: worktreePath });
11465
- } catch {
11467
+ async function validateWorktreeExists(gitRoot, _worktreeDirectory, name) {
11468
+ const worktreesResult = await listWorktrees2(gitRoot);
11469
+ if (isErr(worktreesResult)) {
11470
+ return err(new WorktreeNotFoundError(name));
11471
+ }
11472
+ const worktree = worktreesResult.value.worktrees.find(
11473
+ (wt) => wt.name === name
11474
+ );
11475
+ if (!worktree) {
11466
11476
  return err(new WorktreeNotFoundError(name));
11467
11477
  }
11478
+ return ok({ path: worktree.path });
11468
11479
  }
11469
- async function validateWorktreeDoesNotExist(_gitRoot, worktreeDirectory, name) {
11470
- const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
11471
- try {
11472
- await fs2.access(worktreePath);
11480
+ async function validateWorktreeDoesNotExist(gitRoot, _worktreeDirectory, name) {
11481
+ const worktreesResult = await listWorktrees2(gitRoot);
11482
+ if (isErr(worktreesResult)) {
11473
11483
  return err(new WorktreeAlreadyExistsError(name));
11474
- } catch {
11475
- return ok({ path: worktreePath });
11476
11484
  }
11485
+ const worktree = worktreesResult.value.worktrees.find(
11486
+ (wt) => wt.name === name
11487
+ );
11488
+ if (worktree) {
11489
+ return err(new WorktreeAlreadyExistsError(name));
11490
+ }
11491
+ return ok(void 0);
11477
11492
  }
11478
11493
  function validateWorktreeName(name) {
11479
11494
  if (!name || name.trim() === "") {
11480
11495
  return err(new Error("Phantom name cannot be empty"));
11481
11496
  }
11482
- const validNamePattern = /^[a-zA-Z0-9\-_.\/]+$/;
11497
+ const validNamePattern = /^[a-zA-Z0-9\-_./]+$/;
11483
11498
  if (!validNamePattern.test(name)) {
11484
11499
  return err(
11485
11500
  new Error(
@@ -11516,6 +11531,77 @@ async function execInWorktree(gitRoot, worktreeDirectory, worktreeName, command2
11516
11531
  });
11517
11532
  }
11518
11533
 
11534
+ // ../core/src/shell.ts
11535
+ async function shellInWorktree(gitRoot, worktreeDirectory, worktreeName) {
11536
+ const validation = await validateWorktreeExists(
11537
+ gitRoot,
11538
+ worktreeDirectory,
11539
+ worktreeName
11540
+ );
11541
+ if (isErr(validation)) {
11542
+ return err(validation.error);
11543
+ }
11544
+ const worktreePath = validation.value.path;
11545
+ const shell = process.env.SHELL || "/bin/sh";
11546
+ return spawnProcess({
11547
+ command: shell,
11548
+ args: [],
11549
+ options: {
11550
+ cwd: worktreePath,
11551
+ env: {
11552
+ ...process.env,
11553
+ ...getPhantomEnv(worktreeName, worktreePath)
11554
+ }
11555
+ }
11556
+ });
11557
+ }
11558
+
11559
+ // ../core/src/worktree/attach.ts
11560
+ import { existsSync } from "node:fs";
11561
+
11562
+ // ../core/src/worktree/file-copier.ts
11563
+ import { copyFile, mkdir, stat } from "node:fs/promises";
11564
+ import path2 from "node:path";
11565
+ var FileCopyError = class extends Error {
11566
+ file;
11567
+ constructor(file, message) {
11568
+ super(`Failed to copy ${file}: ${message}`);
11569
+ this.name = "FileCopyError";
11570
+ this.file = file;
11571
+ }
11572
+ };
11573
+ async function copyFiles(sourceDir, targetDir, files) {
11574
+ const copiedFiles = [];
11575
+ const skippedFiles = [];
11576
+ for (const file of files) {
11577
+ const sourcePath = path2.join(sourceDir, file);
11578
+ const targetPath = path2.join(targetDir, file);
11579
+ try {
11580
+ const stats = await stat(sourcePath);
11581
+ if (!stats.isFile()) {
11582
+ skippedFiles.push(file);
11583
+ continue;
11584
+ }
11585
+ const targetDirPath = path2.dirname(targetPath);
11586
+ await mkdir(targetDirPath, { recursive: true });
11587
+ await copyFile(sourcePath, targetPath);
11588
+ copiedFiles.push(file);
11589
+ } catch (error2) {
11590
+ if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT") {
11591
+ skippedFiles.push(file);
11592
+ } else {
11593
+ return err(
11594
+ new FileCopyError(
11595
+ file,
11596
+ error2 instanceof Error ? error2.message : String(error2)
11597
+ )
11598
+ );
11599
+ }
11600
+ }
11601
+ }
11602
+ return ok({ copiedFiles, skippedFiles });
11603
+ }
11604
+
11519
11605
  // ../core/src/worktree/post-create.ts
11520
11606
  async function executePostCreateCommands(options) {
11521
11607
  const { gitRoot, worktreesDirectory, worktreeName, commands: commands2 } = options;
@@ -11560,7 +11646,57 @@ async function copyFilesToWorktree(gitRoot, worktreesDirectory, worktreeName, fi
11560
11646
  return ok(void 0);
11561
11647
  }
11562
11648
 
11649
+ // ../core/src/worktree/attach.ts
11650
+ async function attachWorktreeCore(gitRoot, worktreeDirectory, name, postCreateCopyFiles, postCreateCommands) {
11651
+ const validation = validateWorktreeName(name);
11652
+ if (isErr(validation)) {
11653
+ return validation;
11654
+ }
11655
+ const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
11656
+ if (existsSync(worktreePath)) {
11657
+ return err(new WorktreeAlreadyExistsError(name));
11658
+ }
11659
+ const branchCheckResult = await branchExists(gitRoot, name);
11660
+ if (isErr(branchCheckResult)) {
11661
+ return err(branchCheckResult.error);
11662
+ }
11663
+ if (!branchCheckResult.value) {
11664
+ return err(new BranchNotFoundError(name));
11665
+ }
11666
+ const attachResult = await attachWorktree(gitRoot, worktreePath, name);
11667
+ if (isErr(attachResult)) {
11668
+ return err(attachResult.error);
11669
+ }
11670
+ if (postCreateCopyFiles && postCreateCopyFiles.length > 0) {
11671
+ const copyResult = await copyFilesToWorktree(
11672
+ gitRoot,
11673
+ worktreeDirectory,
11674
+ name,
11675
+ postCreateCopyFiles
11676
+ );
11677
+ if (isErr(copyResult)) {
11678
+ console.warn(
11679
+ `Warning: Failed to copy some files: ${copyResult.error.message}`
11680
+ );
11681
+ }
11682
+ }
11683
+ if (postCreateCommands && postCreateCommands.length > 0) {
11684
+ console.log("\nRunning post-create commands...");
11685
+ const commandsResult = await executePostCreateCommands({
11686
+ gitRoot,
11687
+ worktreesDirectory: worktreeDirectory,
11688
+ worktreeName: name,
11689
+ commands: postCreateCommands
11690
+ });
11691
+ if (isErr(commandsResult)) {
11692
+ return err(new WorktreeError(commandsResult.error.message));
11693
+ }
11694
+ }
11695
+ return ok(worktreePath);
11696
+ }
11697
+
11563
11698
  // ../core/src/worktree/create.ts
11699
+ import fs3 from "node:fs/promises";
11564
11700
  async function createWorktree(gitRoot, worktreeDirectory, name, options, postCreateCopyFiles, postCreateCommands) {
11565
11701
  const nameValidation = validateWorktreeName(name);
11566
11702
  if (isErr(nameValidation)) {
@@ -11687,187 +11823,34 @@ async function getWorktreeChangesStatus(worktreePath) {
11687
11823
  changedFiles: stdout2.split("\n").length
11688
11824
  };
11689
11825
  }
11690
- } catch {
11691
- }
11692
- return {
11693
- hasUncommittedChanges: false,
11694
- changedFiles: 0
11695
- };
11696
- }
11697
- async function removeWorktree(gitRoot, worktreePath, force = false) {
11698
- const args2 = ["worktree", "remove"];
11699
- if (force) {
11700
- args2.push("--force");
11701
- }
11702
- args2.push(worktreePath);
11703
- await executeGitCommand(args2, {
11704
- cwd: gitRoot
11705
- });
11706
- }
11707
- async function deleteBranch(gitRoot, branchName) {
11708
- try {
11709
- await executeGitCommand(["branch", "-D", branchName], { cwd: gitRoot });
11710
- return ok(true);
11711
- } catch (error2) {
11712
- const errorMessage = error2 instanceof Error ? error2.message : String(error2);
11713
- return err(new WorktreeError(`branch delete failed: ${errorMessage}`));
11714
- }
11715
- }
11716
- async function deleteWorktree(gitRoot, worktreeDirectory, name, options, preDeleteCommands) {
11717
- const { force = false } = options || {};
11718
- const validation = await validateWorktreeExists(
11719
- gitRoot,
11720
- worktreeDirectory,
11721
- name
11722
- );
11723
- if (isErr(validation)) {
11724
- return err(validation.error);
11725
- }
11726
- const worktreePath = validation.value.path;
11727
- const status = await getWorktreeChangesStatus(worktreePath);
11728
- if (status.hasUncommittedChanges && !force) {
11729
- return err(
11730
- new WorktreeError(
11731
- `Worktree '${name}' has uncommitted changes (${status.changedFiles} files). Use --force to delete anyway.`
11732
- )
11733
- );
11734
- }
11735
- if (preDeleteCommands && preDeleteCommands.length > 0) {
11736
- console.log("\nRunning pre-delete commands...");
11737
- const preDeleteResult = await executePreDeleteCommands({
11738
- gitRoot,
11739
- worktreesDirectory: worktreeDirectory,
11740
- worktreeName: name,
11741
- commands: preDeleteCommands
11742
- });
11743
- if (isErr(preDeleteResult)) {
11744
- return err(new WorktreeError(preDeleteResult.error.message));
11745
- }
11746
- }
11747
- try {
11748
- await removeWorktree(gitRoot, worktreePath, force);
11749
- const branchName = name;
11750
- const branchResult = await deleteBranch(gitRoot, branchName);
11751
- let message;
11752
- if (isOk(branchResult)) {
11753
- message = `Deleted worktree '${name}' and its branch '${branchName}'`;
11754
- } else {
11755
- message = `Deleted worktree '${name}'`;
11756
- message += `
11757
- Note: Branch '${branchName}' could not be deleted: ${branchResult.error.message}`;
11758
- }
11759
- if (status.hasUncommittedChanges) {
11760
- message = `Warning: Worktree '${name}' had uncommitted changes (${status.changedFiles} files)
11761
- ${message}`;
11762
- }
11763
- return ok({
11764
- message,
11765
- hasUncommittedChanges: status.hasUncommittedChanges,
11766
- changedFiles: status.hasUncommittedChanges ? status.changedFiles : void 0
11767
- });
11768
- } catch (error2) {
11769
- const errorMessage = error2 instanceof Error ? error2.message : String(error2);
11770
- return err(new WorktreeError(`worktree remove failed: ${errorMessage}`));
11771
- }
11772
- }
11773
-
11774
- // ../core/src/worktree/list.ts
11775
- async function getWorktreeStatus(worktreePath) {
11776
- try {
11777
- const { stdout: stdout2 } = await executeGitCommandInDirectory(worktreePath, [
11778
- "status",
11779
- "--porcelain"
11780
- ]);
11781
- return !stdout2;
11782
- } catch {
11783
- return true;
11784
- }
11785
- }
11786
- async function listWorktrees2(gitRoot, worktreeDirectory) {
11787
- try {
11788
- const gitWorktrees = await listWorktrees(gitRoot);
11789
- const phantomWorktrees = gitWorktrees.filter(
11790
- (worktree) => worktree.path.startsWith(worktreeDirectory)
11791
- );
11792
- if (phantomWorktrees.length === 0) {
11793
- return ok({
11794
- worktrees: [],
11795
- message: "No worktrees found"
11796
- });
11797
- }
11798
- const worktrees = await Promise.all(
11799
- phantomWorktrees.map(async (gitWorktree) => {
11800
- const name = gitWorktree.path.substring(worktreeDirectory.length + 1);
11801
- const isClean = await getWorktreeStatus(gitWorktree.path);
11802
- return {
11803
- name,
11804
- path: gitWorktree.path,
11805
- branch: gitWorktree.branch || "(detached HEAD)",
11806
- isClean
11807
- };
11808
- })
11809
- );
11810
- return ok({
11811
- worktrees
11812
- });
11813
- } catch (error2) {
11814
- const errorMessage = error2 instanceof Error ? error2.message : String(error2);
11815
- throw new Error(`Failed to list worktrees: ${errorMessage}`);
11816
- }
11817
- }
11818
-
11819
- // ../core/src/worktree/attach.ts
11820
- import { existsSync } from "node:fs";
11821
- async function attachWorktreeCore(gitRoot, worktreeDirectory, name, postCreateCopyFiles, postCreateCommands) {
11822
- const validation = validateWorktreeName(name);
11823
- if (isErr(validation)) {
11824
- return validation;
11825
- }
11826
- const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
11827
- if (existsSync(worktreePath)) {
11828
- return err(new WorktreeAlreadyExistsError(name));
11829
- }
11830
- const branchCheckResult = await branchExists(gitRoot, name);
11831
- if (isErr(branchCheckResult)) {
11832
- return err(branchCheckResult.error);
11833
- }
11834
- if (!branchCheckResult.value) {
11835
- return err(new BranchNotFoundError(name));
11836
- }
11837
- const attachResult = await attachWorktree(gitRoot, worktreePath, name);
11838
- if (isErr(attachResult)) {
11839
- return err(attachResult.error);
11840
- }
11841
- if (postCreateCopyFiles && postCreateCopyFiles.length > 0) {
11842
- const copyResult = await copyFilesToWorktree(
11843
- gitRoot,
11844
- worktreeDirectory,
11845
- name,
11846
- postCreateCopyFiles
11847
- );
11848
- if (isErr(copyResult)) {
11849
- console.warn(
11850
- `Warning: Failed to copy some files: ${copyResult.error.message}`
11851
- );
11852
- }
11826
+ } catch {
11853
11827
  }
11854
- if (postCreateCommands && postCreateCommands.length > 0) {
11855
- console.log("\nRunning post-create commands...");
11856
- const commandsResult = await executePostCreateCommands({
11857
- gitRoot,
11858
- worktreesDirectory: worktreeDirectory,
11859
- worktreeName: name,
11860
- commands: postCreateCommands
11861
- });
11862
- if (isErr(commandsResult)) {
11863
- return err(new WorktreeError(commandsResult.error.message));
11864
- }
11828
+ return {
11829
+ hasUncommittedChanges: false,
11830
+ changedFiles: 0
11831
+ };
11832
+ }
11833
+ async function removeWorktree(gitRoot, worktreePath, force = false) {
11834
+ const args2 = ["worktree", "remove"];
11835
+ if (force) {
11836
+ args2.push("--force");
11865
11837
  }
11866
- return ok(worktreePath);
11838
+ args2.push(worktreePath);
11839
+ await executeGitCommand(args2, {
11840
+ cwd: gitRoot
11841
+ });
11867
11842
  }
11868
-
11869
- // ../core/src/worktree/where.ts
11870
- async function whereWorktree(gitRoot, worktreeDirectory, name) {
11843
+ async function deleteBranch(gitRoot, branchName) {
11844
+ try {
11845
+ await executeGitCommand(["branch", "-D", branchName], { cwd: gitRoot });
11846
+ return ok(true);
11847
+ } catch (error2) {
11848
+ const errorMessage = error2 instanceof Error ? error2.message : String(error2);
11849
+ return err(new WorktreeError(`branch delete failed: ${errorMessage}`));
11850
+ }
11851
+ }
11852
+ async function deleteWorktree(gitRoot, worktreeDirectory, name, options, preDeleteCommands) {
11853
+ const { force = false } = options || {};
11871
11854
  const validation = await validateWorktreeExists(
11872
11855
  gitRoot,
11873
11856
  worktreeDirectory,
@@ -11876,14 +11859,57 @@ async function whereWorktree(gitRoot, worktreeDirectory, name) {
11876
11859
  if (isErr(validation)) {
11877
11860
  return err(validation.error);
11878
11861
  }
11879
- return ok({
11880
- path: validation.value.path
11881
- });
11862
+ const worktreePath = validation.value.path;
11863
+ const status = await getWorktreeChangesStatus(worktreePath);
11864
+ if (status.hasUncommittedChanges && !force) {
11865
+ return err(
11866
+ new WorktreeError(
11867
+ `Worktree '${name}' has uncommitted changes (${status.changedFiles} files). Use --force to delete anyway.`
11868
+ )
11869
+ );
11870
+ }
11871
+ if (preDeleteCommands && preDeleteCommands.length > 0) {
11872
+ console.log("\nRunning pre-delete commands...");
11873
+ const preDeleteResult = await executePreDeleteCommands({
11874
+ gitRoot,
11875
+ worktreesDirectory: worktreeDirectory,
11876
+ worktreeName: name,
11877
+ commands: preDeleteCommands
11878
+ });
11879
+ if (isErr(preDeleteResult)) {
11880
+ return err(new WorktreeError(preDeleteResult.error.message));
11881
+ }
11882
+ }
11883
+ try {
11884
+ await removeWorktree(gitRoot, worktreePath, force);
11885
+ const branchName = name;
11886
+ const branchResult = await deleteBranch(gitRoot, branchName);
11887
+ let message;
11888
+ if (isOk(branchResult)) {
11889
+ message = `Deleted worktree '${name}' and its branch '${branchName}'`;
11890
+ } else {
11891
+ message = `Deleted worktree '${name}'`;
11892
+ message += `
11893
+ Note: Branch '${branchName}' could not be deleted: ${branchResult.error.message}`;
11894
+ }
11895
+ if (status.hasUncommittedChanges) {
11896
+ message = `Warning: Worktree '${name}' had uncommitted changes (${status.changedFiles} files)
11897
+ ${message}`;
11898
+ }
11899
+ return ok({
11900
+ message,
11901
+ hasUncommittedChanges: status.hasUncommittedChanges,
11902
+ changedFiles: status.hasUncommittedChanges ? status.changedFiles : void 0
11903
+ });
11904
+ } catch (error2) {
11905
+ const errorMessage = error2 instanceof Error ? error2.message : String(error2);
11906
+ return err(new WorktreeError(`worktree remove failed: ${errorMessage}`));
11907
+ }
11882
11908
  }
11883
11909
 
11884
11910
  // ../core/src/worktree/select.ts
11885
- async function selectWorktreeWithFzf(gitRoot, worktreeDirectory) {
11886
- const listResult = await listWorktrees2(gitRoot, worktreeDirectory);
11911
+ async function selectWorktreeWithFzf(gitRoot) {
11912
+ const listResult = await listWorktrees2(gitRoot);
11887
11913
  if (isErr(listResult)) {
11888
11914
  return listResult;
11889
11915
  }
@@ -11895,9 +11921,8 @@ async function selectWorktreeWithFzf(gitRoot, worktreeDirectory) {
11895
11921
  };
11896
11922
  }
11897
11923
  const list = worktrees.map((wt) => {
11898
- const branchInfo = wt.branch ? `(${wt.branch})` : "";
11899
11924
  const status = !wt.isClean ? " [dirty]" : "";
11900
- return `${wt.name} ${branchInfo}${status}`;
11925
+ return `${wt.name} (${wt.pathToDisplay})${status}`;
11901
11926
  });
11902
11927
  const fzfResult = await selectWithFzf(list, {
11903
11928
  prompt: "Select worktree> ",
@@ -11930,28 +11955,18 @@ async function selectWorktreeWithFzf(gitRoot, worktreeDirectory) {
11930
11955
  };
11931
11956
  }
11932
11957
 
11933
- // ../core/src/shell.ts
11934
- async function shellInWorktree(gitRoot, worktreeDirectory, worktreeName) {
11958
+ // ../core/src/worktree/where.ts
11959
+ async function whereWorktree(gitRoot, worktreeDirectory, name) {
11935
11960
  const validation = await validateWorktreeExists(
11936
11961
  gitRoot,
11937
11962
  worktreeDirectory,
11938
- worktreeName
11963
+ name
11939
11964
  );
11940
11965
  if (isErr(validation)) {
11941
11966
  return err(validation.error);
11942
11967
  }
11943
- const worktreePath = validation.value.path;
11944
- const shell = process.env.SHELL || "/bin/sh";
11945
- return spawnProcess({
11946
- command: shell,
11947
- args: [],
11948
- options: {
11949
- cwd: worktreePath,
11950
- env: {
11951
- ...process.env,
11952
- ...getPhantomEnv(worktreeName, worktreePath)
11953
- }
11954
- }
11968
+ return ok({
11969
+ path: validation.value.path
11955
11970
  });
11956
11971
  }
11957
11972
 
@@ -12745,10 +12760,7 @@ async function deleteHandler(args2) {
12745
12760
  }
12746
12761
  worktreeName = currentWorktree;
12747
12762
  } else if (useFzf) {
12748
- const selectResult = await selectWorktreeWithFzf(
12749
- context.gitRoot,
12750
- context.worktreesDirectory
12751
- );
12763
+ const selectResult = await selectWorktreeWithFzf(context.gitRoot);
12752
12764
  if (isErr(selectResult)) {
12753
12765
  exitWithError(selectResult.error.message, exitCodes.generalError);
12754
12766
  }
@@ -12838,119 +12850,299 @@ async function execHandler(args2) {
12838
12850
  exitCodes.validationError
12839
12851
  );
12840
12852
  }
12841
- commandArgs = positionals.slice(1);
12853
+ commandArgs = positionals.slice(1);
12854
+ }
12855
+ try {
12856
+ const gitRoot = await getGitRoot();
12857
+ const context = await createContext(gitRoot);
12858
+ if (tmuxOption && !await isInsideTmux()) {
12859
+ exitWithError(
12860
+ "The --tmux option can only be used inside a tmux session",
12861
+ exitCodes.validationError
12862
+ );
12863
+ }
12864
+ let worktreeName;
12865
+ if (useFzf) {
12866
+ const selectResult = await selectWorktreeWithFzf(context.gitRoot);
12867
+ if (isErr(selectResult)) {
12868
+ exitWithError(selectResult.error.message, exitCodes.generalError);
12869
+ }
12870
+ if (!selectResult.value) {
12871
+ exitWithSuccess();
12872
+ }
12873
+ worktreeName = selectResult.value.name;
12874
+ } else {
12875
+ worktreeName = positionals[0];
12876
+ }
12877
+ const validation = await validateWorktreeExists(
12878
+ context.gitRoot,
12879
+ context.worktreesDirectory,
12880
+ worktreeName
12881
+ );
12882
+ if (isErr(validation)) {
12883
+ exitWithError(validation.error.message, exitCodes.generalError);
12884
+ }
12885
+ if (tmuxDirection) {
12886
+ output.log(
12887
+ `Executing command in worktree '${worktreeName}' in tmux ${tmuxDirection === "new" ? "window" : "pane"}...`
12888
+ );
12889
+ const [command2, ...args3] = commandArgs;
12890
+ const tmuxResult = await executeTmuxCommand({
12891
+ direction: tmuxDirection,
12892
+ command: command2,
12893
+ args: args3,
12894
+ cwd: validation.value.path,
12895
+ env: getPhantomEnv(worktreeName, validation.value.path),
12896
+ windowName: tmuxDirection === "new" ? worktreeName : void 0
12897
+ });
12898
+ if (isErr(tmuxResult)) {
12899
+ output.error(tmuxResult.error.message);
12900
+ const exitCode = "exitCode" in tmuxResult.error ? tmuxResult.error.exitCode ?? exitCodes.generalError : exitCodes.generalError;
12901
+ exitWithError("", exitCode);
12902
+ }
12903
+ exitWithSuccess();
12904
+ }
12905
+ const result = await execInWorktree(
12906
+ context.gitRoot,
12907
+ context.worktreesDirectory,
12908
+ worktreeName,
12909
+ commandArgs,
12910
+ { interactive: true }
12911
+ );
12912
+ if (isErr(result)) {
12913
+ const exitCode = result.error instanceof WorktreeNotFoundError ? exitCodes.notFound : result.error.exitCode || exitCodes.generalError;
12914
+ exitWithError(result.error.message, exitCode);
12915
+ }
12916
+ process.exit(result.value.exitCode);
12917
+ } catch (error2) {
12918
+ exitWithError(
12919
+ error2 instanceof Error ? error2.message : String(error2),
12920
+ exitCodes.generalError
12921
+ );
12922
+ }
12923
+ }
12924
+
12925
+ // src/help/github.ts
12926
+ var githubHelp = {
12927
+ name: "github",
12928
+ usage: "phantom github <subcommand> [options]",
12929
+ description: "GitHub-specific commands for phantom",
12930
+ examples: [
12931
+ {
12932
+ command: "phantom github checkout 123",
12933
+ description: "Create a worktree for PR or issue #123"
12934
+ },
12935
+ {
12936
+ command: "phantom gh checkout 456",
12937
+ description: "Same as above, using the gh alias"
12938
+ }
12939
+ ],
12940
+ notes: [
12941
+ "Subcommands:",
12942
+ " checkout Create a worktree for a GitHub PR or issue",
12943
+ "",
12944
+ "Alias: 'gh' can be used instead of 'github'",
12945
+ "",
12946
+ "Requirements:",
12947
+ " - GitHub CLI (gh) must be installed",
12948
+ " - Must be authenticated with 'gh auth login'"
12949
+ ]
12950
+ };
12951
+ var githubCheckoutHelp = {
12952
+ name: "github checkout",
12953
+ usage: "phantom github checkout <number> [options]",
12954
+ description: "Create a worktree for a GitHub PR or issue",
12955
+ options: [
12956
+ {
12957
+ name: "--base",
12958
+ type: "string",
12959
+ description: "Base branch for new issue branches (issues only, default: repository HEAD)"
12960
+ }
12961
+ ],
12962
+ examples: [
12963
+ {
12964
+ command: "phantom github checkout 123",
12965
+ description: "Create a worktree for PR #123 (checks out PR branch)"
12966
+ },
12967
+ {
12968
+ command: "phantom github checkout 456",
12969
+ description: "Create a worktree for issue #456 (creates new branch)"
12970
+ },
12971
+ {
12972
+ command: "phantom github checkout 789 --base develop",
12973
+ description: "Create a worktree for issue #789 based on develop branch"
12974
+ }
12975
+ ],
12976
+ notes: [
12977
+ "For PRs: Creates worktree named 'pulls/{number}' with the PR's branch",
12978
+ "For Issues: Creates worktree named 'issues/{number}' with a new branch",
12979
+ "",
12980
+ "Requirements:",
12981
+ " - GitHub CLI (gh) must be installed",
12982
+ " - Must be authenticated with 'gh auth login'"
12983
+ ]
12984
+ };
12985
+
12986
+ // src/help.ts
12987
+ import { stdout } from "node:process";
12988
+ var HelpFormatter = class {
12989
+ width;
12990
+ indent = " ";
12991
+ constructor() {
12992
+ this.width = stdout.columns || 80;
12993
+ }
12994
+ formatMainHelp(commands2) {
12995
+ const lines = [];
12996
+ lines.push(this.bold("Phantom - Git Worktree Manager"));
12997
+ lines.push("");
12998
+ lines.push(
12999
+ this.dim(
13000
+ "A CLI tool for managing Git worktrees with enhanced functionality"
13001
+ )
13002
+ );
13003
+ lines.push("");
13004
+ lines.push(this.section("USAGE"));
13005
+ lines.push(`${this.indent}phantom <command> [options]`);
13006
+ lines.push("");
13007
+ lines.push(this.section("COMMANDS"));
13008
+ const maxNameLength = Math.max(...commands2.map((cmd) => cmd.name.length));
13009
+ for (const cmd of commands2) {
13010
+ const paddedName = cmd.name.padEnd(maxNameLength + 2);
13011
+ lines.push(`${this.indent}${this.cyan(paddedName)}${cmd.description}`);
13012
+ }
13013
+ lines.push("");
13014
+ lines.push(this.section("GLOBAL OPTIONS"));
13015
+ const helpOption = "-h, --help";
13016
+ const versionOption = "-v, --version";
13017
+ const globalOptionWidth = Math.max(helpOption.length, versionOption.length) + 2;
13018
+ lines.push(
13019
+ `${this.indent}${this.cyan(helpOption.padEnd(globalOptionWidth))}Show help`
13020
+ );
13021
+ lines.push(
13022
+ `${this.indent}${this.cyan(versionOption.padEnd(globalOptionWidth))}Show version`
13023
+ );
13024
+ lines.push("");
13025
+ lines.push(
13026
+ this.dim(
13027
+ "Run 'phantom <command> --help' for more information on a command."
13028
+ )
13029
+ );
13030
+ return lines.join("\n");
12842
13031
  }
12843
- try {
12844
- const gitRoot = await getGitRoot();
12845
- const context = await createContext(gitRoot);
12846
- if (tmuxOption && !await isInsideTmux()) {
12847
- exitWithError(
12848
- "The --tmux option can only be used inside a tmux session",
12849
- exitCodes.validationError
13032
+ formatCommandHelp(help) {
13033
+ const lines = [];
13034
+ lines.push(this.bold(`phantom ${help.name}`));
13035
+ lines.push(this.dim(help.description));
13036
+ lines.push("");
13037
+ lines.push(this.section("USAGE"));
13038
+ lines.push(`${this.indent}${help.usage}`);
13039
+ lines.push("");
13040
+ if (help.options && help.options.length > 0) {
13041
+ lines.push(this.section("OPTIONS"));
13042
+ const maxOptionLength = Math.max(
13043
+ ...help.options.map((opt) => this.formatOptionName(opt).length)
12850
13044
  );
13045
+ for (const option of help.options) {
13046
+ const optionName = this.formatOptionName(option);
13047
+ const paddedName = optionName.padEnd(maxOptionLength + 2);
13048
+ const description = this.wrapText(
13049
+ option.description,
13050
+ maxOptionLength + 4
13051
+ );
13052
+ lines.push(`${this.indent}${this.cyan(paddedName)}${description[0]}`);
13053
+ for (let i = 1; i < description.length; i++) {
13054
+ lines.push(
13055
+ `${this.indent}${" ".repeat(maxOptionLength + 2)}${description[i]}`
13056
+ );
13057
+ }
13058
+ if (option.example) {
13059
+ const exampleIndent = " ".repeat(maxOptionLength + 4);
13060
+ lines.push(
13061
+ `${this.indent}${exampleIndent}${this.dim(`Example: ${option.example}`)}`
13062
+ );
13063
+ }
13064
+ }
13065
+ lines.push("");
12851
13066
  }
12852
- let worktreeName;
12853
- if (useFzf) {
12854
- const selectResult = await selectWorktreeWithFzf(
12855
- context.gitRoot,
12856
- context.worktreesDirectory
12857
- );
12858
- if (isErr(selectResult)) {
12859
- exitWithError(selectResult.error.message, exitCodes.generalError);
13067
+ if (help.examples && help.examples.length > 0) {
13068
+ lines.push(this.section("EXAMPLES"));
13069
+ for (const example of help.examples) {
13070
+ lines.push(`${this.indent}${this.dim(example.description)}`);
13071
+ lines.push(`${this.indent}${this.indent}$ ${example.command}`);
13072
+ lines.push("");
12860
13073
  }
12861
- if (!selectResult.value) {
12862
- exitWithSuccess();
13074
+ }
13075
+ if (help.notes && help.notes.length > 0) {
13076
+ lines.push(this.section("NOTES"));
13077
+ for (const note of help.notes) {
13078
+ const wrappedNote = this.wrapText(note, 2);
13079
+ for (const line of wrappedNote) {
13080
+ lines.push(`${this.indent}${line}`);
13081
+ }
12863
13082
  }
12864
- worktreeName = selectResult.value.name;
12865
- } else {
12866
- worktreeName = positionals[0];
13083
+ lines.push("");
12867
13084
  }
12868
- const validation = await validateWorktreeExists(
12869
- context.gitRoot,
12870
- context.worktreesDirectory,
12871
- worktreeName
12872
- );
12873
- if (isErr(validation)) {
12874
- exitWithError(validation.error.message, exitCodes.generalError);
13085
+ return lines.join("\n");
13086
+ }
13087
+ formatOptionName(option) {
13088
+ const parts = [];
13089
+ if (option.short) {
13090
+ parts.push(`-${option.short},`);
12875
13091
  }
12876
- if (tmuxDirection) {
12877
- output.log(
12878
- `Executing command in worktree '${worktreeName}' in tmux ${tmuxDirection === "new" ? "window" : "pane"}...`
12879
- );
12880
- const [command2, ...args3] = commandArgs;
12881
- const tmuxResult = await executeTmuxCommand({
12882
- direction: tmuxDirection,
12883
- command: command2,
12884
- args: args3,
12885
- cwd: validation.value.path,
12886
- env: getPhantomEnv(worktreeName, validation.value.path),
12887
- windowName: tmuxDirection === "new" ? worktreeName : void 0
12888
- });
12889
- if (isErr(tmuxResult)) {
12890
- output.error(tmuxResult.error.message);
12891
- const exitCode = "exitCode" in tmuxResult.error ? tmuxResult.error.exitCode ?? exitCodes.generalError : exitCodes.generalError;
12892
- exitWithError("", exitCode);
13092
+ parts.push(`--${option.name}`);
13093
+ if (option.type === "string") {
13094
+ parts.push(option.multiple ? "<value>..." : "<value>");
13095
+ }
13096
+ return parts.join(" ");
13097
+ }
13098
+ wrapText(text, indent) {
13099
+ const maxWidth = this.width - indent - 2;
13100
+ const words = text.split(" ");
13101
+ const lines = [];
13102
+ let currentLine = "";
13103
+ for (const word of words) {
13104
+ if (currentLine.length + word.length + 1 > maxWidth) {
13105
+ lines.push(currentLine);
13106
+ currentLine = word;
13107
+ } else {
13108
+ currentLine = currentLine ? `${currentLine} ${word}` : word;
12893
13109
  }
12894
- exitWithSuccess();
12895
13110
  }
12896
- const result = await execInWorktree(
12897
- context.gitRoot,
12898
- context.worktreesDirectory,
12899
- worktreeName,
12900
- commandArgs,
12901
- { interactive: true }
12902
- );
12903
- if (isErr(result)) {
12904
- const exitCode = result.error instanceof WorktreeNotFoundError ? exitCodes.notFound : result.error.exitCode || exitCodes.generalError;
12905
- exitWithError(result.error.message, exitCode);
13111
+ if (currentLine) {
13112
+ lines.push(currentLine);
12906
13113
  }
12907
- process.exit(result.value.exitCode);
12908
- } catch (error2) {
12909
- exitWithError(
12910
- error2 instanceof Error ? error2.message : String(error2),
12911
- exitCodes.generalError
12912
- );
13114
+ return lines;
13115
+ }
13116
+ section(text) {
13117
+ return this.bold(text);
13118
+ }
13119
+ bold(text) {
13120
+ return `\x1B[1m${text}\x1B[0m`;
13121
+ }
13122
+ dim(text) {
13123
+ return `\x1B[2m${text}\x1B[0m`;
13124
+ }
13125
+ cyan(text) {
13126
+ return `\x1B[36m${text}\x1B[0m`;
13127
+ }
13128
+ };
13129
+ var helpFormatter = new HelpFormatter();
13130
+
13131
+ // src/handlers/github.ts
13132
+ async function githubHandler(args2) {
13133
+ if (args2.length === 0) {
13134
+ console.log(helpFormatter.formatCommandHelp(githubHelp));
13135
+ return;
12913
13136
  }
13137
+ throw new Error(`Unknown github subcommand: ${args2[0]}`);
12914
13138
  }
12915
13139
 
12916
13140
  // src/handlers/github-checkout.ts
12917
13141
  import { parseArgs as parseArgs5 } from "node:util";
12918
13142
 
12919
- // ../github/src/api/types.ts
12920
- function isPullRequest(issue2) {
12921
- return issue2.pullRequest !== void 0;
12922
- }
12923
-
12924
- // ../github/src/api/repo-info.ts
13143
+ // ../github/src/client.ts
12925
13144
  import { execFile as execFile2 } from "node:child_process";
12926
13145
  import { promisify as promisify2 } from "node:util";
12927
- var execFileAsync = promisify2(execFile2);
12928
- var repoInfoSchema = external_exports.object({
12929
- owner: external_exports.string(),
12930
- repo: external_exports.string()
12931
- });
12932
- async function getGitHubRepoInfo() {
12933
- try {
12934
- const { stdout: stdout2 } = await execFileAsync("gh", [
12935
- "repo",
12936
- "view",
12937
- "--json",
12938
- "owner,name"
12939
- ]);
12940
- const data = JSON.parse(stdout2);
12941
- return repoInfoSchema.parse({
12942
- owner: data.owner.login,
12943
- repo: data.name
12944
- });
12945
- } catch (error2) {
12946
- const errorMessage = error2 instanceof Error ? error2.message : String(error2);
12947
- throw new Error(`Failed to get repository info: ${errorMessage}`);
12948
- }
12949
- }
12950
-
12951
- // ../github/src/client.ts
12952
- import { execFile as execFile3 } from "node:child_process";
12953
- import { promisify as promisify3 } from "node:util";
12954
13146
 
12955
13147
  // ../../node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js
12956
13148
  function getUserAgent() {
@@ -16480,10 +16672,10 @@ var Octokit2 = Octokit.plugin(requestLog, legacyRestEndpointMethods, paginateRes
16480
16672
  );
16481
16673
 
16482
16674
  // ../github/src/client.ts
16483
- var execFileAsync2 = promisify3(execFile3);
16675
+ var execFileAsync = promisify2(execFile2);
16484
16676
  async function getGitHubToken() {
16485
16677
  try {
16486
- const { stdout: stdout2 } = await execFileAsync2("gh", ["auth", "token"]);
16678
+ const { stdout: stdout2 } = await execFileAsync("gh", ["auth", "token"]);
16487
16679
  return stdout2.trim();
16488
16680
  } catch (error2) {
16489
16681
  const errorMessage = error2 instanceof Error ? error2.message : String(error2);
@@ -16546,25 +16738,57 @@ async function fetchIssue(owner, repo, number3) {
16546
16738
  repo,
16547
16739
  issue_number: issueNumber
16548
16740
  });
16549
- let pullRequest;
16550
- if (data.pull_request) {
16551
- const pr = await fetchPullRequest(owner, repo, number3);
16552
- if (pr) {
16553
- pullRequest = pr;
16554
- }
16555
- }
16556
- return {
16557
- number: data.number,
16558
- pullRequest
16559
- };
16741
+ let pullRequest;
16742
+ if (data.pull_request) {
16743
+ const pr = await fetchPullRequest(owner, repo, number3);
16744
+ if (pr) {
16745
+ pullRequest = pr;
16746
+ }
16747
+ }
16748
+ return {
16749
+ number: data.number,
16750
+ pullRequest
16751
+ };
16752
+ } catch (error2) {
16753
+ if (error2 instanceof Error && "status" in error2 && error2.status === 404) {
16754
+ return null;
16755
+ }
16756
+ throw error2;
16757
+ }
16758
+ }
16759
+
16760
+ // ../github/src/api/repo-info.ts
16761
+ import { execFile as execFile3 } from "node:child_process";
16762
+ import { promisify as promisify3 } from "node:util";
16763
+ var execFileAsync2 = promisify3(execFile3);
16764
+ var repoInfoSchema = external_exports.object({
16765
+ owner: external_exports.string(),
16766
+ repo: external_exports.string()
16767
+ });
16768
+ async function getGitHubRepoInfo() {
16769
+ try {
16770
+ const { stdout: stdout2 } = await execFileAsync2("gh", [
16771
+ "repo",
16772
+ "view",
16773
+ "--json",
16774
+ "owner,name"
16775
+ ]);
16776
+ const data = JSON.parse(stdout2);
16777
+ return repoInfoSchema.parse({
16778
+ owner: data.owner.login,
16779
+ repo: data.name
16780
+ });
16560
16781
  } catch (error2) {
16561
- if (error2 instanceof Error && "status" in error2 && error2.status === 404) {
16562
- return null;
16563
- }
16564
- throw error2;
16782
+ const errorMessage = error2 instanceof Error ? error2.message : String(error2);
16783
+ throw new Error(`Failed to get repository info: ${errorMessage}`);
16565
16784
  }
16566
16785
  }
16567
16786
 
16787
+ // ../github/src/api/types.ts
16788
+ function isPullRequest(issue2) {
16789
+ return issue2.pullRequest !== void 0;
16790
+ }
16791
+
16568
16792
  // ../github/src/checkout/issue.ts
16569
16793
  async function checkoutIssue(issue2, base) {
16570
16794
  if (isPullRequest(issue2)) {
@@ -16771,221 +16995,6 @@ Opening worktree '${result.value.worktree}' in tmux ${tmuxDirection === "new" ?
16771
16995
  }
16772
16996
  }
16773
16997
 
16774
- // src/help.ts
16775
- import { stdout } from "node:process";
16776
- var HelpFormatter = class {
16777
- width;
16778
- indent = " ";
16779
- constructor() {
16780
- this.width = stdout.columns || 80;
16781
- }
16782
- formatMainHelp(commands2) {
16783
- const lines = [];
16784
- lines.push(this.bold("Phantom - Git Worktree Manager"));
16785
- lines.push("");
16786
- lines.push(
16787
- this.dim(
16788
- "A CLI tool for managing Git worktrees with enhanced functionality"
16789
- )
16790
- );
16791
- lines.push("");
16792
- lines.push(this.section("USAGE"));
16793
- lines.push(`${this.indent}phantom <command> [options]`);
16794
- lines.push("");
16795
- lines.push(this.section("COMMANDS"));
16796
- const maxNameLength = Math.max(...commands2.map((cmd) => cmd.name.length));
16797
- for (const cmd of commands2) {
16798
- const paddedName = cmd.name.padEnd(maxNameLength + 2);
16799
- lines.push(`${this.indent}${this.cyan(paddedName)}${cmd.description}`);
16800
- }
16801
- lines.push("");
16802
- lines.push(this.section("GLOBAL OPTIONS"));
16803
- const helpOption = "-h, --help";
16804
- const versionOption = "-v, --version";
16805
- const globalOptionWidth = Math.max(helpOption.length, versionOption.length) + 2;
16806
- lines.push(
16807
- `${this.indent}${this.cyan(helpOption.padEnd(globalOptionWidth))}Show help`
16808
- );
16809
- lines.push(
16810
- `${this.indent}${this.cyan(versionOption.padEnd(globalOptionWidth))}Show version`
16811
- );
16812
- lines.push("");
16813
- lines.push(
16814
- this.dim(
16815
- "Run 'phantom <command> --help' for more information on a command."
16816
- )
16817
- );
16818
- return lines.join("\n");
16819
- }
16820
- formatCommandHelp(help) {
16821
- const lines = [];
16822
- lines.push(this.bold(`phantom ${help.name}`));
16823
- lines.push(this.dim(help.description));
16824
- lines.push("");
16825
- lines.push(this.section("USAGE"));
16826
- lines.push(`${this.indent}${help.usage}`);
16827
- lines.push("");
16828
- if (help.options && help.options.length > 0) {
16829
- lines.push(this.section("OPTIONS"));
16830
- const maxOptionLength = Math.max(
16831
- ...help.options.map((opt) => this.formatOptionName(opt).length)
16832
- );
16833
- for (const option of help.options) {
16834
- const optionName = this.formatOptionName(option);
16835
- const paddedName = optionName.padEnd(maxOptionLength + 2);
16836
- const description = this.wrapText(
16837
- option.description,
16838
- maxOptionLength + 4
16839
- );
16840
- lines.push(`${this.indent}${this.cyan(paddedName)}${description[0]}`);
16841
- for (let i = 1; i < description.length; i++) {
16842
- lines.push(
16843
- `${this.indent}${" ".repeat(maxOptionLength + 2)}${description[i]}`
16844
- );
16845
- }
16846
- if (option.example) {
16847
- const exampleIndent = " ".repeat(maxOptionLength + 4);
16848
- lines.push(
16849
- `${this.indent}${exampleIndent}${this.dim(`Example: ${option.example}`)}`
16850
- );
16851
- }
16852
- }
16853
- lines.push("");
16854
- }
16855
- if (help.examples && help.examples.length > 0) {
16856
- lines.push(this.section("EXAMPLES"));
16857
- for (const example of help.examples) {
16858
- lines.push(`${this.indent}${this.dim(example.description)}`);
16859
- lines.push(`${this.indent}${this.indent}$ ${example.command}`);
16860
- lines.push("");
16861
- }
16862
- }
16863
- if (help.notes && help.notes.length > 0) {
16864
- lines.push(this.section("NOTES"));
16865
- for (const note of help.notes) {
16866
- const wrappedNote = this.wrapText(note, 2);
16867
- for (const line of wrappedNote) {
16868
- lines.push(`${this.indent}${line}`);
16869
- }
16870
- }
16871
- lines.push("");
16872
- }
16873
- return lines.join("\n");
16874
- }
16875
- formatOptionName(option) {
16876
- const parts = [];
16877
- if (option.short) {
16878
- parts.push(`-${option.short},`);
16879
- }
16880
- parts.push(`--${option.name}`);
16881
- if (option.type === "string") {
16882
- parts.push(option.multiple ? "<value>..." : "<value>");
16883
- }
16884
- return parts.join(" ");
16885
- }
16886
- wrapText(text, indent) {
16887
- const maxWidth = this.width - indent - 2;
16888
- const words = text.split(" ");
16889
- const lines = [];
16890
- let currentLine = "";
16891
- for (const word of words) {
16892
- if (currentLine.length + word.length + 1 > maxWidth) {
16893
- lines.push(currentLine);
16894
- currentLine = word;
16895
- } else {
16896
- currentLine = currentLine ? `${currentLine} ${word}` : word;
16897
- }
16898
- }
16899
- if (currentLine) {
16900
- lines.push(currentLine);
16901
- }
16902
- return lines;
16903
- }
16904
- section(text) {
16905
- return this.bold(text);
16906
- }
16907
- bold(text) {
16908
- return `\x1B[1m${text}\x1B[0m`;
16909
- }
16910
- dim(text) {
16911
- return `\x1B[2m${text}\x1B[0m`;
16912
- }
16913
- cyan(text) {
16914
- return `\x1B[36m${text}\x1B[0m`;
16915
- }
16916
- };
16917
- var helpFormatter = new HelpFormatter();
16918
-
16919
- // src/help/github.ts
16920
- var githubHelp = {
16921
- name: "github",
16922
- usage: "phantom github <subcommand> [options]",
16923
- description: "GitHub-specific commands for phantom",
16924
- examples: [
16925
- {
16926
- command: "phantom github checkout 123",
16927
- description: "Create a worktree for PR or issue #123"
16928
- },
16929
- {
16930
- command: "phantom gh checkout 456",
16931
- description: "Same as above, using the gh alias"
16932
- }
16933
- ],
16934
- notes: [
16935
- "Subcommands:",
16936
- " checkout Create a worktree for a GitHub PR or issue",
16937
- "",
16938
- "Alias: 'gh' can be used instead of 'github'",
16939
- "",
16940
- "Requirements:",
16941
- " - GitHub CLI (gh) must be installed",
16942
- " - Must be authenticated with 'gh auth login'"
16943
- ]
16944
- };
16945
- var githubCheckoutHelp = {
16946
- name: "github checkout",
16947
- usage: "phantom github checkout <number> [options]",
16948
- description: "Create a worktree for a GitHub PR or issue",
16949
- options: [
16950
- {
16951
- name: "--base",
16952
- type: "string",
16953
- description: "Base branch for new issue branches (issues only, default: repository HEAD)"
16954
- }
16955
- ],
16956
- examples: [
16957
- {
16958
- command: "phantom github checkout 123",
16959
- description: "Create a worktree for PR #123 (checks out PR branch)"
16960
- },
16961
- {
16962
- command: "phantom github checkout 456",
16963
- description: "Create a worktree for issue #456 (creates new branch)"
16964
- },
16965
- {
16966
- command: "phantom github checkout 789 --base develop",
16967
- description: "Create a worktree for issue #789 based on develop branch"
16968
- }
16969
- ],
16970
- notes: [
16971
- "For PRs: Creates worktree named 'pulls/{number}' with the PR's branch",
16972
- "For Issues: Creates worktree named 'issues/{number}' with a new branch",
16973
- "",
16974
- "Requirements:",
16975
- " - GitHub CLI (gh) must be installed",
16976
- " - Must be authenticated with 'gh auth login'"
16977
- ]
16978
- };
16979
-
16980
- // src/handlers/github.ts
16981
- async function githubHandler(args2) {
16982
- if (args2.length === 0) {
16983
- console.log(helpFormatter.formatCommandHelp(githubHelp));
16984
- return;
16985
- }
16986
- throw new Error(`Unknown github subcommand: ${args2[0]}`);
16987
- }
16988
-
16989
16998
  // src/handlers/list.ts
16990
16999
  import { parseArgs as parseArgs6 } from "node:util";
16991
17000
  async function listHandler(args2 = []) {
@@ -17006,12 +17015,8 @@ async function listHandler(args2 = []) {
17006
17015
  });
17007
17016
  try {
17008
17017
  const gitRoot = await getGitRoot();
17009
- const context = await createContext(gitRoot);
17010
17018
  if (values.fzf) {
17011
- const selectResult = await selectWorktreeWithFzf(
17012
- context.gitRoot,
17013
- context.worktreesDirectory
17014
- );
17019
+ const selectResult = await selectWorktreeWithFzf(gitRoot);
17015
17020
  if (isErr(selectResult)) {
17016
17021
  exitWithError(selectResult.error.message, exitCodes.generalError);
17017
17022
  }
@@ -17019,10 +17024,7 @@ async function listHandler(args2 = []) {
17019
17024
  output.log(selectResult.value.name);
17020
17025
  }
17021
17026
  } else {
17022
- const result = await listWorktrees2(
17023
- context.gitRoot,
17024
- context.worktreesDirectory
17025
- );
17027
+ const result = await listWorktrees2(gitRoot);
17026
17028
  if (isErr(result)) {
17027
17029
  exitWithError("Failed to list worktrees", exitCodes.generalError);
17028
17030
  }
@@ -17038,14 +17040,9 @@ async function listHandler(args2 = []) {
17038
17040
  output.log(worktree.name);
17039
17041
  }
17040
17042
  } else {
17041
- const maxNameLength = Math.max(
17042
- ...worktrees.map((wt) => wt.name.length)
17043
- );
17044
17043
  for (const worktree of worktrees) {
17045
- const paddedName = worktree.name.padEnd(maxNameLength + 2);
17046
- const branchInfo = worktree.branch ? `(${worktree.branch})` : "";
17047
17044
  const status = !worktree.isClean ? " [dirty]" : "";
17048
- output.log(`${paddedName} ${branchInfo}${status}`);
17045
+ output.log(`${worktree.name} (${worktree.pathToDisplay})${status}`);
17049
17046
  }
17050
17047
  }
17051
17048
  }
@@ -25808,7 +25805,7 @@ var StdioServerTransport = class {
25808
25805
  // ../mcp/package.json
25809
25806
  var package_default = {
25810
25807
  name: "@aku11i/phantom-mcp",
25811
- version: "3.0.1",
25808
+ version: "3.1.0",
25812
25809
  private: true,
25813
25810
  type: "module",
25814
25811
  main: "./src/index.ts",
@@ -25963,11 +25960,7 @@ var listWorktreesTool = {
25963
25960
  inputSchema: schema4,
25964
25961
  handler: async () => {
25965
25962
  const gitRoot = await getGitRoot();
25966
- const context = await createContext(gitRoot);
25967
- const result = await listWorktrees2(
25968
- context.gitRoot,
25969
- context.worktreesDirectory
25970
- );
25963
+ const result = await listWorktrees2(gitRoot);
25971
25964
  if (!isOk(result)) {
25972
25965
  throw new Error("Failed to list worktrees");
25973
25966
  }
@@ -26150,10 +26143,7 @@ async function shellHandler(args2) {
26150
26143
  );
26151
26144
  }
26152
26145
  if (useFzf) {
26153
- const selectResult = await selectWorktreeWithFzf(
26154
- context.gitRoot,
26155
- context.worktreesDirectory
26156
- );
26146
+ const selectResult = await selectWorktreeWithFzf(context.gitRoot);
26157
26147
  if (isErr(selectResult)) {
26158
26148
  exitWithError(selectResult.error.message, exitCodes.generalError);
26159
26149
  }
@@ -26219,13 +26209,15 @@ import { parseArgs as parseArgs9 } from "node:util";
26219
26209
  // package.json
26220
26210
  var package_default2 = {
26221
26211
  name: "@aku11i/phantom-cli",
26222
- version: "3.0.1",
26212
+ version: "3.1.0",
26223
26213
  private: true,
26224
26214
  type: "module",
26225
26215
  scripts: {
26226
26216
  phantom: "node --no-warnings --experimental-strip-types src/bin/phantom.ts",
26227
26217
  prebuild: "git clean -fdx dist",
26228
26218
  build: "node build.ts",
26219
+ precompile: "rm -f output/*",
26220
+ compile: "node --no-warnings --experimental-strip-types build-executable.ts",
26229
26221
  typecheck: "tsc --noEmit",
26230
26222
  "test:shell": "pnpm run test:shell:bash && pnpm run test:shell:zsh && pnpm run test:shell:fish",
26231
26223
  "test:shell:bash": "node --test --experimental-strip-types --experimental-test-module-mocks src/completions/phantom.bash.test.shell.js",
@@ -26301,10 +26293,7 @@ async function whereHandler(args2) {
26301
26293
  }
26302
26294
  const context = await createContext(gitRoot);
26303
26295
  if (useFzf) {
26304
- const selectResult = await selectWorktreeWithFzf(
26305
- context.gitRoot,
26306
- context.worktreesDirectory
26307
- );
26296
+ const selectResult = await selectWorktreeWithFzf(context.gitRoot);
26308
26297
  if (isErr(selectResult)) {
26309
26298
  exitWithError(selectResult.error.message, exitCodes.generalError);
26310
26299
  }