gitdirector 1.6.0__tar.gz → 1.7.2__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.
Files changed (59) hide show
  1. {gitdirector-1.6.0 → gitdirector-1.7.2}/PKG-INFO +27 -6
  2. {gitdirector-1.6.0 → gitdirector-1.7.2}/README.md +26 -5
  3. {gitdirector-1.6.0 → gitdirector-1.7.2}/pyproject.toml +1 -1
  4. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/cli.py +2 -0
  5. gitdirector-1.7.2/src/gitdirector/commands/completion.py +74 -0
  6. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/gd_tmux.py +9 -1
  7. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/help.py +4 -2
  8. gitdirector-1.7.2/src/gitdirector/commands/reset.py +82 -0
  9. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/app.py +128 -26
  10. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/app_sessions.py +1 -0
  11. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/app_ui.py +2 -0
  12. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/panel_view.py +15 -0
  13. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/panels.py +20 -0
  14. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/commit.py +38 -13
  15. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/diff.py +1 -0
  16. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/panels.py +33 -8
  17. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/repos.py +7 -7
  18. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/terminal_caps.py +4 -0
  19. gitdirector-1.7.2/src/gitdirector/commands/tui/terminal_widget.py +901 -0
  20. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/config.py +85 -48
  21. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/integrations/tmux/core.py +194 -14
  22. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/integrations/tmux/monitor.py +77 -13
  23. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/integrations/tmux/panels.py +286 -102
  24. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/repo.py +4 -0
  25. gitdirector-1.6.0/src/gitdirector/commands/completion.py +0 -41
  26. gitdirector-1.6.0/src/gitdirector/commands/tui/terminal_widget.py +0 -482
  27. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/__init__.py +0 -0
  28. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/__init__.py +0 -0
  29. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/autoclean.py +0 -0
  30. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/capture.py +0 -0
  31. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/cd.py +0 -0
  32. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/gd_send.py +0 -0
  33. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/info.py +0 -0
  34. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/link.py +0 -0
  35. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/listt.py +0 -0
  36. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/pull.py +0 -0
  37. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/status.py +0 -0
  38. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/__init__.py +0 -0
  39. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/app_groups.py +0 -0
  40. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/app_panels.py +0 -0
  41. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/app_repos.py +0 -0
  42. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/constants.py +0 -0
  43. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/diff_renderer.py +0 -0
  44. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/__init__.py +0 -0
  45. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/_shared.py +0 -0
  46. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/diff_files.py +0 -0
  47. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/groups.py +0 -0
  48. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/session_actions.py +0 -0
  49. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/screens/sessions.py +0 -0
  50. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/tui/table_text.py +0 -0
  51. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/commands/unlink.py +0 -0
  52. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/github_credential_helper.py +0 -0
  53. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/info.py +0 -0
  54. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/integrations/__init__.py +0 -0
  55. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/integrations/tmux/__init__.py +0 -0
  56. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/manager.py +0 -0
  57. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/storage.py +0 -0
  58. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/ui_theme.py +0 -0
  59. {gitdirector-1.6.0 → gitdirector-1.7.2}/src/gitdirector/version_check.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: gitdirector
3
- Version: 1.6.0
3
+ Version: 1.7.2
4
4
  Summary: A terminal based control plane for developers working across multiple repositories. Launch multiple AI coding agents, multiple tmux sessions and track changes across all your repos in one place.
5
5
  Keywords: git,repository,manager,cli,synchronization,batch
6
6
  Author: Anito Anto
@@ -74,6 +74,7 @@ If you find GitDirector useful, please star this repository on GitHub, we need m
74
74
  | `gitdirector pull [--yes]` | Pull latest changes for all tracked repositories |
75
75
  | `gitdirector cd NAME` | Open or switch to a tmux session for a repository |
76
76
  | `gitdirector autoclean` | Remove broken repository links from tracking |
77
+ | `gitdirector reset [--yes]` | Kill all sessions and panels, wipe ~/.gitdirector, and recreate the config |
77
78
  | `gitdirector info PATH\|NAME [--full]` | Show file statistics for a repository |
78
79
  | `gitdirector gd-tmux PATH\|NAME "command" [--description TEXT]` | Create a gd tmux session and run a command in it |
79
80
  | `gitdirector gd-capture SESSION [--lines N] [--full]` | Print the scrollback of a live gd tmux session |
@@ -104,17 +105,17 @@ Features:
104
105
  - `/` to filter the active tab
105
106
  - `s` to sort the active table
106
107
  - `i` to show repository info (file count, lines, tokens, max depth, top file types)
107
- - `g` on the Repositories tab to open Git operations: status, timeline, branches, remotes, pull, and push
108
+ - `g` on the Repositories tab to open Git operations: status, timeline, branches, remotes, pull, push, and a **Diff Viewer** section with **Review Diff** for uncommitted changes
108
109
  - `r` to refresh all statuses
109
110
  - Press `enter` on any repository to open an action menu:
110
111
  - **New tmux session** — create and attach a session for the repository
111
- - **Review Diff** — open a two-pane viewer for uncommitted changes (left: file list with GitHub-style status pills and +/- counts; right: per-file unified diff with GitHub-dark syntax highlighting, line numbers, and green/red backgrounds for added/removed lines). Navigate files with `j`/`k`, `n`/`p`, `g`/`G`, or `]`/`[`. Switch the focused panel with `tab`. `r` refreshes, `esc` closes.
112
112
  - **Attach existing session** — switch to any already-running tmux session
113
113
  - **Launch AI agent** — open OpenCode, Claude Code, GitHub Copilot, Codex, or Pi in a new tmux session
114
114
  - **Remove session** — kill a running tmux session
115
+ - **Review Diff** (from the `g` Git menu) — open a two-pane viewer for uncommitted changes (left: file list with GitHub-style status pills and +/- counts; right: per-file unified diff with GitHub-dark syntax highlighting, line numbers, and green/red backgrounds for added/removed lines). Navigate files with `j`/`k`, `n`/`p`, `g`/`G`, or `]`/`[`. Switch the focused panel with `tab`. `r` refreshes, `esc` closes.
115
116
  - **Repository groups** appear directly in the Repositories tab when linked repositories share the same parent directory. Group rows can be expanded/collapsed with `space`; press `enter` on a group to start, attach, remove, or launch AI-agent sessions rooted at that parent directory.
116
117
  - **Sessions tab** (press `2`) lists every active `gd/*` tmux session with its status, purpose, repository, **description**, and full session name. The description column is free-form text stored on the session (default `"-"`), with a width that scales to your terminal and wraps long text. Highlight a row and press `d` to edit its description.
117
- - **Panels tab** (press `3`) manages reusable tmux panel layouts. Press `n` to create a panel, or `enter` on a panel to open, reconfigure, rename, or delete it.
118
+ - **Panels tab** (press `3`) manages reusable tmux panel layouts. Press `n` to create a panel, or `enter` on a panel to open, reconfigure, rename, or delete it. Inside a panel you can **drag with the mouse to select text and copy it to the OS clipboard** on release; pressing `y` copies the entire visible pane as a fallback. GitDirector prefers native clipboard tools such as `pbcopy`, `wl-copy`, `xclip`, `xsel`, or `clip.exe`, and falls back to OSC 52 when needed.
118
119
 
119
120
  ### unlink
120
121
 
@@ -223,6 +224,15 @@ gitdirector autoclean
223
224
 
224
225
  Scans the tracked repositories in `~/.gitdirector/config.yaml` for paths that no longer exist on disk and removes them from the config. Lists any broken links for review and asks for confirmation before deleting them.
225
226
 
227
+ ### reset
228
+
229
+ ```bash
230
+ gitdirector reset # asks for confirmation
231
+ gitdirector reset --yes # skip the confirmation prompt
232
+ ```
233
+
234
+ Destructive cleanup. Kills every `gd/*` tmux session (regular sessions and panels), wipes the entire `~/.gitdirector/` directory, and recreates an empty `config.yaml` with defaults. Useful when the local state is corrupted or you want to start fresh — all linked repositories, panel layouts, version-check cache, and tmux theme files are removed in one step.
235
+
226
236
  ### gd-capture
227
237
 
228
238
  ```bash
@@ -263,7 +273,7 @@ If you are an AI coding agent (Claude Code, OpenCode, GitHub Copilot, Codex, Pi,
263
273
 
264
274
  ## Configuration
265
275
 
266
- Config is stored at `~/.gitdirector/config.yaml`.
276
+ Main config is stored at `~/.gitdirector/config.yaml`:
267
277
 
268
278
  ```yaml
269
279
  repositories:
@@ -271,6 +281,11 @@ repositories:
271
281
  - /path/to/repo2
272
282
  max_workers: 10 # optional, valid range 1-32, default 10
273
283
  theme: rose-pine # optional, default rose-pine
284
+ ```
285
+
286
+ Secrets (GitHub credentials) are stored in a separate file at `~/.gitdirector/secrets.yaml`:
287
+
288
+ ```yaml
274
289
  github_username: your-github-username # optional
275
290
  github_PAT: github_pat_or_classic_pat # optional
276
291
  ```
@@ -281,7 +296,7 @@ GitDirector first runs git commands using your normal local git credentials. If
281
296
 
282
297
  - This only applies to HTTPS GitHub remotes.
283
298
  - SSH remotes still use your normal SSH key/agent setup.
284
- - The PAT is stored in plaintext in `~/.gitdirector/config.yaml`; use an appropriately scoped token and protect that file.
299
+ - The PAT is stored in plaintext in `~/.gitdirector/secrets.yaml`; use an appropriately scoped token and protect that file.
285
300
  - The PAT is not passed on the command line or shown in TUI command output.
286
301
 
287
302
  ### Available Themes
@@ -304,6 +319,12 @@ eval "$(gitdirector completion zsh)"
304
319
  gitdirector completion fish | source
305
320
  ```
306
321
 
322
+ The `zsh` script auto-loads `compinit` if `compdef` is not yet available, so the `eval` form works in fresh shells. For the fastest setup (no subprocess on every `TAB`), write the script to a file in your `$fpath` (commonly `~/.zsh/completions/_gitdirector`) and let `compinit` autoload it:
323
+
324
+ ```bash
325
+ gitdirector completion zsh > "${fpath[1]}/_gitdirector"
326
+ ```
327
+
307
328
  ## License
308
329
 
309
330
  MIT
@@ -32,6 +32,7 @@ If you find GitDirector useful, please star this repository on GitHub, we need m
32
32
  | `gitdirector pull [--yes]` | Pull latest changes for all tracked repositories |
33
33
  | `gitdirector cd NAME` | Open or switch to a tmux session for a repository |
34
34
  | `gitdirector autoclean` | Remove broken repository links from tracking |
35
+ | `gitdirector reset [--yes]` | Kill all sessions and panels, wipe ~/.gitdirector, and recreate the config |
35
36
  | `gitdirector info PATH\|NAME [--full]` | Show file statistics for a repository |
36
37
  | `gitdirector gd-tmux PATH\|NAME "command" [--description TEXT]` | Create a gd tmux session and run a command in it |
37
38
  | `gitdirector gd-capture SESSION [--lines N] [--full]` | Print the scrollback of a live gd tmux session |
@@ -62,17 +63,17 @@ Features:
62
63
  - `/` to filter the active tab
63
64
  - `s` to sort the active table
64
65
  - `i` to show repository info (file count, lines, tokens, max depth, top file types)
65
- - `g` on the Repositories tab to open Git operations: status, timeline, branches, remotes, pull, and push
66
+ - `g` on the Repositories tab to open Git operations: status, timeline, branches, remotes, pull, push, and a **Diff Viewer** section with **Review Diff** for uncommitted changes
66
67
  - `r` to refresh all statuses
67
68
  - Press `enter` on any repository to open an action menu:
68
69
  - **New tmux session** — create and attach a session for the repository
69
- - **Review Diff** — open a two-pane viewer for uncommitted changes (left: file list with GitHub-style status pills and +/- counts; right: per-file unified diff with GitHub-dark syntax highlighting, line numbers, and green/red backgrounds for added/removed lines). Navigate files with `j`/`k`, `n`/`p`, `g`/`G`, or `]`/`[`. Switch the focused panel with `tab`. `r` refreshes, `esc` closes.
70
70
  - **Attach existing session** — switch to any already-running tmux session
71
71
  - **Launch AI agent** — open OpenCode, Claude Code, GitHub Copilot, Codex, or Pi in a new tmux session
72
72
  - **Remove session** — kill a running tmux session
73
+ - **Review Diff** (from the `g` Git menu) — open a two-pane viewer for uncommitted changes (left: file list with GitHub-style status pills and +/- counts; right: per-file unified diff with GitHub-dark syntax highlighting, line numbers, and green/red backgrounds for added/removed lines). Navigate files with `j`/`k`, `n`/`p`, `g`/`G`, or `]`/`[`. Switch the focused panel with `tab`. `r` refreshes, `esc` closes.
73
74
  - **Repository groups** appear directly in the Repositories tab when linked repositories share the same parent directory. Group rows can be expanded/collapsed with `space`; press `enter` on a group to start, attach, remove, or launch AI-agent sessions rooted at that parent directory.
74
75
  - **Sessions tab** (press `2`) lists every active `gd/*` tmux session with its status, purpose, repository, **description**, and full session name. The description column is free-form text stored on the session (default `"-"`), with a width that scales to your terminal and wraps long text. Highlight a row and press `d` to edit its description.
75
- - **Panels tab** (press `3`) manages reusable tmux panel layouts. Press `n` to create a panel, or `enter` on a panel to open, reconfigure, rename, or delete it.
76
+ - **Panels tab** (press `3`) manages reusable tmux panel layouts. Press `n` to create a panel, or `enter` on a panel to open, reconfigure, rename, or delete it. Inside a panel you can **drag with the mouse to select text and copy it to the OS clipboard** on release; pressing `y` copies the entire visible pane as a fallback. GitDirector prefers native clipboard tools such as `pbcopy`, `wl-copy`, `xclip`, `xsel`, or `clip.exe`, and falls back to OSC 52 when needed.
76
77
 
77
78
  ### unlink
78
79
 
@@ -181,6 +182,15 @@ gitdirector autoclean
181
182
 
182
183
  Scans the tracked repositories in `~/.gitdirector/config.yaml` for paths that no longer exist on disk and removes them from the config. Lists any broken links for review and asks for confirmation before deleting them.
183
184
 
185
+ ### reset
186
+
187
+ ```bash
188
+ gitdirector reset # asks for confirmation
189
+ gitdirector reset --yes # skip the confirmation prompt
190
+ ```
191
+
192
+ Destructive cleanup. Kills every `gd/*` tmux session (regular sessions and panels), wipes the entire `~/.gitdirector/` directory, and recreates an empty `config.yaml` with defaults. Useful when the local state is corrupted or you want to start fresh — all linked repositories, panel layouts, version-check cache, and tmux theme files are removed in one step.
193
+
184
194
  ### gd-capture
185
195
 
186
196
  ```bash
@@ -221,7 +231,7 @@ If you are an AI coding agent (Claude Code, OpenCode, GitHub Copilot, Codex, Pi,
221
231
 
222
232
  ## Configuration
223
233
 
224
- Config is stored at `~/.gitdirector/config.yaml`.
234
+ Main config is stored at `~/.gitdirector/config.yaml`:
225
235
 
226
236
  ```yaml
227
237
  repositories:
@@ -229,6 +239,11 @@ repositories:
229
239
  - /path/to/repo2
230
240
  max_workers: 10 # optional, valid range 1-32, default 10
231
241
  theme: rose-pine # optional, default rose-pine
242
+ ```
243
+
244
+ Secrets (GitHub credentials) are stored in a separate file at `~/.gitdirector/secrets.yaml`:
245
+
246
+ ```yaml
232
247
  github_username: your-github-username # optional
233
248
  github_PAT: github_pat_or_classic_pat # optional
234
249
  ```
@@ -239,7 +254,7 @@ GitDirector first runs git commands using your normal local git credentials. If
239
254
 
240
255
  - This only applies to HTTPS GitHub remotes.
241
256
  - SSH remotes still use your normal SSH key/agent setup.
242
- - The PAT is stored in plaintext in `~/.gitdirector/config.yaml`; use an appropriately scoped token and protect that file.
257
+ - The PAT is stored in plaintext in `~/.gitdirector/secrets.yaml`; use an appropriately scoped token and protect that file.
243
258
  - The PAT is not passed on the command line or shown in TUI command output.
244
259
 
245
260
  ### Available Themes
@@ -262,6 +277,12 @@ eval "$(gitdirector completion zsh)"
262
277
  gitdirector completion fish | source
263
278
  ```
264
279
 
280
+ The `zsh` script auto-loads `compinit` if `compdef` is not yet available, so the `eval` form works in fresh shells. For the fastest setup (no subprocess on every `TAB`), write the script to a file in your `$fpath` (commonly `~/.zsh/completions/_gitdirector`) and let `compinit` autoload it:
281
+
282
+ ```bash
283
+ gitdirector completion zsh > "${fpath[1]}/_gitdirector"
284
+ ```
285
+
265
286
  ## License
266
287
 
267
288
  MIT
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "gitdirector"
7
- version = "1.6.0"
7
+ version = "1.7.2"
8
8
  description = "A terminal based control plane for developers working across multiple repositories. Launch multiple AI coding agents, multiple tmux sessions and track changes across all your repos in one place."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -20,6 +20,7 @@ from .commands import (
20
20
  listt,
21
21
  print_update_notice,
22
22
  pull,
23
+ reset,
23
24
  status,
24
25
  tui,
25
26
  unlink,
@@ -59,6 +60,7 @@ cd.register(cli)
59
60
  help.register(cli)
60
61
  tui.register(cli)
61
62
  autoclean.register(cli)
63
+ reset.register(cli)
62
64
  info.register(cli)
63
65
  gd_tmux.register(cli)
64
66
  capture.register(cli)
@@ -0,0 +1,74 @@
1
+ import click
2
+ from click.shell_completion import CompletionItem, get_completion_class
3
+
4
+ from ..config import Config
5
+
6
+ SUPPORTED_SHELLS = ("bash", "zsh", "fish")
7
+
8
+
9
+ def _completion_var(prog_name: str) -> str:
10
+ return f"_{prog_name.replace('-', '_').replace('.', '_').upper()}_COMPLETE"
11
+
12
+
13
+ _ZSH_COMPINIT_BOOTSTRAP = (
14
+ "\n"
15
+ "# Ensure ``compdef`` is available when this script is ``eval``'d in a\n"
16
+ "# shell that has not yet loaded ``compinit``. Without this guard the\n"
17
+ "# ``compdef`` call below fails with ``command not found: compdef``.\n"
18
+ "if ! typeset -f compdef >/dev/null 2>&1; then\n"
19
+ " autoload -U +X compinit\n"
20
+ " compinit\n"
21
+ "fi\n"
22
+ )
23
+
24
+
25
+ def _patch_zsh_source(source: str) -> str:
26
+ """Inject a compinit bootstrap so ``eval`` works without prior setup.
27
+
28
+ Click's zsh output ends with ``compdef ...`` which requires the
29
+ ``compdef`` builtin provided by ``compinit``. When the script is
30
+ eval'd in a fresh zsh that hasn't loaded ``compinit`` yet, that
31
+ final call fails. Inserting a bootstrap right after the
32
+ ``#compdef`` directive ensures ``compdef`` is available without
33
+ changing behavior when the script is dropped into ``$fpath`` and
34
+ autoloaded by ``compinit`` (in which case ``compdef`` already
35
+ exists and the bootstrap is a no-op).
36
+ """
37
+ marker = "\n_gitdirector_completion() {"
38
+ if marker not in source:
39
+ return source
40
+ return source.replace(marker, _ZSH_COMPINIT_BOOTSTRAP + "\n_gitdirector_completion() {", 1)
41
+
42
+
43
+ def completion_source(cli: click.Group, shell: str, *, prog_name: str = "gitdirector") -> str:
44
+ complete_cls = get_completion_class(shell)
45
+ if complete_cls is None:
46
+ raise click.ClickException(f"Unsupported shell: {shell}")
47
+ source = complete_cls(cli, {}, prog_name, _completion_var(prog_name)).source()
48
+ if shell == "zsh":
49
+ source = _patch_zsh_source(source)
50
+ return source
51
+
52
+
53
+ def complete_repository_names(
54
+ _ctx: click.Context, _param: click.Parameter, incomplete: str
55
+ ) -> list[CompletionItem]:
56
+ try:
57
+ repositories = Config().repositories
58
+ except (OSError, RuntimeError, ValueError):
59
+ return []
60
+
61
+ prefix = incomplete.lower()
62
+ return [
63
+ CompletionItem(repo.name, help=str(repo))
64
+ for repo in sorted(repositories, key=lambda path: (path.name.lower(), str(path)))
65
+ if repo.name.lower().startswith(prefix)
66
+ ]
67
+
68
+
69
+ def register(cli: click.Group):
70
+ @cli.command()
71
+ @click.argument("shell", type=click.Choice(SUPPORTED_SHELLS))
72
+ def completion(shell: str):
73
+ """Print shell completion setup for bash, zsh, or fish."""
74
+ click.echo(completion_source(cli, shell), nl=False)
@@ -73,6 +73,7 @@ def register(cli: click.Group):
73
73
  from ..integrations.tmux import (
74
74
  TmuxError,
75
75
  create_tmux_session,
76
+ kill_tmux_session,
76
77
  launch_command_in_tmux_session,
77
78
  )
78
79
  except ImportError:
@@ -82,6 +83,7 @@ def register(cli: click.Group):
82
83
  )
83
84
  raise SystemExit(1)
84
85
 
86
+ session_name: str | None = None
85
87
  try:
86
88
  session_name = create_tmux_session(
87
89
  repo_path.name, repo_path, purpose="shell", description=description
@@ -89,5 +91,11 @@ def register(cli: click.Group):
89
91
  click.echo(session_name)
90
92
  launch_command_in_tmux_session(session_name, command)
91
93
  except TmuxError as exc:
94
+ if session_name is not None:
95
+ kill_tmux_session(session_name)
92
96
  console.print(f"\n [red]tmux command failed:[/red] {exc}\n")
93
- raise SystemExit(1)
97
+ raise SystemExit(1) from exc
98
+ except BaseException:
99
+ if session_name is not None:
100
+ kill_tmux_session(session_name)
101
+ raise
@@ -1,5 +1,6 @@
1
1
  import click
2
2
  from rich.table import Table
3
+ from rich.text import Text
3
4
 
4
5
  from . import console, get_version, print_update_notice
5
6
 
@@ -33,6 +34,7 @@ def show_help():
33
34
  ("cd NAME", "Open or switch to a tmux session for a repository"),
34
35
  ("console", "Interactive TUI for browsing and opening repositories"),
35
36
  ("autoclean", "Remove broken repository links from tracking"),
37
+ ("reset [--yes]", "Kill all sessions and panels, wipe ~/.gitdirector, recreate config"),
36
38
  ("info PATH|NAME [--full]", "Show file statistics for a repository"),
37
39
  (
38
40
  'gd-tmux PATH|NAME "cmd" [--description "..."]',
@@ -42,11 +44,11 @@ def show_help():
42
44
  "gd-capture SESSION [--lines N] [--full]",
43
45
  "Print the current scrollback of a live gd tmux session",
44
46
  ),
45
- ("gd-send SESSION [TEXT] [--enter|--key C-c]", "Send text or C-c to a gd session"),
47
+ ("gd-send SESSION [TEXT] [--enter | --key C-c]", "Send text or C-c to a gd session"),
46
48
  ("completion SHELL", "Print shell completion setup for bash, zsh, or fish"),
47
49
  ("help", "Show this help message"),
48
50
  ]:
49
- cmd_table.add_row(cmd, desc)
51
+ cmd_table.add_row(Text(cmd), desc)
50
52
 
51
53
  console.print(cmd_table)
52
54
 
@@ -0,0 +1,82 @@
1
+ import shutil
2
+ from pathlib import Path
3
+
4
+ import click
5
+
6
+ from ..config import Config
7
+ from . import console
8
+
9
+
10
+ def register(cli: click.Group):
11
+ @cli.command()
12
+ @click.option(
13
+ "--yes",
14
+ "-y",
15
+ is_flag=True,
16
+ help="Skip the confirmation prompt and reset immediately.",
17
+ )
18
+ def reset(yes: bool):
19
+ """Kill all sessions and panels, wipe ~/.gitdirector, and recreate config."""
20
+ _reset(confirm=not yes)
21
+
22
+
23
+ def _reset(*, confirm: bool = True) -> None:
24
+ config_dir = Path.home() / ".gitdirector"
25
+
26
+ if confirm and not click.confirm(
27
+ f" This will kill every gd tmux session and permanently delete {config_dir}. Continue?",
28
+ default=False,
29
+ ):
30
+ console.print()
31
+ console.print(" [dim]Cancelled.[/dim]")
32
+ console.print()
33
+ return
34
+
35
+ console.print()
36
+
37
+ killed = _kill_all_sessions()
38
+ if killed:
39
+ console.print(f" [green]Killed {len(killed)} session(s):[/green]")
40
+ for name in killed:
41
+ console.print(f" [dim]-[/dim] {name}")
42
+ else:
43
+ console.print(" [dim]No active gd tmux sessions to kill.[/dim]")
44
+
45
+ _wipe_config_dir(config_dir)
46
+
47
+ config = _recreate_config()
48
+
49
+ console.print()
50
+ console.print(f" [green]Wiped and recreated:[/green] {config.config_file}")
51
+ console.print()
52
+
53
+
54
+ def _kill_all_sessions() -> list[str]:
55
+ try:
56
+ from ..integrations.tmux import kill_all_gd_sessions
57
+ except ImportError:
58
+ console.print(" [yellow]tmux integration unavailable; skipping session kill.[/yellow]")
59
+ return []
60
+
61
+ try:
62
+ return kill_all_gd_sessions()
63
+ except Exception as exc:
64
+ console.print(f" [yellow]Failed to kill some sessions: {exc}[/yellow]")
65
+ return []
66
+
67
+
68
+ def _wipe_config_dir(config_dir: Path) -> None:
69
+ if not config_dir.exists():
70
+ console.print(f" [dim]No existing {config_dir} to remove.[/dim]")
71
+ return
72
+
73
+ try:
74
+ shutil.rmtree(config_dir)
75
+ except OSError as exc:
76
+ raise RuntimeError(f"Failed to remove {config_dir}: {exc}") from exc
77
+
78
+
79
+ def _recreate_config() -> Config:
80
+ config = Config()
81
+ config.clear()
82
+ return config