sitedrift 0.1.0 → 0.2.0

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/AGENTS.md ADDED
@@ -0,0 +1,101 @@
1
+ # sitedrift for agents
2
+
3
+ sitedrift compares a local site with production and keeps a shared review-note
4
+ channel for humans and AI tools. Prefer the packaged MCP server. Use the JSON CLI
5
+ only when the host cannot run MCP.
6
+
7
+ ## Fast path
8
+
9
+ 1. Install once: `npm install --global sitedrift`
10
+ 2. In the project, create `sitedrift.config.json`:
11
+
12
+ ```json
13
+ {
14
+ "dev": "http://localhost:4321",
15
+ "live": "https://example.com",
16
+ "open": true
17
+ }
18
+ ```
19
+
20
+ 3. Start the app: `sitedrift`
21
+ 4. Configure the AI host to run:
22
+
23
+ ```json
24
+ {
25
+ "command": "sitedrift-mcp",
26
+ "args": []
27
+ }
28
+ ```
29
+
30
+ No global install: use `"command": "npx"` and
31
+ `"args": ["-y", "sitedrift", "mcp"]`.
32
+
33
+ Common one-command setup:
34
+
35
+ ```bash
36
+ codex mcp add sitedrift -- sitedrift-mcp
37
+ claude mcp add sitedrift -- sitedrift-mcp
38
+ ```
39
+
40
+ For Cursor and other JSON-configured hosts, put this in the host's MCP
41
+ configuration under `mcpServers`:
42
+
43
+ ```json
44
+ {
45
+ "sitedrift": {
46
+ "command": "sitedrift-mcp",
47
+ "args": []
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## Agent workflow
53
+
54
+ 1. Call `sitedrift_context` first. Do not guess the URLs or active session.
55
+ 2. Inspect the requested route in the viewer or with the host's browser tools.
56
+ 3. Call `sitedrift_notes_list` before adding notes to avoid duplicates.
57
+ 4. Add one concrete finding per `sitedrift_note_add` call. Always provide
58
+ `route`; provide `side` when the issue belongs specifically to DEV or LIVE.
59
+ 5. Re-list notes after code changes. Resolve only findings you verified.
60
+ 6. Remove or clear notes only when the user explicitly requests it.
61
+
62
+ ## MCP tools
63
+
64
+ - `sitedrift_context`: active targets, viewer URL, and capabilities.
65
+ - `sitedrift_notes_list`: shared findings.
66
+ - `sitedrift_note_add`: add one actionable finding.
67
+ - `sitedrift_note_resolve`: mark a verified finding complete.
68
+ - `sitedrift_note_reopen`: reopen a regressed or incomplete finding.
69
+ - `sitedrift_note_remove`: permanently remove one finding.
70
+ - `sitedrift_notes_clear`: permanently remove all findings.
71
+ - `sitedrift_setup`: return install, config, HTTPS, and MCP setup instructions.
72
+
73
+ Default port is `4178`. Pass `port` to every tool when the user runs another
74
+ session port.
75
+
76
+ ## CLI fallback
77
+
78
+ ```bash
79
+ sitedrift context
80
+ sitedrift notes list
81
+ sitedrift notes add "CTA differs" --route /pricing --side live --author agent
82
+ sitedrift notes resolve <id>
83
+ ```
84
+
85
+ All CLI output is JSON. The MCP server communicates over stdio and writes no
86
+ logs to stdout.
87
+
88
+ ## HTTPS
89
+
90
+ Loopback HTTP is normally sufficient. When the compared site requires HTTPS:
91
+
92
+ ```bash
93
+ sitedrift --setup-https
94
+ sitedrift --https
95
+ ```
96
+
97
+ ## Security
98
+
99
+ sitedrift accepts loopback hosts only. The control API uses a random bearer
100
+ token stored in `~/.sitedrift/sessions/<port>.json` with mode `0600`. DEV and
101
+ LIVE render on separate origins. Never expose sitedrift through a public proxy.
package/README.md CHANGED
@@ -5,15 +5,11 @@ that frames your local site and production **side-by-side on the same route**,
5
5
  locked to the same scroll — then overlays them in `difference` mode so the only
6
6
  things that light up are the pixels that actually changed.
7
7
 
8
- ```
9
- ┌─────────────── sitedrift ───────────────┐
10
- │ DEV ▸ /pricing 200 LIVE ▸ /pricing 200 │
11
- │ ┌───────────┐ │ ┌───────────┐ Overlay ▸ Diff │
12
- │ $19 │ │ $29 │ ≠ meta │
13
- │ │ [Start…] │ │ │ [Get…] │ ✓ author notes │
14
- │ └───────────┘ │ └───────────┘ │
15
- └──────────────────────────────────────────┘
16
- ```
8
+ <p align="center">
9
+ <img src="docs/images/sitedrift-split.jpg" alt="sitedrift comparing a redesigned local product page with production" width="100%">
10
+ </p>
11
+
12
+ <p align="center"><strong>Same route. Same scroll. Every change visible.</strong></p>
17
13
 
18
14
  ---
19
15
 
@@ -39,6 +35,72 @@ npm i -g sitedrift
39
35
  sitedrift /pricing -d http://localhost:4321 -l https://example.com -o
40
36
  ```
41
37
 
38
+ For a project you use repeatedly, add `sitedrift.config.json`:
39
+
40
+ ```json
41
+ {
42
+ "dev": "http://localhost:4321",
43
+ "live": "https://example.com",
44
+ "author": "joe",
45
+ "open": true
46
+ }
47
+ ```
48
+
49
+ Configuration precedence is **flag > environment > project file > default**.
50
+ The file is discovered from the current directory upward; `--config <file>`
51
+ selects one explicitly.
52
+
53
+ ### HTTPS
54
+
55
+ The default (`http://127.0.0.1`) just works — loopback is a browser "secure
56
+ context", so you usually need nothing. When you do want HTTPS:
57
+
58
+ ```bash
59
+ sitedrift --setup-https # one-time: generate + trust a local cert
60
+ sitedrift --https # serve over HTTPS from then on
61
+ ```
62
+
63
+ `--setup-https` uses [mkcert](https://github.com/FiloSottile/mkcert) if it's
64
+ installed — that gives a **locally-trusted cert with zero browser warnings**. If
65
+ mkcert isn't found it falls back to an `openssl` self-signed cert and prints the
66
+ one command to trust it on your OS. Already have a cert? Skip all of this and
67
+ pass `--cert <file> --key <file>`.
68
+
69
+ ---
70
+
71
+ ## See the whole review loop
72
+
73
+ The included example compares a fictional Northstar release candidate against
74
+ production. It uses realistic release drift: primary CTA, metric values, and a
75
+ release badge change while the underlying layout stays aligned.
76
+
77
+ <table>
78
+ <tr>
79
+ <td width="50%">
80
+ <img src="docs/images/sitedrift-diff.jpg" alt="Difference overlay showing only changed pixels">
81
+ <br><strong>Pixel difference</strong><br>
82
+ Overlay both pages and light up only what changed.
83
+ </td>
84
+ <td width="50%">
85
+ <img src="docs/images/sitedrift-collaboration.jpg" alt="Review drawer with notes from a human and an AI agent">
86
+ <br><strong>Human + AI review channel</strong><br>
87
+ Share route-specific findings through the viewer, CLI, or MCP.
88
+ </td>
89
+ </tr>
90
+ </table>
91
+
92
+ <p align="center">
93
+ <img src="docs/images/sitedrift-mobile.jpg" alt="sitedrift Solo mode on a narrow mobile viewport" width="360">
94
+ <br><strong>Focused mobile review</strong><br>
95
+ Narrow screens default to Solo; Swap flips between DEV and LIVE.
96
+ </p>
97
+
98
+ Rebuild these screenshots from the deterministic local showcase:
99
+
100
+ ```bash
101
+ npm run docs:screenshots
102
+ ```
103
+
42
104
  ---
43
105
 
44
106
  ## What it does
@@ -59,7 +121,7 @@ sitedrift /pricing -d http://localhost:4321 -l https://example.com -o
59
121
  file the viewer polls every 4s, so a teammate or an AI coding session can leave
60
122
  notes that appear live. Click a note to jump to its route, copy a per-note
61
123
  deep link, dock or float the drawer, and **Send to vault** or export Markdown.
62
- - **No dependencies.** Node standard library only.
124
+ - **No runtime dependencies.** Node standard library only.
63
125
 
64
126
  ### Keyboard
65
127
 
@@ -82,7 +144,6 @@ Shortcuts work whether focus is in the viewer chrome or inside either pane.
82
144
  ## Options
83
145
 
84
146
  Every option is a CLI flag, and also reads a `SITEDRIFT_<NAME>` env var.
85
- Precedence is **flag > env > default**.
86
147
 
87
148
  | Flag | Env | Default | Purpose |
88
149
  |---|---|---|---|
@@ -91,36 +152,85 @@ Precedence is **flag > env > default**.
91
152
  | `-p, --port <n>` | `SITEDRIFT_PORT` | `4178` | Listen port. |
92
153
  | `--host <addr>` | `SITEDRIFT_HOST` | `127.0.0.1` | Bind address. |
93
154
  | `-o, --open` | — | off | Open the viewer in your browser. |
94
- | `--http` | — | | Force plain HTTP (ignore `--cert`/`--key`). |
95
- | `--cert <file>` / `--key <file>` | `SITEDRIFT_CERT` / `_KEY` | | If both set, serve over HTTPS. |
155
+ | `--https` | — | off | Serve HTTPS with an auto cert (mkcert if present, else openssl). |
156
+ | `--setup-https` | | | One-time: generate + trust a local cert, then exit. |
157
+ | `--http` | — | — | Force plain HTTP (the default; overrides `--https`). |
158
+ | `--cert <file>` / `--key <file>` | `SITEDRIFT_CERT` / `_KEY` | — | Bring your own cert; if both set, serve over HTTPS. |
96
159
  | `--notes <file>` | `SITEDRIFT_NOTES` | `$TMPDIR/sitedrift-notes.json` | Shared review-notes file. |
97
160
  | `--brand <text>` | `SITEDRIFT_BRAND` | — | Strip `\| <text>` from titles in pane headers. |
98
161
  | `--author <name>` | `SITEDRIFT_AUTHOR` | `you` | Byline for notes added in the viewer. |
99
162
  | `--vault <dir>` | `SITEDRIFT_VAULT` | — | Enable **Send to vault** (writes the review markdown here). |
163
+ | `--config <file>` | — | discovered | Read project configuration from JSON. |
100
164
 
101
165
  A positional `[path]` (e.g. `sitedrift /pricing`) sets the initial route.
102
166
  `-h, --help` and `-v, --version` do what you'd expect.
103
167
 
168
+ ### AI and automation
169
+
170
+ The running process writes a private mode-`0600` descriptor under
171
+ `~/.sitedrift/sessions/`. The npm package includes a zero-dependency stdio MCP
172
+ server and an `AGENTS.md` operating guide.
173
+
174
+ Configure an MCP host with:
175
+
176
+ ```json
177
+ {
178
+ "command": "sitedrift-mcp",
179
+ "args": []
180
+ }
181
+ ```
182
+
183
+ Codex and Claude Code can register it directly:
184
+
185
+ ```bash
186
+ codex mcp add sitedrift -- sitedrift-mcp
187
+ claude mcp add sitedrift -- sitedrift-mcp
188
+ ```
189
+
190
+ Without a global install:
191
+
192
+ ```json
193
+ {
194
+ "command": "npx",
195
+ "args": ["-y", "sitedrift", "mcp"]
196
+ }
197
+ ```
198
+
199
+ Agents call `sitedrift_context` first, then use the note tools to share findings
200
+ with the user. The server also exposes `sitedrift://guide`, a `review_route`
201
+ prompt, and `sitedrift_setup` for install/config/HTTPS guidance.
202
+
203
+ For hosts without MCP, use the JSON CLI instead of scraping the viewer or
204
+ constructing authenticated requests:
205
+
206
+ ```bash
207
+ sitedrift context
208
+ sitedrift notes list
209
+ sitedrift notes add "CTA differs" --route /pricing --side live --author codex
210
+ sitedrift notes resolve <id>
211
+ sitedrift notes reopen <id>
212
+ sitedrift notes remove <id>
213
+ sitedrift notes clear
214
+ ```
215
+
216
+ Commands print JSON and return non-zero on failure. They work over HTTP or local
217
+ HTTPS without an agent-specific SDK.
218
+
104
219
  ### HTTP endpoints
105
220
 
106
221
  | Route | Purpose |
107
222
  |---|---|
108
223
  | `GET /` | The viewer. |
109
224
  | `GET /health` | `{ dev, live, version }`. |
110
- | `GET /notes` · `POST /notes` | Read / mutate notes (`op: add\|remove\|toggle\|clear`). |
225
+ | `GET /api/v1/session` | Authenticated session context and capabilities. |
226
+ | `GET /api/v1/notes` · `POST /api/v1/notes` | Authenticated note list / operations. |
111
227
  | `GET /notes.md` | Notes as a Markdown checklist. |
112
- | `POST /notes/save` | Write the notes markdown into `--vault`. |
228
+ | `POST /api/v1/notes/save` | Write notes markdown into `--vault`. |
113
229
  | `GET /icon.svg` | The app mark / favicon. |
114
- | `GET /__dev/*` · `GET /__live/*` | Proxied origins. |
230
+ | frame ports: `GET /__dev/*` · `GET /__live/*` | Isolated proxied origins. |
115
231
 
116
- `POST /notes` requires `Content-Type: application/json`, so a cross-origin page
117
- can't forge a no-preflight write. Add a note from anywhere:
118
-
119
- ```bash
120
- curl -X POST localhost:4178/notes -H 'content-type: application/json' \
121
- -d '{"op":"add","text":"H1 on /about is larger on LIVE",
122
- "author":"claude","route":"/about","side":"live"}'
123
- ```
232
+ The control API requires the per-session bearer token. The CLI commands above
233
+ are the supported machine interface.
124
234
 
125
235
  Most viewer state (route, layout, scroll mode, focus) is mirrored into the URL
126
236
  query string, so a link reproduces the exact view.
@@ -131,12 +241,26 @@ query string, so a link reproduces the exact view.
131
241
 
132
242
  The proxy strips `Content-Security-Policy`, `X-Frame-Options`, and the
133
243
  Cross-Origin-{Embedder,Opener,Resource}-Policy headers so production can be
134
- framed next to dev. That is safe **only on loopback**:
244
+ framed next to dev.
135
245
 
136
- - It binds to `127.0.0.1` unless you override `--host`. **Do not** bind it to a
137
- public interface or put it behind a public proxy.
246
+ - Only loopback hosts are accepted, and Host headers are validated.
247
+ - The viewer/control API uses `--port`; DEV and LIVE frames use `--port + 1`
248
+ and `--port + 2`, so neither page can inspect the other.
249
+ - Framed pages communicate through a narrow `postMessage` bridge and cannot
250
+ access the viewer DOM, bearer token, notes API, or vault endpoint.
138
251
  - Treat the notes file as plaintext shared scratch space.
139
252
 
253
+ ## Development
254
+
255
+ ```bash
256
+ npm test
257
+ npm run test:e2e:visual
258
+ npm run test:e2e:visual:update # intentionally accept visual changes
259
+ ```
260
+
261
+ The visual suite uses deterministic origins and checked-in Chromium baselines
262
+ for desktop split, narrow Solo, difference overlay, and the notes drawer.
263
+
140
264
  ## Limitations
141
265
 
142
266
  - **URL rewriting is regex-based**, tuned for static sites (e.g. Astro builds).