git-watchtower 2.1.0 → 2.1.2
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 +50 -61
- package/package.json +2 -2
- package/src/git/branch.js +2 -2
- package/src/git/commands.js +5 -1
- package/src/server/coordinator.js +28 -0
package/README.md
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# Git Watchtower
|
|
2
4
|
|
|
5
|
+
## Keep up with your AI coding agents.
|
|
6
|
+
|
|
7
|
+
### Monitor git branches in real-time with activity sparklines, instant notifications, and a web dashboard.
|
|
8
|
+
|
|
9
|
+
Built for teams working with Claude Code, Codex, and other AI agents.
|
|
10
|
+
|
|
3
11
|
[](https://www.npmjs.com/package/git-watchtower)
|
|
4
12
|
[](https://www.npmjs.com/package/git-watchtower)
|
|
5
13
|
[](LICENSE)
|
|
6
14
|
|
|
7
|
-
|
|
15
|
+
#### Visit our website → [gitwatchtower.dev](https://gitwatchtower.dev)
|
|
16
|
+
|
|
17
|
+
[Quick Start](https://gitwatchtower.dev/guides/quick-start/) · [Configuration](https://gitwatchtower.dev/guides/configuration/) · [Web Dashboard](https://gitwatchtower.dev/guides/web-dashboard/) · [Keyboard Controls](https://gitwatchtower.dev/guides/keyboard-controls/) · [Server Modes](https://gitwatchtower.dev/guides/server-modes/) · [Troubleshooting](https://gitwatchtower.dev/guides/troubleshooting/)
|
|
18
|
+
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
## Features
|
|
8
24
|
|
|
9
25
|
- **Live branch monitoring** with activity sparklines and ahead/behind counters
|
|
10
26
|
- **Web dashboard** for browser-based branch management and PR workflows
|
|
@@ -14,32 +30,14 @@ Monitor and switch between git branches in real-time. Built for working with web
|
|
|
14
30
|
- **Optional dev server** with live reload, or run your own command (Next.js, Vite, etc.)
|
|
15
31
|
- **Zero dependencies** — uses only Node.js built-in modules
|
|
16
32
|
|
|
17
|
-

|
|
18
|
-
|
|
19
33
|
## Why Git Watchtower?
|
|
20
34
|
|
|
21
|
-
When you're using AI coding agents on the web
|
|
35
|
+
When you're using AI coding agents on the web — Claude Code, OpenAI Codex, and others — they create branches and push commits while you're not looking. You end up with multiple branches to check on and no easy way to know when they've been updated or what changed.
|
|
22
36
|
|
|
23
37
|
Git Watchtower watches your remote and notifies you when branches are updated. Preview what changed, switch with a keypress, undo if needed.
|
|
24
38
|
|
|
25
39
|
Also works for human collaborators, but the primary use case is keeping tabs on AI agents coding on different branches.
|
|
26
40
|
|
|
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
|
-

|
|
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)
|
|
42
|
-
|
|
43
41
|
## Installation
|
|
44
42
|
|
|
45
43
|
```bash
|
|
@@ -53,10 +51,7 @@ npx git-watchtower
|
|
|
53
51
|
## Quick Start
|
|
54
52
|
|
|
55
53
|
```bash
|
|
56
|
-
# Navigate to any git repository
|
|
57
54
|
cd your-project
|
|
58
|
-
|
|
59
|
-
# Start Git Watchtower
|
|
60
55
|
git-watchtower
|
|
61
56
|
```
|
|
62
57
|
|
|
@@ -84,11 +79,19 @@ git-watchtower --init
|
|
|
84
79
|
git-watchtower --help
|
|
85
80
|
```
|
|
86
81
|
|
|
87
|
-
|
|
82
|
+
## Web Dashboard
|
|
83
|
+
|
|
84
|
+
Launch a browser-based dashboard alongside the terminal UI with `--web`:
|
|
88
85
|
|
|
89
|
-
|
|
86
|
+
```bash
|
|
87
|
+
git-watchtower --web
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+

|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
Real-time branch monitoring, PR workflows, CI status, and session statistics — all in a rich browser interface. When running multiple instances across different projects, they coordinate automatically into a single multi-project dashboard. Press `W` in the TUI to toggle the web dashboard on or off at any time.
|
|
93
|
+
|
|
94
|
+
## Server Modes
|
|
92
95
|
|
|
93
96
|
| Mode | Flag | Description |
|
|
94
97
|
|------|------|-------------|
|
|
@@ -96,46 +99,28 @@ Git Watchtower supports three server modes:
|
|
|
96
99
|
| **Custom Command** | `--mode command -c "npm run dev"` | Run your own dev server (Next.js, Vite, Nuxt, etc.) |
|
|
97
100
|
| **No Server** | `--no-server` | Branch monitoring only |
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
## Configuration
|
|
102
|
+
## 🎰 Casino Mode
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
Yes, it's a real feature. Every `git fetch` is a slot-machine spin, every commit is a payout. Enable with `--casino` or `"casinoMode": true`.
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|---------|-------------|---------|
|
|
107
|
-
| Server mode | static, command, or none | static |
|
|
108
|
-
| Port | Server port number | 3000 |
|
|
109
|
-
| Web dashboard | Enable browser dashboard | false (use `--web`) |
|
|
110
|
-
| Auto-pull | Auto-pull when current branch has updates | true |
|
|
111
|
-
| Polling interval | How often to check for git updates | 5 seconds |
|
|
112
|
-
| Sound notifications | Audio alerts for updates | true |
|
|
113
|
-
| Visible branches | Number of branches shown in list | 7 |
|
|
106
|
+
## Documentation
|
|
114
107
|
|
|
115
|
-
|
|
108
|
+
Full docs at **[gitwatchtower.dev](https://gitwatchtower.dev)**.
|
|
116
109
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
| `v` | Preview branch (commits & files) |
|
|
124
|
-
| `/` | Search/filter branches |
|
|
125
|
-
| `b` | Branch actions (PR, CI, merge, approve) |
|
|
126
|
-
| `u` | Undo last branch switch |
|
|
127
|
-
| `S` | Stash changes |
|
|
128
|
-
| `W` | Toggle web dashboard |
|
|
129
|
-
| `q` | Quit |
|
|
130
|
-
|
|
131
|
-
[Full keyboard reference →](docs/keyboard-controls.md)
|
|
110
|
+
- [Quick Start](https://gitwatchtower.dev/guides/quick-start/) — install, first run, and the configuration wizard
|
|
111
|
+
- [Configuration](https://gitwatchtower.dev/guides/configuration/) — every setting, CLI flag, and environment variable
|
|
112
|
+
- [Web Dashboard](https://gitwatchtower.dev/guides/web-dashboard/) — browser UI with PR workflows and CI status
|
|
113
|
+
- [Keyboard Controls](https://gitwatchtower.dev/guides/keyboard-controls/) — full key reference
|
|
114
|
+
- [Server Modes](https://gitwatchtower.dev/guides/server-modes/) — static site, custom command, and no-server modes
|
|
115
|
+
- [Troubleshooting](https://gitwatchtower.dev/guides/troubleshooting/) — common issues and fixes
|
|
132
116
|
|
|
133
117
|
## Requirements
|
|
134
118
|
|
|
135
|
-
- **Node.js**
|
|
119
|
+
- **Node.js** 20.0.0 or higher
|
|
136
120
|
- **Git** installed and in PATH
|
|
137
121
|
- **Git remote** configured (any name, defaults to `origin`)
|
|
138
122
|
- **Terminal** with ANSI color support
|
|
123
|
+
- **Optional**: [`gh`](https://cli.github.com/) or [`glab`](https://gitlab.com/gitlab-org/cli) CLI for branch actions (PR create, approve, merge, CI status)
|
|
139
124
|
|
|
140
125
|
## How It Works
|
|
141
126
|
|
|
@@ -146,10 +131,6 @@ Settings are saved to `.watchtowerrc.json` in your project directory. Key settin
|
|
|
146
131
|
5. **Live Reload** — In static site mode, notifies connected browsers via SSE when files change
|
|
147
132
|
6. **Web Dashboard** — Optional browser UI that mirrors and extends the TUI via SSE
|
|
148
133
|
|
|
149
|
-
## Troubleshooting
|
|
150
|
-
|
|
151
|
-
Common issues and solutions are covered in the [troubleshooting guide](docs/troubleshooting.md).
|
|
152
|
-
|
|
153
134
|
## Contributing
|
|
154
135
|
|
|
155
136
|
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
@@ -174,6 +155,14 @@ npm test
|
|
|
174
155
|
node bin/git-watchtower.js
|
|
175
156
|
```
|
|
176
157
|
|
|
158
|
+
The documentation site lives in [`website/`](website/) and is built with Astro Starlight:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
cd website
|
|
162
|
+
npm install
|
|
163
|
+
npm run dev
|
|
164
|
+
```
|
|
165
|
+
|
|
177
166
|
## License
|
|
178
167
|
|
|
179
|
-
MIT License
|
|
168
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-watchtower",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
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": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"bugs": {
|
|
48
48
|
"url": "https://github.com/drummel/git-watchtower/issues"
|
|
49
49
|
},
|
|
50
|
-
"homepage": "https://
|
|
50
|
+
"homepage": "https://gitwatchtower.dev",
|
|
51
51
|
"engines": {
|
|
52
52
|
"node": ">=20.0.0"
|
|
53
53
|
},
|
package/src/git/branch.js
CHANGED
|
@@ -103,7 +103,7 @@ async function getAllBranches(options = {}) {
|
|
|
103
103
|
// Use \x1f (Unit Separator) as delimiter since | can appear in commit subjects
|
|
104
104
|
const delimiter = '\x1f';
|
|
105
105
|
const localResult = await execGit(
|
|
106
|
-
['for-each-ref', '--sort=-committerdate', `--format=%(refname:short)${delimiter}%(committerdate:iso8601)${delimiter}%(objectname:short)${delimiter}%(subject)`, 'refs/heads/'],
|
|
106
|
+
['for-each-ref', '--sort=-committerdate', `--format=%(refname:short)${delimiter}%(committerdate:iso8601-strict)${delimiter}%(objectname:short)${delimiter}%(subject)`, 'refs/heads/'],
|
|
107
107
|
{ cwd }
|
|
108
108
|
);
|
|
109
109
|
|
|
@@ -128,7 +128,7 @@ async function getAllBranches(options = {}) {
|
|
|
128
128
|
|
|
129
129
|
// Get remote branches
|
|
130
130
|
const remoteResult = await execGit(
|
|
131
|
-
['for-each-ref', '--sort=-committerdate', `--format=%(refname:short)${delimiter}%(committerdate:iso8601)${delimiter}%(objectname:short)${delimiter}%(subject)`, `refs/remotes/${remoteName}/`],
|
|
131
|
+
['for-each-ref', '--sort=-committerdate', `--format=%(refname:short)${delimiter}%(committerdate:iso8601-strict)${delimiter}%(objectname:short)${delimiter}%(subject)`, `refs/remotes/${remoteName}/`],
|
|
132
132
|
{ cwd }
|
|
133
133
|
);
|
|
134
134
|
|
package/src/git/commands.js
CHANGED
|
@@ -261,8 +261,12 @@ async function getCommitsByDay(branchName, days = 7, cwd) {
|
|
|
261
261
|
const counts = new Array(days).fill(0);
|
|
262
262
|
|
|
263
263
|
try {
|
|
264
|
+
// %cI is strict ISO 8601 (YYYY-MM-DDTHH:MM:SS±HH:MM). %ci uses a
|
|
265
|
+
// space separator and a compact ±HHMM offset — V8 parses it today,
|
|
266
|
+
// but the spec doesn't require engines to accept non-strict forms,
|
|
267
|
+
// so rely on the strict variant for Date(string) parsing.
|
|
264
268
|
const { stdout } = await execGit(
|
|
265
|
-
['log', branchName, '--format=%
|
|
269
|
+
['log', branchName, '--format=%cI', `--since=${days} days ago`],
|
|
266
270
|
{ cwd, timeout: 10000 }
|
|
267
271
|
);
|
|
268
272
|
|
|
@@ -459,12 +459,26 @@ class Coordinator {
|
|
|
459
459
|
|
|
460
460
|
/**
|
|
461
461
|
* Send a JSON message over a socket.
|
|
462
|
+
*
|
|
463
|
+
* Honours outbound backpressure: if the per-socket write buffer is
|
|
464
|
+
* already at or above MAX_IPC_BUFFER, drop the worker rather than
|
|
465
|
+
* letting Node's internal buffer grow without bound. A wedged or
|
|
466
|
+
* paused worker would otherwise let coordinator memory climb on
|
|
467
|
+
* every pushState / command broadcast — symmetric with the inbound
|
|
468
|
+
* MAX_IPC_BUFFER policy in _handleWorkerConnection. The worker is
|
|
469
|
+
* expected to reconnect; until it does, dropping it is preferable
|
|
470
|
+
* to OOM-ing the coordinator.
|
|
471
|
+
*
|
|
462
472
|
* @param {net.Socket} socket
|
|
463
473
|
* @param {Object} msg
|
|
464
474
|
* @private
|
|
465
475
|
*/
|
|
466
476
|
_sendMessage(socket, msg) {
|
|
467
477
|
try {
|
|
478
|
+
if (socket.writableLength >= MAX_IPC_BUFFER) {
|
|
479
|
+
socket.destroy();
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
468
482
|
socket.write(JSON.stringify(msg) + '\n');
|
|
469
483
|
} catch (e) { /* peer socket closed between iteration and write — peer will reconnect if it recovers */ }
|
|
470
484
|
}
|
|
@@ -643,12 +657,25 @@ class Worker {
|
|
|
643
657
|
// ─── Private ─────────────────────────────────────────────────
|
|
644
658
|
|
|
645
659
|
/**
|
|
660
|
+
* Send a JSON message to the coordinator.
|
|
661
|
+
*
|
|
662
|
+
* Outbound backpressure mirrors Coordinator._sendMessage: if the
|
|
663
|
+
* write buffer already exceeds MAX_IPC_BUFFER, destroy the socket
|
|
664
|
+
* rather than letting state pushes accumulate unboundedly while
|
|
665
|
+
* a wedged coordinator can't drain them. The worker's _connected
|
|
666
|
+
* flag flips to false on socket close, so subsequent pushState
|
|
667
|
+
* calls become no-ops until reconnect.
|
|
668
|
+
*
|
|
646
669
|
* @param {Object} msg
|
|
647
670
|
* @private
|
|
648
671
|
*/
|
|
649
672
|
_send(msg) {
|
|
650
673
|
if (this.socket && this._connected) {
|
|
651
674
|
try {
|
|
675
|
+
if (this.socket.writableLength >= MAX_IPC_BUFFER) {
|
|
676
|
+
this.socket.destroy();
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
652
679
|
this.socket.write(JSON.stringify(msg) + '\n');
|
|
653
680
|
} catch (e) { /* coordinator socket closed between isConnected() check and write */ }
|
|
654
681
|
}
|
|
@@ -694,4 +721,5 @@ module.exports = {
|
|
|
694
721
|
WATCHTOWER_DIR,
|
|
695
722
|
LOCK_FILE,
|
|
696
723
|
SOCKET_PATH,
|
|
724
|
+
MAX_IPC_BUFFER,
|
|
697
725
|
};
|