From ddb79c7ced6393439c819992002ce33501aa7711 Mon Sep 17 00:00:00 2001 From: Robin Quintero Date: Sat, 22 Aug 2026 21:29:54 -0500 Subject: [PATCH] fix: make try init re-source safe through the shell wrapper The shell wrapper shadows the binary, so `try init` inside a sourced shell (e.g. `source ~/.zshrc` twice) fell through to the interactive selector instead of re-emitting the wrapper. Dispatch `init` in the `exec` path so re-init behaves like a plain `try init`. Adds shell-eval regression tests for bash and zsh covering `try exec init PATH` re-emitting the wrapper with the new path. --- spec/init_spec.md | 8 ++++++++ spec/tests/test_36_shell_eval.sh | 19 +++++++++++++++++++ try.rb | 6 ++++++ 3 files changed, 33 insertions(+) diff --git a/spec/init_spec.md b/spec/init_spec.md index 6e61448..95e7f12 100644 --- a/spec/init_spec.md +++ b/spec/init_spec.md @@ -89,6 +89,14 @@ The wrapper interprets `try exec` exit codes: | 0 | Success | `eval` the output (execute shell commands) | | 1 | Cancelled/Error | Print the output (show message to user) | +## Re-sourcing Safety + +The shell wrapper shadows the `try` binary. When a shell config is sourced +again (`source ~/.zshrc`), `try init` must dispatch to the init logic through +the wrapper and re-emit the function definition — never fall through to the +interactive selector. `try exec init [PATH]` must therefore behave like +`try init [PATH]`. + ## Testing Test that init produces valid shell syntax: diff --git a/spec/tests/test_36_shell_eval.sh b/spec/tests/test_36_shell_eval.sh index e19bc3c..f225179 100644 --- a/spec/tests/test_36_shell_eval.sh +++ b/spec/tests/test_36_shell_eval.sh @@ -32,6 +32,17 @@ else fail "bash try exec should produce script with directory" "2025-01-01-hello" "$bash_out" "init_spec.md" fi +# Test: `try exec init PATH` re-emits the wrapper with the new path. +# The shell wrapper shadows the binary, so a re-source (`source ~/.zshrc`) +# routes `try init` through `exec`; it must dispatch to init, not the selector. +mkdir -p "$EVAL_DIR/other" +bash_out=$("$TRY_BIN_PATH" exec --path "$EVAL_DIR" init "$EVAL_DIR/other" 2>/dev/null) +if echo "$bash_out" | grep -qF -- "--path '$EVAL_DIR/other'"; then + pass +else + fail "bash exec init should re-emit wrapper with new path" "--path '$EVAL_DIR/other'" "$bash_out" "init_spec.md" +fi + # --- zsh --- if command -v zsh >/dev/null 2>&1; then @@ -56,6 +67,14 @@ if command -v zsh >/dev/null 2>&1; then else fail "zsh try exec should produce script with directory" "2025-01-01-hello" "$zsh_out" "init_spec.md" fi + + # Test: zsh exec init re-emits wrapper with new path (re-source safe) + zsh_out=$("$TRY_BIN_PATH" exec --path "$EVAL_DIR" init "$EVAL_DIR/other" 2>/dev/null) + if echo "$zsh_out" | grep -qF -- "--path '$EVAL_DIR/other'"; then + pass + else + fail "zsh exec init should re-emit wrapper with new path" "--path '$EVAL_DIR/other'" "$zsh_out" "init_spec.md" + fi else pass # skip pass # skip diff --git a/try.rb b/try.rb index c3b3c0a..258bddb 100755 --- a/try.rb +++ b/try.rb @@ -1683,6 +1683,12 @@ def worktree_path(tries_path, repo_dir, custom_name) when 'clone' ARGV.shift emit_script(cmd_clone!(ARGV, tries_path)) + when 'init' + # Re-sourcing support: the shell wrapper shadows the binary, so a + # second `try init` (e.g. from `source ~/.zshrc`) must re-emit the + # wrapper instead of falling through to the interactive selector. + ARGV.shift + cmd_init!(ARGV, tries_path) when 'worktree' ARGV.shift repo = ARGV.shift