From 9d0cc1eaadc21df5b6cea834e87362fc8acbe50f Mon Sep 17 00:00:00 2001 From: Tom Elizaga Date: Mon, 14 Sep 2026 09:24:06 -0700 Subject: [PATCH 1/5] docs: rewrite Copilot instructions and align contributor guides with the current layout .github/copilot-instructions.md predated the lib/ modularization: it described bin/gtr as a 961-line monolith with a case block at fixed line numbers, an `open` command, cmd_* functions inside bin/gtr, six lib files, and GTR_VERSION on line 8. Rewritten as a condensed guide that matches bin/git-gtr, lib/*.sh, lib/commands/*.sh, the adapter registry, the BATS suite, and the CI gates. The per-pattern instruction files and CONTRIBUTING.md carried the same drift plus one larger error: they told contributors to hand-edit the three completion files, which are generated by scripts/generate-completions.sh and rejected by CI when they differ. - completions.instructions.md: rewritten around the generator; applyTo now covers scripts/generate-completions.sh and the real fish filename - testing.instructions.md: add the BATS/ShellCheck/completions gates, drop "all manual", open -> editor, source nano.sh (cursor.sh does not exist under adapters/editor), add pr/clean/trust smoke lines, GTR_DEBUG - lib.instructions.md: replace a stale core.sh line reference with get_current_branch(), add .gtrconfig and trust gating to the cfg_default precedence, open -> editor - sh.instructions.md: set -e lives in bin/git-gtr, add GTR_DEBUG, note gh/glab as optional deps - editor/ai.instructions.md, CONTRIBUTING.md: regenerate completions instead of editing three files; name the _help_* functions - CHANGELOG: record under Unreleased --- .github/copilot-instructions.md | 110 ++++++------ .github/instructions/ai.instructions.md | 4 +- .../instructions/completions.instructions.md | 156 ++++-------------- .github/instructions/editor.instructions.md | 7 +- .github/instructions/lib.instructions.md | 9 +- .github/instructions/sh.instructions.md | 5 +- .github/instructions/testing.instructions.md | 31 +++- CHANGELOG.md | 5 + CONTRIBUTING.md | 6 +- 9 files changed, 140 insertions(+), 193 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index efd8f3e..fa33992 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,83 +1,83 @@ # Copilot Instructions -## Architecture & Flow +Condensed guide for AI agents working in this repository. `AGENTS.md` and `CLAUDE.md` are the long-form versions; keep all three consistent. -`bin/gtr` (961 lines) dispatches to `cmd_*` functions (case block lines 36‑77). Libraries sourced at startup: +## What This Is -- `lib/core.sh` - create/list/remove/resolve worktrees -- `lib/config.sh` - git config wrapper with precedence -- `lib/ui.sh` - log_error/log_info/prompts -- `lib/copy.sh` - glob pattern file copying -- `lib/hooks.sh` - postCreate/postRemove execution -- `lib/platform.sh` - OS detection + GUI helpers +`git gtr` (Git Worktree Runner) is a Bash CLI that wraps `git worktree` with editor and AI-tool launching, file copying, hooks, and pull-request checkout. It is installed as a git subcommand. User-facing docs always say `git gtr`, never `./bin/gtr`. -Adapters in `adapters/{editor,ai}` each implement two functions with strict contracts (see below). +## Layout -## Key Concepts +- `bin/git-gtr` - entry point. Sets `set -e`, defines `GTR_VERSION`, sources every library, and dispatches in `main()` with a `case` on the first argument. +- `bin/gtr` - development wrapper that `exec`s `bin/git-gtr`. +- `lib/*.sh` - sourced in this order: `ui.sh` (logging, prompts), `args.sh` (flag parser that fills `_arg_*` vars), `config.sh` (`cfg_get`, `cfg_default`, `cfg_get_all`), `platform.sh` (OS detection), `core.sh` (worktree CRUD, `resolve_target`, `resolve_base_dir`, `sanitize_branch_name`), `copy.sh`, `hooks.sh` (`run_hooks_in`), `provider.sh` (GitHub/GitLab detection for `clean`), `adapters.sh` (adapter registries and loaders), `launch.sh` (editor/AI launch orchestration). +- `lib/commands/*.sh` - one file per subcommand defining `cmd_()` (18 files, including `pr.sh` and `trust.sh`). Help text lives in `lib/commands/help.sh` as `_help_()` functions; `cmd_help` finds them by name, with a small `case` mapping aliases such as `ls` to `list`. +- `adapters/editor/nano.sh`, `adapters/ai/claude.sh`, `adapters/ai/cursor.sh` - the only file-based adapters. Every other editor and AI tool is a registry line in `lib/adapters.sh`. +- `completions/` - generated output. Never edit by hand (see Common Changes). +- `tests/*.bats` - BATS suite (29 files) with shared fixtures in `tests/test_helper.bash`. -- Special ID `1` = main repo (usable in `open`, `go`, `ai`). -- Folder naming = sanitized branch (`feature/auth` → `feature-auth`). -- Base dir resolution (`resolve_base_dir`): config `gtr.worktrees.dir` → env → default `-worktrees`; relative paths resolved from repo root; tilde expanded; warns if inside repo unignored. -- Target resolution (`resolve_target`): ID `1` → current → sanitized path → scan directories; returns TSV: `is_main\tpath\tbranch`. -- Config precedence (`cfg_default`): git config (local→global→system) → env → fallback. Multi-value keys merged & deduped (`cfg_get_all`). +## Commands -## Adapter Contract +`new`, `pr`, `rm`, `mv|rename`, `go`, `run`, `editor`, `ai`, `copy`, `ls|list`, `clean`, `doctor`, `adapter|adapters`, `config`, `completion`, `init`, `trust`, `version`, `help`. There is no `open` command; the editor command is `editor`. `cd` has no `cmd_*` handler: the dispatcher prints setup instructions because `gtr cd` is a shell function emitted by `init`. -Editor: `editor_can_open`, `editor_open `; AI: `ai_can_start`, `ai_start [args...]`. Must check tool availability (`command -v`), emit errors via `log_error`, never silently fail, and avoid side effects outside the target directory (AI uses subshell `(cd ...)`). Update README, help (`cmd_help`), completions. +Dispatch names that differ from the command: `new`→`cmd_create`, `rm`→`cmd_remove`, `mv|rename`→`cmd_rename`, `ls|list`→`cmd_list`, `adapter|adapters`→`cmd_adapter`. Everything else is `cmd_`. -## Manual Testing (Essential Subset) +## Key Concepts -```bash -./bin/gtr new feature/x # creates folder feature-x -./bin/gtr open feature/x # loads configured editor -./bin/gtr ai feature/x # starts configured AI tool -./bin/gtr list # lists main + worktrees -./bin/gtr rm feature/x # removes worktree -./bin/gtr go feature/x # prints path (use in cd) -``` +- Special ID `1` means the main repository in `go`, `editor`, `ai`, `run`, and other commands that take a worktree target. +- Folder name = sanitized branch (`feature/auth` → `feature-auth`); `--folder` replaces it, `--name` adds a suffix. +- `resolve_base_dir`: `gtr.worktrees.dir` → `GTR_WORKTREES_DIR` → `-worktrees` sibling. Relative paths resolve from the repo root, tilde expands, and it warns when the directory sits inside the repo without a `.gitignore` entry. +- `resolve_target`: ID `1` → current branch → sanitized path match → full scan. Returns TSV `is_main\tpath\tbranch`. +- Config precedence (`cfg_default`): local git config → `.gtrconfig` → global/system git config → `GTR_*` env var → default. Multi-value keys (`gtr.copy.*`, `gtr.hook.*`) merge and dedupe through `cfg_get_all`. +- `.gtrconfig` settings that execute code (hooks, editor/AI defaults) are ignored until `git gtr trust` approves them. +- `new --porcelain` prints exactly three `keyvalue` records (`path`, `branch`, `hook_status`) on stdout and everything else on stderr. Keep that contract stable; it is documented in `docs/agent-usage.md`. +- `new` inherits sparse-checkout from the base worktree on Git 2.36+ (`gtr.sparse.inherit`, `--sparse`, `--no-sparse`). + +## Adapter Contract + +Editor adapters define `editor_can_open` and `editor_open `. AI adapters define `ai_can_start` and `ai_start [args...]`, and run the tool in a subshell: `(cd "$path" && ...)`. Probe with `command -v`, report a missing tool with `log_error` plus an install hint, never fail silently, and keep side effects inside the target directory. -Advanced: `--force --name backend` (same branch multi-worktree); `git config --add gtr.copy.include "**/.env.example"`; hooks: `git config --add gtr.hook.postCreate "npm install"`. -Full matrix: see `.github/instructions/testing.instructions.md`. +Standard tools are registry lines, not files. `_EDITOR_REGISTRY` entries are `name|cmd|type|err_msg|flags`; `_AI_REGISTRY` entries are `name|cmd|err_msg|info_lines`. Write an adapter file only for behavior the registry builders cannot express. A file override wins over a registry entry of the same name. ## Common Changes -**Add command**: new `cmd_()` function in `bin/gtr` + case entry (lines 36‑77) + help text in `cmd_help` + all three completions (bash/zsh/fish) + README docs. +**Add a command**: create `lib/commands/.sh` with `cmd_()`; add a `case` entry to `main()` in `bin/git-gtr`; add `_help_()` to `lib/commands/help.sh` (found by name; add a `case` alias in `cmd_help` only if the command has aliases); add the command and its flags to the `generate_bash`, `generate_zsh`, and `generate_fish` templates in `scripts/generate-completions.sh`; run `./scripts/generate-completions.sh`; add `tests/cmd_.bats`; document it in README. -**Add adapter**: two functions (see contract below), `log_error` with install instructions, quote all paths, check `command -v`. Update: README, help text (`cmd_help`), completions (all three). +**Add an adapter**: add a registry line in `lib/adapters.sh`; run `./scripts/generate-completions.sh`; update the adapter tables in README and `docs/configuration.md` and the tool list in `lib/commands/help.sh`. -**Modify core (`lib/*.sh`)**: keep backwards compatibility, always quote variables `"$var"`, support Git <2.22 fallback (`branch --show-current` → `rev-parse --abbrev-ref HEAD`), test manually across macOS/Linux. +**Change a flag**: update the command's `parse_args` spec, its `_help_()`, the three completion templates, the regenerated completions, README, and the matching BATS file. -## Patterns & Gotchas +**Modify `lib/*.sh`**: keep existing configs working, quote every path, add fallbacks for Git older than 2.22 (see `get_current_branch` in `lib/core.sh`), and stay Bash 3.2 compatible. -- Always quote paths (spaces). Avoid unguarded globbing. -- `set -e` active: ensure non-critical failures are guarded (`command || true`). -- Multi-value config keys require `git config --add` (do not overwrite entire list unintentionally). -- If placing worktrees inside repo (relative path), add directory to `.gitignore` to prevent accidental commits. +## Validation -## Debugging +```bash +bats tests/ # full suite; bats tests/cmd_list.bats for one file +shellcheck bin/gtr bin/git-gtr lib/*.sh lib/commands/*.sh adapters/editor/*.sh adapters/ai/*.sh +./scripts/generate-completions.sh --check # committed completions match the generator +``` -Trace: `bash -x ./bin/gtr new test`; scoped: `set -x` / `set +x`; list function: `declare -f resolve_target`; inspect var: `echo "DEBUG=$var" >&2`; adapter sourcing: `bash -c 'source adapters/ai/claude.sh && ai_can_start && echo OK'`. +CI (`.github/workflows/lint.yml`) runs exactly these three jobs on every pull request. Smoke-test by hand in a throwaway repo: `./bin/gtr new x`, `./bin/gtr list`, `./bin/gtr go x`, `./bin/gtr rm x`. -## Troubleshooting Quick +## Patterns & Gotchas + +- `set -e` is global. Guard anything allowed to fail: `result=$(fn) || true`, or test it inside `if`. +- Quote every path and branch; both may contain spaces or slashes. +- Multi-value config keys need `git config --add`; a plain `set` overwrites the list. +- Call `sanitize_branch_name`; do not reimplement it. +- Never hand-edit `completions/*`. CI rejects files that differ from the generator output. -Permission: `chmod +x bin/gtr`. Missing adapter: `gtr adapter`. Install check: `./bin/gtr doctor`. Config issues: `git config --list | grep gtr`. Worktree confusion: inspect `resolve_target` logic & naming. Symlink problems: ensure `/usr/local/bin` exists then `ln -s "$(pwd)/bin/gtr" /usr/local/bin/gtr`. +## Debugging -## Version +`bash -x ./bin/gtr ` gives a full trace. `GTR_DEBUG=1 ./bin/gtr ` prints `file:line:function` when a command fails under `set -e`. `declare -f resolve_target` confirms a function is loaded. `./bin/gtr doctor` and `./bin/gtr adapter` check the environment. -Update `GTR_VERSION` (line 8 `bin/gtr`) when releasing; affects `gtr version` / `--version`. +## Releasing -## Documentation Structure +Bump `GTR_VERSION` in `bin/git-gtr`, add a dated `CHANGELOG.md` entry, and publish a GitHub release. `.github/workflows/homebrew.yml` then updates the Homebrew tap formula. -- **`.github/copilot-instructions.md`** (this file) - High-level guide for AI agents -- **`.github/instructions/*.instructions.md`** - Specific guidance by file pattern: - - `testing.instructions.md` - Manual testing checklist (applies to: `bin/gtr`, `lib/**/*.sh`, `adapters/**/*.sh`) - - `sh.instructions.md` - Shell scripting conventions (applies to: `**/*.sh`, `**/*.bash`, `**/*.fish`) - - `lib.instructions.md` - Core library modification guidelines (applies to: `lib/**/*.sh`) - - `editor.instructions.md` - Editor adapter contract (applies to: `adapters/editor/**/*.sh`) - - `ai.instructions.md` - AI tool adapter contract (applies to: `adapters/ai/**/*.sh`) - - `completions.instructions.md` - Shell completion updates (applies to: `completions/*`) -- **`README.md`** - User-facing documentation -- **`CONTRIBUTING.md`** - Contribution guidelines -- **`CLAUDE.md`** - Extended development guide for Claude Code +## Documentation Map -Feedback: Ask if more detail needed on copy patterns, hooks, or multi-worktree `--force` safety. +- `AGENTS.md` / `CLAUDE.md` - long-form architecture and workflow guide +- `.github/instructions/*.instructions.md` - file-pattern guidance: `testing`, `sh`, `lib`, `editor`, `ai`, `completions` +- `README.md` - user docs, with `docs/configuration.md`, `docs/advanced-usage.md`, `docs/agent-usage.md`, `docs/troubleshooting.md` +- `CONTRIBUTING.md` - contribution process and manual test checklist diff --git a/.github/instructions/ai.instructions.md b/.github/instructions/ai.instructions.md index 51d8eee..c6abc88 100644 --- a/.github/instructions/ai.instructions.md +++ b/.github/instructions/ai.instructions.md @@ -44,7 +44,7 @@ ai_start() { File-based adapters take precedence over registry entries of the same name. -**Also update**: README, completions (bash/zsh/fish), help text in `lib/commands/help.sh` +**Also update**: README and `docs/configuration.md` tool tables, help text in `lib/commands/help.sh` (`_help_ai`); then run `./scripts/generate-completions.sh` (completions are generated and checked in CI) ## Contract & Guidelines @@ -54,5 +54,5 @@ File-based adapters take precedence over registry entries of the same name. - Keep side effects confined to worktree directory; do not modify repo root unintentionally. - Accept extra args after `--`: preserve ordering (`ai_start` receives already-shifted args). - Prefer fast startup; heavy initialization belongs in hooks (`postCreate`), not adapters. -- When adding adapter: update `cmd_help`, README tool list, and completions (bash/zsh/fish). +- When adding adapter: update help text, README and `docs/configuration.md` tool lists, then regenerate completions. - Inspect function definition if needed: `declare -f ai_start`. diff --git a/.github/instructions/completions.instructions.md b/.github/instructions/completions.instructions.md index 877a95c..8dc386d 100644 --- a/.github/instructions/completions.instructions.md +++ b/.github/instructions/completions.instructions.md @@ -1,144 +1,58 @@ --- -applyTo: completions/gtr.bash, completions/_git-gtr, completions/gtr.fish +applyTo: completions/*, scripts/generate-completions.sh --- # Completions Instructions -## Overview +## Generated Files -Shell completions provide tab-completion for `git gtr` commands, flags, branches, and adapter names across Bash, Zsh, and Fish shells. +`completions/gtr.bash` (Bash), `completions/_git-gtr` (Zsh), and `completions/git-gtr.fish` (Fish) are **generated** by `scripts/generate-completions.sh`. Each file starts with an `AUTO-GENERATED ... DO NOT EDIT MANUALLY` header. CI (`.github/workflows/lint.yml`) runs `./scripts/generate-completions.sh --check` and fails when any committed file differs from the generator output. -## When to Update Completions +Sources of truth: -**Always update all three completion files** when: +- Adapter names: `_EDITOR_REGISTRY` and `_AI_REGISTRY` in `lib/adapters.sh`, plus any `adapters/{editor,ai}/*.sh` file overrides. +- Config keys: `_CFG_KEY_MAP` in `lib/config.sh`. +- Commands, their flags, and which commands accept branch arguments: the `generate_bash`, `generate_zsh`, and `generate_fish` templates inside the script. -- Adding new commands (e.g., `git gtr new-command`) -- Adding new flags to existing commands (e.g., `--new-flag`) -- Adding editor or AI adapters (completion must list available adapters) -- Changing command names or flag names +`git gtr completion ` (`lib/commands/completion.sh`) prints the matching generated file from the source checkout or the Homebrew install layout. It does not build completions at runtime. -## File Responsibilities +## Making Changes -- **`completions/gtr.bash`** - Bash completion (requires bash-completion v2+) -- **`completions/_git-gtr`** - Zsh completion (uses Zsh completion system) -- **`completions/gtr.fish`** - Fish shell completion +| Change | Edit | Then | +| ------------------------ | --------------------------------------------------------------------- | ----------------------------------- | +| New editor or AI adapter | registry line in `lib/adapters.sh` | `./scripts/generate-completions.sh` | +| New config key | `_CFG_KEY_MAP` in `lib/config.sh` | `./scripts/generate-completions.sh` | +| New command or flag | all three `generate_*` templates in `scripts/generate-completions.sh` | `./scripts/generate-completions.sh` | -## Implementation Pattern +Commit the regenerated files together with the source change. Keep the three templates in sync: same commands, same flags per command, and the same branch-completion behavior (git branches plus special ID `1` for commands that take a worktree target). -Each completion file implements: +## Testing -1. **Command completion** - Top-level commands (`new`, `rm`, `editor`, `ai`, `list`, etc.) -2. **Flag completion** - Command-specific flags (e.g., `--from`, `--force`, `--editor`) -3. **Branch completion** - Dynamic completion of git branches plus special ID `1` (via `git branch`) -4. **Adapter completion** - Editor names (`cursor`, `vscode`, `zed`) and AI tool names (`aider`, `claude`, `codex`) - -## Testing Completions - -**Manual testing** (no automated tests): +`./scripts/generate-completions.sh --check` verifies the committed files. Interactive behavior is checked by hand, and all three shells require git's own completion to be enabled: ```bash -# Bash - source the completion file (requires git's bash completion to be loaded) +# Bash source completions/gtr.bash -git gtr # Should show commands -git gtr new # Should show flags -git gtr go # Should show branches + '1' -git gtr editor # Should show branches + '1' -git gtr editor --editor # Should show editor names - -# Zsh - copy to fpath directory and reload (requires git's zsh completion) -mkdir -p ~/.zsh/completions -cp completions/_git-gtr ~/.zsh/completions/ -# Add to ~/.zshrc: fpath=(~/.zsh/completions $fpath) -# Add to ~/.zshrc: autoload -Uz compinit && compinit -exec zsh # Reload shell -git gtr # Should show commands -git gtr new # Should show flags -git gtr go # Should show branches + '1' - -# Fish - symlink to ~/.config/fish/completions/ -ln -s "$(pwd)/completions/gtr.fish" ~/.config/fish/completions/ -exec fish # Reload shell -git gtr # Should show commands -git gtr new # Should show flags -git gtr go # Should show branches + '1' -``` - -**Important**: All shell completions require git's own completion system to be enabled for the `git` command. The completions integrate with git's subcommand completion framework. - -## Branch Completion Logic - -All three completions dynamically fetch current git branches: - -- Use `git branch --format='%(refname:short)'` to get branch names -- Add special ID `1` for main repo (allows `git gtr go 1`, `git gtr editor 1`, etc.) -- Return combined list of branches + `1` for commands that accept branch arguments (go, editor, ai, rm) - -## Adapter Name Updates - -When adding an editor or AI adapter: - -**Bash** (`completions/gtr.bash`): - -- Update `_gtr_editors` array or case statement -- Update flag completion for `--editor` in `open` command - -**Zsh** (`completions/_git-gtr`): - -- Update `_arguments` completion specs for `--editor` or `--ai` -- Use `_values` or `_alternative` for adapter names +git gtr # commands +git gtr new # flags +git gtr go # branches + '1' +git gtr editor --editor # editor names -**Fish** (`completions/gtr.fish`): +# Zsh (add before compinit in ~/.zshrc) +eval "$(git gtr completion zsh)" -- Update `complete -c git` lines for editor/AI flags -- List adapter names explicitly or parse from `git gtr adapter` output - -## Keep in Sync - -The three completion files must stay synchronized: - -- Same commands supported -- Same flags for each command -- Same adapter names -- Same branch completion behavior - -## Examples - -**Adding a new command `git gtr status`**: - -1. Add `status` to main command list in all three files -2. Add flag completion if the command has flags -3. Test tab completion works - -**Adding a new editor `sublime`**: - -1. Create `adapters/editor/sublime.sh` with contract functions -2. Add `sublime` to editor list in all three completion files -3. Update help text in `bin/gtr` (`cmd_help` function) -4. Update README with installation instructions -5. Test `git gtr open --editor s` completes to `sublime` - -## Common Pitfalls - -- **Forgetting to update all three files** - Always update Bash, Zsh, AND Fish -- **Hardcoding adapter names** - Keep adapter lists in sync with actual files in `adapters/{editor,ai}/` -- **Not testing** - Source/reload completions and test with `` key -- **Case sensitivity** - Command and flag names must match exactly (case-sensitive) - -## Bash-Specific Notes - -- Requires `bash-completion` v2+ package -- Use `COMPREPLY` array to return completions -- Use `compgen` to filter based on current word (`$cur`) -- Check `$COMP_CWORD` for argument position +# Fish +git gtr completion fish > ~/.config/fish/completions/git-gtr.fish +``` -## Zsh-Specific Notes +## Shell Notes -- Uses `_arguments` completion framework -- Supports more sophisticated completion logic (descriptions, grouping) -- Use `_describe` for simple lists, `_arguments` for complex commands +- Bash: defines `_git_gtr`, which git's bash-completion (v2+) discovers for `git gtr`, and fills `COMPREPLY` with `compgen`. +- Zsh: `#compdef _git-gtr git-gtr gtr`, built on `_arguments`. +- Fish: `complete -c git` with `__fish_git_gtr_needs_command` and `__fish_git_gtr_using_command` predicates. -## Fish-Specific Notes +## Pitfalls -- Uses `complete -c git` with custom predicates (`__fish_git_gtr_needs_command`, `__fish_git_gtr_using_command`) to handle git subcommand context -- Conditions can check previous arguments with custom functions to detect `git gtr` usage -- Can call external commands for dynamic completion +- Editing `completions/*` directly: CI rejects it and the next regeneration discards it. +- Updating one shell template but not the other two. +- Skipping `./scripts/generate-completions.sh --check` before pushing. diff --git a/.github/instructions/editor.instructions.md b/.github/instructions/editor.instructions.md index 7bc3c3d..b6058cf 100644 --- a/.github/instructions/editor.instructions.md +++ b/.github/instructions/editor.instructions.md @@ -48,8 +48,9 @@ File-based adapters take precedence over registry entries of the same name. **Also update**: - README.md (setup instructions) -- All three completion files: `completions/gtr.bash`, `completions/_git-gtr`, `completions/gtr.fish` -- Help text in `lib/commands/help.sh` (`cmd_help` function) +- Completions: run `./scripts/generate-completions.sh` (registry names are picked up automatically; the files under `completions/` are generated and checked in CI) +- Help text in `lib/commands/help.sh` (`_help_editor`) +- Editor table in `docs/configuration.md` ## Contract & Guidelines @@ -58,6 +59,6 @@ File-based adapters take precedence over registry entries of the same name. - Use `log_error` with actionable install guidance if command missing. - Keep adapter lean: no project scans, no blocking prompts. - Naming: file/registry name = tool name (`zed` → `zed` flag). Avoid uppercase. -- Update: README editor list, completions (bash/zsh/fish), help (`Available editors:`), optional screenshots. +- Update: README editor list, `docs/configuration.md` editor table, help text, then regenerate completions. - Fallback behavior: if editor absent, fail clearly; do NOT silently defer to file browser. - Inspect function definition if needed: `declare -f editor_open`. diff --git a/.github/instructions/lib.instructions.md b/.github/instructions/lib.instructions.md index 717a759..25c097c 100644 --- a/.github/instructions/lib.instructions.md +++ b/.github/instructions/lib.instructions.md @@ -9,14 +9,17 @@ applyTo: lib/**/*.sh - **Maintain backwards compatibility** with existing configs - **Quote all paths**: Support spaces in directory names - **Use `log_error` / `log_info`** from `lib/ui.sh` for user messages -- **Git version fallbacks**: Check `lib/core.sh:97-100` for example (Git 2.22+ `--show-current` vs older `rev-parse`) +- **Git version fallbacks**: See `get_current_branch()` in `lib/core.sh` (Git 2.22+ `branch --show-current`, falling back to `rev-parse --abbrev-ref HEAD`) +- **Regenerate completions** after touching `_EDITOR_REGISTRY`, `_AI_REGISTRY`, or `_CFG_KEY_MAP`: `./scripts/generate-completions.sh` (CI runs `--check`) ## Key Functions & Responsibilities - `resolve_base_dir`: config/env/default selection; warn if inside repo & not ignored. - `resolve_target`: ID `1` + branch/current + sanitized path scan; returns TSV. - `create_worktree`: decides remote/local/new; respects `--force` + `--name` safety. -- `cfg_default`: precedence local→global→system→env→fallback (do not reorder). +- `cfg_default`: precedence local git config → `.gtrconfig` → global/system git config → `GTR_*` env var → fallback (do not reorder). `cfg_default_trusted_file` uses the same order but ignores `.gtrconfig` values until `git gtr trust` approves them. +- `sanitize_branch_name`: branch name → folder name; the only place that logic lives. +- `run_hooks_in` (`lib/hooks.sh`): runs postCreate/preRemove/postRemove/postCd hooks, trust-gated for `.gtrconfig`. - `cfg_get_all`: merge multi-value keys; preserves order; deduplicates. ## Change Guidelines @@ -25,4 +28,4 @@ applyTo: lib/**/*.sh - Add new config keys with `gtr.` prefix; avoid collisions. - For performance-sensitive loops (e.g. directory scans) prefer built-ins (`find`, `grep`) with minimal subshells. - Any new Git command: add fallback for older versions or guard with detection. -- Manual test after changes (subset): `new`, `open`, `ai`, `rm`, `list --porcelain`, `config set/get/unset`, `go 1`, hooks run once. +- Run `bats tests/` and ShellCheck, then smoke-test the affected subset: `new`, `editor`, `ai`, `rm`, `list --porcelain`, `config set/get/unset`, `go 1`, hooks run once. diff --git a/.github/instructions/sh.instructions.md b/.github/instructions/sh.instructions.md index 99d0d0b..6b6a7ae 100644 --- a/.github/instructions/sh.instructions.md +++ b/.github/instructions/sh.instructions.md @@ -20,7 +20,7 @@ applyTo: **/*.bash, **/*.fish, **/*.sh ### Strict Mode & Safety -- Global `set -e` in `bin/gtr`: guard non-critical commands with `|| true`. +- Global `set -e` in `bin/git-gtr` (every sourced library inherits it): guard non-critical commands with `|| true`. - Prefer `[ ]` over `[[ ]]` for POSIX portability (use `[[` only when needed). - Always quote glob inputs; disable unintended globbing (`set -f` temporarily if required). @@ -32,13 +32,14 @@ applyTo: **/*.bash, **/*.fish, **/*.sh ### Debugging - Quick trace: `bash -x ./bin/gtr `. +- Failure location: `GTR_DEBUG=1 ./bin/gtr ` prints `file:line:function` when a command fails under `set -e`. - Inline: wrap suspicious block with `set -x` / `set +x`. - Function presence: `declare -f create_worktree` or `declare -f resolve_target`. - Variable inspection: `echo "DEBUG var=$var" >&2` (stderr keeps stdout clean for command substitution). ### External Commands -- Keep dependencies minimal: only `git`, `sed`, `awk`, `find`, `grep` (avoid jq/curl unless justified). +- Keep dependencies minimal: only `git`, `sed`, `awk`, `find`, `grep` (avoid jq/curl unless justified). `gh` and `glab` are optional and used only by `pr` and `clean --merged/--closed`. - Check availability before use if adding new tools. ### Quoting & Paths diff --git a/.github/instructions/testing.instructions.md b/.github/instructions/testing.instructions.md index 41a1c4c..6013620 100644 --- a/.github/instructions/testing.instructions.md +++ b/.github/instructions/testing.instructions.md @@ -1,10 +1,23 @@ --- -applyTo: bin/gtr, lib/**/*.sh, adapters/**/*.sh +applyTo: bin/git-gtr, bin/gtr, lib/**/*.sh, adapters/**/*.sh, tests/**/*.bats --- # Testing Instructions -Run after core or adapter changes; all manual (no automated tests). +Run the automated checks after any change, then the manual matrix for the areas you touched. + +## Automated Checks (CI gates) + +```bash +bats tests/ # BATS suite, 29 files; fixtures in tests/test_helper.bash +bats tests/cmd_list.bats # one file; add --filter "name" for one test +shellcheck bin/gtr bin/git-gtr lib/*.sh lib/commands/*.sh adapters/editor/*.sh adapters/ai/*.sh +./scripts/generate-completions.sh --check # committed completions match the generator +``` + +These three jobs are exactly what `.github/workflows/lint.yml` runs on every pull request. + +## Manual Matrix ```bash # Basic create/remove @@ -31,7 +44,7 @@ Run after core or adapter changes; all manual (no automated tests). # Editor + AI adapters ./bin/gtr config set gtr.editor.default cursor -./bin/gtr open test-feature +./bin/gtr editor test-feature ./bin/gtr config set gtr.ai.default claude ./bin/gtr ai test-feature @@ -43,6 +56,13 @@ Run after core or adapter changes; all manual (no automated tests). cd "$(./bin/gtr go 1)" # repo root cd "$(./bin/gtr go test-feature)" # worktree path +# Pull request worktrees (needs gh) and PR-based cleanup +./bin/gtr pr 123 # folder from the PR head branch +./bin/gtr clean --merged --dry-run # preview, remove nothing + +# .gtrconfig trust (hooks and defaults stay inert until approved) +./bin/gtr trust + # Config commands ./bin/gtr config set gtr.editor.default cursor ./bin/gtr config get gtr.editor.default @@ -72,7 +92,7 @@ git --version ## Adapter Sourcing Checks ```bash -bash -c 'source adapters/editor/cursor.sh && editor_can_open && echo OK' +bash -c 'source adapters/editor/nano.sh && editor_can_open && echo OK' bash -c 'source adapters/ai/claude.sh && ai_can_start && echo OK' ``` @@ -80,6 +100,7 @@ bash -c 'source adapters/ai/claude.sh && ai_can_start && echo OK' ```bash bash -x ./bin/gtr new test-feature # global trace +GTR_DEBUG=1 ./bin/gtr new test-feature # file:line:function on set -e failures set -x; create_worktree ...; set +x # scoped trace inside function declare -f resolve_target # confirm function loaded echo "DEBUG worktree_path=$worktree_path" >&2 # variable inspection @@ -87,6 +108,7 @@ echo "DEBUG worktree_path=$worktree_path" >&2 # variable inspection ## Success Criteria +- `bats tests/`, ShellCheck, and `./scripts/generate-completions.sh --check` pass. - All commands exit 0 (except intentional failures) and produce expected side-effects. - No unquoted path errors; spaces handled. - Hooks run only once per creation/removal. @@ -95,5 +117,6 @@ echo "DEBUG worktree_path=$worktree_path" >&2 # variable inspection ## When Adding Features +- Add or extend the matching `tests/cmd_.bats`; BATS covers behavior, this matrix covers what BATS cannot (editors, AI tools, shell integration). - Extend this matrix minimally (keep concise). - Prefer adding under relevant section (e.g. new flag under create/remove). diff --git a/CHANGELOG.md b/CHANGELOG.md index 08c4d93..ffd1a9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this ## [Unreleased] +### Changed + +- `.github/copilot-instructions.md` rewritten for the current `bin/git-gtr` and `lib/` layout; it had described a single-file `bin/gtr` with an `open` command since before the modularization. +- `.github/instructions/*.instructions.md` and `CONTRIBUTING.md` now state that `completions/*` are generated by `scripts/generate-completions.sh` rather than hand-edited, name `editor` instead of the removed `open` command, list the BATS, ShellCheck, and completions CI gates, include `.gtrconfig` in the config precedence, and point at `bin/git-gtr` for `set -e`. + ## [2.11.0] - 2026-08-19 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5f22a38..2420cf8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,7 +119,7 @@ Format: `name|cmd|type|err_msg|flags` where: Create `adapters/editor/yourname.sh` implementing `editor_can_open()` and `editor_open()`. See `adapters/editor/nano.sh` for an example. -**Also update**: README.md, all three completion files, help text in `lib/commands/help.sh`. +**Also update**: README.md, help text in `lib/commands/help.sh`, then run `./scripts/generate-completions.sh` (the files under `completions/` are generated; CI checks them). #### Adding an AI Tool Adapter @@ -137,7 +137,7 @@ Format: `name|cmd|err_msg|info_lines` (info lines are semicolon-separated). Create `adapters/ai/yourname.sh` implementing `ai_can_start()` and `ai_start()`. See `adapters/ai/claude.sh` for an example. -**Also update**: README.md, completions, help text. +**Also update**: README.md, help text, then regenerate completions with `./scripts/generate-completions.sh`. #### Adding Core Features @@ -182,7 +182,7 @@ Please also test your changes manually on: - [ ] Remove worktree by branch name - [ ] List worktrees - [ ] Test configuration commands -- [ ] Test completions (tab completion works) +- [ ] `./scripts/generate-completions.sh --check` passes (regenerate after changing adapters, config keys, commands, or flags) - [ ] Test `git gtr go 1` for main repo - [ ] Test `git gtr go ` for worktrees From 325eafa449df6489403d03346f9470bb593a56c9 Mon Sep 17 00:00:00 2001 From: Tom Elizaga Date: Mon, 14 Sep 2026 10:57:58 -0700 Subject: [PATCH 2/5] Address PR review: name docs/configuration.md in adapter checklists CONTRIBUTING.md's two adapter "Also update" entries now list the docs/configuration.md editor list and AI tool table, matching the editor/ai instruction files. Also correct those files and the Copilot guide to say "list" for editors, since docs/configuration.md presents editors as a bullet list and only AI tools as a table. --- .github/copilot-instructions.md | 2 +- .github/instructions/ai.instructions.md | 2 +- .github/instructions/editor.instructions.md | 4 ++-- CONTRIBUTING.md | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index fa33992..aabb5ca 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -43,7 +43,7 @@ Standard tools are registry lines, not files. `_EDITOR_REGISTRY` entries are `na **Add a command**: create `lib/commands/.sh` with `cmd_()`; add a `case` entry to `main()` in `bin/git-gtr`; add `_help_()` to `lib/commands/help.sh` (found by name; add a `case` alias in `cmd_help` only if the command has aliases); add the command and its flags to the `generate_bash`, `generate_zsh`, and `generate_fish` templates in `scripts/generate-completions.sh`; run `./scripts/generate-completions.sh`; add `tests/cmd_.bats`; document it in README. -**Add an adapter**: add a registry line in `lib/adapters.sh`; run `./scripts/generate-completions.sh`; update the adapter tables in README and `docs/configuration.md` and the tool list in `lib/commands/help.sh`. +**Add an adapter**: add a registry line in `lib/adapters.sh`; run `./scripts/generate-completions.sh`; update the adapter lists in README and `docs/configuration.md` and the tool list in `lib/commands/help.sh`. **Change a flag**: update the command's `parse_args` spec, its `_help_()`, the three completion templates, the regenerated completions, README, and the matching BATS file. diff --git a/.github/instructions/ai.instructions.md b/.github/instructions/ai.instructions.md index c6abc88..7b924b7 100644 --- a/.github/instructions/ai.instructions.md +++ b/.github/instructions/ai.instructions.md @@ -44,7 +44,7 @@ ai_start() { File-based adapters take precedence over registry entries of the same name. -**Also update**: README and `docs/configuration.md` tool tables, help text in `lib/commands/help.sh` (`_help_ai`); then run `./scripts/generate-completions.sh` (completions are generated and checked in CI) +**Also update**: the README tool list and the `docs/configuration.md` AI tool table, help text in `lib/commands/help.sh` (`_help_ai`); then run `./scripts/generate-completions.sh` (completions are generated and checked in CI) ## Contract & Guidelines diff --git a/.github/instructions/editor.instructions.md b/.github/instructions/editor.instructions.md index b6058cf..d9e3e00 100644 --- a/.github/instructions/editor.instructions.md +++ b/.github/instructions/editor.instructions.md @@ -50,7 +50,7 @@ File-based adapters take precedence over registry entries of the same name. - README.md (setup instructions) - Completions: run `./scripts/generate-completions.sh` (registry names are picked up automatically; the files under `completions/` are generated and checked in CI) - Help text in `lib/commands/help.sh` (`_help_editor`) -- Editor table in `docs/configuration.md` +- Editor list (**Setup editors**) in `docs/configuration.md` ## Contract & Guidelines @@ -59,6 +59,6 @@ File-based adapters take precedence over registry entries of the same name. - Use `log_error` with actionable install guidance if command missing. - Keep adapter lean: no project scans, no blocking prompts. - Naming: file/registry name = tool name (`zed` → `zed` flag). Avoid uppercase. -- Update: README editor list, `docs/configuration.md` editor table, help text, then regenerate completions. +- Update: README editor list, `docs/configuration.md` editor list, help text, then regenerate completions. - Fallback behavior: if editor absent, fail clearly; do NOT silently defer to file browser. - Inspect function definition if needed: `declare -f editor_open`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2420cf8..03cecea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,7 +119,7 @@ Format: `name|cmd|type|err_msg|flags` where: Create `adapters/editor/yourname.sh` implementing `editor_can_open()` and `editor_open()`. See `adapters/editor/nano.sh` for an example. -**Also update**: README.md, help text in `lib/commands/help.sh`, then run `./scripts/generate-completions.sh` (the files under `completions/` are generated; CI checks them). +**Also update**: README.md, the editor list in `docs/configuration.md`, help text in `lib/commands/help.sh`, then run `./scripts/generate-completions.sh` (the files under `completions/` are generated; CI checks them). #### Adding an AI Tool Adapter @@ -137,7 +137,7 @@ Format: `name|cmd|err_msg|info_lines` (info lines are semicolon-separated). Create `adapters/ai/yourname.sh` implementing `ai_can_start()` and `ai_start()`. See `adapters/ai/claude.sh` for an example. -**Also update**: README.md, help text, then regenerate completions with `./scripts/generate-completions.sh`. +**Also update**: README.md, the AI tool table in `docs/configuration.md`, help text, then regenerate completions with `./scripts/generate-completions.sh`. #### Adding Core Features From cbddad0df8369513f0c14f9fb9a6ea7dbd536a6e Mon Sep 17 00:00:00 2001 From: Tom Elizaga Date: Mon, 14 Sep 2026 11:09:53 -0700 Subject: [PATCH 3/5] Address PR review: correct the postCd hook dispatcher description The review of #197 established that run_hooks_in does not handle postCd. This PR added the same incorrect claim: run_hooks evaluates each hook in a subshell and serves postRemove, run_hooks_in adds a cd for postCreate and preRemove, and postCd goes through run_hooks_export or the eval loop inside the init-generated shell functions. --- .github/copilot-instructions.md | 2 +- .github/instructions/lib.instructions.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index aabb5ca..66984bf 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -10,7 +10,7 @@ Condensed guide for AI agents working in this repository. `AGENTS.md` and `CLAUD - `bin/git-gtr` - entry point. Sets `set -e`, defines `GTR_VERSION`, sources every library, and dispatches in `main()` with a `case` on the first argument. - `bin/gtr` - development wrapper that `exec`s `bin/git-gtr`. -- `lib/*.sh` - sourced in this order: `ui.sh` (logging, prompts), `args.sh` (flag parser that fills `_arg_*` vars), `config.sh` (`cfg_get`, `cfg_default`, `cfg_get_all`), `platform.sh` (OS detection), `core.sh` (worktree CRUD, `resolve_target`, `resolve_base_dir`, `sanitize_branch_name`), `copy.sh`, `hooks.sh` (`run_hooks_in`), `provider.sh` (GitHub/GitLab detection for `clean`), `adapters.sh` (adapter registries and loaders), `launch.sh` (editor/AI launch orchestration). +- `lib/*.sh` - sourced in this order: `ui.sh` (logging, prompts), `args.sh` (flag parser that fills `_arg_*` vars), `config.sh` (`cfg_get`, `cfg_default`, `cfg_get_all`), `platform.sh` (OS detection), `core.sh` (worktree CRUD, `resolve_target`, `resolve_base_dir`, `sanitize_branch_name`), `copy.sh`, `hooks.sh` (`run_hooks_in`/`run_hooks`, plus `run_hooks_export` for postCd), `provider.sh` (GitHub/GitLab detection for `clean`), `adapters.sh` (adapter registries and loaders), `launch.sh` (editor/AI launch orchestration). - `lib/commands/*.sh` - one file per subcommand defining `cmd_()` (18 files, including `pr.sh` and `trust.sh`). Help text lives in `lib/commands/help.sh` as `_help_()` functions; `cmd_help` finds them by name, with a small `case` mapping aliases such as `ls` to `list`. - `adapters/editor/nano.sh`, `adapters/ai/claude.sh`, `adapters/ai/cursor.sh` - the only file-based adapters. Every other editor and AI tool is a registry line in `lib/adapters.sh`. - `completions/` - generated output. Never edit by hand (see Common Changes). diff --git a/.github/instructions/lib.instructions.md b/.github/instructions/lib.instructions.md index 25c097c..d357e9c 100644 --- a/.github/instructions/lib.instructions.md +++ b/.github/instructions/lib.instructions.md @@ -19,7 +19,7 @@ applyTo: lib/**/*.sh - `create_worktree`: decides remote/local/new; respects `--force` + `--name` safety. - `cfg_default`: precedence local git config → `.gtrconfig` → global/system git config → `GTR_*` env var → fallback (do not reorder). `cfg_default_trusted_file` uses the same order but ignores `.gtrconfig` values until `git gtr trust` approves them. - `sanitize_branch_name`: branch name → folder name; the only place that logic lives. -- `run_hooks_in` (`lib/hooks.sh`): runs postCreate/preRemove/postRemove/postCd hooks, trust-gated for `.gtrconfig`. +- `lib/hooks.sh` dispatchers: `run_hooks` evaluates each hook in its own subshell and serves postRemove directly; `run_hooks_in` is the same after a `cd` into the target worktree (postCreate, preRemove); `run_hooks_export` evaluates postCd hooks without a subshell so their exports survive, and its callers wrap it in one. The `gtr cd` functions generated by `init` evaluate postCd hooks themselves. Every path skips untrusted `.gtrconfig` hooks. - `cfg_get_all`: merge multi-value keys; preserves order; deduplicates. ## Change Guidelines From 57ff3be62283e67b8cb6eabbcde9fe7935bcd059 Mon Sep 17 00:00:00 2001 From: Tom Elizaga Date: Mon, 14 Sep 2026 11:13:57 -0700 Subject: [PATCH 4/5] Address PR review: name the run_hooks_export call sites explicitly The review read "its callers wrap it in one" as contradicting the purpose of run_hooks_export. Both call sites do use a subshell, as lib/hooks.sh itself instructs, so the wording now names them and says what the subshell is for: the exports reach the editor or AI tool started in the same block without leaking into the main script. --- .github/instructions/lib.instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/instructions/lib.instructions.md b/.github/instructions/lib.instructions.md index d357e9c..dc772ff 100644 --- a/.github/instructions/lib.instructions.md +++ b/.github/instructions/lib.instructions.md @@ -19,7 +19,7 @@ applyTo: lib/**/*.sh - `create_worktree`: decides remote/local/new; respects `--force` + `--name` safety. - `cfg_default`: precedence local git config → `.gtrconfig` → global/system git config → `GTR_*` env var → fallback (do not reorder). `cfg_default_trusted_file` uses the same order but ignores `.gtrconfig` values until `git gtr trust` approves them. - `sanitize_branch_name`: branch name → folder name; the only place that logic lives. -- `lib/hooks.sh` dispatchers: `run_hooks` evaluates each hook in its own subshell and serves postRemove directly; `run_hooks_in` is the same after a `cd` into the target worktree (postCreate, preRemove); `run_hooks_export` evaluates postCd hooks without a subshell so their exports survive, and its callers wrap it in one. The `gtr cd` functions generated by `init` evaluate postCd hooks themselves. Every path skips untrusted `.gtrconfig` hooks. +- `lib/hooks.sh` dispatchers: `run_hooks` evaluates each hook in its own subshell and serves postRemove directly; `run_hooks_in` is the same after a `cd` into the target worktree (postCreate, preRemove); `run_hooks_export` evaluates postCd hooks directly rather than in a nested subshell, so their exports reach the tool launched beside them; `lib/launch.sh` and `lib/commands/ai.sh` each call it inside a `( cd "$worktree" ... )` block that also launches the editor or AI tool, which is what keeps those exports out of the main script. The `gtr cd` functions generated by `init` evaluate postCd hooks themselves. Every path skips untrusted `.gtrconfig` hooks. - `cfg_get_all`: merge multi-value keys; preserves order; deduplicates. ## Change Guidelines From b3ceaba2515def7e8d8f3a51e4d658457567c07f Mon Sep 17 00:00:00 2001 From: Tom Elizaga Date: Mon, 14 Sep 2026 11:20:44 -0700 Subject: [PATCH 5/5] Correct four claims an independent verification pass disproved Checked every added assertion against the code at 57ff3be: - GTR_DEBUG does not report file:line:function. bin/git-gtr installs an ERR trap but sets `set -e` without `set -E`, so the trap is not inherited by functions and never fires for failures inside cmd_* handlers. Verified with a minimal repro (silent under `set -e`, fires under `set -eE`) and against the real binary. Stated in three files; all now describe the limitation and point to `bash -x`. - postCd hooks reach the AI tool only. Both run_hooks_export call sites are AI paths; _auto_launch_editor, _open_editor and cmd_editor run no hooks. - `git gtr completion zsh` does not print the generated file. Only the bash and fish branches cat it; zsh emits a zstyle + fpath + compinit snippet. - `version` has no cmd_version; main() answers it inline. Also widen sh.instructions.md's applyTo to cover bin/git-gtr and bin/gtr, which it describes but did not match, and correct the `cd` dispatch wording. --- .github/copilot-instructions.md | 6 +++--- .github/instructions/completions.instructions.md | 2 +- .github/instructions/lib.instructions.md | 2 +- .github/instructions/sh.instructions.md | 4 ++-- .github/instructions/testing.instructions.md | 3 ++- CHANGELOG.md | 1 + 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 66984bf..04a0e16 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -18,9 +18,9 @@ Condensed guide for AI agents working in this repository. `AGENTS.md` and `CLAUD ## Commands -`new`, `pr`, `rm`, `mv|rename`, `go`, `run`, `editor`, `ai`, `copy`, `ls|list`, `clean`, `doctor`, `adapter|adapters`, `config`, `completion`, `init`, `trust`, `version`, `help`. There is no `open` command; the editor command is `editor`. `cd` has no `cmd_*` handler: the dispatcher prints setup instructions because `gtr cd` is a shell function emitted by `init`. +`new`, `pr`, `rm`, `mv|rename`, `go`, `run`, `editor`, `ai`, `copy`, `ls|list`, `clean`, `doctor`, `adapter|adapters`, `config`, `completion`, `init`, `trust`, `version`, `help`. There is no `open` command; the editor command is `editor`. `cd` has no `cmd_*` handler: the dispatcher errors and points at `git gtr help init`, because `gtr cd` is a shell function emitted by `init`. -Dispatch names that differ from the command: `new`→`cmd_create`, `rm`→`cmd_remove`, `mv|rename`→`cmd_rename`, `ls|list`→`cmd_list`, `adapter|adapters`→`cmd_adapter`. Everything else is `cmd_`. +Dispatch names that differ from the command: `new`→`cmd_create`, `rm`→`cmd_remove`, `mv|rename`→`cmd_rename`, `ls|list`→`cmd_list`, `adapter|adapters`→`cmd_adapter`. Everything else is `cmd_`, except `version`, which `main()` answers inline, and `cd`. ## Key Concepts @@ -69,7 +69,7 @@ CI (`.github/workflows/lint.yml`) runs exactly these three jobs on every pull re ## Debugging -`bash -x ./bin/gtr ` gives a full trace. `GTR_DEBUG=1 ./bin/gtr ` prints `file:line:function` when a command fails under `set -e`. `declare -f resolve_target` confirms a function is loaded. `./bin/gtr doctor` and `./bin/gtr adapter` check the environment. +`bash -x ./bin/gtr ` gives a full trace. `GTR_DEBUG=1` installs an ERR trap in `bin/git-gtr`, but the script uses `set -e` without `set -E`, so the trap is not inherited by functions and stays silent for failures inside `cmd_*` handlers; use `bash -x` for those. `declare -f resolve_target` confirms a function is loaded. `./bin/gtr doctor` and `./bin/gtr adapter` check the environment. ## Releasing diff --git a/.github/instructions/completions.instructions.md b/.github/instructions/completions.instructions.md index 8dc386d..a30e15d 100644 --- a/.github/instructions/completions.instructions.md +++ b/.github/instructions/completions.instructions.md @@ -14,7 +14,7 @@ Sources of truth: - Config keys: `_CFG_KEY_MAP` in `lib/config.sh`. - Commands, their flags, and which commands accept branch arguments: the `generate_bash`, `generate_zsh`, and `generate_fish` templates inside the script. -`git gtr completion ` (`lib/commands/completion.sh`) prints the matching generated file from the source checkout or the Homebrew install layout. It does not build completions at runtime. +`git gtr completion ` (`lib/commands/completion.sh`) resolves the asset from the source checkout or the Homebrew install layout. For bash and fish it prints the generated file; for zsh it prints a `zstyle` + `fpath` + `compinit` snippet that puts the generated `_git-gtr` on your fpath. It never builds completions at runtime. ## Making Changes diff --git a/.github/instructions/lib.instructions.md b/.github/instructions/lib.instructions.md index dc772ff..6987d6e 100644 --- a/.github/instructions/lib.instructions.md +++ b/.github/instructions/lib.instructions.md @@ -19,7 +19,7 @@ applyTo: lib/**/*.sh - `create_worktree`: decides remote/local/new; respects `--force` + `--name` safety. - `cfg_default`: precedence local git config → `.gtrconfig` → global/system git config → `GTR_*` env var → fallback (do not reorder). `cfg_default_trusted_file` uses the same order but ignores `.gtrconfig` values until `git gtr trust` approves them. - `sanitize_branch_name`: branch name → folder name; the only place that logic lives. -- `lib/hooks.sh` dispatchers: `run_hooks` evaluates each hook in its own subshell and serves postRemove directly; `run_hooks_in` is the same after a `cd` into the target worktree (postCreate, preRemove); `run_hooks_export` evaluates postCd hooks directly rather than in a nested subshell, so their exports reach the tool launched beside them; `lib/launch.sh` and `lib/commands/ai.sh` each call it inside a `( cd "$worktree" ... )` block that also launches the editor or AI tool, which is what keeps those exports out of the main script. The `gtr cd` functions generated by `init` evaluate postCd hooks themselves. Every path skips untrusted `.gtrconfig` hooks. +- `lib/hooks.sh` dispatchers: `run_hooks` evaluates each hook in its own subshell and serves postRemove directly; `run_hooks_in` is the same after a `cd` into the target worktree (postCreate, preRemove); `run_hooks_export` evaluates postCd hooks directly rather than in a nested subshell, so their exports reach the tool launched beside them; `lib/launch.sh` and `lib/commands/ai.sh` each call it inside a `( cd "$worktree" ... )` block that also launches the AI tool, which is what keeps those exports out of the main script. The editor paths (`_auto_launch_editor`, `_open_editor`, `cmd_editor`) run no postCd hooks at all. The `gtr cd` functions generated by `init` evaluate postCd hooks themselves. Every path skips untrusted `.gtrconfig` hooks. - `cfg_get_all`: merge multi-value keys; preserves order; deduplicates. ## Change Guidelines diff --git a/.github/instructions/sh.instructions.md b/.github/instructions/sh.instructions.md index 6b6a7ae..6495a43 100644 --- a/.github/instructions/sh.instructions.md +++ b/.github/instructions/sh.instructions.md @@ -1,5 +1,5 @@ --- -applyTo: **/*.bash, **/*.fish, **/*.sh +applyTo: bin/git-gtr, bin/gtr, **/*.bash, **/*.fish, **/*.sh --- # Shell Instructions @@ -32,7 +32,7 @@ applyTo: **/*.bash, **/*.fish, **/*.sh ### Debugging - Quick trace: `bash -x ./bin/gtr `. -- Failure location: `GTR_DEBUG=1 ./bin/gtr ` prints `file:line:function` when a command fails under `set -e`. +- `GTR_DEBUG=1` installs an ERR trap in `bin/git-gtr`, but the script sets `set -e` without `set -E`, so the trap is not inherited by functions and does not fire for failures inside `cmd_*` handlers. Prefer `bash -x` until that changes. - Inline: wrap suspicious block with `set -x` / `set +x`. - Function presence: `declare -f create_worktree` or `declare -f resolve_target`. - Variable inspection: `echo "DEBUG var=$var" >&2` (stderr keeps stdout clean for command substitution). diff --git a/.github/instructions/testing.instructions.md b/.github/instructions/testing.instructions.md index 6013620..691a22f 100644 --- a/.github/instructions/testing.instructions.md +++ b/.github/instructions/testing.instructions.md @@ -100,7 +100,8 @@ bash -c 'source adapters/ai/claude.sh && ai_can_start && echo OK' ```bash bash -x ./bin/gtr new test-feature # global trace -GTR_DEBUG=1 ./bin/gtr new test-feature # file:line:function on set -e failures +# Note: GTR_DEBUG=1 installs an ERR trap, but bin/git-gtr lacks set -E, +# so it does not fire for failures inside functions. Use bash -x. set -x; create_worktree ...; set +x # scoped trace inside function declare -f resolve_target # confirm function loaded echo "DEBUG worktree_path=$worktree_path" >&2 # variable inspection diff --git a/CHANGELOG.md b/CHANGELOG.md index ffd1a9e..7894591 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this - `.github/copilot-instructions.md` rewritten for the current `bin/git-gtr` and `lib/` layout; it had described a single-file `bin/gtr` with an `open` command since before the modularization. - `.github/instructions/*.instructions.md` and `CONTRIBUTING.md` now state that `completions/*` are generated by `scripts/generate-completions.sh` rather than hand-edited, name `editor` instead of the removed `open` command, list the BATS, ShellCheck, and completions CI gates, include `.gtrconfig` in the config precedence, and point at `bin/git-gtr` for `set -e`. +- The same guidance now describes the `lib/hooks.sh` dispatchers accurately, notes that `postCd` hooks run only on the AI-tool path, records that `git gtr completion zsh` emits an fpath snippet rather than the generated file, and warns that `GTR_DEBUG` cannot report failures inside functions because `bin/git-gtr` does not set `set -E`. ## [2.11.0] - 2026-08-19