@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.
- package/package.json +4 -1
- package/phantom.js +97 -52
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aku11i/phantom",
|
|
3
|
-
"version": "
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
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 = `
|
|
9530
|
-
const branchName = `
|
|
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 = `
|
|
9569
|
-
const localBranch = `
|
|
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 '
|
|
9870
|
-
"For Issues: Creates worktree named '
|
|
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: "
|
|
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: "
|
|
13681
|
+
version: "2.0.0",
|
|
13637
13682
|
private: true,
|
|
13638
13683
|
type: "module",
|
|
13639
13684
|
scripts: {
|