wtcode 0.3.0__tar.gz → 0.4.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wtcode
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Launch your favorite code tool in a git worktree
5
5
  Author-email: Jaeho Shin <netj@sparcs.org>
6
6
  License-Expression: MIT
@@ -61,6 +61,7 @@ wtcode --exec CMD [CMD-ARGS...]
61
61
 
62
62
  - **`BRANCH`** -- Git branch or worktree name. If omitted and [fzf](https://github.com/junegunn/fzf) is available, interactively select one. Surround with `:` to create a new branch (use `:::name` or `name:::` to avoid fzf matching the colons).
63
63
  - **`CMD`** -- Command to launch in the worktree. Defaults to `$WTCODE_CMD`, or the first available of: `claude`, `aider`, `codex`, `$SHELL`.
64
+ When `CMD` resolves to plain `claude` (no extra args) in a worktree that already existed, wtcode launches `claude /resume` so it opens straight into your last session there. Press `Esc` in the picker to start a new session instead.
64
65
  - **`--exec`** -- Skip the branch argument; select interactively via fzf, then launch `CMD`.
65
66
  - **`--help`** / **`--version`** -- Show help or version info.
66
67
 
@@ -43,6 +43,7 @@ wtcode --exec CMD [CMD-ARGS...]
43
43
 
44
44
  - **`BRANCH`** -- Git branch or worktree name. If omitted and [fzf](https://github.com/junegunn/fzf) is available, interactively select one. Surround with `:` to create a new branch (use `:::name` or `name:::` to avoid fzf matching the colons).
45
45
  - **`CMD`** -- Command to launch in the worktree. Defaults to `$WTCODE_CMD`, or the first available of: `claude`, `aider`, `codex`, `$SHELL`.
46
+ When `CMD` resolves to plain `claude` (no extra args) in a worktree that already existed, wtcode launches `claude /resume` so it opens straight into your last session there. Press `Esc` in the picker to start a new session instead.
46
47
  - **`--exec`** -- Skip the branch argument; select interactively via fzf, then launch `CMD`.
47
48
  - **`--help`** / **`--version`** -- Show help or version info.
48
49
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wtcode"
7
- version = "0.3.0"
7
+ version = "0.4.0"
8
8
  description = "Launch your favorite code tool in a git worktree"
9
9
  license = "MIT"
10
10
  readme = "README.md"
@@ -1,3 +1,3 @@
1
1
  """wtcode -- launch your favorite code tool in a git worktree."""
2
2
 
3
- __version__ = "0.3.0"
3
+ __version__ = "0.4.0"
@@ -8,6 +8,10 @@ shopt -s extglob
8
8
  ${WTCODE_DEBUG:+set -x}
9
9
 
10
10
  --msg() { echo "wtcode: $*" >&2; }
11
+ @q() {
12
+ local quoted=$({ set +x; } 2>/dev/null; exec 2>&1; PS4=; set -x; : "$@")
13
+ echo "${quoted:2}" # lstrip the ': ' prefix to get the compact bash-quoted form
14
+ }
11
15
  --sanitize-branch-name() {
12
16
  printf '%s' "$1" |
13
17
  tr '[:upper:]' '[:lower:]' | # lowercase
@@ -16,7 +20,7 @@ ${WTCODE_DEBUG:+set -x}
16
20
  sed 's/^-//; s/-$//' # trim leading/trailing hyphens
17
21
  }
18
22
 
19
- WTCODE_VERSION=0.3.0
23
+ WTCODE_VERSION=0.4.0
20
24
  --version() { echo "wtcode $WTCODE_VERSION"; }
21
25
  --help() {
22
26
  cat <<USAGE
@@ -43,6 +47,12 @@ Environment variables:
43
47
  split-window - create split pane with send-keys
44
48
  new-window - create new window with send-keys
45
49
  exec - exec the tool directly (opt out of send-keys)
50
+ WTCODE_TERMINAL_MODE Outside tmux, control how the tool is launched:
51
+ send-keys - reuse the current tab/window via AppleScript
52
+ (default; macOS only). Terminal.app and Ghostty
53
+ 1.3+ use their own scripting support; any other
54
+ terminal falls back to simulated keystrokes
55
+ exec - exec the tool directly (opt out of send-keys)
46
56
  WTCODE_DEBUG Enable debug tracing when set
47
57
  GIT_WORKTREE_ROOT Override the directory where worktrees are created
48
58
 
@@ -69,6 +79,7 @@ WTCODE_CMDS_TO_TRY=(
69
79
  ###############################################################################
70
80
  --enter-git-worktree() {
71
81
  local branch_name=
82
+ WTCODE_WORKTREE_EXISTED=false
72
83
 
73
84
  # 1. determine which branch/worktree to use
74
85
  if [[ $# -gt 0 ]]; then
@@ -172,6 +183,7 @@ WTCODE_CMDS_TO_TRY=(
172
183
  if [[ -n $existing_worktree ]]; then
173
184
  --msg "branch '$branch_name' is checked out at: $existing_worktree"
174
185
  cd "$existing_worktree"
186
+ WTCODE_WORKTREE_EXISTED=true
175
187
  return 0
176
188
  fi
177
189
  fi
@@ -207,6 +219,7 @@ WTCODE_CMDS_TO_TRY=(
207
219
 
208
220
  if [[ -e "$worktree_path"/.git ]]; then
209
221
  --msg "using existing worktree: $worktree_path"
222
+ WTCODE_WORKTREE_EXISTED=true
210
223
  elif [[ -n ${remote_branch-} ]] && ! git rev-parse --verify "refs/heads/$branch_name" &>/dev/null; then
211
224
  # remote branch: create local tracking branch in a new worktree
212
225
  --msg "creating worktree for remote branch: $remote_branch"
@@ -295,6 +308,116 @@ WTCODE_CMDS_TO_TRY=(
295
308
  --msg "created .claude/.gitignore"
296
309
  }
297
310
 
311
+ ###############################################################################
312
+ ## --terminal-send-keys -- tmux-like send-keys for GUI terminal apps
313
+ ###############################################################################
314
+ # Reuses the current tab/window in the surrounding terminal app, outside
315
+ # tmux. cd_cmd/run_cmd are sent as two separate lines rather than one
316
+ # `cd X && cmd` line, since the shell's PROMPT_COMMAND (what updates the
317
+ # tab/window title via OSC 7/6) only fires between commands, at the next
318
+ # prompt -- a single `&&` line never shows one, so the title would stay
319
+ # stale for as long as cmd runs.
320
+ #
321
+ # macOS-only: dispatches on $TERM_PROGRAM by looking for a matching
322
+ # --terminal-send-keys--macos--$TERM_PROGRAM function -- add support for
323
+ # another terminal app by just defining one, named to match its
324
+ # $TERM_PROGRAM value exactly. `type osascript` fails (and this returns 1)
325
+ # on any other platform, so this whole mechanism is a no-op there and
326
+ # callers just fall back to exec. Also returns 1 if there's no terminal
327
+ # emulator signal (TERM_PROGRAM/TERMINAL_EMULATOR, as in ~/.zprofile) at all.
328
+ --terminal-send-keys() {
329
+ local worktree_path="$PWD"
330
+ local cd_cmd="cd $(@q "$worktree_path")"
331
+ local run_cmd="$(@q "$@")"
332
+
333
+ # TODO: support Linux/general-unix terminals (and SSH sessions) too --
334
+ # e.g. terminals with OSC 7/6 + a way to inject text (wezterm cli,
335
+ # kitty @ send-text, iterm2's escape sequences, etc). For now this whole
336
+ # mechanism is macOS-only and returns 1 (falls back to exec) elsewhere.
337
+ type osascript &>/dev/null || return 1
338
+
339
+ local termprog=${TERM_PROGRAM-${TERMINAL_EMULATOR-}}
340
+ [[ -n $termprog ]] || return 1
341
+ if type -- "--terminal-send-keys--macos--$termprog" &>/dev/null; then
342
+ "--terminal-send-keys--macos--$termprog" "$cd_cmd" "$run_cmd"
343
+ else
344
+ --terminal-send-keys--macos--system-events "$cd_cmd" "$run_cmd"
345
+ fi
346
+ }
347
+
348
+ # `do script ... in front window`: reuses Terminal's front window via a real
349
+ # Apple Event, not a keystroke. `osascript -` reads the script from stdin;
350
+ # without it, osascript treats argv[0] as a script *file* path.
351
+ --terminal-send-keys--macos--Apple_Terminal() {
352
+ local result
353
+ result=$(osascript - "$@" <<'APPLESCRIPT'
354
+ on run argv
355
+ tell application "Terminal"
356
+ try
357
+ repeat with line_cmd in argv
358
+ do script (line_cmd as text) in front window
359
+ end repeat
360
+ set frontmost of front window to true
361
+ return "OK"
362
+ on error
363
+ return "NOTFOUND"
364
+ end try
365
+ end tell
366
+ end run
367
+ APPLESCRIPT
368
+ ) || return 1
369
+ [[ $result == OK ]]
370
+ }
371
+
372
+ # Ghostty 1.3+ ships a real AppleScript dictionary: `input text ... to
373
+ # term` targets the terminal focused in the front window's selected tab.
374
+ # Falls back to --macos--system-events since this is still a young feature.
375
+ --terminal-send-keys--macos--ghostty() {
376
+ local result rc
377
+ result=$(osascript - "$@" <<'APPLESCRIPT'
378
+ on run argv
379
+ tell application "Ghostty"
380
+ try
381
+ set term to focused terminal of selected tab of front window
382
+ repeat with line_cmd in argv
383
+ input text ((line_cmd as text) & "\n") to term
384
+ end repeat
385
+ return "OK"
386
+ on error
387
+ return "NOTFOUND"
388
+ end try
389
+ end tell
390
+ end run
391
+ APPLESCRIPT
392
+ ); rc=$?
393
+ [[ $rc -eq 0 && $result == OK ]] || --terminal-send-keys--macos--system-events "$@"
394
+ }
395
+
396
+ # Last resort: fake keystrokes via System Events (needs Accessibility
397
+ # permission). No `activate` call -- $TERM_PROGRAM isn't always a real app
398
+ # name, so this relies on the calling terminal still being frontmost.
399
+ --terminal-send-keys--macos--system-events() {
400
+ local result
401
+ result=$(osascript - "$@" <<'APPLESCRIPT'
402
+ on run argv
403
+ tell application "System Events"
404
+ try
405
+ repeat with line_cmd in argv
406
+ keystroke (line_cmd as text)
407
+ key code 36 -- Return
408
+ delay 0.05
409
+ end repeat
410
+ return "OK"
411
+ on error
412
+ return "NOTFOUND"
413
+ end try
414
+ end tell
415
+ end run
416
+ APPLESCRIPT
417
+ ) || return 1
418
+ [[ $result == OK ]]
419
+ }
420
+
298
421
  ###############################################################################
299
422
  ## --launch-code-tool -- resolve and exec the tool in the worktree
300
423
  ###############################################################################
@@ -308,6 +431,14 @@ WTCODE_CMDS_TO_TRY=(
308
431
  [[ $# -gt 0 ]] || set -- "${SHELL:-bash}"
309
432
  fi
310
433
 
434
+ # default to resuming the last session when relaunching claude in a
435
+ # worktree that already existed; press Esc in the picker to start fresh
436
+ # instead. only kicks in when no CMD-ARGS were given, so explicit flags
437
+ # (e.g. `claude --resume`) are never overridden.
438
+ if [[ $1 == claude && $# -eq 1 && ${WTCODE_WORKTREE_EXISTED:-false} == true ]]; then
439
+ set -- "$1" /resume
440
+ fi
441
+
311
442
  [[ $1 == claude ]] && --provision-claude-settings
312
443
 
313
444
  --msg "launching: $*"
@@ -320,12 +451,7 @@ WTCODE_CMDS_TO_TRY=(
320
451
  case $mode in
321
452
  send-keys|split-window|new-window)
322
453
  local worktree_path="$PWD"
323
- # quote each argument for shell safety
324
- local quoted_args=()
325
- for arg in "$@"; do
326
- quoted_args+=("$(printf '%q' "$arg")")
327
- done
328
- local cmd="cd $(printf '%q' "$worktree_path") && ${quoted_args[*]}"
454
+ local cmd="cd $(@q "$worktree_path") && $(@q "$@")"
329
455
 
330
456
  case $mode in
331
457
  send-keys)
@@ -356,7 +482,27 @@ WTCODE_CMDS_TO_TRY=(
356
482
  esac
357
483
  fi
358
484
 
359
- # outside tmux, WTCODE_TMUX_MODE=exec, or unknown mode: exec directly
485
+ # outside tmux: reuse the current tab/window if the terminal app supports
486
+ # it (see --terminal-send-keys). set WTCODE_TERMINAL_MODE=exec to opt out
487
+ if [[ -z ${TMUX:-} ]]; then
488
+ local mode=${WTCODE_TERMINAL_MODE:-send-keys}
489
+ case $mode in
490
+ send-keys)
491
+ if --terminal-send-keys "$@"; then
492
+ return 0
493
+ fi
494
+ --msg "could not reuse the current tab/window; falling back to exec"
495
+ ;;
496
+ exec)
497
+ # explicitly opt out of send-keys, fall through to exec
498
+ ;;
499
+ *)
500
+ --msg "unknown WTCODE_TERMINAL_MODE: $mode (expected: send-keys, exec)"
501
+ ;;
502
+ esac
503
+ fi
504
+
505
+ # outside tmux, WTCODE_TMUX_MODE=exec, unsupported terminal, or unknown mode: exec directly
360
506
  exec "$@"
361
507
  }
362
508
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wtcode
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Launch your favorite code tool in a git worktree
5
5
  Author-email: Jaeho Shin <netj@sparcs.org>
6
6
  License-Expression: MIT
@@ -61,6 +61,7 @@ wtcode --exec CMD [CMD-ARGS...]
61
61
 
62
62
  - **`BRANCH`** -- Git branch or worktree name. If omitted and [fzf](https://github.com/junegunn/fzf) is available, interactively select one. Surround with `:` to create a new branch (use `:::name` or `name:::` to avoid fzf matching the colons).
63
63
  - **`CMD`** -- Command to launch in the worktree. Defaults to `$WTCODE_CMD`, or the first available of: `claude`, `aider`, `codex`, `$SHELL`.
64
+ When `CMD` resolves to plain `claude` (no extra args) in a worktree that already existed, wtcode launches `claude /resume` so it opens straight into your last session there. Press `Esc` in the picker to start a new session instead.
64
65
  - **`--exec`** -- Skip the branch argument; select interactively via fzf, then launch `CMD`.
65
66
  - **`--help`** / **`--version`** -- Show help or version info.
66
67
 
File without changes
File without changes
File without changes