@ohmaseclaro/fleetwatch 0.1.2 → 0.1.3

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 (2) hide show
  1. package/README.md +209 -74
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -2,82 +2,189 @@
2
2
 
3
3
  > Watch every Claude Code, Cowork, and Cursor session from your phone — live.
4
4
 
5
- A single command starts a local daemon that tails your AI coding agent
6
- transcripts and serves a mobile-friendly web UI. Pair your phone via QR code
7
- or open it from anywhere via a free ngrok tunnel.
5
+ [![npm version](https://img.shields.io/npm/v/@ohmaseclaro/fleetwatch.svg?color=D97757)](https://www.npmjs.com/package/@ohmaseclaro/fleetwatch)
6
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+ [![node >= 20](https://img.shields.io/badge/node-%3E%3D20-3C873A.svg)](https://nodejs.org)
8
+
9
+ A single command turns your laptop into a live dashboard for every AI coding
10
+ agent running on it. Pair your phone via QR code (or open from anywhere via
11
+ free ngrok tunnel) and watch sessions stream in real time — message-by-message,
12
+ tool-call-by-tool-call, screenshot-by-screenshot.
8
13
 
9
14
  ```bash
10
15
  npx @ohmaseclaro/fleetwatch
11
- # or install globally:
12
- npm install -g @ohmaseclaro/fleetwatch && fleetwatch
13
16
  ```
14
17
 
15
- ## What it does
18
+ That's the entire setup. No accounts, no signup, no config. Auto-discovers
19
+ Claude Code, Cowork, and Cursor data wherever you've installed them.
20
+
21
+ ---
22
+
23
+ ## What you see
24
+
25
+ ```text
26
+ fleetwatch v0.1.2
27
+ ─────────────────────────────────────────
28
+
29
+ Open this on your phone (works anywhere — via ngrok):
30
+
31
+ https://given-relapsing-plop.ngrok-free.dev/?token=HWRfx3wlwTrlS8ALSsA2nEuP9Gfv1M8l
32
+
33
+ Or scan the QR code below:
34
+
35
+ ▄▄▄▄▄▄▄ ▄ ▄▄ ▄▄▄ ▄ ▄▄▄▄ ▄▄▄▄▄▄▄
36
+ █ ▄▄▄ █ █▀ ▄ ▀██▀ ▄▄▄█▀▄ ▀ █ ▄▄▄ █
37
+ █ ███ █ █ ████▀▀▄ ▄▀ ▄▀▀███ █ ███ █
38
+ █▄▄▄▄▄█ █▀█ ▄▀█▀▄▀▄▀▄▀▄ ▄▀▄ ▄ █▄▄▄▄▄█
39
+ ▄ ▄ ▄▄█▄▀▀▀█▀█ █▀▀▀█▄██ █▄▄▄▄▄ ▄
40
+ ▄ █▄▄▄▄▀ █▄ ▄ ███ ▀█▀▄▄ ▄█▀ ▀▄▀▀▀▀
41
+ ██▀▀▀█▄▀▀█ ▀ █ ▄ █▀▄▄██▀▄ █▄██▀▄██▄
42
+ ▀█▀▀▄▄▄▄▄ ▀█▄ ██ █ ▄█████▀▄▄▄██▄█
43
+ █▄█▄▄▄▄██▀ ▀▀▄▀▀ █ █ ▀▄ █▄▀█▄█▄▀▀▄█▄▀
44
+ ▀▄█ ▀▀▄▀▀█ ▀▄▄▄▄ ▄▀▄▀ ▄ ▀ █▄██▀██▄▀
45
+ ▄██▄▄▀▀ ▄█▄▀█ █ ▄▀█▄█▄ ▀█▀▄▄█▀ █▀
46
+ █▀▀█ █▄▄ █▄ █ ██ ▄ ▄▄██ ▀▄█▄▀ ██▄▄▄
47
+ █ █ ▀▄██ ▄▄ ▀▄▄ █▄█▀█ ▄▀ ▄▄▄██▀▄███
48
+ ▀▀▀█▀▀▄▀ ▀▄▀▀▄▄██ ▄▄███▀ ██▀▀▄▀▀▀
49
+ ▄▄▄██▀▄██▀▄▀▄ ██▀█ ▄██▀ ▄ ▄███▄ █ █
50
+ ▄▄▄▄▄▄▄ █▀█▄▄ ▀█ ▄▀ ▄█▄█ █ ▄ █ ▀
51
+ █ ▄▄▄ █ ▄ ▄▀▄█▀▄▀▀▀████ █▄▄▄███▄▄
52
+ █ ███ █ ▄▀ ▀▀██ ▄█▀ ▀ ▄ █▀▀▄██▀ ▀▀▀
53
+ █▄▄▄▄▄█ ▄▄▀█ ███ █▀▀█████ ▀█ ▀ ▄▀ ██▄
54
+ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
55
+
56
+ Host: YA-MN9RV4054G
57
+ Port: 7878
58
+ Tunnel: https://given-relapsing-plop.ngrok-free.dev (token via ngrok.yml (~/Library/Application Support/ngrok/ngrok.yml))
59
+ Auth: pairing token only (set PASSWORD to add a password)
60
+ Cowork: off (toggle in Settings)
61
+
62
+ Press Ctrl+C to stop.
63
+ ```
64
+
65
+ Scan the QR or paste the URL into your phone's browser. You'll see every
66
+ session sorted by most-recent activity, with live status (running / waiting /
67
+ errored / idle), source icons (Claude / Cowork / Cursor), and message-level
68
+ streaming as the agents work.
69
+
70
+ ---
71
+
72
+ ## Features
16
73
 
17
- - **Tracks Claude Code, Cowork, and Cursor** automatically — discovers data
18
- in standard locations and falls back to a bounded filesystem search if
19
- you've installed in a non-standard place.
20
- - **Mobile-first PWA** open the URL on your phone, add to home screen,
21
- watch sessions live as they run on your desktop.
22
- - **Source tabs with icons** — filter to Claude, Cowork, Cursor, or All.
23
- Each row shows status (running / awaiting / errored / idle) with a
24
- colored stripe on the left edge for in-flight sessions.
74
+ - **Three providers, auto-discovered**
75
+ - Claude Code (`~/.claude/projects/*.jsonl`)
76
+ - Cowork (`~/Library/Application Support/Claude/local-agent-mode-sessions/`)
77
+ - Cursor IDE (`~/Library/Application Support/Cursor/User/globalStorage/state.vscdb`)
78
+ - **Filterable tabs** All / Claude / Cowork / Cursor, each with a brand icon
79
+ - **Live streaming** — WebSocket; events arrive on your phone within
80
+ milliseconds of being written
25
81
  - **Image attachments** — screenshots from the screenshot tool, user-pasted
26
- images, render inline with a tap-to-zoom lightbox.
82
+ images render inline with a tap-to-zoom lightbox
27
83
  - **Session info modal** — tap (i) on any session to see the full transcript
28
- path, project, git branch, session ID, file size, with copy-to-clipboard.
29
- - **Auto-tunnel via ngrok** — works on any network when you have a free
30
- authtoken; auto-picks it up from your existing `~/.../ngrok.yml` if you've
31
- run `ngrok config add-authtoken …` before.
32
- - **Optional password** — set `PASSWORD=…` in `.env` to require a password
33
- before any device can connect. Bcrypt-hashed in memory, never on disk.
34
- - **Read-only** — never writes to source data; opens DBs read-only; never
35
- follows symlinks during discovery.
84
+ path, project, git branch, session ID, file size, with copy-to-clipboard
85
+ - **Auto ngrok tunnel** — works on any network when you have a free authtoken;
86
+ auto-picks it up from existing `~/.../ngrok.yml` if you've run
87
+ `ngrok config add-authtoken …` before
88
+ - **Optional password gate** — set `PASSWORD=…` in `.env` to require a
89
+ password before any device can connect (bcrypt-hashed in memory, never on
90
+ disk)
91
+ - **JWT auth** — 30-day tokens issued on login; WebSocket and attachment
92
+ endpoints all authed
93
+ - **Read-only by design** — never writes to source data; opens DBs read-only;
94
+ never follows symlinks during discovery; respects file inodes for safe
95
+ rotation
96
+ - **Robust file discovery** — env var → known paths → bounded filesystem
97
+ search, with mandatory verify predicates so VSCode's `state.vscdb` never
98
+ gets mistaken for Cursor's
99
+
100
+ ---
101
+
102
+ ## Install
103
+
104
+ ### Run without installing (recommended)
105
+
106
+ ```bash
107
+ npx @ohmaseclaro/fleetwatch
108
+ ```
36
109
 
37
- ## Quick start
110
+ > If you're hacking on the fleetwatch source itself, run `npm start` or
111
+ > `node dist/server/index.js` from the repo — running `npx` from inside the
112
+ > repo will collide with the in-repo `package.json` and fail with
113
+ > `command not found`.
114
+
115
+ ### Install globally
38
116
 
39
117
  ```bash
40
- # Install globally
41
118
  npm install -g @ohmaseclaro/fleetwatch
42
-
43
- # Run — auto-discovers Claude / Cursor data, prints QR code
44
119
  fleetwatch
45
120
  ```
46
121
 
47
- Scan the QR with your phone. You're done.
122
+ After global install, the `fleetwatch` command is on your PATH.
123
+
124
+ ---
125
+
126
+ ## ngrok setup (optional — for access from anywhere)
127
+
128
+ By default fleetwatch only works on the same Wi-Fi as your laptop. To reach
129
+ it from cellular, coffee shops, anywhere — start ngrok automatically:
48
130
 
49
- ### First-time ngrok (optional but recommended)
131
+ 1. **Sign up free** (no credit card): <https://dashboard.ngrok.com/signup>
132
+ 2. **Copy your authtoken**: <https://dashboard.ngrok.com/get-started/your-authtoken>
133
+ 3. **Run with the token**:
50
134
 
51
- For access from anywhere (cellular, coffee shops, etc.) you'll need a free
52
- ngrok authtoken:
135
+ ```bash
136
+ fleetwatch --ngrok-authtoken <your-token>
137
+ ```
53
138
 
54
- 1. Sign up: <https://dashboard.ngrok.com/signup>
55
- 2. Copy your authtoken: <https://dashboard.ngrok.com/get-started/your-authtoken>
56
- 3. `fleetwatch --ngrok-authtoken <your-token>` (persisted for future runs)
139
+ The token is persisted to `~/.config/fleetwatch/config.json` so future
140
+ runs Just Work.
57
141
 
58
- Or set `NGROK_AUTHTOKEN=…` in `.env`. Or if you've already run
59
- `ngrok config add-authtoken …` fleetwatch picks it up automatically.
142
+ Already ran `ngrok config add-authtoken …` for another project? Fleetwatch
143
+ finds it automaticallyzero extra config.
144
+
145
+ ---
146
+
147
+ ## Password protection (recommended with ngrok)
148
+
149
+ Once you put a tunnel on the public internet, anyone with the URL can
150
+ connect. Add a password:
151
+
152
+ ```bash
153
+ echo 'PASSWORD=correct horse battery staple' >> .env
154
+ fleetwatch
155
+ ```
156
+
157
+ Or use the **Password protection** section of the Settings screen in the UI
158
+ (visible only from the desktop, not the phone). Devices must enter the
159
+ password before connecting; bcrypt hash lives in memory only.
160
+
161
+ After successful login the client gets a 30-day JWT and the pairing token
162
+ is no longer used — the QR URL can leak without compromising the daemon.
163
+
164
+ ---
60
165
 
61
166
  ## Configuration
62
167
 
63
- All optional. Defaults work out of the box.
168
+ All env vars are optional. Defaults work out of the box.
64
169
 
65
170
  | Env var | Description |
66
171
  |---|---|
67
- | `NGROK_AUTHTOKEN` | ngrok free-tier authtoken. Required for the public tunnel. |
172
+ | `NGROK_AUTHTOKEN` | ngrok free-tier authtoken. Enables the public tunnel. |
68
173
  | `NGROK_DISABLED=1` | Skip the ngrok tunnel even if a token is available. |
69
174
  | `CURSOR_DISABLED=1` | Skip the Cursor provider entirely. |
70
- | `PASSWORD` | Optional password — devices must enter it to connect. Bcrypt-hashed in memory only. |
71
- | `JWT_SECRET` | JWT signing secret (auto-generated + persisted otherwise). |
175
+ | `PASSWORD` | Optional password — required to connect when set. Bcrypt-hashed in memory only. |
176
+ | `JWT_SECRET` | JWT signing secret (auto-generated and persisted if not set). |
72
177
  | `CLAUDE_PROJECTS_DIR` | Override Claude Code projects dir. |
73
178
  | `COWORK_DIR` | Override Cowork sessions dir. |
74
179
  | `CLAUDE_HISTORY_FILE` | Override `history.jsonl` path. |
75
180
  | `CURSOR_DB_PATH` | Override Cursor `state.vscdb` path. |
181
+ | `PORT` | Override default port (`7878`). |
182
+ | `HOST` | Override default bind address (`0.0.0.0`). |
76
183
 
77
- `.env` files are read from `./.env` and `~/.config/fleetwatch/.env`
78
- (in that order; shell env always wins).
184
+ `.env` files are read from `./.env` then `~/.config/fleetwatch/.env`.
185
+ Shell env always wins.
79
186
 
80
- ## CLI
187
+ ### CLI flags
81
188
 
82
189
  ```
83
190
  fleetwatch [options]
@@ -93,37 +200,45 @@ fleetwatch [options]
93
200
  --help, -h Show help
94
201
  ```
95
202
 
203
+ ---
204
+
96
205
  ## Providers
97
206
 
98
- Out of the box:
207
+ Each "provider" surfaces sessions from one source. Discovery is robust —
208
+ every provider tries the default path, then OS-specific alternatives, then
209
+ a bounded filesystem search, with a `verify()` predicate that confirms
210
+ the candidate is actually that provider's data.
99
211
 
100
- | Provider | Source data |
101
- |---|---|
102
- | **Claude Code** | `~/.claude/projects/*.jsonl` (the CLI agent) |
103
- | **Cowork** | `~/Library/Application Support/Claude/local-agent-mode-sessions/.../*.jsonl` |
104
- | **Cursor** | `~/Library/Application Support/Cursor/User/globalStorage/state.vscdb` |
212
+ | Provider | Discovers | Format |
213
+ |---|---|---|
214
+ | **Claude Code** | `~/.claude/projects/*.jsonl` (plus `$CLAUDE_PROJECTS_DIR`, XDG dirs, fallback search) | Append-only JSONL |
215
+ | **Cowork** | `~/Library/Application Support/Claude/local-agent-mode-sessions/` | Append-only JSONL (same schema as Claude Code) |
216
+ | **Cursor** | `~/Library/Application Support/Cursor/User/globalStorage/state.vscdb` (plus Linux/Windows paths) | SQLite, read-only |
217
+
218
+ ### Adding a new provider
105
219
 
106
- Discovery is robust each provider tries the default location, then an
107
- ordered list of OS-specific alternatives, then a bounded filesystem search
108
- under known app-data dirs (`~/.config/`, `~/Library/Application Support/`),
109
- with a mandatory `verify()` predicate that opens the candidate and
110
- confirms it's actually that provider's data (so VSCode's `state.vscdb`
111
- never gets mistaken for Cursor's).
220
+ Aider? Continue? GitHub Copilot Chat? Custom internal agents? Extending
221
+ fleetwatch with a new source is intentionally small: declare a
222
+ `ProviderInfo`, declare a `DiscoverySpec`, implement `onStart` /
223
+ `backfillSession`.
112
224
 
113
- Adding a new provider (Aider, Continue, anything else) is small — extend
114
- `BaseProvider`, declare a `DiscoverySpec`, implement `onStart` /
115
- `backfillSession`. See [docs/ADD_A_PROVIDER.md](docs/ADD_A_PROVIDER.md).
225
+ Full guide: [`docs/ADD_A_PROVIDER.md`](docs/ADD_A_PROVIDER.md)
226
+
227
+ ---
116
228
 
117
229
  ## Security
118
230
 
119
- - All connections require either the pairing token (in the QR URL) or a
120
- successful login via password (if `PASSWORD` is set).
121
- - After login, the client gets a 30-day JWT; the pairing token is no
122
- longer used.
123
- - WebSocket connections authenticate via JWT.
124
- - Image attachments served from an authed endpoint with content-addressed
125
- hashes no enumeration possible.
126
- - No telemetry. No external calls (except ngrok if enabled).
231
+ - All HTTP and WebSocket endpoints require auth (pairing token OR JWT).
232
+ - Image attachments served from content-addressed (sha256) URLs no
233
+ enumeration possible.
234
+ - Daemon is **read-only**:
235
+ - JSONL files opened with append-only tailing (rotation-safe via inode)
236
+ - SQLite opened with `readonly: true` + `fileMustExist: true`
237
+ - Never follows symlinks during discovery
238
+ - No telemetry. No external network calls except ngrok (when enabled).
239
+ - All state lives in `~/.config/fleetwatch/` — a single JSON file.
240
+
241
+ ---
127
242
 
128
243
  ## Development
129
244
 
@@ -131,26 +246,46 @@ Adding a new provider (Aider, Continue, anything else) is small — extend
131
246
  git clone https://github.com/ohmaseclaro/fleetwatch
132
247
  cd fleetwatch
133
248
  npm install
134
- npm run dev:web # Vite HMR on :5173
135
- npm run dev:server # daemon with watch on :7878 (separate terminal)
249
+
250
+ # In one terminal: Vite HMR for the PWA
251
+ npm run dev:web
252
+
253
+ # In another: daemon in watch mode
254
+ npm run dev:server
136
255
  ```
137
256
 
138
257
  Production build:
139
258
 
140
259
  ```bash
141
- npm run build # web → dist/web, server → dist/server
142
- npm start # run the compiled daemon
260
+ npm run build
261
+ npm start # serves built bundle on :7878
143
262
  ```
144
263
 
264
+ ---
265
+
145
266
  ## Releasing
146
267
 
268
+ [`scripts/release.sh`](scripts/release.sh) handles everything:
269
+
147
270
  ```bash
148
- npm run release # bumps version, builds, publishes, tags
271
+ ./scripts/release.sh patch # 0.1.2 0.1.3
272
+ ./scripts/release.sh minor # 0.1.2 → 0.2.0
273
+ ./scripts/release.sh major # 0.1.2 → 1.0.0
274
+ ./scripts/release.sh patch --otp=123456 # if 2FA is enforced
149
275
  ```
150
276
 
151
- See [scripts/release.sh](scripts/release.sh) for details, or
152
- [docs/PUBLISHING.md](docs/PUBLISHING.md) for first-time setup.
277
+ The script:
278
+ - verifies clean tree + on `main`/`master`
279
+ - runs typecheck + build
280
+ - bumps the version
281
+ - creates a `vX.Y.Z` commit + tag
282
+ - publishes to npm (token from `.env` via project `.npmrc`)
283
+ - pushes to GitHub
284
+
285
+ First-time setup: [`docs/PUBLISHING.md`](docs/PUBLISHING.md).
286
+
287
+ ---
153
288
 
154
289
  ## License
155
290
 
156
- MIT — see [LICENSE](LICENSE).
291
+ [MIT](LICENSE) © Augusto Claro
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohmaseclaro/fleetwatch",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "Watch every Claude Code, Cowork, and Cursor session from your phone — multi-provider agent observability with live updates over LAN or ngrok.",
6
6
  "keywords": [