|
1 | 1 | # Copilot Instructions |
2 | 2 |
|
3 | | -## Architecture & Flow |
| 3 | +Condensed guide for AI agents working in this repository. `AGENTS.md` and `CLAUDE.md` are the long-form versions; keep all three consistent. |
4 | 4 |
|
5 | | -`bin/gtr` (961 lines) dispatches to `cmd_*` functions (case block lines 36‑77). Libraries sourced at startup: |
| 5 | +## What This Is |
6 | 6 |
|
7 | | -- `lib/core.sh` - create/list/remove/resolve worktrees |
8 | | -- `lib/config.sh` - git config wrapper with precedence |
9 | | -- `lib/ui.sh` - log_error/log_info/prompts |
10 | | -- `lib/copy.sh` - glob pattern file copying |
11 | | -- `lib/hooks.sh` - postCreate/postRemove execution |
12 | | -- `lib/platform.sh` - OS detection + GUI helpers |
| 7 | +`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`. |
13 | 8 |
|
14 | | -Adapters in `adapters/{editor,ai}` each implement two functions with strict contracts (see below). |
| 9 | +## Layout |
15 | 10 |
|
16 | | -## Key Concepts |
| 11 | +- `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. |
| 12 | +- `bin/gtr` - development wrapper that `exec`s `bin/git-gtr`. |
| 13 | +- `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). |
| 14 | +- `lib/commands/*.sh` - one file per subcommand defining `cmd_<name>()` (18 files, including `pr.sh` and `trust.sh`). Help text lives in `lib/commands/help.sh` as `_help_<command>()` functions; `cmd_help` finds them by name, with a small `case` mapping aliases such as `ls` to `list`. |
| 15 | +- `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`. |
| 16 | +- `completions/` - generated output. Never edit by hand (see Common Changes). |
| 17 | +- `tests/*.bats` - BATS suite (29 files) with shared fixtures in `tests/test_helper.bash`. |
17 | 18 |
|
18 | | -- Special ID `1` = main repo (usable in `open`, `go`, `ai`). |
19 | | -- Folder naming = sanitized branch (`feature/auth` → `feature-auth`). |
20 | | -- Base dir resolution (`resolve_base_dir`): config `gtr.worktrees.dir` → env → default `<repo>-worktrees`; relative paths resolved from repo root; tilde expanded; warns if inside repo unignored. |
21 | | -- Target resolution (`resolve_target`): ID `1` → current → sanitized path → scan directories; returns TSV: `is_main\tpath\tbranch`. |
22 | | -- Config precedence (`cfg_default`): git config (local→global→system) → env → fallback. Multi-value keys merged & deduped (`cfg_get_all`). |
| 19 | +## Commands |
23 | 20 |
|
24 | | -## Adapter Contract |
| 21 | +`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`. |
25 | 22 |
|
26 | | -Editor: `editor_can_open`, `editor_open <path>`; AI: `ai_can_start`, `ai_start <path> [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. |
| 23 | +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_<command>`, except `version`, which `main()` answers inline, and `cd`. |
27 | 24 |
|
28 | | -## Manual Testing (Essential Subset) |
| 25 | +## Key Concepts |
29 | 26 |
|
30 | | -```bash |
31 | | -./bin/gtr new feature/x # creates folder feature-x |
32 | | -./bin/gtr open feature/x # loads configured editor |
33 | | -./bin/gtr ai feature/x # starts configured AI tool |
34 | | -./bin/gtr list # lists main + worktrees |
35 | | -./bin/gtr rm feature/x # removes worktree |
36 | | -./bin/gtr go feature/x # prints path (use in cd) |
37 | | -``` |
| 27 | +- Special ID `1` means the main repository in `go`, `editor`, `ai`, `run`, and other commands that take a worktree target. |
| 28 | +- Folder name = sanitized branch (`feature/auth` → `feature-auth`); `--folder` replaces it, `--name` adds a suffix. |
| 29 | +- `resolve_base_dir`: `gtr.worktrees.dir` → `GTR_WORKTREES_DIR` → `<repo>-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. |
| 30 | +- `resolve_target`: ID `1` → current branch → sanitized path match → full scan. Returns TSV `is_main\tpath\tbranch`. |
| 31 | +- 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`. |
| 32 | +- `.gtrconfig` settings that execute code (hooks, editor/AI defaults) are ignored until `git gtr trust` approves them. |
| 33 | +- `new --porcelain` prints exactly three `key<TAB>value` records (`path`, `branch`, `hook_status`) on stdout and everything else on stderr. Keep that contract stable; it is documented in `docs/agent-usage.md`. |
| 34 | +- `new` inherits sparse-checkout from the base worktree on Git 2.36+ (`gtr.sparse.inherit`, `--sparse`, `--no-sparse`). |
| 35 | + |
| 36 | +## Adapter Contract |
| 37 | + |
| 38 | +Editor adapters define `editor_can_open` and `editor_open <path>`. AI adapters define `ai_can_start` and `ai_start <path> [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. |
38 | 39 |
|
39 | | -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"`. |
40 | | -Full matrix: see `.github/instructions/testing.instructions.md`. |
| 40 | +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. |
41 | 41 |
|
42 | 42 | ## Common Changes |
43 | 43 |
|
44 | | -**Add command**: new `cmd_<name>()` function in `bin/gtr` + case entry (lines 36‑77) + help text in `cmd_help` + all three completions (bash/zsh/fish) + README docs. |
| 44 | +**Add a command**: create `lib/commands/<name>.sh` with `cmd_<name>()`; add a `case` entry to `main()` in `bin/git-gtr`; add `_help_<name>()` 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_<name>.bats`; document it in README. |
45 | 45 |
|
46 | | -**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). |
| 46 | +**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`. |
47 | 47 |
|
48 | | -**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. |
| 48 | +**Change a flag**: update the command's `parse_args` spec, its `_help_<name>()`, the three completion templates, the regenerated completions, README, and the matching BATS file. |
49 | 49 |
|
50 | | -## Patterns & Gotchas |
| 50 | +**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. |
51 | 51 |
|
52 | | -- Always quote paths (spaces). Avoid unguarded globbing. |
53 | | -- `set -e` active: ensure non-critical failures are guarded (`command || true`). |
54 | | -- Multi-value config keys require `git config --add` (do not overwrite entire list unintentionally). |
55 | | -- If placing worktrees inside repo (relative path), add directory to `.gitignore` to prevent accidental commits. |
| 52 | +## Validation |
56 | 53 |
|
57 | | -## Debugging |
| 54 | +```bash |
| 55 | +bats tests/ # full suite; bats tests/cmd_list.bats for one file |
| 56 | +shellcheck bin/gtr bin/git-gtr lib/*.sh lib/commands/*.sh adapters/editor/*.sh adapters/ai/*.sh |
| 57 | +./scripts/generate-completions.sh --check # committed completions match the generator |
| 58 | +``` |
58 | 59 |
|
59 | | -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'`. |
| 60 | +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`. |
60 | 61 |
|
61 | | -## Troubleshooting Quick |
| 62 | +## Patterns & Gotchas |
| 63 | + |
| 64 | +- `set -e` is global. Guard anything allowed to fail: `result=$(fn) || true`, or test it inside `if`. |
| 65 | +- Quote every path and branch; both may contain spaces or slashes. |
| 66 | +- Multi-value config keys need `git config --add`; a plain `set` overwrites the list. |
| 67 | +- Call `sanitize_branch_name`; do not reimplement it. |
| 68 | +- Never hand-edit `completions/*`. CI rejects files that differ from the generator output. |
62 | 69 |
|
63 | | -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`. |
| 70 | +## Debugging |
64 | 71 |
|
65 | | -## Version |
| 72 | +`bash -x ./bin/gtr <cmd>` gives a full trace. `GTR_DEBUG=1` reports `ERROR at <file>:<line> in <function>()` for an unguarded failure, including one raised inside a subshell such as the one `cmd_run` uses. Handled error paths add no such line. `declare -f resolve_target` confirms a function is loaded. `./bin/gtr doctor` and `./bin/gtr adapter` check the environment. |
66 | 73 |
|
67 | | -Update `GTR_VERSION` (line 8 `bin/gtr`) when releasing; affects `gtr version` / `--version`. |
| 74 | +## Releasing |
68 | 75 |
|
69 | | -## Documentation Structure |
| 76 | +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. |
70 | 77 |
|
71 | | -- **`.github/copilot-instructions.md`** (this file) - High-level guide for AI agents |
72 | | -- **`.github/instructions/*.instructions.md`** - Specific guidance by file pattern: |
73 | | - - `testing.instructions.md` - Manual testing checklist (applies to: `bin/gtr`, `lib/**/*.sh`, `adapters/**/*.sh`) |
74 | | - - `sh.instructions.md` - Shell scripting conventions (applies to: `**/*.sh`, `**/*.bash`, `**/*.fish`) |
75 | | - - `lib.instructions.md` - Core library modification guidelines (applies to: `lib/**/*.sh`) |
76 | | - - `editor.instructions.md` - Editor adapter contract (applies to: `adapters/editor/**/*.sh`) |
77 | | - - `ai.instructions.md` - AI tool adapter contract (applies to: `adapters/ai/**/*.sh`) |
78 | | - - `completions.instructions.md` - Shell completion updates (applies to: `completions/*`) |
79 | | -- **`README.md`** - User-facing documentation |
80 | | -- **`CONTRIBUTING.md`** - Contribution guidelines |
81 | | -- **`CLAUDE.md`** - Extended development guide for Claude Code |
| 78 | +## Documentation Map |
82 | 79 |
|
83 | | -Feedback: Ask if more detail needed on copy patterns, hooks, or multi-worktree `--force` safety. |
| 80 | +- `AGENTS.md` / `CLAUDE.md` - long-form architecture and workflow guide |
| 81 | +- `.github/instructions/*.instructions.md` - file-pattern guidance: `testing`, `sh`, `lib`, `editor`, `ai`, `completions` |
| 82 | +- `README.md` - user docs, with `docs/configuration.md`, `docs/advanced-usage.md`, `docs/agent-usage.md`, `docs/troubleshooting.md` |
| 83 | +- `CONTRIBUTING.md` - contribution process and manual test checklist |
0 commit comments