@aku11i/phantom 2.2.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/phantom.js +121 -189
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aku11i/phantom",
3
- "version": "2.2.4",
3
+ "version": "3.0.0",
4
4
  "description": "A powerful CLI tool for managing Git worktrees for parallel development",
5
5
  "keywords": [
6
6
  "git",
package/phantom.js CHANGED
@@ -4206,8 +4206,7 @@ var phantomConfigSchema = external_exports.object({
4206
4206
  preDelete: external_exports.object({
4207
4207
  commands: external_exports.array(external_exports.string()).optional()
4208
4208
  }).passthrough().optional(),
4209
- worktreesDirectory: external_exports.string().optional(),
4210
- defaultBranch: external_exports.string().optional()
4209
+ worktreesDirectory: external_exports.string().optional()
4211
4210
  }).passthrough();
4212
4211
  function validateConfig(config) {
4213
4212
  const result = phantomConfigSchema.safeParse(config);
@@ -5239,6 +5238,26 @@ async function attachHandler(args2) {
5239
5238
  exec: {
5240
5239
  type: "string",
5241
5240
  short: "x"
5241
+ },
5242
+ tmux: {
5243
+ type: "boolean",
5244
+ short: "t"
5245
+ },
5246
+ "tmux-vertical": {
5247
+ type: "boolean"
5248
+ },
5249
+ "tmux-v": {
5250
+ type: "boolean"
5251
+ },
5252
+ "tmux-horizontal": {
5253
+ type: "boolean"
5254
+ },
5255
+ "tmux-h": {
5256
+ type: "boolean"
5257
+ },
5258
+ "copy-file": {
5259
+ type: "string",
5260
+ multiple: true
5242
5261
  }
5243
5262
  }
5244
5263
  });
@@ -5249,19 +5268,34 @@ async function attachHandler(args2) {
5249
5268
  );
5250
5269
  }
5251
5270
  const [branchName] = positionals;
5252
- if (values.shell && values.exec) {
5271
+ const tmuxOption = values.tmux || values["tmux-vertical"] || values["tmux-v"] || values["tmux-horizontal"] || values["tmux-h"];
5272
+ const copyFileOptions = values["copy-file"];
5273
+ const tmuxDirection = values.tmux ? "new" : values["tmux-vertical"] || values["tmux-v"] ? "vertical" : values["tmux-horizontal"] || values["tmux-h"] ? "horizontal" : void 0;
5274
+ if ([values.shell, values.exec, tmuxOption].filter(Boolean).length > 1) {
5253
5275
  exitWithError(
5254
- "Cannot use both --shell and --exec options",
5276
+ "Cannot use --shell, --exec, and --tmux options together",
5255
5277
  exitCodes.validationError
5256
5278
  );
5257
5279
  }
5258
5280
  const gitRoot = await getGitRoot();
5259
5281
  const context = await createContext(gitRoot);
5282
+ let copyFiles2 = context.config?.postCreate?.copyFiles ?? [];
5283
+ if (copyFileOptions && copyFileOptions.length > 0) {
5284
+ const cliCopyFiles = Array.isArray(copyFileOptions) ? copyFileOptions : [copyFileOptions];
5285
+ copyFiles2 = [.../* @__PURE__ */ new Set([...copyFiles2, ...cliCopyFiles])];
5286
+ }
5287
+ const postCreateCopyFiles = copyFiles2.length > 0 ? copyFiles2 : void 0;
5288
+ if (tmuxOption && !await isInsideTmux()) {
5289
+ exitWithError(
5290
+ "The --tmux option can only be used inside a tmux session",
5291
+ exitCodes.validationError
5292
+ );
5293
+ }
5260
5294
  const result = await attachWorktreeCore(
5261
5295
  context.gitRoot,
5262
5296
  context.worktreesDirectory,
5263
5297
  branchName,
5264
- context.config?.postCreate?.copyFiles,
5298
+ postCreateCopyFiles,
5265
5299
  context.config?.postCreate?.commands
5266
5300
  );
5267
5301
  if (isErr(result)) {
@@ -5275,6 +5309,7 @@ async function attachHandler(args2) {
5275
5309
  exitWithError(error.message, exitCodes.generalError);
5276
5310
  }
5277
5311
  output.log(`Attached phantom: ${branchName}`);
5312
+ const worktreePath = result.value;
5278
5313
  if (values.shell) {
5279
5314
  const shellResult = await shellInWorktree(
5280
5315
  context.gitRoot,
@@ -5296,6 +5331,21 @@ async function attachHandler(args2) {
5296
5331
  if (isErr(execResult)) {
5297
5332
  exitWithError(execResult.error.message, exitCodes.generalError);
5298
5333
  }
5334
+ } else if (tmuxDirection) {
5335
+ output.log(
5336
+ `Opening worktree '${branchName}' in tmux ${tmuxDirection === "new" ? "window" : "pane"}...`
5337
+ );
5338
+ const shell = process.env.SHELL || "/bin/sh";
5339
+ const tmuxResult = await executeTmuxCommand({
5340
+ direction: tmuxDirection,
5341
+ command: shell,
5342
+ cwd: worktreePath,
5343
+ env: getPhantomEnv(branchName, worktreePath),
5344
+ windowName: tmuxDirection === "new" ? branchName : void 0
5345
+ });
5346
+ if (isErr(tmuxResult)) {
5347
+ exitWithError(tmuxResult.error.message, exitCodes.generalError);
5348
+ }
5299
5349
  }
5300
5350
  }
5301
5351
 
@@ -5314,7 +5364,7 @@ _phantom_completion() {
5314
5364
  local cur prev words cword
5315
5365
  _init_completion || return
5316
5366
 
5317
- local commands="create attach list where delete exec review shell github gh version completion mcp"
5367
+ local commands="create attach list where delete exec shell github gh version completion mcp"
5318
5368
  local global_opts="--help --version"
5319
5369
 
5320
5370
  if [[ \${cword} -eq 1 ]]; then
@@ -5354,12 +5404,17 @@ _phantom_completion() {
5354
5404
  # Don't complete anything specific for exec commands
5355
5405
  return 0
5356
5406
  ;;
5407
+ --copy-file)
5408
+ # Complete files
5409
+ _filedir
5410
+ return 0
5411
+ ;;
5357
5412
  *)
5358
5413
  if [[ \${cword} -eq 2 ]]; then
5359
5414
  # First argument: branch name (not completing - user needs to provide)
5360
5415
  return 0
5361
5416
  else
5362
- local opts="--shell --exec"
5417
+ local opts="--shell --exec --tmux --tmux-vertical --tmux-horizontal --copy-file"
5363
5418
  COMPREPLY=( $(compgen -W "\${opts}" -- "\${cur}") )
5364
5419
  return 0
5365
5420
  fi
@@ -5416,24 +5471,6 @@ _phantom_completion() {
5416
5471
  ;;
5417
5472
  esac
5418
5473
  ;;
5419
- review)
5420
- case "\${prev}" in
5421
- --base)
5422
- # Don't complete anything specific for base reference
5423
- return 0
5424
- ;;
5425
- *)
5426
- if [[ "\${cur}" == -* ]]; then
5427
- local opts="--fzf --base"
5428
- COMPREPLY=( $(compgen -W "\${opts}" -- "\${cur}") )
5429
- else
5430
- local worktrees=$(_phantom_list_worktrees)
5431
- COMPREPLY=( $(compgen -W "\${worktrees}" -- "\${cur}") )
5432
- fi
5433
- return 0
5434
- ;;
5435
- esac
5436
- ;;
5437
5474
  shell)
5438
5475
  case "\${prev}" in
5439
5476
  --tmux|-t|--tmux-vertical|--tmux-horizontal)
@@ -5545,7 +5582,6 @@ complete -c phantom -n "__phantom_using_command" -a "list" -d "List all Git work
5545
5582
  complete -c phantom -n "__phantom_using_command" -a "where" -d "Output the filesystem path of a specific worktree"
5546
5583
  complete -c phantom -n "__phantom_using_command" -a "delete" -d "Delete a Git worktree (phantom)"
5547
5584
  complete -c phantom -n "__phantom_using_command" -a "exec" -d "Execute a command in a worktree directory"
5548
- complete -c phantom -n "__phantom_using_command" -a "review" -d "Review changes in a worktree with a local PR review interface (experimental)"
5549
5585
  complete -c phantom -n "__phantom_using_command" -a "shell" -d "Open an interactive shell in a worktree directory"
5550
5586
  complete -c phantom -n "__phantom_using_command" -a "github" -d "GitHub integration commands"
5551
5587
  complete -c phantom -n "__phantom_using_command" -a "gh" -d "GitHub integration commands (alias)"
@@ -5569,6 +5605,10 @@ complete -c phantom -n "__phantom_using_command create" -l base -d "Branch or co
5569
5605
  # attach command options
5570
5606
  complete -c phantom -n "__phantom_using_command attach" -l shell -d "Open an interactive shell in the worktree after attaching (-s)"
5571
5607
  complete -c phantom -n "__phantom_using_command attach" -l exec -d "Execute a command in the worktree after attaching (-x)" -x
5608
+ complete -c phantom -n "__phantom_using_command attach" -l tmux -d "Open the worktree in a new tmux window (-t)"
5609
+ complete -c phantom -n "__phantom_using_command attach" -l tmux-vertical -d "Open the worktree in a vertical tmux pane"
5610
+ complete -c phantom -n "__phantom_using_command attach" -l tmux-horizontal -d "Open the worktree in a horizontal tmux pane"
5611
+ complete -c phantom -n "__phantom_using_command attach" -l copy-file -d "Copy specified files from the current worktree" -r
5572
5612
 
5573
5613
  # list command options
5574
5614
  complete -c phantom -n "__phantom_using_command list" -l fzf -d "Use fzf for interactive selection"
@@ -5591,11 +5631,6 @@ complete -c phantom -n "__phantom_using_command exec" -l tmux-vertical -d "Execu
5591
5631
  complete -c phantom -n "__phantom_using_command exec" -l tmux-horizontal -d "Execute command in horizontal split pane"
5592
5632
  complete -c phantom -n "__phantom_using_command exec" -a "(__phantom_list_worktrees)"
5593
5633
 
5594
- # review command options
5595
- complete -c phantom -n "__phantom_using_command review" -l fzf -d "Use fzf for interactive selection"
5596
- complete -c phantom -n "__phantom_using_command review" -l base -d "Base reference for comparison" -x
5597
- complete -c phantom -n "__phantom_using_command review" -a "(__phantom_list_worktrees)"
5598
-
5599
5634
  # shell command options
5600
5635
  complete -c phantom -n "__phantom_using_command shell" -l fzf -d "Use fzf for interactive selection"
5601
5636
  complete -c phantom -n "__phantom_using_command shell" -l tmux -d "Open shell in new tmux window (-t)"
@@ -5632,7 +5667,6 @@ _phantom() {
5632
5667
  'where:Output the filesystem path of a specific worktree'
5633
5668
  'delete:Delete a Git worktree (phantom)'
5634
5669
  'exec:Execute a command in a worktree directory'
5635
- 'review:Review changes in a worktree with a local PR review interface (experimental)'
5636
5670
  'shell:Open an interactive shell in a worktree directory'
5637
5671
  'github:GitHub integration commands'
5638
5672
  'gh:GitHub integration commands (alias)'
@@ -5653,18 +5687,16 @@ _phantom() {
5653
5687
  _arguments '--shell[Open an interactive shell in the new worktree after creation (-s)]' '--exec[Execute a command in the new worktree after creation (-x)]:command:' '--tmux[Open the worktree in a new tmux window (-t)]' '--tmux-vertical[Open the worktree in a vertical tmux pane]' '--tmux-horizontal[Open the worktree in a horizontal tmux pane]' '*--copy-file[Copy specified files from the current worktree]:file:_files' '--base[Branch or commit to create the new worktree from (defaults to HEAD)]:branch/commit:' '1:name:'
5654
5688
  ;;
5655
5689
  attach)
5656
- _arguments '--shell[Open an interactive shell in the worktree after attaching (-s)]' '--exec[Execute a command in the worktree after attaching (-x)]:command:' '1:branch-name:'
5690
+ _arguments '--shell[Open an interactive shell in the worktree after attaching (-s)]' '--exec[Execute a command in the worktree after attaching (-x)]:command:' '--tmux[Open the worktree in a new tmux window (-t)]' '--tmux-vertical[Open the worktree in a vertical tmux pane]' '--tmux-horizontal[Open the worktree in a horizontal tmux pane]' '*--copy-file[Copy specified files from the current worktree]:file:_files' '1:branch-name:'
5657
5691
  ;;
5658
5692
  list)
5659
5693
  _arguments '--fzf[Use fzf for interactive selection]' '--names[Output only phantom names (for scripts and completion)]'
5660
5694
  ;;
5661
- where|delete|review|shell)
5695
+ where|delete|shell)
5662
5696
  local worktrees
5663
5697
  worktrees=(\${(f)"$(phantom list --names 2>/dev/null)"})
5664
5698
  if [[ \${line[1]} == "where" ]]; then
5665
5699
  _arguments '--fzf[Use fzf for interactive selection]' '1:worktree:(\${(q)worktrees[@]})'
5666
- elif [[ \${line[1]} == "review" ]]; then
5667
- _arguments '--fzf[Use fzf for interactive selection]' '--base[Base reference for comparison]:reference:' '1:worktree:(\${(q)worktrees[@]})'
5668
5700
  elif [[ \${line[1]} == "shell" ]]; then
5669
5701
  _arguments '--fzf[Use fzf for interactive selection]' '--tmux[Open shell in new tmux window (-t)]' '--tmux-vertical[Open shell in vertical split pane]' '--tmux-horizontal[Open shell in horizontal split pane]' '1:worktree:(\${(q)worktrees[@]})'
5670
5702
  elif [[ \${line[1]} == "delete" ]]; then
@@ -9613,8 +9645,8 @@ async function checkoutIssue(issue, base) {
9613
9645
  async function checkoutPullRequest(pullRequest) {
9614
9646
  const gitRoot = await getGitRoot();
9615
9647
  const context = await createContext(gitRoot);
9616
- const worktreeName = `pulls/${pullRequest.number}`;
9617
- const localBranch = `pulls/${pullRequest.number}`;
9648
+ const worktreeName = pullRequest.head.ref;
9649
+ const localBranch = pullRequest.head.ref;
9618
9650
  const existsResult = await validateWorktreeExists(
9619
9651
  context.gitRoot,
9620
9652
  context.worktreesDirectory,
@@ -13322,7 +13354,7 @@ var StdioServerTransport = class {
13322
13354
  // ../mcp/package.json
13323
13355
  var package_default = {
13324
13356
  name: "@aku11i/phantom-mcp",
13325
- version: "2.2.4",
13357
+ version: "3.0.0",
13326
13358
  private: true,
13327
13359
  type: "module",
13328
13360
  main: "./src/index.ts",
@@ -13601,97 +13633,10 @@ async function mcpHandler(args2 = []) {
13601
13633
  }
13602
13634
  }
13603
13635
 
13604
- // src/handlers/review.ts
13605
- import { parseArgs as parseArgs8 } from "node:util";
13606
- async function reviewHandler(args2) {
13607
- const { positionals, values } = parseArgs8({
13608
- args: args2,
13609
- options: {
13610
- fzf: {
13611
- type: "boolean",
13612
- default: false
13613
- },
13614
- base: {
13615
- type: "string"
13616
- }
13617
- },
13618
- strict: true,
13619
- allowPositionals: true
13620
- });
13621
- const useFzf = values.fzf ?? false;
13622
- const base = values.base;
13623
- if (useFzf) {
13624
- if (positionals.length > 0) {
13625
- exitWithError(
13626
- "Cannot specify worktree name when using --fzf",
13627
- exitCodes.validationError
13628
- );
13629
- }
13630
- } else {
13631
- if (positionals.length !== 1) {
13632
- exitWithError(
13633
- "Usage: phantom review <worktree-name> [--base <ref>]",
13634
- exitCodes.validationError
13635
- );
13636
- }
13637
- }
13638
- try {
13639
- const gitRoot = await getGitRoot();
13640
- const context = await createContext(gitRoot);
13641
- let worktreeName;
13642
- if (useFzf) {
13643
- const selectResult = await selectWorktreeWithFzf(
13644
- context.gitRoot,
13645
- context.worktreesDirectory
13646
- );
13647
- if (isErr(selectResult)) {
13648
- exitWithError(selectResult.error.message, exitCodes.generalError);
13649
- }
13650
- if (!selectResult.value) {
13651
- exitWithSuccess();
13652
- }
13653
- worktreeName = selectResult.value.name;
13654
- } else {
13655
- worktreeName = positionals[0];
13656
- }
13657
- const validation = await validateWorktreeExists(
13658
- context.gitRoot,
13659
- context.worktreesDirectory,
13660
- worktreeName
13661
- );
13662
- if (isErr(validation)) {
13663
- exitWithError(validation.error.message, exitCodes.generalError);
13664
- }
13665
- const baseRef = base ?? `origin/${context.config?.defaultBranch ?? "main"}`;
13666
- output.log(`Opening review for worktree '${worktreeName}'...`);
13667
- output.log(
13668
- "powered by yoshiko-pg/difit (https://github.com/yoshiko-pg/difit)"
13669
- );
13670
- const command2 = ["difit", "HEAD", baseRef];
13671
- const result = await execInWorktree(
13672
- context.gitRoot,
13673
- context.worktreesDirectory,
13674
- worktreeName,
13675
- command2,
13676
- { interactive: true }
13677
- );
13678
- if (isErr(result)) {
13679
- const exitCode = result.error instanceof WorktreeNotFoundError ? exitCodes.notFound : result.error.exitCode || exitCodes.generalError;
13680
- exitWithError(result.error.message, exitCode);
13681
- }
13682
- process.exit(result.value.exitCode);
13683
- } catch (error) {
13684
- exitWithError(
13685
- error instanceof Error ? error.message : String(error),
13686
- exitCodes.generalError
13687
- );
13688
- }
13689
- }
13690
-
13691
13636
  // src/handlers/shell.ts
13692
- import { parseArgs as parseArgs9 } from "node:util";
13637
+ import { parseArgs as parseArgs8 } from "node:util";
13693
13638
  async function shellHandler(args2) {
13694
- const { positionals, values } = parseArgs9({
13639
+ const { positionals, values } = parseArgs8({
13695
13640
  args: args2,
13696
13641
  options: {
13697
13642
  fzf: {
@@ -13815,12 +13760,12 @@ async function shellHandler(args2) {
13815
13760
  }
13816
13761
 
13817
13762
  // src/handlers/version.ts
13818
- import { parseArgs as parseArgs10 } from "node:util";
13763
+ import { parseArgs as parseArgs9 } from "node:util";
13819
13764
 
13820
13765
  // package.json
13821
13766
  var package_default2 = {
13822
13767
  name: "@aku11i/phantom-cli",
13823
- version: "2.2.4",
13768
+ version: "3.0.0",
13824
13769
  private: true,
13825
13770
  type: "module",
13826
13771
  scripts: {
@@ -13852,7 +13797,7 @@ function getVersion() {
13852
13797
 
13853
13798
  // src/handlers/version.ts
13854
13799
  function versionHandler(args2 = []) {
13855
- parseArgs10({
13800
+ parseArgs9({
13856
13801
  args: args2,
13857
13802
  options: {},
13858
13803
  strict: true,
@@ -13864,9 +13809,9 @@ function versionHandler(args2 = []) {
13864
13809
  }
13865
13810
 
13866
13811
  // src/handlers/where.ts
13867
- import { parseArgs as parseArgs11 } from "node:util";
13812
+ import { parseArgs as parseArgs10 } from "node:util";
13868
13813
  async function whereHandler(args2) {
13869
- const { positionals, values } = parseArgs11({
13814
+ const { positionals, values } = parseArgs10({
13870
13815
  args: args2,
13871
13816
  options: {
13872
13817
  fzf: {
@@ -13946,6 +13891,39 @@ var attachHelp = {
13946
13891
  type: "string",
13947
13892
  description: "Execute a command in the worktree after attaching",
13948
13893
  example: "--exec 'git pull'"
13894
+ },
13895
+ {
13896
+ name: "tmux",
13897
+ short: "t",
13898
+ type: "boolean",
13899
+ description: "Open the worktree in a new tmux window after attaching"
13900
+ },
13901
+ {
13902
+ name: "tmux-vertical",
13903
+ type: "boolean",
13904
+ description: "Open the worktree in a vertical tmux pane after attaching"
13905
+ },
13906
+ {
13907
+ name: "tmux-v",
13908
+ type: "boolean",
13909
+ description: "Alias for --tmux-vertical"
13910
+ },
13911
+ {
13912
+ name: "tmux-horizontal",
13913
+ type: "boolean",
13914
+ description: "Open the worktree in a horizontal tmux pane after attaching"
13915
+ },
13916
+ {
13917
+ name: "tmux-h",
13918
+ type: "boolean",
13919
+ description: "Alias for --tmux-horizontal"
13920
+ },
13921
+ {
13922
+ name: "copy-file",
13923
+ type: "string",
13924
+ multiple: true,
13925
+ description: "Copy specified files from the current worktree before attaching. Can be used multiple times",
13926
+ example: "--copy-file .env --copy-file .npmrc"
13949
13927
  }
13950
13928
  ],
13951
13929
  examples: [
@@ -13960,12 +13938,21 @@ var attachHelp = {
13960
13938
  {
13961
13939
  description: "Attach to a branch and pull latest changes",
13962
13940
  command: "phantom attach develop --exec 'git pull'"
13941
+ },
13942
+ {
13943
+ description: "Attach and open the worktree in a tmux window",
13944
+ command: "phantom attach feature-branch --tmux"
13945
+ },
13946
+ {
13947
+ description: "Attach and copy shared environment files",
13948
+ command: "phantom attach feature-branch --copy-file .env --copy-file .npmrc"
13963
13949
  }
13964
13950
  ],
13965
13951
  notes: [
13966
13952
  "The branch must already exist locally",
13967
13953
  "To work with remote branches, first checkout the branch with git",
13968
- "Only one of --shell or --exec options can be used at a time"
13954
+ "Only one of --shell, --exec, or tmux options can be used at a time",
13955
+ "The tmux options require running phantom inside an active tmux session"
13969
13956
  ]
13970
13957
  };
13971
13958
 
@@ -14235,55 +14222,6 @@ var listHelp = {
14235
14222
  ]
14236
14223
  };
14237
14224
 
14238
- // src/help/review.ts
14239
- var reviewHelp = {
14240
- name: "review",
14241
- description: "Review changes in a worktree with a local PR review interface (experimental)",
14242
- usage: "phantom review [options] <worktree-name>",
14243
- options: [
14244
- {
14245
- name: "--fzf",
14246
- type: "boolean",
14247
- description: "Use fzf for interactive worktree selection"
14248
- },
14249
- {
14250
- name: "--base",
14251
- type: "string",
14252
- description: "Base reference for comparison (default: origin/<defaultBranch>)"
14253
- }
14254
- ],
14255
- examples: [
14256
- {
14257
- description: "Review changes against default branch",
14258
- command: "phantom review feature-auth"
14259
- },
14260
- {
14261
- description: "Review changes against specific remote branch",
14262
- command: "phantom review feature-login --base origin/feature-auth"
14263
- },
14264
- {
14265
- description: "Review changes against local branch",
14266
- command: "phantom review feature-auth --base main"
14267
- },
14268
- {
14269
- description: "Interactive worktree selection",
14270
- command: "phantom review --fzf"
14271
- },
14272
- {
14273
- description: "Interactive selection with custom base",
14274
- command: "phantom review --fzf --base origin/staging"
14275
- }
14276
- ],
14277
- notes: [
14278
- "\u26A0\uFE0F This is an experimental feature and may change in future versions",
14279
- "Uses difit to provide a GitHub-like PR review interface locally",
14280
- "Default base is origin/<defaultBranch> where defaultBranch is from config or 'main'",
14281
- "The --base value is passed directly to difit as the comparison reference",
14282
- "Requires difit to be installed separately (e.g., npm install -g difit)",
14283
- "powered by yoshiko-pg/difit (https://github.com/yoshiko-pg/difit)"
14284
- ]
14285
- };
14286
-
14287
14225
  // src/help/shell.ts
14288
14226
  var shellHelp = {
14289
14227
  name: "shell",
@@ -14431,12 +14369,6 @@ var commands = [
14431
14369
  handler: execHandler,
14432
14370
  help: execHelp
14433
14371
  },
14434
- {
14435
- name: "review",
14436
- description: "Review changes in a worktree with a local PR review interface (experimental)",
14437
- handler: reviewHandler,
14438
- help: reviewHelp
14439
- },
14440
14372
  {
14441
14373
  name: "shell",
14442
14374
  description: "Open an interactive shell in a worktree directory",