@aku11i/phantom 0.8.1 → 1.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/README.ja.md +97 -339
- package/README.md +95 -340
- package/dist/phantom.js +519 -84
- package/dist/phantom.js.map +4 -4
- package/package.json +1 -1
package/dist/phantom.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/bin/phantom.ts
|
|
4
|
-
import { argv, exit } from "node:process";
|
|
4
|
+
import { argv, exit as exit2 } from "node:process";
|
|
5
5
|
|
|
6
6
|
// src/cli/handlers/attach.ts
|
|
7
7
|
import { parseArgs } from "node:util";
|
|
@@ -67,6 +67,18 @@ var err = (error) => ({
|
|
|
67
67
|
var isOk = (result) => result.ok;
|
|
68
68
|
var isErr = (result) => !result.ok;
|
|
69
69
|
|
|
70
|
+
// src/core/worktree/validate.ts
|
|
71
|
+
import fs from "node:fs/promises";
|
|
72
|
+
|
|
73
|
+
// src/core/paths.ts
|
|
74
|
+
import { join } from "node:path";
|
|
75
|
+
function getPhantomDirectory(gitRoot) {
|
|
76
|
+
return join(gitRoot, ".git", "phantom", "worktrees");
|
|
77
|
+
}
|
|
78
|
+
function getWorktreePath(gitRoot, name) {
|
|
79
|
+
return join(getPhantomDirectory(gitRoot), name);
|
|
80
|
+
}
|
|
81
|
+
|
|
70
82
|
// src/core/worktree/errors.ts
|
|
71
83
|
var WorktreeError = class extends Error {
|
|
72
84
|
constructor(message) {
|
|
@@ -99,58 +111,39 @@ var BranchNotFoundError = class extends WorktreeError {
|
|
|
99
111
|
}
|
|
100
112
|
};
|
|
101
113
|
|
|
102
|
-
// src/core/worktree/validate.ts
|
|
103
|
-
import fs from "node:fs/promises";
|
|
104
|
-
|
|
105
|
-
// src/core/paths.ts
|
|
106
|
-
import { join } from "node:path";
|
|
107
|
-
function getPhantomDirectory(gitRoot) {
|
|
108
|
-
return join(gitRoot, ".git", "phantom", "worktrees");
|
|
109
|
-
}
|
|
110
|
-
function getWorktreePath(gitRoot, name) {
|
|
111
|
-
return join(getPhantomDirectory(gitRoot), name);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
114
|
// src/core/worktree/validate.ts
|
|
115
115
|
async function validateWorktreeExists(gitRoot, name) {
|
|
116
116
|
const worktreePath = getWorktreePath(gitRoot, name);
|
|
117
117
|
try {
|
|
118
118
|
await fs.access(worktreePath);
|
|
119
|
-
return {
|
|
120
|
-
exists: true,
|
|
121
|
-
path: worktreePath
|
|
122
|
-
};
|
|
119
|
+
return ok({ path: worktreePath });
|
|
123
120
|
} catch {
|
|
124
|
-
return
|
|
125
|
-
exists: false,
|
|
126
|
-
message: `Worktree '${name}' does not exist`
|
|
127
|
-
};
|
|
121
|
+
return err(new WorktreeNotFoundError(name));
|
|
128
122
|
}
|
|
129
123
|
}
|
|
130
124
|
async function validateWorktreeDoesNotExist(gitRoot, name) {
|
|
131
125
|
const worktreePath = getWorktreePath(gitRoot, name);
|
|
132
126
|
try {
|
|
133
127
|
await fs.access(worktreePath);
|
|
134
|
-
return
|
|
135
|
-
exists: true,
|
|
136
|
-
message: `Worktree '${name}' already exists`
|
|
137
|
-
};
|
|
128
|
+
return err(new WorktreeAlreadyExistsError(name));
|
|
138
129
|
} catch {
|
|
139
|
-
return {
|
|
140
|
-
exists: false,
|
|
141
|
-
path: worktreePath
|
|
142
|
-
};
|
|
130
|
+
return ok({ path: worktreePath });
|
|
143
131
|
}
|
|
144
132
|
}
|
|
145
133
|
function validateWorktreeName(name) {
|
|
146
134
|
if (!name || name.trim() === "") {
|
|
147
135
|
return err(new Error("Phantom name cannot be empty"));
|
|
148
136
|
}
|
|
149
|
-
|
|
150
|
-
|
|
137
|
+
const validNamePattern = /^[a-zA-Z0-9\-_.\/]+$/;
|
|
138
|
+
if (!validNamePattern.test(name)) {
|
|
139
|
+
return err(
|
|
140
|
+
new Error(
|
|
141
|
+
"Phantom name can only contain letters, numbers, hyphens, underscores, dots, and slashes"
|
|
142
|
+
)
|
|
143
|
+
);
|
|
151
144
|
}
|
|
152
|
-
if (name.
|
|
153
|
-
return err(new Error("Phantom name cannot
|
|
145
|
+
if (name.includes("..")) {
|
|
146
|
+
return err(new Error("Phantom name cannot contain consecutive dots"));
|
|
154
147
|
}
|
|
155
148
|
return ok(void 0);
|
|
156
149
|
}
|
|
@@ -218,10 +211,10 @@ async function spawnProcess(config) {
|
|
|
218
211
|
// src/core/process/exec.ts
|
|
219
212
|
async function execInWorktree(gitRoot, worktreeName, command2, options = {}) {
|
|
220
213
|
const validation = await validateWorktreeExists(gitRoot, worktreeName);
|
|
221
|
-
if (
|
|
222
|
-
return err(
|
|
214
|
+
if (isErr(validation)) {
|
|
215
|
+
return err(validation.error);
|
|
223
216
|
}
|
|
224
|
-
const worktreePath = validation.path;
|
|
217
|
+
const worktreePath = validation.value.path;
|
|
225
218
|
const [cmd, ...args2] = command2;
|
|
226
219
|
const stdio = options.interactive ? "inherit" : ["ignore", "inherit", "inherit"];
|
|
227
220
|
return spawnProcess({
|
|
@@ -234,13 +227,22 @@ async function execInWorktree(gitRoot, worktreeName, command2, options = {}) {
|
|
|
234
227
|
});
|
|
235
228
|
}
|
|
236
229
|
|
|
230
|
+
// src/core/process/env.ts
|
|
231
|
+
function getPhantomEnv(worktreeName, worktreePath) {
|
|
232
|
+
return {
|
|
233
|
+
PHANTOM: "1",
|
|
234
|
+
PHANTOM_NAME: worktreeName,
|
|
235
|
+
PHANTOM_PATH: worktreePath
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
237
239
|
// src/core/process/shell.ts
|
|
238
240
|
async function shellInWorktree(gitRoot, worktreeName) {
|
|
239
241
|
const validation = await validateWorktreeExists(gitRoot, worktreeName);
|
|
240
|
-
if (
|
|
241
|
-
return err(
|
|
242
|
+
if (isErr(validation)) {
|
|
243
|
+
return err(validation.error);
|
|
242
244
|
}
|
|
243
|
-
const worktreePath = validation.path;
|
|
245
|
+
const worktreePath = validation.value.path;
|
|
244
246
|
const shell = process.env.SHELL || "/bin/sh";
|
|
245
247
|
return spawnProcess({
|
|
246
248
|
command: shell,
|
|
@@ -249,9 +251,7 @@ async function shellInWorktree(gitRoot, worktreeName) {
|
|
|
249
251
|
cwd: worktreePath,
|
|
250
252
|
env: {
|
|
251
253
|
...process.env,
|
|
252
|
-
|
|
253
|
-
PHANTOM_NAME: worktreeName,
|
|
254
|
-
PHANTOM_PATH: worktreePath
|
|
254
|
+
...getPhantomEnv(worktreeName, worktreePath)
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
257
|
});
|
|
@@ -406,10 +406,11 @@ async function attachHandler(args2) {
|
|
|
406
406
|
exitWithError(shellResult.error.message, exitCodes.generalError);
|
|
407
407
|
}
|
|
408
408
|
} else if (values.exec) {
|
|
409
|
+
const shell = process.env.SHELL || "/bin/sh";
|
|
409
410
|
const execResult = await execInWorktree(
|
|
410
411
|
gitRoot,
|
|
411
412
|
branchName,
|
|
412
|
-
values.exec
|
|
413
|
+
[shell, "-c", values.exec],
|
|
413
414
|
{ interactive: true }
|
|
414
415
|
);
|
|
415
416
|
if (isErr(execResult)) {
|
|
@@ -418,6 +419,198 @@ async function attachHandler(args2) {
|
|
|
418
419
|
}
|
|
419
420
|
}
|
|
420
421
|
|
|
422
|
+
// src/cli/handlers/completion.ts
|
|
423
|
+
import { exit } from "node:process";
|
|
424
|
+
var FISH_COMPLETION_SCRIPT = `# Fish completion for phantom
|
|
425
|
+
# Place this in ~/.config/fish/completions/phantom.fish
|
|
426
|
+
|
|
427
|
+
function __phantom_list_worktrees
|
|
428
|
+
phantom list --names 2>/dev/null
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
function __phantom_using_command
|
|
432
|
+
set -l cmd (commandline -opc)
|
|
433
|
+
set -l cmd_count (count $cmd)
|
|
434
|
+
if test $cmd_count -eq 1
|
|
435
|
+
# No subcommand yet, so any command can be used
|
|
436
|
+
if test (count $argv) -eq 0
|
|
437
|
+
return 0
|
|
438
|
+
else
|
|
439
|
+
return 1
|
|
440
|
+
end
|
|
441
|
+
else if test $cmd_count -ge 2
|
|
442
|
+
# Check if we're in the context of a specific command
|
|
443
|
+
if test (count $argv) -gt 0 -a "$argv[1]" = "$cmd[2]"
|
|
444
|
+
return 0
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
return 1
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
# Disable file completion for phantom
|
|
451
|
+
complete -c phantom -f
|
|
452
|
+
|
|
453
|
+
# Main commands
|
|
454
|
+
complete -c phantom -n "__phantom_using_command" -a "create" -d "Create a new Git worktree (phantom)"
|
|
455
|
+
complete -c phantom -n "__phantom_using_command" -a "attach" -d "Attach to an existing branch by creating a new worktree"
|
|
456
|
+
complete -c phantom -n "__phantom_using_command" -a "list" -d "List all Git worktrees (phantoms)"
|
|
457
|
+
complete -c phantom -n "__phantom_using_command" -a "where" -d "Output the filesystem path of a specific worktree"
|
|
458
|
+
complete -c phantom -n "__phantom_using_command" -a "delete" -d "Delete a Git worktree (phantom)"
|
|
459
|
+
complete -c phantom -n "__phantom_using_command" -a "exec" -d "Execute a command in a worktree directory"
|
|
460
|
+
complete -c phantom -n "__phantom_using_command" -a "shell" -d "Open an interactive shell in a worktree directory"
|
|
461
|
+
complete -c phantom -n "__phantom_using_command" -a "version" -d "Display phantom version information"
|
|
462
|
+
complete -c phantom -n "__phantom_using_command" -a "completion" -d "Generate shell completion scripts"
|
|
463
|
+
|
|
464
|
+
# Global options
|
|
465
|
+
complete -c phantom -l help -d "Show help (-h)"
|
|
466
|
+
complete -c phantom -l version -d "Show version (-v)"
|
|
467
|
+
|
|
468
|
+
# create command options
|
|
469
|
+
complete -c phantom -n "__phantom_using_command create" -l shell -d "Open an interactive shell in the new worktree after creation (-s)"
|
|
470
|
+
complete -c phantom -n "__phantom_using_command create" -l exec -d "Execute a command in the new worktree after creation (-x)" -x
|
|
471
|
+
complete -c phantom -n "__phantom_using_command create" -l tmux -d "Open the worktree in a new tmux window (-t)"
|
|
472
|
+
complete -c phantom -n "__phantom_using_command create" -l tmux-vertical -d "Open the worktree in a vertical tmux pane"
|
|
473
|
+
complete -c phantom -n "__phantom_using_command create" -l tmux-horizontal -d "Open the worktree in a horizontal tmux pane"
|
|
474
|
+
complete -c phantom -n "__phantom_using_command create" -l copy-file -d "Copy specified files from the current worktree" -r
|
|
475
|
+
|
|
476
|
+
# attach command options
|
|
477
|
+
complete -c phantom -n "__phantom_using_command attach" -l shell -d "Open an interactive shell in the worktree after attaching (-s)"
|
|
478
|
+
complete -c phantom -n "__phantom_using_command attach" -l exec -d "Execute a command in the worktree after attaching (-x)" -x
|
|
479
|
+
|
|
480
|
+
# list command options
|
|
481
|
+
complete -c phantom -n "__phantom_using_command list" -l fzf -d "Use fzf for interactive selection"
|
|
482
|
+
complete -c phantom -n "__phantom_using_command list" -l names -d "Output only phantom names (for scripts and completion)"
|
|
483
|
+
|
|
484
|
+
# where command options
|
|
485
|
+
complete -c phantom -n "__phantom_using_command where" -l fzf -d "Use fzf for interactive selection"
|
|
486
|
+
complete -c phantom -n "__phantom_using_command where" -a "(__phantom_list_worktrees)"
|
|
487
|
+
|
|
488
|
+
# delete command options
|
|
489
|
+
complete -c phantom -n "__phantom_using_command delete" -l force -d "Force deletion even if worktree has uncommitted changes (-f)"
|
|
490
|
+
complete -c phantom -n "__phantom_using_command delete" -l current -d "Delete the current worktree"
|
|
491
|
+
complete -c phantom -n "__phantom_using_command delete" -l fzf -d "Use fzf for interactive selection"
|
|
492
|
+
complete -c phantom -n "__phantom_using_command delete" -a "(__phantom_list_worktrees)"
|
|
493
|
+
|
|
494
|
+
# exec command - accept worktree names and then any command
|
|
495
|
+
complete -c phantom -n "__phantom_using_command exec" -a "(__phantom_list_worktrees)"
|
|
496
|
+
|
|
497
|
+
# shell command options
|
|
498
|
+
complete -c phantom -n "__phantom_using_command shell" -l fzf -d "Use fzf for interactive selection"
|
|
499
|
+
complete -c phantom -n "__phantom_using_command shell" -a "(__phantom_list_worktrees)"
|
|
500
|
+
|
|
501
|
+
# completion command - shell names
|
|
502
|
+
complete -c phantom -n "__phantom_using_command completion" -a "fish zsh" -d "Shell type"`;
|
|
503
|
+
var ZSH_COMPLETION_SCRIPT = `#compdef phantom
|
|
504
|
+
# Zsh completion for phantom
|
|
505
|
+
# Place this in a directory in your $fpath (e.g., ~/.zsh/completions/)
|
|
506
|
+
# Or load dynamically with: eval "$(phantom completion zsh)"
|
|
507
|
+
|
|
508
|
+
# Only define the function, don't execute it
|
|
509
|
+
_phantom() {
|
|
510
|
+
local -a commands
|
|
511
|
+
commands=(
|
|
512
|
+
'create:Create a new Git worktree (phantom)'
|
|
513
|
+
'attach:Attach to an existing branch by creating a new worktree'
|
|
514
|
+
'list:List all Git worktrees (phantoms)'
|
|
515
|
+
'where:Output the filesystem path of a specific worktree'
|
|
516
|
+
'delete:Delete a Git worktree (phantom)'
|
|
517
|
+
'exec:Execute a command in a worktree directory'
|
|
518
|
+
'shell:Open an interactive shell in a worktree directory'
|
|
519
|
+
'version:Display phantom version information'
|
|
520
|
+
'completion:Generate shell completion scripts'
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
_arguments -C \\
|
|
524
|
+
'--help[Show help (-h)]' \\
|
|
525
|
+
'--version[Show version (-v)]' \\
|
|
526
|
+
'1:command:->command' \\
|
|
527
|
+
'*::arg:->args'
|
|
528
|
+
|
|
529
|
+
case \${state} in
|
|
530
|
+
command)
|
|
531
|
+
_describe 'phantom command' commands
|
|
532
|
+
;;
|
|
533
|
+
args)
|
|
534
|
+
case \${line[1]} in
|
|
535
|
+
create)
|
|
536
|
+
_arguments \\
|
|
537
|
+
'--shell[Open an interactive shell in the new worktree after creation (-s)]' \\
|
|
538
|
+
'--exec[Execute a command in the new worktree after creation (-x)]:command:' \\
|
|
539
|
+
'--tmux[Open the worktree in a new tmux window (-t)]' \\
|
|
540
|
+
'--tmux-vertical[Open the worktree in a vertical tmux pane]' \\
|
|
541
|
+
'--tmux-horizontal[Open the worktree in a horizontal tmux pane]' \\
|
|
542
|
+
'*--copy-file[Copy specified files from the current worktree]:file:_files' \\
|
|
543
|
+
'1:name:'
|
|
544
|
+
;;
|
|
545
|
+
attach)
|
|
546
|
+
_arguments \\
|
|
547
|
+
'--shell[Open an interactive shell in the worktree after attaching (-s)]' \\
|
|
548
|
+
'--exec[Execute a command in the worktree after attaching (-x)]:command:' \\
|
|
549
|
+
'1:worktree-name:' \\
|
|
550
|
+
'2:branch-name:'
|
|
551
|
+
;;
|
|
552
|
+
list)
|
|
553
|
+
_arguments \\
|
|
554
|
+
'--fzf[Use fzf for interactive selection]' \\
|
|
555
|
+
'--names[Output only phantom names (for scripts and completion)]'
|
|
556
|
+
;;
|
|
557
|
+
where|delete|shell)
|
|
558
|
+
local worktrees
|
|
559
|
+
worktrees=(\${(f)"$(phantom list --names 2>/dev/null)"})
|
|
560
|
+
if [[ \${line[1]} == "where" || \${line[1]} == "shell" ]]; then
|
|
561
|
+
_arguments \\
|
|
562
|
+
'--fzf[Use fzf for interactive selection]' \\
|
|
563
|
+
'1:worktree:(\${(q)worktrees[@]})'
|
|
564
|
+
elif [[ \${line[1]} == "delete" ]]; then
|
|
565
|
+
_arguments \\
|
|
566
|
+
'--force[Force deletion even if worktree has uncommitted changes (-f)]' \\
|
|
567
|
+
'--current[Delete the current worktree]' \\
|
|
568
|
+
'--fzf[Use fzf for interactive selection]' \\
|
|
569
|
+
'1:worktree:(\${(q)worktrees[@]})'
|
|
570
|
+
fi
|
|
571
|
+
;;
|
|
572
|
+
exec)
|
|
573
|
+
local worktrees
|
|
574
|
+
worktrees=(\${(f)"$(phantom list --names 2>/dev/null)"})
|
|
575
|
+
_arguments \\
|
|
576
|
+
'1:worktree:(\${(q)worktrees[@]})' \\
|
|
577
|
+
'*:command:_command_names'
|
|
578
|
+
;;
|
|
579
|
+
completion)
|
|
580
|
+
_arguments \\
|
|
581
|
+
'1:shell:(fish zsh)'
|
|
582
|
+
;;
|
|
583
|
+
esac
|
|
584
|
+
;;
|
|
585
|
+
esac
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
# Register the completion function if loading dynamically
|
|
589
|
+
if [[ -n \${ZSH_VERSION} ]]; then
|
|
590
|
+
autoload -Uz compinit && compinit -C
|
|
591
|
+
compdef _phantom phantom
|
|
592
|
+
fi`;
|
|
593
|
+
function completionHandler(args2) {
|
|
594
|
+
const shell = args2[0];
|
|
595
|
+
if (!shell) {
|
|
596
|
+
output.error("Usage: phantom completion <shell>");
|
|
597
|
+
output.error("Supported shells: fish, zsh");
|
|
598
|
+
exit(1);
|
|
599
|
+
}
|
|
600
|
+
switch (shell.toLowerCase()) {
|
|
601
|
+
case "fish":
|
|
602
|
+
console.log(FISH_COMPLETION_SCRIPT);
|
|
603
|
+
break;
|
|
604
|
+
case "zsh":
|
|
605
|
+
console.log(ZSH_COMPLETION_SCRIPT);
|
|
606
|
+
break;
|
|
607
|
+
default:
|
|
608
|
+
output.error(`Unsupported shell: ${shell}`);
|
|
609
|
+
output.error("Supported shells: fish, zsh");
|
|
610
|
+
exit(1);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
421
614
|
// src/cli/handlers/create.ts
|
|
422
615
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
423
616
|
|
|
@@ -523,11 +716,14 @@ async function isInsideTmux() {
|
|
|
523
716
|
return process.env.TMUX !== void 0;
|
|
524
717
|
}
|
|
525
718
|
async function executeTmuxCommand(options) {
|
|
526
|
-
const { direction, command: command2, cwd, env } = options;
|
|
719
|
+
const { direction, command: command2, args: args2, cwd, env, windowName } = options;
|
|
527
720
|
const tmuxArgs = [];
|
|
528
721
|
switch (direction) {
|
|
529
722
|
case "new":
|
|
530
723
|
tmuxArgs.push("new-window");
|
|
724
|
+
if (windowName) {
|
|
725
|
+
tmuxArgs.push("-n", windowName);
|
|
726
|
+
}
|
|
531
727
|
break;
|
|
532
728
|
case "vertical":
|
|
533
729
|
tmuxArgs.push("split-window", "-v");
|
|
@@ -545,6 +741,9 @@ async function executeTmuxCommand(options) {
|
|
|
545
741
|
}
|
|
546
742
|
}
|
|
547
743
|
tmuxArgs.push(command2);
|
|
744
|
+
if (args2 && args2.length > 0) {
|
|
745
|
+
tmuxArgs.push(...args2);
|
|
746
|
+
}
|
|
548
747
|
const result = await spawnProcess({
|
|
549
748
|
command: "tmux",
|
|
550
749
|
args: tmuxArgs
|
|
@@ -619,8 +818,8 @@ async function createWorktree(gitRoot, name, options = {}) {
|
|
|
619
818
|
await fs3.mkdir(worktreesPath, { recursive: true });
|
|
620
819
|
}
|
|
621
820
|
const validation = await validateWorktreeDoesNotExist(gitRoot, name);
|
|
622
|
-
if (validation
|
|
623
|
-
return err(
|
|
821
|
+
if (isErr(validation)) {
|
|
822
|
+
return err(validation.error);
|
|
624
823
|
}
|
|
625
824
|
try {
|
|
626
825
|
await addWorktree({
|
|
@@ -825,11 +1024,8 @@ Opening worktree '${worktreeName}' in tmux ${tmuxDirection === "new" ? "window"
|
|
|
825
1024
|
direction: tmuxDirection,
|
|
826
1025
|
command: shell,
|
|
827
1026
|
cwd: result.value.path,
|
|
828
|
-
env:
|
|
829
|
-
|
|
830
|
-
PHANTOM_NAME: worktreeName,
|
|
831
|
-
PHANTOM_PATH: result.value.path
|
|
832
|
-
}
|
|
1027
|
+
env: getPhantomEnv(worktreeName, result.value.path),
|
|
1028
|
+
windowName: tmuxDirection === "new" ? worktreeName : void 0
|
|
833
1029
|
});
|
|
834
1030
|
if (isErr(tmuxResult)) {
|
|
835
1031
|
output.error(tmuxResult.error.message);
|
|
@@ -956,10 +1152,10 @@ async function deleteBranch(gitRoot, branchName) {
|
|
|
956
1152
|
async function deleteWorktree(gitRoot, name, options = {}) {
|
|
957
1153
|
const { force = false } = options;
|
|
958
1154
|
const validation = await validateWorktreeExists(gitRoot, name);
|
|
959
|
-
if (
|
|
960
|
-
return err(
|
|
1155
|
+
if (isErr(validation)) {
|
|
1156
|
+
return err(validation.error);
|
|
961
1157
|
}
|
|
962
|
-
const worktreePath = validation.path;
|
|
1158
|
+
const worktreePath = validation.value.path;
|
|
963
1159
|
const status = await getWorktreeStatus(worktreePath);
|
|
964
1160
|
if (status.hasUncommittedChanges && !force) {
|
|
965
1161
|
return err(
|
|
@@ -1114,7 +1310,7 @@ async function selectWorktreeWithFzf(gitRoot) {
|
|
|
1114
1310
|
});
|
|
1115
1311
|
const fzfResult = await selectWithFzf(list, {
|
|
1116
1312
|
prompt: "Select worktree> ",
|
|
1117
|
-
header: "Git Worktrees
|
|
1313
|
+
header: "Git Worktrees"
|
|
1118
1314
|
});
|
|
1119
1315
|
if (isErr(fzfResult)) {
|
|
1120
1316
|
return fzfResult;
|
|
@@ -1228,21 +1424,106 @@ async function deleteHandler(args2) {
|
|
|
1228
1424
|
// src/cli/handlers/exec.ts
|
|
1229
1425
|
import { parseArgs as parseArgs4 } from "node:util";
|
|
1230
1426
|
async function execHandler(args2) {
|
|
1231
|
-
const { positionals } = parseArgs4({
|
|
1427
|
+
const { positionals, values } = parseArgs4({
|
|
1232
1428
|
args: args2,
|
|
1233
|
-
options: {
|
|
1429
|
+
options: {
|
|
1430
|
+
fzf: {
|
|
1431
|
+
type: "boolean",
|
|
1432
|
+
default: false
|
|
1433
|
+
},
|
|
1434
|
+
tmux: {
|
|
1435
|
+
type: "boolean",
|
|
1436
|
+
short: "t"
|
|
1437
|
+
},
|
|
1438
|
+
"tmux-vertical": {
|
|
1439
|
+
type: "boolean"
|
|
1440
|
+
},
|
|
1441
|
+
"tmux-v": {
|
|
1442
|
+
type: "boolean"
|
|
1443
|
+
},
|
|
1444
|
+
"tmux-horizontal": {
|
|
1445
|
+
type: "boolean"
|
|
1446
|
+
},
|
|
1447
|
+
"tmux-h": {
|
|
1448
|
+
type: "boolean"
|
|
1449
|
+
}
|
|
1450
|
+
},
|
|
1234
1451
|
strict: true,
|
|
1235
1452
|
allowPositionals: true
|
|
1236
1453
|
});
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1454
|
+
const useFzf = values.fzf ?? false;
|
|
1455
|
+
const tmuxOption = values.tmux || values["tmux-vertical"] || values["tmux-v"] || values["tmux-horizontal"] || values["tmux-h"];
|
|
1456
|
+
let tmuxDirection;
|
|
1457
|
+
if (values.tmux) {
|
|
1458
|
+
tmuxDirection = "new";
|
|
1459
|
+
} else if (values["tmux-vertical"] || values["tmux-v"]) {
|
|
1460
|
+
tmuxDirection = "vertical";
|
|
1461
|
+
} else if (values["tmux-horizontal"] || values["tmux-h"]) {
|
|
1462
|
+
tmuxDirection = "horizontal";
|
|
1463
|
+
}
|
|
1464
|
+
let commandArgs;
|
|
1465
|
+
if (useFzf) {
|
|
1466
|
+
if (positionals.length < 1) {
|
|
1467
|
+
exitWithError(
|
|
1468
|
+
"Usage: phantom exec --fzf <command> [args...]",
|
|
1469
|
+
exitCodes.validationError
|
|
1470
|
+
);
|
|
1471
|
+
}
|
|
1472
|
+
commandArgs = positionals;
|
|
1473
|
+
} else {
|
|
1474
|
+
if (positionals.length < 2) {
|
|
1475
|
+
exitWithError(
|
|
1476
|
+
"Usage: phantom exec <worktree-name> <command> [args...]",
|
|
1477
|
+
exitCodes.validationError
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
commandArgs = positionals.slice(1);
|
|
1242
1481
|
}
|
|
1243
|
-
const [worktreeName, ...commandArgs] = positionals;
|
|
1244
1482
|
try {
|
|
1245
1483
|
const gitRoot = await getGitRoot();
|
|
1484
|
+
if (tmuxOption && !await isInsideTmux()) {
|
|
1485
|
+
exitWithError(
|
|
1486
|
+
"The --tmux option can only be used inside a tmux session",
|
|
1487
|
+
exitCodes.validationError
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
let worktreeName;
|
|
1491
|
+
if (useFzf) {
|
|
1492
|
+
const selectResult = await selectWorktreeWithFzf(gitRoot);
|
|
1493
|
+
if (isErr(selectResult)) {
|
|
1494
|
+
exitWithError(selectResult.error.message, exitCodes.generalError);
|
|
1495
|
+
}
|
|
1496
|
+
if (!selectResult.value) {
|
|
1497
|
+
exitWithSuccess();
|
|
1498
|
+
}
|
|
1499
|
+
worktreeName = selectResult.value.name;
|
|
1500
|
+
} else {
|
|
1501
|
+
worktreeName = positionals[0];
|
|
1502
|
+
}
|
|
1503
|
+
const validation = await validateWorktreeExists(gitRoot, worktreeName);
|
|
1504
|
+
if (isErr(validation)) {
|
|
1505
|
+
exitWithError(validation.error.message, exitCodes.generalError);
|
|
1506
|
+
}
|
|
1507
|
+
if (tmuxDirection) {
|
|
1508
|
+
output.log(
|
|
1509
|
+
`Executing command in worktree '${worktreeName}' in tmux ${tmuxDirection === "new" ? "window" : "pane"}...`
|
|
1510
|
+
);
|
|
1511
|
+
const [command2, ...args3] = commandArgs;
|
|
1512
|
+
const tmuxResult = await executeTmuxCommand({
|
|
1513
|
+
direction: tmuxDirection,
|
|
1514
|
+
command: command2,
|
|
1515
|
+
args: args3,
|
|
1516
|
+
cwd: validation.value.path,
|
|
1517
|
+
env: getPhantomEnv(worktreeName, validation.value.path),
|
|
1518
|
+
windowName: tmuxDirection === "new" ? worktreeName : void 0
|
|
1519
|
+
});
|
|
1520
|
+
if (isErr(tmuxResult)) {
|
|
1521
|
+
output.error(tmuxResult.error.message);
|
|
1522
|
+
const exitCode = "exitCode" in tmuxResult.error ? tmuxResult.error.exitCode ?? exitCodes.generalError : exitCodes.generalError;
|
|
1523
|
+
exitWithError("", exitCode);
|
|
1524
|
+
}
|
|
1525
|
+
exitWithSuccess();
|
|
1526
|
+
}
|
|
1246
1527
|
const result = await execInWorktree(
|
|
1247
1528
|
gitRoot,
|
|
1248
1529
|
worktreeName,
|
|
@@ -1336,12 +1617,37 @@ async function shellHandler(args2) {
|
|
|
1336
1617
|
fzf: {
|
|
1337
1618
|
type: "boolean",
|
|
1338
1619
|
default: false
|
|
1620
|
+
},
|
|
1621
|
+
tmux: {
|
|
1622
|
+
type: "boolean",
|
|
1623
|
+
short: "t"
|
|
1624
|
+
},
|
|
1625
|
+
"tmux-vertical": {
|
|
1626
|
+
type: "boolean"
|
|
1627
|
+
},
|
|
1628
|
+
"tmux-v": {
|
|
1629
|
+
type: "boolean"
|
|
1630
|
+
},
|
|
1631
|
+
"tmux-horizontal": {
|
|
1632
|
+
type: "boolean"
|
|
1633
|
+
},
|
|
1634
|
+
"tmux-h": {
|
|
1635
|
+
type: "boolean"
|
|
1339
1636
|
}
|
|
1340
1637
|
},
|
|
1341
1638
|
strict: true,
|
|
1342
1639
|
allowPositionals: true
|
|
1343
1640
|
});
|
|
1344
1641
|
const useFzf = values.fzf ?? false;
|
|
1642
|
+
const tmuxOption = values.tmux || values["tmux-vertical"] || values["tmux-v"] || values["tmux-horizontal"] || values["tmux-h"];
|
|
1643
|
+
let tmuxDirection;
|
|
1644
|
+
if (values.tmux) {
|
|
1645
|
+
tmuxDirection = "new";
|
|
1646
|
+
} else if (values["tmux-vertical"] || values["tmux-v"]) {
|
|
1647
|
+
tmuxDirection = "vertical";
|
|
1648
|
+
} else if (values["tmux-horizontal"] || values["tmux-h"]) {
|
|
1649
|
+
tmuxDirection = "horizontal";
|
|
1650
|
+
}
|
|
1345
1651
|
if (positionals.length === 0 && !useFzf) {
|
|
1346
1652
|
exitWithError(
|
|
1347
1653
|
"Usage: phantom shell <worktree-name> or phantom shell --fzf",
|
|
@@ -1357,6 +1663,12 @@ async function shellHandler(args2) {
|
|
|
1357
1663
|
let worktreeName;
|
|
1358
1664
|
try {
|
|
1359
1665
|
const gitRoot = await getGitRoot();
|
|
1666
|
+
if (tmuxOption && !await isInsideTmux()) {
|
|
1667
|
+
exitWithError(
|
|
1668
|
+
"The --tmux option can only be used inside a tmux session",
|
|
1669
|
+
exitCodes.validationError
|
|
1670
|
+
);
|
|
1671
|
+
}
|
|
1360
1672
|
if (useFzf) {
|
|
1361
1673
|
const selectResult = await selectWorktreeWithFzf(gitRoot);
|
|
1362
1674
|
if (isErr(selectResult)) {
|
|
@@ -1370,13 +1682,31 @@ async function shellHandler(args2) {
|
|
|
1370
1682
|
worktreeName = positionals[0];
|
|
1371
1683
|
}
|
|
1372
1684
|
const validation = await validateWorktreeExists(gitRoot, worktreeName);
|
|
1373
|
-
if (
|
|
1374
|
-
exitWithError(
|
|
1375
|
-
|
|
1376
|
-
|
|
1685
|
+
if (isErr(validation)) {
|
|
1686
|
+
exitWithError(validation.error.message, exitCodes.generalError);
|
|
1687
|
+
}
|
|
1688
|
+
if (tmuxDirection) {
|
|
1689
|
+
output.log(
|
|
1690
|
+
`Opening worktree '${worktreeName}' in tmux ${tmuxDirection === "new" ? "window" : "pane"}...`
|
|
1377
1691
|
);
|
|
1692
|
+
const shell = process.env.SHELL || "/bin/sh";
|
|
1693
|
+
const tmuxResult = await executeTmuxCommand({
|
|
1694
|
+
direction: tmuxDirection,
|
|
1695
|
+
command: shell,
|
|
1696
|
+
cwd: validation.value.path,
|
|
1697
|
+
env: getPhantomEnv(worktreeName, validation.value.path),
|
|
1698
|
+
windowName: tmuxDirection === "new" ? worktreeName : void 0
|
|
1699
|
+
});
|
|
1700
|
+
if (isErr(tmuxResult)) {
|
|
1701
|
+
output.error(tmuxResult.error.message);
|
|
1702
|
+
const exitCode = "exitCode" in tmuxResult.error ? tmuxResult.error.exitCode ?? exitCodes.generalError : exitCodes.generalError;
|
|
1703
|
+
exitWithError("", exitCode);
|
|
1704
|
+
}
|
|
1705
|
+
exitWithSuccess();
|
|
1378
1706
|
}
|
|
1379
|
-
output.log(
|
|
1707
|
+
output.log(
|
|
1708
|
+
`Entering worktree '${worktreeName}' at ${validation.value.path}`
|
|
1709
|
+
);
|
|
1380
1710
|
output.log("Type 'exit' to return to your original directory\n");
|
|
1381
1711
|
const result = await shellInWorktree(gitRoot, worktreeName);
|
|
1382
1712
|
if (isErr(result)) {
|
|
@@ -1399,7 +1729,7 @@ import { parseArgs as parseArgs7 } from "node:util";
|
|
|
1399
1729
|
var package_default = {
|
|
1400
1730
|
name: "@aku11i/phantom",
|
|
1401
1731
|
packageManager: "pnpm@10.8.1",
|
|
1402
|
-
version: "0.
|
|
1732
|
+
version: "1.0.0",
|
|
1403
1733
|
description: "A powerful CLI tool for managing Git worktrees for parallel development",
|
|
1404
1734
|
keywords: [
|
|
1405
1735
|
"git",
|
|
@@ -1479,11 +1809,11 @@ import { parseArgs as parseArgs8 } from "node:util";
|
|
|
1479
1809
|
// src/core/worktree/where.ts
|
|
1480
1810
|
async function whereWorktree(gitRoot, name) {
|
|
1481
1811
|
const validation = await validateWorktreeExists(gitRoot, name);
|
|
1482
|
-
if (
|
|
1483
|
-
return err(
|
|
1812
|
+
if (isErr(validation)) {
|
|
1813
|
+
return err(validation.error);
|
|
1484
1814
|
}
|
|
1485
1815
|
return ok({
|
|
1486
|
-
path: validation.path
|
|
1816
|
+
path: validation.value.path
|
|
1487
1817
|
});
|
|
1488
1818
|
}
|
|
1489
1819
|
|
|
@@ -1729,10 +2059,41 @@ var attachHelp = {
|
|
|
1729
2059
|
]
|
|
1730
2060
|
};
|
|
1731
2061
|
|
|
2062
|
+
// src/cli/help/completion.ts
|
|
2063
|
+
var completionHelp = {
|
|
2064
|
+
name: "completion",
|
|
2065
|
+
usage: "phantom completion <shell>",
|
|
2066
|
+
description: "Generate shell completion scripts for fish or zsh",
|
|
2067
|
+
examples: [
|
|
2068
|
+
{
|
|
2069
|
+
command: "phantom completion fish > ~/.config/fish/completions/phantom.fish",
|
|
2070
|
+
description: "Generate and install Fish completion"
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
command: "phantom completion fish | source",
|
|
2074
|
+
description: "Load Fish completion in current session"
|
|
2075
|
+
},
|
|
2076
|
+
{
|
|
2077
|
+
command: "phantom completion zsh > ~/.zsh/completions/_phantom",
|
|
2078
|
+
description: "Generate and install Zsh completion"
|
|
2079
|
+
},
|
|
2080
|
+
{
|
|
2081
|
+
command: 'eval "$(phantom completion zsh)"',
|
|
2082
|
+
description: "Load Zsh completion in current session"
|
|
2083
|
+
}
|
|
2084
|
+
],
|
|
2085
|
+
notes: [
|
|
2086
|
+
"Supported shells: fish, zsh",
|
|
2087
|
+
"After installing completions, you may need to restart your shell or source the completion file",
|
|
2088
|
+
"For Fish: completions are loaded automatically from ~/.config/fish/completions/",
|
|
2089
|
+
"For Zsh: ensure the completion file is in a directory in your $fpath"
|
|
2090
|
+
]
|
|
2091
|
+
};
|
|
2092
|
+
|
|
1732
2093
|
// src/cli/help/create.ts
|
|
1733
2094
|
var createHelp = {
|
|
1734
2095
|
name: "create",
|
|
1735
|
-
description: "Create a new Git worktree
|
|
2096
|
+
description: "Create a new Git worktree",
|
|
1736
2097
|
usage: "phantom create <name> [options]",
|
|
1737
2098
|
options: [
|
|
1738
2099
|
{
|
|
@@ -1804,7 +2165,7 @@ var createHelp = {
|
|
|
1804
2165
|
// src/cli/help/delete.ts
|
|
1805
2166
|
var deleteHelp = {
|
|
1806
2167
|
name: "delete",
|
|
1807
|
-
description: "Delete a Git worktree
|
|
2168
|
+
description: "Delete a Git worktree",
|
|
1808
2169
|
usage: "phantom delete <name> [options]",
|
|
1809
2170
|
options: [
|
|
1810
2171
|
{
|
|
@@ -1853,7 +2214,29 @@ var deleteHelp = {
|
|
|
1853
2214
|
var execHelp = {
|
|
1854
2215
|
name: "exec",
|
|
1855
2216
|
description: "Execute a command in a worktree directory",
|
|
1856
|
-
usage: "phantom exec <worktree-name> <command> [args...]",
|
|
2217
|
+
usage: "phantom exec [options] <worktree-name> <command> [args...]",
|
|
2218
|
+
options: [
|
|
2219
|
+
{
|
|
2220
|
+
name: "--fzf",
|
|
2221
|
+
type: "boolean",
|
|
2222
|
+
description: "Use fzf for interactive worktree selection"
|
|
2223
|
+
},
|
|
2224
|
+
{
|
|
2225
|
+
name: "--tmux, -t",
|
|
2226
|
+
type: "boolean",
|
|
2227
|
+
description: "Execute command in new tmux window"
|
|
2228
|
+
},
|
|
2229
|
+
{
|
|
2230
|
+
name: "--tmux-vertical, --tmux-v",
|
|
2231
|
+
type: "boolean",
|
|
2232
|
+
description: "Execute command in vertical split pane"
|
|
2233
|
+
},
|
|
2234
|
+
{
|
|
2235
|
+
name: "--tmux-horizontal, --tmux-h",
|
|
2236
|
+
type: "boolean",
|
|
2237
|
+
description: "Execute command in horizontal split pane"
|
|
2238
|
+
}
|
|
2239
|
+
],
|
|
1857
2240
|
examples: [
|
|
1858
2241
|
{
|
|
1859
2242
|
description: "Run npm test in a worktree",
|
|
@@ -1866,19 +2249,37 @@ var execHelp = {
|
|
|
1866
2249
|
{
|
|
1867
2250
|
description: "Run a complex command with arguments",
|
|
1868
2251
|
command: "phantom exec staging npm run build -- --production"
|
|
2252
|
+
},
|
|
2253
|
+
{
|
|
2254
|
+
description: "Execute with interactive selection",
|
|
2255
|
+
command: "phantom exec --fzf npm run dev"
|
|
2256
|
+
},
|
|
2257
|
+
{
|
|
2258
|
+
description: "Run dev server in new tmux window",
|
|
2259
|
+
command: "phantom exec --tmux feature-auth npm run dev"
|
|
2260
|
+
},
|
|
2261
|
+
{
|
|
2262
|
+
description: "Run tests in vertical split pane",
|
|
2263
|
+
command: "phantom exec --tmux-v feature-auth npm test"
|
|
2264
|
+
},
|
|
2265
|
+
{
|
|
2266
|
+
description: "Interactive selection with tmux",
|
|
2267
|
+
command: "phantom exec --fzf --tmux npm run dev"
|
|
1869
2268
|
}
|
|
1870
2269
|
],
|
|
1871
2270
|
notes: [
|
|
1872
2271
|
"The command is executed with the worktree directory as the working directory",
|
|
1873
2272
|
"All arguments after the worktree name are passed to the command",
|
|
1874
|
-
"The exit code of the executed command is preserved"
|
|
2273
|
+
"The exit code of the executed command is preserved",
|
|
2274
|
+
"With --fzf, select the worktree interactively before executing the command",
|
|
2275
|
+
"Tmux options require being inside a tmux session"
|
|
1875
2276
|
]
|
|
1876
2277
|
};
|
|
1877
2278
|
|
|
1878
2279
|
// src/cli/help/list.ts
|
|
1879
2280
|
var listHelp = {
|
|
1880
2281
|
name: "list",
|
|
1881
|
-
description: "List all Git worktrees
|
|
2282
|
+
description: "List all Git worktrees",
|
|
1882
2283
|
usage: "phantom list [options]",
|
|
1883
2284
|
options: [
|
|
1884
2285
|
{
|
|
@@ -1889,7 +2290,7 @@ var listHelp = {
|
|
|
1889
2290
|
{
|
|
1890
2291
|
name: "--names",
|
|
1891
2292
|
type: "boolean",
|
|
1892
|
-
description: "Output only
|
|
2293
|
+
description: "Output only worktree names (for scripts and completion)"
|
|
1893
2294
|
}
|
|
1894
2295
|
],
|
|
1895
2296
|
examples: [
|
|
@@ -1924,6 +2325,21 @@ var shellHelp = {
|
|
|
1924
2325
|
name: "--fzf",
|
|
1925
2326
|
type: "boolean",
|
|
1926
2327
|
description: "Use fzf for interactive selection"
|
|
2328
|
+
},
|
|
2329
|
+
{
|
|
2330
|
+
name: "--tmux, -t",
|
|
2331
|
+
type: "boolean",
|
|
2332
|
+
description: "Open shell in new tmux window"
|
|
2333
|
+
},
|
|
2334
|
+
{
|
|
2335
|
+
name: "--tmux-vertical, --tmux-v",
|
|
2336
|
+
type: "boolean",
|
|
2337
|
+
description: "Open shell in vertical split pane"
|
|
2338
|
+
},
|
|
2339
|
+
{
|
|
2340
|
+
name: "--tmux-horizontal, --tmux-h",
|
|
2341
|
+
type: "boolean",
|
|
2342
|
+
description: "Open shell in horizontal split pane"
|
|
1927
2343
|
}
|
|
1928
2344
|
],
|
|
1929
2345
|
examples: [
|
|
@@ -1934,13 +2350,26 @@ var shellHelp = {
|
|
|
1934
2350
|
{
|
|
1935
2351
|
description: "Open a shell with interactive fzf selection",
|
|
1936
2352
|
command: "phantom shell --fzf"
|
|
2353
|
+
},
|
|
2354
|
+
{
|
|
2355
|
+
description: "Open a shell in a new tmux window",
|
|
2356
|
+
command: "phantom shell feature-auth --tmux"
|
|
2357
|
+
},
|
|
2358
|
+
{
|
|
2359
|
+
description: "Open a shell in a vertical tmux pane",
|
|
2360
|
+
command: "phantom shell feature-auth --tmux-v"
|
|
2361
|
+
},
|
|
2362
|
+
{
|
|
2363
|
+
description: "Interactive selection with tmux",
|
|
2364
|
+
command: "phantom shell --fzf --tmux"
|
|
1937
2365
|
}
|
|
1938
2366
|
],
|
|
1939
2367
|
notes: [
|
|
1940
2368
|
"Uses your default shell from the SHELL environment variable",
|
|
1941
2369
|
"The shell starts with the worktree directory as the working directory",
|
|
1942
2370
|
"Type 'exit' to return to your original directory",
|
|
1943
|
-
"With --fzf, you can interactively select the worktree to enter"
|
|
2371
|
+
"With --fzf, you can interactively select the worktree to enter",
|
|
2372
|
+
"Tmux options require being inside a tmux session"
|
|
1944
2373
|
]
|
|
1945
2374
|
};
|
|
1946
2375
|
|
|
@@ -2044,6 +2473,12 @@ var commands = [
|
|
|
2044
2473
|
description: "Display phantom version information",
|
|
2045
2474
|
handler: versionHandler,
|
|
2046
2475
|
help: versionHelp
|
|
2476
|
+
},
|
|
2477
|
+
{
|
|
2478
|
+
name: "completion",
|
|
2479
|
+
description: "Generate shell completion scripts",
|
|
2480
|
+
handler: completionHandler,
|
|
2481
|
+
help: completionHelp
|
|
2047
2482
|
}
|
|
2048
2483
|
];
|
|
2049
2484
|
function printHelp(commands2) {
|
|
@@ -2076,18 +2511,18 @@ function findCommand(args2, commands2) {
|
|
|
2076
2511
|
var args = argv.slice(2);
|
|
2077
2512
|
if (args.length === 0 || args[0] === "-h" || args[0] === "--help") {
|
|
2078
2513
|
printHelp(commands);
|
|
2079
|
-
|
|
2514
|
+
exit2(0);
|
|
2080
2515
|
}
|
|
2081
2516
|
if (args[0] === "--version" || args[0] === "-v") {
|
|
2082
2517
|
versionHandler();
|
|
2083
|
-
|
|
2518
|
+
exit2(0);
|
|
2084
2519
|
}
|
|
2085
2520
|
var { command, remainingArgs } = findCommand(args, commands);
|
|
2086
2521
|
if (!command || !command.handler) {
|
|
2087
2522
|
console.error(`Error: Unknown command '${args.join(" ")}'
|
|
2088
2523
|
`);
|
|
2089
2524
|
printHelp(commands);
|
|
2090
|
-
|
|
2525
|
+
exit2(1);
|
|
2091
2526
|
}
|
|
2092
2527
|
if (remainingArgs.includes("--help") || remainingArgs.includes("-h")) {
|
|
2093
2528
|
if (command.help) {
|
|
@@ -2095,7 +2530,7 @@ if (remainingArgs.includes("--help") || remainingArgs.includes("-h")) {
|
|
|
2095
2530
|
} else {
|
|
2096
2531
|
console.log(`Help not available for command '${command.name}'`);
|
|
2097
2532
|
}
|
|
2098
|
-
|
|
2533
|
+
exit2(0);
|
|
2099
2534
|
}
|
|
2100
2535
|
try {
|
|
2101
2536
|
await command.handler(remainingArgs);
|
|
@@ -2104,6 +2539,6 @@ try {
|
|
|
2104
2539
|
"Error:",
|
|
2105
2540
|
error instanceof Error ? error.message : String(error)
|
|
2106
2541
|
);
|
|
2107
|
-
|
|
2542
|
+
exit2(1);
|
|
2108
2543
|
}
|
|
2109
2544
|
//# sourceMappingURL=phantom.js.map
|