@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.
- package/package.json +1 -1
- 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,
|
|
3687
|
+
function resolveComponent(base, relative2, options, skipNormalization) {
|
|
3688
3688
|
const target = {};
|
|
3689
3689
|
if (!skipNormalization) {
|
|
3690
3690
|
base = parse4(serialize(base, options), options);
|
|
3691
|
-
|
|
3691
|
+
relative2 = parse4(serialize(relative2, options), options);
|
|
3692
3692
|
}
|
|
3693
3693
|
options = options || {};
|
|
3694
|
-
if (!options.tolerant &&
|
|
3695
|
-
target.scheme =
|
|
3696
|
-
target.userinfo =
|
|
3697
|
-
target.host =
|
|
3698
|
-
target.port =
|
|
3699
|
-
target.path = removeDotSegments(
|
|
3700
|
-
target.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 (
|
|
3703
|
-
target.userinfo =
|
|
3704
|
-
target.host =
|
|
3705
|
-
target.port =
|
|
3706
|
-
target.path = removeDotSegments(
|
|
3707
|
-
target.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 (!
|
|
3709
|
+
if (!relative2.path) {
|
|
3710
3710
|
target.path = base.path;
|
|
3711
|
-
if (
|
|
3712
|
-
target.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 (
|
|
3718
|
-
target.path = removeDotSegments(
|
|
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 = "/" +
|
|
3721
|
+
target.path = "/" + relative2.path;
|
|
3722
3722
|
} else if (!base.path) {
|
|
3723
|
-
target.path =
|
|
3723
|
+
target.path = relative2.path;
|
|
3724
3724
|
} else {
|
|
3725
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
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 =
|
|
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 =
|
|
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/
|
|
11073
|
-
import
|
|
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/
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
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
|
-
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
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
|
-
|
|
11433
|
-
|
|
11434
|
-
|
|
11435
|
-
|
|
11436
|
-
);
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
}
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
|
|
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
|
-
|
|
11454
|
-
|
|
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
|
-
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
|
|
11465
|
-
|
|
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(
|
|
11470
|
-
const
|
|
11471
|
-
|
|
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
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
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
|
-
|
|
11838
|
+
args2.push(worktreePath);
|
|
11839
|
+
await executeGitCommand(args2, {
|
|
11840
|
+
cwd: gitRoot
|
|
11841
|
+
});
|
|
11867
11842
|
}
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
|
|
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
|
-
|
|
11880
|
-
|
|
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
|
|
11886
|
-
const listResult = await listWorktrees2(gitRoot
|
|
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} ${
|
|
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/
|
|
11934
|
-
async function
|
|
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
|
-
|
|
11963
|
+
name
|
|
11939
11964
|
);
|
|
11940
11965
|
if (isErr(validation)) {
|
|
11941
11966
|
return err(validation.error);
|
|
11942
11967
|
}
|
|
11943
|
-
|
|
11944
|
-
|
|
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
|
-
|
|
12844
|
-
const
|
|
12845
|
-
|
|
12846
|
-
|
|
12847
|
-
|
|
12848
|
-
|
|
12849
|
-
|
|
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
|
-
|
|
12853
|
-
|
|
12854
|
-
const
|
|
12855
|
-
|
|
12856
|
-
|
|
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
|
-
|
|
12862
|
-
|
|
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
|
-
|
|
12865
|
-
} else {
|
|
12866
|
-
worktreeName = positionals[0];
|
|
13083
|
+
lines.push("");
|
|
12867
13084
|
}
|
|
12868
|
-
|
|
12869
|
-
|
|
12870
|
-
|
|
12871
|
-
|
|
12872
|
-
)
|
|
12873
|
-
|
|
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
|
-
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
|
|
12882
|
-
|
|
12883
|
-
|
|
12884
|
-
|
|
12885
|
-
|
|
12886
|
-
|
|
12887
|
-
|
|
12888
|
-
|
|
12889
|
-
|
|
12890
|
-
|
|
12891
|
-
|
|
12892
|
-
|
|
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
|
-
|
|
12897
|
-
|
|
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
|
-
|
|
12908
|
-
}
|
|
12909
|
-
|
|
12910
|
-
|
|
12911
|
-
|
|
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/
|
|
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
|
|
16675
|
+
var execFileAsync = promisify2(execFile2);
|
|
16484
16676
|
async function getGitHubToken() {
|
|
16485
16677
|
try {
|
|
16486
|
-
const { stdout: stdout2 } = await
|
|
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
|
-
|
|
16562
|
-
|
|
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(`${
|
|
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
|
|
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
|
|
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
|
|
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
|
}
|