@aku11i/phantom 1.3.0 → 2.0.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 +4 -1
  2. package/phantom.js +97 -52
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aku11i/phantom",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "description": "A powerful CLI tool for managing Git worktrees for parallel development",
5
5
  "keywords": [
6
6
  "git",
@@ -31,5 +31,8 @@
31
31
  "README.md",
32
32
  "LICENSE"
33
33
  ],
34
+ "engines": {
35
+ "node": ">=22.0.0"
36
+ },
34
37
  "dependencies": {}
35
38
  }
package/phantom.js CHANGED
@@ -4203,13 +4203,15 @@ var phantomConfigSchema = external_exports.object({
4203
4203
  copyFiles: external_exports.array(external_exports.string()).optional(),
4204
4204
  commands: external_exports.array(external_exports.string()).optional()
4205
4205
  }).passthrough().optional(),
4206
+ preDelete: external_exports.object({
4207
+ commands: external_exports.array(external_exports.string()).optional()
4208
+ }).passthrough().optional(),
4206
4209
  worktreesDirectory: external_exports.string().optional()
4207
4210
  }).passthrough();
4208
4211
  function validateConfig(config) {
4209
4212
  const result = phantomConfigSchema.safeParse(config);
4210
4213
  if (!result.success) {
4211
4214
  const error = result.error;
4212
- const formattedError = error.format();
4213
4215
  const firstError = error.errors[0];
4214
4216
  const path3 = firstError.path.join(".");
4215
4217
  const message = path3 ? `${path3}: ${firstError.message}` : firstError.message;
@@ -4403,7 +4405,7 @@ async function fetch(options = {}) {
4403
4405
  }
4404
4406
 
4405
4407
  // ../git/src/libs/list-worktrees.ts
4406
- async function listWorktrees(gitRoot) {
4408
+ async function listWorktrees(_gitRoot) {
4407
4409
  const { stdout: stdout2 } = await executeGitCommand([
4408
4410
  "worktree",
4409
4411
  "list",
@@ -4695,7 +4697,7 @@ async function selectWithFzf(items, options = {}) {
4695
4697
 
4696
4698
  // ../core/src/worktree/validate.ts
4697
4699
  import fs2 from "node:fs/promises";
4698
- async function validateWorktreeExists(gitRoot, worktreeDirectory, name) {
4700
+ async function validateWorktreeExists(_gitRoot, worktreeDirectory, name) {
4699
4701
  const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
4700
4702
  try {
4701
4703
  await fs2.access(worktreePath);
@@ -4704,7 +4706,7 @@ async function validateWorktreeExists(gitRoot, worktreeDirectory, name) {
4704
4706
  return err(new WorktreeNotFoundError(name));
4705
4707
  }
4706
4708
  }
4707
- async function validateWorktreeDoesNotExist(gitRoot, worktreeDirectory, name) {
4709
+ async function validateWorktreeDoesNotExist(_gitRoot, worktreeDirectory, name) {
4708
4710
  const worktreePath = getWorktreePathFromDirectory(worktreeDirectory, name);
4709
4711
  try {
4710
4712
  await fs2.access(worktreePath);
@@ -4879,6 +4881,39 @@ async function createWorktree(gitRoot, worktreeDirectory, name, options, postCre
4879
4881
  }
4880
4882
  }
4881
4883
 
4884
+ // ../core/src/worktree/pre-delete.ts
4885
+ async function executePreDeleteCommands(options) {
4886
+ const { gitRoot, worktreesDirectory, worktreeName, commands: commands2 } = options;
4887
+ const executedCommands = [];
4888
+ for (const command2 of commands2) {
4889
+ console.log(`Executing pre-delete command: ${command2}`);
4890
+ const shell = process.env.SHELL || "/bin/sh";
4891
+ const cmdResult = await execInWorktree(
4892
+ gitRoot,
4893
+ worktreesDirectory,
4894
+ worktreeName,
4895
+ [shell, "-c", command2]
4896
+ );
4897
+ if (isErr(cmdResult)) {
4898
+ const errorMessage = cmdResult.error instanceof Error ? cmdResult.error.message : String(cmdResult.error);
4899
+ return err(
4900
+ new Error(
4901
+ `Failed to execute pre-delete command "${command2}": ${errorMessage}`
4902
+ )
4903
+ );
4904
+ }
4905
+ if (cmdResult.value.exitCode !== 0) {
4906
+ return err(
4907
+ new Error(
4908
+ `Pre-delete command failed with exit code ${cmdResult.value.exitCode}: ${command2}`
4909
+ )
4910
+ );
4911
+ }
4912
+ executedCommands.push(command2);
4913
+ }
4914
+ return ok({ executedCommands });
4915
+ }
4916
+
4882
4917
  // ../core/src/worktree/delete.ts
4883
4918
  async function getWorktreeChangesStatus(worktreePath) {
4884
4919
  try {
@@ -4900,19 +4935,14 @@ async function getWorktreeChangesStatus(worktreePath) {
4900
4935
  };
4901
4936
  }
4902
4937
  async function removeWorktree(gitRoot, worktreePath, force = false) {
4903
- try {
4904
- await executeGitCommand(["worktree", "remove", worktreePath], {
4905
- cwd: gitRoot
4906
- });
4907
- } catch (error) {
4908
- try {
4909
- await executeGitCommand(["worktree", "remove", "--force", worktreePath], {
4910
- cwd: gitRoot
4911
- });
4912
- } catch {
4913
- throw new Error("Failed to remove worktree");
4914
- }
4938
+ const args2 = ["worktree", "remove"];
4939
+ if (force) {
4940
+ args2.push("--force");
4915
4941
  }
4942
+ args2.push(worktreePath);
4943
+ await executeGitCommand(args2, {
4944
+ cwd: gitRoot
4945
+ });
4916
4946
  }
4917
4947
  async function deleteBranch(gitRoot, branchName) {
4918
4948
  try {
@@ -4923,7 +4953,7 @@ async function deleteBranch(gitRoot, branchName) {
4923
4953
  return err(new WorktreeError(`branch delete failed: ${errorMessage}`));
4924
4954
  }
4925
4955
  }
4926
- async function deleteWorktree(gitRoot, worktreeDirectory, name, options) {
4956
+ async function deleteWorktree(gitRoot, worktreeDirectory, name, options, preDeleteCommands) {
4927
4957
  const { force = false } = options || {};
4928
4958
  const validation = await validateWorktreeExists(
4929
4959
  gitRoot,
@@ -4942,6 +4972,18 @@ async function deleteWorktree(gitRoot, worktreeDirectory, name, options) {
4942
4972
  )
4943
4973
  );
4944
4974
  }
4975
+ if (preDeleteCommands && preDeleteCommands.length > 0) {
4976
+ console.log("\nRunning pre-delete commands...");
4977
+ const preDeleteResult = await executePreDeleteCommands({
4978
+ gitRoot,
4979
+ worktreesDirectory: worktreeDirectory,
4980
+ worktreeName: name,
4981
+ commands: preDeleteCommands
4982
+ });
4983
+ if (isErr(preDeleteResult)) {
4984
+ return err(new WorktreeError(preDeleteResult.error.message));
4985
+ }
4986
+ }
4945
4987
  try {
4946
4988
  await removeWorktree(gitRoot, worktreePath, force);
4947
4989
  const branchName = name;
@@ -5231,7 +5273,6 @@ async function attachHandler(args2) {
5231
5273
  }
5232
5274
  exitWithError(error.message, exitCodes.generalError);
5233
5275
  }
5234
- const worktreePath = result.value;
5235
5276
  output.log(`Attached phantom: ${branchName}`);
5236
5277
  if (values.shell) {
5237
5278
  const shellResult = await shellInWorktree(
@@ -5931,7 +5972,8 @@ async function deleteHandler(args2) {
5931
5972
  worktreeName,
5932
5973
  {
5933
5974
  force: forceDelete
5934
- }
5975
+ },
5976
+ context.config?.preDelete?.commands
5935
5977
  );
5936
5978
  if (isErr(result)) {
5937
5979
  const exitCode = result.error instanceof WorktreeNotFoundError ? exitCodes.validationError : result.error instanceof WorktreeError && result.error.message.includes("uncommitted changes") ? exitCodes.validationError : exitCodes.generalError;
@@ -9526,8 +9568,21 @@ async function checkoutIssue(issue, base) {
9526
9568
  }
9527
9569
  const gitRoot = await getGitRoot();
9528
9570
  const context = await createContext(gitRoot);
9529
- const worktreeName = `issue-${issue.number}`;
9530
- const branchName = `issue-${issue.number}`;
9571
+ const worktreeName = `issues/${issue.number}`;
9572
+ const branchName = `issues/${issue.number}`;
9573
+ const existsResult = await validateWorktreeExists(
9574
+ context.gitRoot,
9575
+ context.worktreesDirectory,
9576
+ worktreeName
9577
+ );
9578
+ if (!isErr(existsResult)) {
9579
+ return ok({
9580
+ message: `Issue #${issue.number} is already checked out`,
9581
+ worktree: worktreeName,
9582
+ path: existsResult.value.path,
9583
+ alreadyExists: true
9584
+ });
9585
+ }
9531
9586
  const result = await createWorktree(
9532
9587
  context.gitRoot,
9533
9588
  context.worktreesDirectory,
@@ -9540,18 +9595,6 @@ async function checkoutIssue(issue, base) {
9540
9595
  context.config?.postCreate?.commands
9541
9596
  );
9542
9597
  if (isErr(result)) {
9543
- if (result.error instanceof WorktreeAlreadyExistsError) {
9544
- const worktreePath = getWorktreePathFromDirectory(
9545
- context.worktreesDirectory,
9546
- worktreeName
9547
- );
9548
- return ok({
9549
- message: `Worktree for issue #${issue.number} is already checked out`,
9550
- worktree: worktreeName,
9551
- path: worktreePath,
9552
- alreadyExists: true
9553
- });
9554
- }
9555
9598
  return err(result.error);
9556
9599
  }
9557
9600
  return ok({
@@ -9565,8 +9608,21 @@ async function checkoutIssue(issue, base) {
9565
9608
  async function checkoutPullRequest(pullRequest) {
9566
9609
  const gitRoot = await getGitRoot();
9567
9610
  const context = await createContext(gitRoot);
9568
- const worktreeName = `pr-${pullRequest.number}`;
9569
- const localBranch = `pr-${pullRequest.number}`;
9611
+ const worktreeName = `pulls/${pullRequest.number}`;
9612
+ const localBranch = `pulls/${pullRequest.number}`;
9613
+ const existsResult = await validateWorktreeExists(
9614
+ context.gitRoot,
9615
+ context.worktreesDirectory,
9616
+ worktreeName
9617
+ );
9618
+ if (!isErr(existsResult)) {
9619
+ return ok({
9620
+ message: `PR #${pullRequest.number} is already checked out`,
9621
+ worktree: worktreeName,
9622
+ path: existsResult.value.path,
9623
+ alreadyExists: true
9624
+ });
9625
+ }
9570
9626
  const upstream = pullRequest.isFromFork ? `origin/pull/${pullRequest.number}/head` : `origin/${pullRequest.head.ref}`;
9571
9627
  const refspec = `${upstream.replace("origin/", "")}:${localBranch}`;
9572
9628
  const fetchResult = await fetch({ refspec });
@@ -9595,18 +9651,6 @@ async function checkoutPullRequest(pullRequest) {
9595
9651
  context.config?.postCreate?.commands
9596
9652
  );
9597
9653
  if (isErr(attachResult)) {
9598
- if (attachResult.error instanceof WorktreeAlreadyExistsError) {
9599
- const worktreePath = getWorktreePathFromDirectory(
9600
- context.worktreesDirectory,
9601
- worktreeName
9602
- );
9603
- return ok({
9604
- message: `Worktree for PR #${pullRequest.number} is already checked out`,
9605
- worktree: worktreeName,
9606
- path: worktreePath,
9607
- alreadyExists: true
9608
- });
9609
- }
9610
9654
  return err(attachResult.error);
9611
9655
  }
9612
9656
  const message = pullRequest.isFromFork ? `Checked out PR #${pullRequest.number} from fork ${pullRequest.head.repo.full_name}` : `Checked out PR #${pullRequest.number} from branch ${pullRequest.head.ref}`;
@@ -9866,8 +9910,8 @@ var githubCheckoutHelp = {
9866
9910
  }
9867
9911
  ],
9868
9912
  notes: [
9869
- "For PRs: Creates worktree named 'pr-{number}' with the PR's branch",
9870
- "For Issues: Creates worktree named 'issue-{number}' with a new branch",
9913
+ "For PRs: Creates worktree named 'pulls/{number}' with the PR's branch",
9914
+ "For Issues: Creates worktree named 'issues/{number}' with a new branch",
9871
9915
  "",
9872
9916
  "Requirements:",
9873
9917
  " - GitHub CLI (gh) must be installed",
@@ -13223,7 +13267,7 @@ var StdioServerTransport = class {
13223
13267
  // ../mcp/package.json
13224
13268
  var package_default = {
13225
13269
  name: "@aku11i/phantom-mcp",
13226
- version: "1.3.0",
13270
+ version: "2.0.0",
13227
13271
  private: true,
13228
13272
  type: "module",
13229
13273
  main: "./src/index.ts",
@@ -13311,7 +13355,8 @@ var deleteWorktreeTool = {
13311
13355
  name,
13312
13356
  {
13313
13357
  force
13314
- }
13358
+ },
13359
+ context.config?.preDelete?.commands
13315
13360
  );
13316
13361
  if (!isOk(result)) {
13317
13362
  throw new Error(result.error.message);
@@ -13633,7 +13678,7 @@ import { parseArgs as parseArgs9 } from "node:util";
13633
13678
  // package.json
13634
13679
  var package_default2 = {
13635
13680
  name: "@aku11i/phantom-cli",
13636
- version: "1.3.0",
13681
+ version: "2.0.0",
13637
13682
  private: true,
13638
13683
  type: "module",
13639
13684
  scripts: {