Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8ab2d56
refactor: standardize AI and editor adapter initialization
helizaga Feb 11, 2026
1aa5b20
refactor: streamline editor adapter scripts with terminal definition
helizaga Feb 11, 2026
9cd81a4
refactor: simplify get_current_branch function logic
helizaga Feb 11, 2026
06c2301
feat: add CI workflow for linting and testing
helizaga Feb 11, 2026
5368d32
fix: address CI failures and review feedback
helizaga Feb 12, 2026
25ede69
refactor: improve error handling in copy_directories function
helizaga Feb 12, 2026
98858e3
refactor: enhance current_branch function for better detection
helizaga Feb 12, 2026
e56424d
refactor: enhance adapter management and command structure
helizaga Feb 12, 2026
194212b
refactor: enhance command context handling with shellcheck directives
helizaga Feb 12, 2026
289124b
refactor: enhance testing documentation and command help
helizaga Feb 12, 2026
41c1488
refactor: enhance argument parsing and command completion
helizaga Feb 12, 2026
8a8d7be
fix: use prefix variable in doctor to resolve ShellCheck SC2034
helizaga Feb 12, 2026
847965e
refactor: enhance adapter and configuration management
helizaga Feb 12, 2026
2fcf302
fix: improve error handling in launch and command scripts
helizaga Feb 12, 2026
1a4b73a
refactor: remove unused functions and improve command clarity
helizaga Feb 12, 2026
e512a10
refactor: simplify worktree management by removing force flag handling
helizaga Feb 12, 2026
7fdcadf
refactor: update shebang and improve pattern matching in scripts
helizaga Feb 12, 2026
4e3f724
refactor: enhance testing and command structure
helizaga Feb 12, 2026
c05ca37
fix: improve directory handling and test execution in clean command
helizaga Feb 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions .github/instructions/ai.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,26 @@
applyTo: adapters/ai/**/*.sh
---

# AI Instructions
# AI Adapter Instructions

## Adding Features
## When to Use a File vs Registry

### New AI Tool Adapter (`adapters/ai/<name>.sh`)
Most AI tools are defined as **registry entries** in `lib/adapters.sh` — no adapter file needed.
Only create an adapter file in `adapters/ai/` for tools that need **custom behavior** beyond the standard builder (see `claude.sh` or `cursor.sh` for examples).

## Adding a Standard AI Tool (Registry)

Add a line to `_AI_REGISTRY` in `lib/adapters.sh`:

```
yourname|yourcmd|ToolName not found. Install with: ...|Extra info;More info
```

Format: `name|cmd|err_msg|info_lines` (info lines are semicolon-separated)

## Adding a Custom AI Tool (File Override)

Create `adapters/ai/<name>.sh` implementing:

```bash
#!/usr/bin/env bash
Expand All @@ -27,7 +42,9 @@ ai_start() {
}
```

**Also update**: Same as editor adapters (README, completions, help text)
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`

## Contract & Guidelines

Expand All @@ -38,5 +55,4 @@ ai_start() {
- 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).
- Test manually: `bash -c 'source adapters/ai/<tool>.sh && ai_can_start && echo OK'`.
- Inspect function definition if needed: `declare -f ai_start`.
30 changes: 24 additions & 6 deletions .github/instructions/editor.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,28 @@
applyTo: adapters/editor/**/*.sh
---

# Editor Instructions
# Editor Adapter Instructions

## Adding Features
## When to Use a File vs Registry

### New Editor Adapter (`adapters/editor/<name>.sh`)
Most editors are defined as **registry entries** in `lib/adapters.sh` — no adapter file needed.
Only create an adapter file in `adapters/editor/` for editors that need **custom behavior** beyond what the standard/terminal builders provide (see `nano.sh` for an example).

## Adding a Standard Editor (Registry)

Add a line to `_EDITOR_REGISTRY` in `lib/adapters.sh`:

```
yourname|yourcmd|standard|EditorName not found. Install from https://...|flags
```

Format: `name|cmd|type|err_msg|flags`
- `type`: `standard` (GUI app) or `terminal` (runs in terminal)
- `flags`: comma-separated — `workspace` (supports .code-workspace), `background` (terminal bg)

## Adding a Custom Editor (File Override)

Create `adapters/editor/<name>.sh` implementing:

```bash
#!/usr/bin/env bash
Expand All @@ -26,20 +43,21 @@ editor_open() {
}
```

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 `bin/gtr` (`cmd_help` function)
- Help text in `lib/commands/help.sh` (`cmd_help` function)

## Contract & Guidelines

- Required functions: `editor_can_open` (probe via `command -v`), `editor_open <path>`.
- Quote all paths; support spaces. Avoid changing PWD globally—no subshell needed (editor opens path).
- Use `log_error` with actionable install guidance if command missing.
- Keep adapter lean: no project scans, no blocking prompts.
- Naming: file name = tool name (`zed.sh` → `zed` flag). Avoid uppercase.
- Naming: file/registry name = tool name (`zed` → `zed` flag). Avoid uppercase.
- Update: README editor list, completions (bash/zsh/fish), help (`Available editors:`), optional screenshots.
- Manual test: `bash -c 'source adapters/editor/<tool>.sh && editor_can_open && editor_open . || echo fail'`.
- Fallback behavior: if editor absent, fail clearly; do NOT silently defer to file browser.
- Inspect function definition if needed: `declare -f editor_open`.
2 changes: 1 addition & 1 deletion .github/instructions/lib.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ applyTo: lib/**/*.sh

## Change Guidelines

- Preserve adapter contracts; do not rename exported functions used by `bin/gtr`.
- Preserve adapter contracts; do not rename exported functions used by command handlers in `lib/commands/`.
- Add new config keys with `gtr.<name>` 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.
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
shellcheck:
name: ShellCheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install ShellCheck
run: sudo apt-get update && sudo apt-get install -y shellcheck

- name: Run ShellCheck
run: |
shellcheck bin/gtr bin/git-gtr lib/*.sh lib/commands/*.sh adapters/editor/*.sh adapters/ai/*.sh

test:
name: Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install BATS
run: sudo apt-get update && sudo apt-get install -y bats

- name: Run tests
run: bats tests/
67 changes: 47 additions & 20 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
- **Development/testing**: `./bin/gtr <command>` (direct execution)
- **User-facing docs**: Always reference `git gtr`, never `./bin/gtr`

## CRITICAL: No Automated Tests
## Testing

This project has **no test suite**. All testing is manual. After any change, run the relevant smoke tests:
This project uses **BATS tests** for core functions and **manual smoke tests** for end-to-end workflows. CI runs ShellCheck + BATS automatically on PRs (`.github/workflows/lint.yml`).

1. Run automated tests: `bats tests/`
2. Run a single test file: `bats tests/config.bats`
3. Run a single test by name: `bats tests/config.bats --filter "cfg_map_to_file_key"`
4. Run relevant manual smoke tests:

```bash
./bin/gtr new test-feature # Create worktree
Expand All @@ -25,7 +30,9 @@ This project has **no test suite**. All testing is manual. After any change, run
./bin/gtr rm test-feature # Clean up
```

For exhaustive testing (hooks, copy patterns, adapters, `--force`, `--from-current`, etc.), see the full checklist in CONTRIBUTING.md or `.github/instructions/testing.instructions.md`.
For exhaustive manual testing (hooks, copy patterns, adapters, `--force`, `--from-current`, etc.), see the full checklist in CONTRIBUTING.md or `.github/instructions/testing.instructions.md`.

**Test files**: `adapters`, `config`, `copy_safety`, `integration_lifecycle`, `parse_args`, `provider`, `resolve_base_dir`, `sanitize_branch_name` (all in `tests/`). Shared fixtures in `tests/test_helper.bash`.

**Tip**: Use a disposable repo for testing to avoid polluting your working tree:

Expand All @@ -39,28 +46,35 @@ mkdir -p /tmp/gtr-test && cd /tmp/gtr-test && git init && git commit --allow-emp
### Binary Structure

- `bin/git-gtr` — Thin wrapper enabling `git gtr` subcommand invocation
- `bin/gtr` — Main script (~1960 lines), contains `main()` dispatcher + all `cmd_*` handlers
- `bin/gtr` — Entry point: sources libraries and commands, contains `main()` dispatcher

### Module Structure

| File | Purpose |
| ----------------- | ----------------------------------------------------------------------------------------------------------- |
| `lib/core.sh` | Worktree CRUD: `create_worktree`, `remove_worktree`, `list_worktrees`, `resolve_target`, `resolve_base_dir` |
| `lib/config.sh` | Git config wrapper with precedence: `cfg_get`, `cfg_default`, `cfg_get_all` |
| `lib/copy.sh` | File/directory copying with glob patterns: `copy_patterns`, `copy_directories` |
| `lib/hooks.sh` | Hook execution: `run_hooks_in` for postCreate/preRemove/postRemove |
| `lib/ui.sh` | Logging (`log_error`, `log_info`, `log_warn`), prompts, formatting |
| `lib/platform.sh` | OS detection, GUI helpers |
| File | Purpose |
| ------------------- | ----------------------------------------------------------------------------------------------------------- |
| `lib/ui.sh` | Logging (`log_error`, `log_info`, `log_warn`), prompts, formatting |
| `lib/args.sh` | Shared argument parser: flag specs (`--flag`, `--flag: val`, aliases), populates `_arg_*` vars |
| `lib/config.sh` | Git config wrapper with precedence: `cfg_get`, `cfg_default`, `cfg_get_all` |
| `lib/platform.sh` | OS detection, GUI helpers |
| `lib/core.sh` | Worktree CRUD: `create_worktree`, `remove_worktree`, `list_worktrees`, `resolve_target`, `resolve_base_dir` |
| `lib/copy.sh` | File/directory copying with glob patterns: `copy_patterns`, `copy_directories` |
| `lib/hooks.sh` | Hook execution: `run_hooks_in` for postCreate/preRemove/postRemove |
| `lib/provider.sh` | Remote hosting detection (GitHub/GitLab) and CLI integration for `clean --merged` |
| `lib/adapters.sh` | Adapter registry, builder functions, generic fallbacks, loader functions |
| `lib/launch.sh` | Editor/AI launch orchestration: `_open_editor`, `_auto_launch_editor`, `_auto_launch_ai` |
| `lib/commands/*.sh` | One file per subcommand: `cmd_create`, `cmd_remove`, etc. (16 files) |

Libraries are sourced in the order listed above (ui → args → config → ... → launch → commands/\*.sh glob).

### Adapters

Editor adapters in `adapters/editor/` and AI adapters in `adapters/ai/` are dynamically sourced via `load_editor_adapter()` and `load_ai_adapter()` in `bin/gtr`.
Most adapters are defined declaratively in the **adapter registry** (`lib/adapters.sh`) using pipe-delimited entries. Custom adapters that need special logic remain as override files in `adapters/editor/` and `adapters/ai/`.

**Editor adapters** (atom, cursor, emacs, idea, nano, nvim, pycharm, sublime, vim, vscode, webstorm, zed): implement `editor_can_open()` + `editor_open(path)`.
**Registry-defined adapters**: atom, cursor, emacs, idea, nvim, pycharm, sublime, vim, vscode, webstorm, zed (editors) and aider, auggie, codex, continue, copilot, gemini, opencode (AI).

**AI adapters** (aider, auggie, claude, codex, continue, copilot, cursor, gemini, opencode): implement `ai_can_start()` + `ai_start(path, args...)`.
**Custom adapter files**: `adapters/editor/nano.sh`, `adapters/ai/claude.sh`, `adapters/ai/cursor.sh` — these implement `editor_can_open()`/`editor_open()` or `ai_can_start()`/`ai_start()` directly.

**Generic fallback**: `GTR_EDITOR_CMD` / `GTR_AI_CMD` env vars allow custom tools without adapter files.
**Loading order**: file override → registry → generic PATH fallback. `GTR_EDITOR_CMD` / `GTR_AI_CMD` env vars allow custom tools without adapters.

### Command Flow

Expand Down Expand Up @@ -106,15 +120,17 @@ cmd_editor() → resolve_target() → load_editor_adapter() → editor_open()

### Adding a New Command

1. Add `cmd_<name>()` function in `bin/gtr`
2. Add case entry in `main()` dispatcher (around line 71)
3. Add help text in `cmd_help()`
1. Create `lib/commands/<name>.sh` with `cmd_<name>()` function
2. Add case entry in `main()` dispatcher in `bin/gtr`
3. Add help text in `lib/commands/help.sh`
4. Update all three completion files: `completions/gtr.bash`, `completions/_git-gtr`, `completions/git-gtr.fish`
5. Update README.md

### Adding an Adapter

Create `adapters/{editor,ai}/<name>.sh` implementing the two required functions (see existing adapters for patterns). Then update: help text in `cmd_help()` and `load_*_adapter()`, all three completions, README.md.
**Standard adapters** (just a command name + error message): Add an entry to `_EDITOR_REGISTRY` or `_AI_REGISTRY` in `lib/adapters.sh`. Then update: help text in `lib/commands/help.sh`, all three completions, README.md.

**Custom adapters** (special logic needed): Create `adapters/{editor,ai}/<name>.sh` implementing the two required functions (see `adapters/ai/claude.sh` for an example). File-based adapters take priority over registry entries.

### Updating the Version

Expand All @@ -128,6 +144,17 @@ When adding commands or flags, update all three files:
- `completions/_git-gtr` (Zsh)
- `completions/git-gtr.fish` (Fish)

## Critical Gotcha: `set -e`

`bin/gtr` runs with `set -e`. Any unguarded non-zero return silently exits the entire script. When calling functions that may `return 1`, guard with `|| true`:

```bash
result=$(my_func) || true # Prevents silent exit
if my_func; then ...; fi # Also safe (if guards the return)
```

This is the most common source of subtle bugs in this codebase.

## Code Style

- Shebang: `#!/usr/bin/env bash`
Expand Down
Loading