git-watchtower 1.10.0 → 1.10.1

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.
package/README.md CHANGED
@@ -4,13 +4,15 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/git-watchtower.svg)](https://www.npmjs.com/package/git-watchtower)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
6
 
7
- Monitor and switch between git branches in real-time. Built for working with web based AI coding agents, like Claude Code Web & Codex.
7
+ Monitor and switch between git branches in real-time. Built for working with web-based AI coding agents, like Claude Code Web & Codex.
8
8
 
9
- - **Live branch monitoring** - Watches your remote for new commits, branches, and deletions
10
- - **Instant notifications** - Visual and audio alerts when any branch is updated
11
- - **Quick switching** - Preview changes and jump to any branch with a keypress
12
- - **Auto-pull** - Automatically pulls when your current branch has remote changes
13
- - **Optional dev server** - Built-in static server with live reload, or run your own command (Next.js. Nuxt.js, Vite, etc)
9
+ - **Live branch monitoring** with activity sparklines and ahead/behind counters
10
+ - **Web dashboard** for browser-based branch management and PR workflows
11
+ - **Instant notifications** with visual and audio alerts when branches update
12
+ - **Quick switching** with preview pane, undo, and stash integration
13
+ - **Auto-pull** when your current branch has remote changes
14
+ - **Optional dev server** with live reload, or run your own command (Next.js, Vite, etc.)
15
+ - **Zero dependencies** — uses only Node.js built-in modules
14
16
 
15
17
  ![Git Watchtower Screenshot](assets/git-watchtower-screenshot.png)
16
18
 
@@ -22,27 +24,21 @@ Git Watchtower watches your remote and notifies you when branches are updated. P
22
24
 
23
25
  Also works for human collaborators, but the primary use case is keeping tabs on AI agents coding on different branches.
24
26
 
25
- Git Watchtower supports **three server modes** to fit your workflow:
26
- - **Static Site Mode** - Built-in server with live reload for HTML/CSS/JS
27
- - **Custom Server Command Mode** - Run your own dev server (Next.js, Vite, Nuxt, etc.)
28
- - **No Server Mode** - Branch monitoring only (ideal for watching multiple AI agents)
29
-
30
- ## Features
31
-
32
- - **Full Terminal UI** - Clean interface with box drawing and colors
33
- - **Activity Sparklines** - 7-day commit history visualization for each branch
34
- - **Branch Search** - Quickly filter branches by name with `/`
35
- - **Preview Pane** - See recent commits and changed files before switching
36
- - **Session History** - Undo branch switches with `u`
37
- - **Visual Alerts** - Flash notifications when updates arrive
38
- - **Audio Notifications** - Optional sound alerts (works on macOS, Linux, Windows)
39
- - **Auto-Pull** - Automatically pulls when your current branch has updates (configurable)
40
- - **Merge Conflict Detection** - Warns you when auto-pull fails
41
- - **Flexible Server Modes** - Static site, custom server command, or no server
42
- - **Server Log View** - Press `l` to view your dev server output (custom server command mode)
43
- - **Server Restart** - Press `R` to restart your dev server (custom server command mode)
44
- - **Configurable Remote** - Works with any git remote name (not just `origin`)
45
- - **Zero Dependencies** - Uses only Node.js built-in modules
27
+ ## Web Dashboard
28
+
29
+ Launch a browser-based dashboard alongside the terminal UI with `--web`:
30
+
31
+ ```bash
32
+ git-watchtower --web
33
+ ```
34
+
35
+ ![Web Dashboard](assets/git-watchtower-web-ui.png)
36
+
37
+ The web dashboard provides real-time branch monitoring, PR workflows, CI status, session statistics, and more all in a rich browser interface. When running multiple instances across different projects, they coordinate automatically into a single multi-project dashboard.
38
+
39
+ Press `W` in the TUI to toggle the web dashboard on or off at any time.
40
+
41
+ [Full web dashboard documentation →](docs/web-dashboard.md)
46
42
 
47
43
  ## Installation
48
44
 
@@ -75,186 +71,64 @@ git-watchtower
75
71
  # Run without dev server (branch monitoring only)
76
72
  git-watchtower --no-server
77
73
 
78
- # Specify a custom port for the dev server
79
- git-watchtower --port 8080
74
+ # Launch with web dashboard
75
+ git-watchtower --web
76
+
77
+ # Specify custom ports
78
+ git-watchtower --port 8080 --web --web-port 9000
80
79
 
81
80
  # Re-run the configuration wizard
82
81
  git-watchtower --init
83
82
 
84
- # Show version
85
- git-watchtower --version
86
-
87
83
  # Show help
88
84
  git-watchtower --help
89
85
  ```
90
86
 
91
- ## Server Modes
92
-
93
- ### Static Site Mode (Default)
94
- Serves static files with automatic live reload. Good for static HTML/CSS/JS sites, projects without a build step, quick prototyping.
95
-
96
- #### Live Reload
97
-
98
- The static server includes automatic live reload powered by Server-Sent Events (SSE). When you save a file, all connected browsers refresh instantly.
99
-
100
- **How it works:**
101
- 1. A small script is automatically injected into HTML pages
102
- 2. The script opens an SSE connection to `/livereload`
103
- 3. When files change in your static directory, the server notifies all browsers
104
- 4. Browsers automatically reload to show your changes
105
-
106
- **File watching behavior:**
107
- - Uses Node.js native `fs.watch()` with recursive watching
108
- - Changes are debounced (100ms) to prevent rapid reloads during saves
109
- - Press `r` to manually trigger a reload for all connected browsers
110
-
111
- **Ignored files:**
87
+ [Full CLI reference →](docs/configuration.md#cli-flags)
112
88
 
113
- The file watcher automatically ignores certain files to prevent unnecessary reloads:
114
-
115
- | Ignored | Reason |
116
- |---------|--------|
117
- | `.git/` directory | Git internals change frequently during commits, fetches, etc. |
118
- | `.gitignore` patterns | Respects your project's ignore rules |
119
-
120
- If a `.gitignore` file exists in your static directory (or project root), those patterns are used to filter file change events. This means changes to `node_modules/`, build artifacts, log files, and other ignored paths won't trigger reloads.
89
+ ## Server Modes
121
90
 
122
- **Supported `.gitignore` patterns:**
123
- - Simple filenames: `foo.txt`
124
- - Wildcards: `*.log`, `file?.txt`
125
- - Globstar: `**/logs`, `logs/**/*.log`
126
- - Directory patterns: `node_modules/`, `dist/`
127
- - Anchored patterns: `/build` (root only)
128
- - Comments and blank lines are ignored
91
+ Git Watchtower supports three server modes:
129
92
 
130
- ### Custom Server Command Mode
131
- Runs your own dev server command (`next dev`, `npm run dev`, `vite`, etc.). Press `l` to view server logs, `R` to restart the server.
93
+ | Mode | Flag | Description |
94
+ |------|------|-------------|
95
+ | **Static Site** | `--mode static` | Built-in server with live reload for HTML/CSS/JS (default) |
96
+ | **Custom Command** | `--mode command -c "npm run dev"` | Run your own dev server (Next.js, Vite, Nuxt, etc.) |
97
+ | **No Server** | `--no-server` | Branch monitoring only |
132
98
 
133
- ### No Server Mode
134
- Branch monitoring only. Use this when watching AI agents push to multiple branches, or when you have your own dev server running separately.
99
+ [Full server modes documentation →](docs/server-modes.md)
135
100
 
136
101
  ## Configuration
137
102
 
138
- On first run, Git Watchtower prompts you to configure:
103
+ Settings are saved to `.watchtowerrc.json` in your project directory. Key settings:
139
104
 
140
105
  | Setting | Description | Default |
141
106
  |---------|-------------|---------|
142
107
  | Server mode | static, command, or none | static |
143
108
  | Port | Server port number | 3000 |
144
- | Static directory | Directory to serve (static site mode) | public |
145
- | Command | Dev server command (custom server command mode) | npm run dev |
146
- | Restart on switch | Restart server on branch switch | true |
109
+ | Web dashboard | Enable browser dashboard | false (use `--web`) |
147
110
  | Auto-pull | Auto-pull when current branch has updates | true |
148
111
  | Polling interval | How often to check for git updates | 5 seconds |
149
112
  | Sound notifications | Audio alerts for updates | true |
150
113
  | Visible branches | Number of branches shown in list | 7 |
151
114
 
152
- Settings are saved to `.watchtowerrc.json` in your project directory.
153
-
154
- ### Example Configuration
155
-
156
- ```json
157
- {
158
- "server": {
159
- "mode": "command",
160
- "command": "npm run dev",
161
- "port": 3000,
162
- "restartOnSwitch": true,
163
- "staticDir": "public"
164
- },
165
- "remoteName": "origin",
166
- "autoPull": true,
167
- "gitPollInterval": 5000,
168
- "soundEnabled": true,
169
- "visibleBranches": 7
170
- }
171
- ```
172
-
173
- ### Environment Variables
174
-
175
- You can also use environment variables:
176
-
177
- ```bash
178
- PORT=8080 git-watchtower
179
- GIT_POLL_INTERVAL=10000 git-watchtower
180
- ```
115
+ [Full configuration reference →](docs/configuration.md)
181
116
 
182
117
  ## Keyboard Controls
183
118
 
184
- ### Navigation
185
119
  | Key | Action |
186
120
  |-----|--------|
187
- | `↑` / `k` | Move selection up |
188
- | `↓` / `j` | Move selection down |
121
+ | `Up` / `k`, `Down` / `j` | Navigate branch list |
189
122
  | `Enter` | Switch to selected branch |
123
+ | `v` | Preview branch (commits & files) |
190
124
  | `/` | Search/filter branches |
191
- | `Esc` | Clear search / Close modal / Quit |
192
-
193
- ### Actions
194
- | Key | Action |
195
- |-----|--------|
196
- | `v` | Preview selected branch (commits & files) |
197
- | `h` | Show switch history |
125
+ | `b` | Branch actions (PR, CI, merge, approve) |
198
126
  | `u` | Undo last branch switch |
199
- | `p` | Force pull current branch |
200
- | `f` | Fetch all branches + refresh sparklines |
201
- | `b` | Branch actions modal (see below) |
202
-
203
- ### Branch Actions (`b`)
204
-
205
- Press `b` on any branch to open an interactive action modal. All actions are always visible — unavailable ones are grayed out with reasons (e.g., "Requires gh CLI", "Run: gh auth login").
206
-
207
- | Key | Action | Requires |
208
- |-----|--------|----------|
209
- | `b` | Open branch on GitHub/GitLab/Bitbucket/Azure DevOps | - |
210
- | `c` | Open Claude Code session in browser | Claude branch with session URL |
211
- | `p` | Create PR (or view existing PR) | `gh` or `glab` CLI |
212
- | `d` | View PR diff on GitHub/GitLab | Open PR |
213
- | `a` | Approve pull request | `gh` or `glab` CLI + open PR |
214
- | `m` | Merge pull request (squash + delete branch) | `gh` or `glab` CLI + open PR |
215
- | `i` | Check CI status | `gh` or `glab` CLI |
216
- | `Esc` | Close modal | - |
217
-
218
- The modal opens instantly and loads PR info in the background. Results are cached per branch and invalidated when the branch receives new commits. The modal auto-detects:
219
- - **Claude Code branches** (`claude/` prefix) and extracts session URLs from commit messages
220
- - **Git hosting platform** from the remote URL (GitHub, GitLab, Bitbucket, Azure DevOps)
221
- - **Existing PRs** and their review/CI status
222
- - **CLI tool availability** — shows install/auth hints when `gh` or `glab` isn't set up
223
-
224
- ### Server Controls
225
- | Key | Mode | Action |
226
- |-----|------|--------|
227
- | `r` | Static site | Force reload all browsers |
228
- | `l` | Custom server command | View server logs |
229
- | `R` | Custom server command | Restart dev server |
230
-
231
- ### Display
232
- | Key | Action |
233
- |-----|--------|
234
- | `s` | Toggle sound notifications |
235
- | `i` | Show server/status info |
236
- | `1-0` | Set visible branch count (1-10) |
237
- | `+` / `-` | Increase/decrease visible branches |
238
-
239
- ### Quit
240
- | Key | Action |
241
- |-----|--------|
127
+ | `S` | Stash changes |
128
+ | `W` | Toggle web dashboard |
242
129
  | `q` | Quit |
243
- | `Ctrl+C` | Quit |
244
-
245
- ## Status Indicators
246
-
247
- | Badge | Meaning |
248
- |-------|---------|
249
- | `★ CURRENT` | Currently checked-out branch |
250
- | `✦ NEW` | Branch created since Watchtower started |
251
- | `↓ UPDATES` | Remote has new commits to pull |
252
- | `✗ DELETED` | Branch was deleted from remote |
253
- | `NO-SERVER` | Running in branch-monitor-only mode |
254
- | `SERVER CRASHED` | Dev server process crashed (custom server command mode) |
255
- | `OFFLINE` | Network connectivity issues detected |
256
- | `DETACHED HEAD` | Not on a branch (commit checkout) |
257
- | `MERGE CONFLICT` | Auto-pull failed due to conflicts |
130
+
131
+ [Full keyboard reference →](docs/keyboard-controls.md)
258
132
 
259
133
  ## Requirements
260
134
 
@@ -265,127 +139,41 @@ The modal opens instantly and loads PR info in the background. Results are cache
265
139
 
266
140
  ## How It Works
267
141
 
268
- 1. **Polling**: Git Watchtower runs `git fetch` periodically to check for updates
269
- 2. **Detection**: Compares commit hashes to detect new commits, branches, and deletions
270
- 3. **Auto-pull**: When your current branch has remote updates, it pulls automatically (if enabled)
271
- 4. **Server**: Depending on mode, either serves static files, runs your command, or does nothing
272
- 5. **Live Reload**: In static site mode, notifies connected browsers via SSE when files change
142
+ 1. **Polling** Runs `git fetch` periodically to check for updates
143
+ 2. **Detection** Compares commit hashes to detect new commits, branches, and deletions
144
+ 3. **Auto-pull** When your current branch has remote updates, pulls automatically (if enabled)
145
+ 4. **Server** Depending on mode, serves static files, runs your command, or does nothing
146
+ 5. **Live Reload** In static site mode, notifies connected browsers via SSE when files change
147
+ 6. **Web Dashboard** — Optional browser UI that mirrors and extends the TUI via SSE
273
148
 
274
149
  ## Troubleshooting
275
150
 
276
- ### "Git is not installed or not in PATH"
277
- Git Watchtower requires Git. Install it from: https://git-scm.com/downloads
278
-
279
- ### "No Git remote configured"
280
- Git Watchtower requires a remote to watch. Add one with:
281
- ```bash
282
- git remote add origin <repository-url>
283
- ```
284
-
285
- ### Using a different remote name
286
- If your remote isn't called `origin`, update your config:
287
- ```json
288
- {
289
- "remoteName": "upstream"
290
- }
291
- ```
292
-
293
- ### Port already in use
294
- Try a different port:
295
- ```bash
296
- git-watchtower -p 3001
297
- ```
298
-
299
- ### Slow fetches / High latency
300
- Git Watchtower will automatically reduce polling frequency on slow networks. You can also increase the interval in your config.
301
-
302
- ### Sound not working
303
- - **macOS**: Uses system sounds via `afplay`
304
- - **Linux**: Requires PulseAudio (`paplay`) or ALSA (`aplay`)
305
- - **Windows**: Uses terminal bell
306
-
307
- Toggle sound with `s` or set `"soundEnabled": false` in config.
308
-
309
- ### Server crashes immediately (custom server command mode)
310
- - Check that your command works when run directly
311
- - View logs with `l` to see error messages
312
- - Try restarting with `R`
151
+ Common issues and solutions are covered in the [troubleshooting guide](docs/troubleshooting.md).
313
152
 
314
153
  ## Contributing
315
154
 
316
- Contributions are welcome! There are several ways to contribute to Git Watchtower:
317
-
318
- ### Reporting Bugs
319
-
320
- If you find a bug, please [open an issue](https://github.com/drummel/git-watchtower/issues/new) on GitHub with:
321
- - A clear, descriptive title
322
- - Steps to reproduce the issue
323
- - Expected vs actual behavior
324
- - Your environment (OS, Node.js version, terminal)
325
- - Any relevant error messages or screenshots
326
-
327
- ### Requesting Features
328
-
329
- Have an idea to improve Git Watchtower? [Submit a feature request](https://github.com/drummel/git-watchtower/issues/new) with:
330
- - A clear description of the feature
331
- - The problem it would solve or use case it addresses
332
- - Any implementation ideas (optional)
333
-
334
- ### Submitting Pull Requests
335
-
336
- 1. Fork the repository
337
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
338
- 3. Commit your changes (`git commit -m 'Add amazing feature'`)
339
- 4. Push to the branch (`git push origin feature/amazing-feature`)
340
- 5. Open a Pull Request
341
-
342
- Please ensure your PR:
343
- - Includes a clear description of the changes
344
- - Maintains the zero-dependency philosophy (Node.js built-ins only)
345
- - Works across platforms (macOS, Linux, Windows) when applicable
155
+ Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
346
156
 
347
157
  ## Development
348
158
 
349
- ### Local Installation
350
-
351
- For local development and testing:
352
-
353
159
  ```bash
354
160
  # Clone the repository
355
161
  git clone https://github.com/drummel/git-watchtower.git
356
162
  cd git-watchtower
357
163
 
358
- # Option 1: npm link (recommended)
359
- # Creates a global symlink - changes take effect immediately
164
+ # Create a global symlink (changes take effect immediately)
360
165
  npm link
361
166
 
362
- # Now you can run from any git repository:
167
+ # Run from any git repository
363
168
  git-watchtower
364
169
 
365
- # Option 2: Run directly without installing
366
- node bin/git-watchtower.js
367
- ```
368
-
369
- ### After Making Code Changes
370
-
371
- | Install Method | Update Process |
372
- |----------------|----------------|
373
- | `npm link` | Nothing - changes apply immediately |
374
- | `npm install -g .` | Run `npm install -g .` again |
375
- | Direct `node bin/...` | Nothing - always runs current code |
376
-
377
- ### Unlinking
378
-
379
- To remove the global symlink:
170
+ # Run tests
171
+ npm test
380
172
 
381
- ```bash
382
- npm unlink -g git-watchtower
173
+ # Run directly without installing
174
+ node bin/git-watchtower.js
383
175
  ```
384
176
 
385
177
  ## License
386
178
 
387
179
  MIT License - see [LICENSE](LICENSE) for details.
388
-
389
- ## Acknowledgments
390
-
391
- - Built with Node.js built-in modules only (no external dependencies)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-watchtower",
3
- "version": "1.10.0",
3
+ "version": "1.10.1",
4
4
  "description": "Terminal-based Git branch monitor with activity sparklines and optional dev server with live reload",
5
5
  "main": "bin/git-watchtower.js",
6
6
  "bin": {
@@ -283,6 +283,12 @@ function getWebDashboardHtml(port) {
283
283
  flex-shrink: 0;
284
284
  min-width: 60px;
285
285
  }
286
+ .branch-badges {
287
+ display: flex;
288
+ gap: 4px;
289
+ justify-content: flex-end;
290
+ flex-wrap: wrap;
291
+ }
286
292
  .branch-time {
287
293
  font-size: 12px;
288
294
  font-family: var(--font-mono);
@@ -1586,26 +1592,6 @@ function getWebDashboardHtml(port) {
1586
1592
  html += '</span>';
1587
1593
  // Copy branch name button
1588
1594
  html += '<button class="copy-btn" data-copy="' + escHtml(b.name) + '" title="Copy branch name" onclick="event.stopPropagation()">&#x1f4cb;</button>';
1589
- if (isCurrent) html += '<span class="branch-current-badge">HEAD</span>';
1590
- if (isPinned) html += '<span class="branch-new-badge" style="color:var(--orange);background:rgba(219,109,40,0.15)">pinned</span>';
1591
- if (b.isNew) html += '<span class="branch-new-badge">new</span>';
1592
- if (b.isDeleted) html += '<span class="branch-deleted-badge">deleted</span>';
1593
- if (b.justUpdated) html += '<span class="branch-updated-badge">updated</span>';
1594
- if (prStatus) {
1595
- var prClass = prStatus.state === 'OPEN' ? 'pr-open' : prStatus.state === 'MERGED' ? 'pr-merged' : 'pr-closed';
1596
- var prUrl = getPrUrl(prStatus.number);
1597
- html += '<span class="pr-badge ' + prClass + '">';
1598
- if (prUrl) {
1599
- html += '<a href="' + escHtml(prUrl) + '" target="_blank" rel="noopener" onclick="event.stopPropagation()">';
1600
- }
1601
- html += (prStatus.state === 'MERGED' ? 'merged' : 'PR #' + prStatus.number);
1602
- if (prUrl) html += '</a>';
1603
- html += '</span>';
1604
- // Copy PR URL
1605
- if (prUrl) {
1606
- html += '<button class="copy-btn" data-copy="' + escHtml(prUrl) + '" title="Copy PR URL" onclick="event.stopPropagation()">&#x1f4cb;</button>';
1607
- }
1608
- }
1609
1595
  html += '</div>'; // branch-name-row
1610
1596
 
1611
1597
  html += '<div class="branch-meta">';
@@ -1628,6 +1614,24 @@ function getWebDashboardHtml(port) {
1628
1614
 
1629
1615
  html += '<div class="branch-right">';
1630
1616
  html += '<span class="branch-time">' + timeAgo(b.date) + '</span>';
1617
+ // Badges
1618
+ var badges = '';
1619
+ if (isCurrent) badges += '<span class="branch-current-badge">HEAD</span>';
1620
+ if (isPinned) badges += '<span class="branch-new-badge" style="color:var(--orange);background:rgba(219,109,40,0.15)">pinned</span>';
1621
+ if (b.isNew) badges += '<span class="branch-new-badge">new</span>';
1622
+ if (b.isDeleted) badges += '<span class="branch-deleted-badge">deleted</span>';
1623
+ if (b.justUpdated) badges += '<span class="branch-updated-badge">updated</span>';
1624
+ if (prStatus) {
1625
+ var prClass = prStatus.state === 'OPEN' ? 'pr-open' : prStatus.state === 'MERGED' ? 'pr-merged' : 'pr-closed';
1626
+ var prUrl = getPrUrl(prStatus.number);
1627
+ badges += '<span class="pr-badge ' + prClass + '">';
1628
+ if (prUrl) badges += '<a href="' + escHtml(prUrl) + '" target="_blank" rel="noopener" onclick="event.stopPropagation()">';
1629
+ badges += (prStatus.state === 'MERGED' ? 'merged' : 'PR #' + prStatus.number);
1630
+ if (prUrl) badges += '</a>';
1631
+ badges += '</span>';
1632
+ if (prUrl) badges += '<button class="copy-btn" data-copy="' + escHtml(prUrl) + '" title="Copy PR URL" onclick="event.stopPropagation()">&#x1f4cb;</button>';
1633
+ }
1634
+ if (badges) html += '<div class="branch-badges">' + badges + '</div>';
1631
1635
  if (ab && (ab.ahead || ab.behind)) {
1632
1636
  html += '<div class="branch-diff">';
1633
1637
  html += '<span class="diff-added">+' + fmtCompact(ab.ahead || 0) + '</span>';