@juangadm/pre-post 0.2.0 → 1.0.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.
Files changed (125) hide show
  1. package/README.md +102 -222
  2. package/dist/bin/cli.js +199 -347
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/browser.d.ts +42 -11
  5. package/dist/browser.d.ts.map +1 -1
  6. package/dist/browser.js +371 -94
  7. package/dist/browser.js.map +1 -1
  8. package/dist/capture.d.ts +1 -6
  9. package/dist/capture.d.ts.map +1 -1
  10. package/dist/capture.js +12 -35
  11. package/dist/capture.js.map +1 -1
  12. package/dist/commands/compare.d.ts +18 -0
  13. package/dist/commands/compare.d.ts.map +1 -0
  14. package/dist/commands/compare.js +64 -0
  15. package/dist/commands/compare.js.map +1 -0
  16. package/dist/commands/detect.d.ts +20 -0
  17. package/dist/commands/detect.d.ts.map +1 -0
  18. package/dist/commands/detect.js +19 -0
  19. package/dist/commands/detect.js.map +1 -0
  20. package/dist/commands/doctor.d.ts +10 -0
  21. package/dist/commands/doctor.d.ts.map +1 -0
  22. package/dist/commands/doctor.js +38 -0
  23. package/dist/commands/doctor.js.map +1 -0
  24. package/dist/commands/login.d.ts +6 -0
  25. package/dist/commands/login.d.ts.map +1 -0
  26. package/dist/commands/login.js +34 -0
  27. package/dist/commands/login.js.map +1 -0
  28. package/dist/commands/pr.d.ts +28 -0
  29. package/dist/commands/pr.d.ts.map +1 -0
  30. package/dist/commands/pr.js +159 -0
  31. package/dist/commands/pr.js.map +1 -0
  32. package/dist/commands/prune.d.ts +10 -0
  33. package/dist/commands/prune.d.ts.map +1 -0
  34. package/dist/commands/prune.js +13 -0
  35. package/dist/commands/prune.js.map +1 -0
  36. package/dist/config.d.ts +36 -0
  37. package/dist/config.d.ts.map +1 -0
  38. package/dist/config.js +60 -0
  39. package/dist/config.js.map +1 -0
  40. package/dist/diff-pool.d.ts +17 -0
  41. package/dist/diff-pool.d.ts.map +1 -0
  42. package/dist/diff-pool.js +89 -0
  43. package/dist/diff-pool.js.map +1 -0
  44. package/dist/diff-worker.d.ts +29 -0
  45. package/dist/diff-worker.d.ts.map +1 -0
  46. package/dist/diff-worker.js +38 -0
  47. package/dist/diff-worker.js.map +1 -0
  48. package/dist/diff.d.ts +37 -0
  49. package/dist/diff.d.ts.map +1 -0
  50. package/dist/diff.js +171 -0
  51. package/dist/diff.js.map +1 -0
  52. package/dist/doctor.d.ts +38 -0
  53. package/dist/doctor.d.ts.map +1 -0
  54. package/dist/doctor.js +72 -0
  55. package/dist/doctor.js.map +1 -0
  56. package/dist/errors.d.ts +38 -0
  57. package/dist/errors.d.ts.map +1 -0
  58. package/dist/errors.js +59 -0
  59. package/dist/errors.js.map +1 -0
  60. package/dist/filename.d.ts +2 -0
  61. package/dist/filename.d.ts.map +1 -1
  62. package/dist/filename.js +2 -1
  63. package/dist/filename.js.map +1 -1
  64. package/dist/git.d.ts +23 -0
  65. package/dist/git.d.ts.map +1 -0
  66. package/dist/git.js +86 -0
  67. package/dist/git.js.map +1 -0
  68. package/dist/github.d.ts +73 -0
  69. package/dist/github.d.ts.map +1 -0
  70. package/dist/github.js +240 -0
  71. package/dist/github.js.map +1 -0
  72. package/dist/index.d.ts +22 -22
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +17 -66
  75. package/dist/index.js.map +1 -1
  76. package/dist/pkg.d.ts +8 -0
  77. package/dist/pkg.d.ts.map +1 -0
  78. package/dist/pkg.js +35 -0
  79. package/dist/pkg.js.map +1 -0
  80. package/dist/report.d.ts +20 -0
  81. package/dist/report.d.ts.map +1 -0
  82. package/dist/report.js +107 -0
  83. package/dist/report.js.map +1 -0
  84. package/dist/routes/imports.d.ts +46 -0
  85. package/dist/routes/imports.d.ts.map +1 -0
  86. package/dist/routes/imports.js +208 -0
  87. package/dist/routes/imports.js.map +1 -0
  88. package/dist/routes/vite.d.ts +15 -0
  89. package/dist/routes/vite.d.ts.map +1 -0
  90. package/dist/routes/vite.js +130 -0
  91. package/dist/routes/vite.js.map +1 -0
  92. package/dist/routes.d.ts +41 -14
  93. package/dist/routes.d.ts.map +1 -1
  94. package/dist/routes.js +271 -141
  95. package/dist/routes.js.map +1 -1
  96. package/dist/run.d.ts +36 -0
  97. package/dist/run.d.ts.map +1 -0
  98. package/dist/run.js +128 -0
  99. package/dist/run.js.map +1 -0
  100. package/dist/sessions.d.ts +50 -0
  101. package/dist/sessions.d.ts.map +1 -0
  102. package/dist/sessions.js +74 -0
  103. package/dist/sessions.js.map +1 -0
  104. package/dist/types.d.ts +118 -41
  105. package/dist/types.d.ts.map +1 -1
  106. package/dist/types.js +1 -0
  107. package/dist/types.js.map +1 -1
  108. package/dist/viewport.d.ts +6 -1
  109. package/dist/viewport.d.ts.map +1 -1
  110. package/dist/viewport.js +13 -7
  111. package/dist/viewport.js.map +1 -1
  112. package/package.json +21 -13
  113. package/skill/SKILL.md +31 -229
  114. package/dist/clipboard.d.ts +0 -9
  115. package/dist/clipboard.d.ts.map +0 -1
  116. package/dist/clipboard.js +0 -26
  117. package/dist/clipboard.js.map +0 -1
  118. package/dist/upload.d.ts +0 -39
  119. package/dist/upload.d.ts.map +0 -1
  120. package/dist/upload.js +0 -149
  121. package/dist/upload.js.map +0 -1
  122. package/skill/scripts/adapters/0x0st.sh +0 -36
  123. package/skill/scripts/adapters/blob.sh +0 -55
  124. package/skill/scripts/adapters/git-native.sh +0 -51
  125. package/skill/scripts/upload-and-copy.sh +0 -230
package/README.md CHANGED
@@ -1,255 +1,135 @@
1
1
  # pre-post
2
2
 
3
- Visual diff tool that captures pre/post screenshots for PRs. Use it as a Claude Code skill for automatic visual documentation, or run it directly from the CLI.
4
-
5
- > Originally forked from [before-and-after](https://github.com/vercel-labs/before-and-after) by [James Clements](https://github.com/jamesclement) / Vercel Labs.
6
-
7
- ## What Changed from the Original
8
-
9
- | Area | before-and-after | pre-post |
10
- |------|-----------------|----------|
11
- | Browser engine | `agent-browser` (Vercel-proprietary) | **Playwright** (direct dependency) |
12
- | Screenshot quality | 1x | **2x retina** (`deviceScaleFactor: 2`) |
13
- | Route detection | Manual | **Automatic** from `git diff` (Next.js App/Pages Router, Remix, SvelteKit) |
14
- | Responsive capture | Single viewport | **Desktop + mobile** per route (`--responsive`) |
15
- | CLI subcommands | URL pairs only | `detect`, `compare`, `run` subcommands |
16
- | Skill orchestration | Basic capture | Full workflow: route detection, Claude refinement, user approval, PR posting |
17
- | Font/animation handling | None | Waits for `document.fonts.ready`, disables CSS animations |
18
-
19
- ## How It Works
20
-
21
- ```mermaid
22
- flowchart TD
23
- A[pre-post] --> B{Mode?}
24
-
25
- B -->|Manual| C["pre-post url1 url2"]
26
- B -->|Automatic| D["pre-post run"]
27
- B -->|Claude Code Skill| E["/pre-post"]
28
-
29
- D --> F["git diff --name-only"]
30
- F --> G{Detect framework}
31
- G -->|Next.js App Router| H[Map files → routes]
32
- G -->|Next.js Pages Router| H
33
- G -->|Remix / SvelteKit| H
34
- G -->|Unknown| I["Default to /"]
35
- H --> J[Route list with confidence]
36
-
37
- E --> F
38
- E --> K[Claude refines routes]
39
- K --> J
40
-
41
- C --> L[Playwright]
42
- J --> L
43
-
44
- L --> M{System Chrome?}
45
- M -->|Found| N[Use system Chrome]
46
- M -->|Not found| O[Use bundled Chromium]
47
- N --> P[Capture screenshots]
48
- O --> P
49
-
50
- P --> Q[Disable animations]
51
- Q --> R[Wait for fonts]
52
- R --> S[Take 2x retina screenshot]
53
-
54
- S --> T{Output}
55
- T -->|Default| U["Save to ~/Downloads"]
56
- T -->|--markdown| V{Upload}
57
- V -->|Default| W["Commit to .pre-post/ (blob+SHA URL)"]
58
- V -->|--upload-url| Y["Custom storage"]
59
- W --> Z[Markdown table for PR]
60
- Y --> Z
61
-
62
- style A fill:#4f46e5,color:#fff
63
- style L fill:#2563eb,color:#fff
64
- style S fill:#059669,color:#fff
65
- ```
66
-
67
- ## Prerequisites
68
-
69
- - **Node.js** 18+
70
- - **Chromium** — install once via Playwright:
71
-
72
- ```bash
73
- npx playwright install chromium
74
- ```
75
-
76
- ## CI / Sandboxed Environments
77
-
78
- pre-post needs a Chromium binary. In restricted environments where `npx playwright install chromium` fails (CDN blocked):
79
-
80
- ```bash
81
- # Point to a pre-installed Chrome/Chromium binary
82
- export PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/path/to/chrome
83
-
84
- # This is treated as an explicit override — pre-post will fail with a
85
- # clear error if the path is wrong, rather than silently falling back.
86
- ```
87
-
88
- When no custom path is set, pre-post auto-detects in order: system Chrome, bundled Playwright Chromium, then any builds in `~/.cache/ms-playwright/`.
89
-
90
- If no browser is available at all, use image-only mode:
91
-
92
- ```bash
93
- pre-post before.png after.png --markdown
94
- ```
95
-
96
- **Proxy URLs**: If your git remote uses a proxy (e.g., `http://proxy@host/git/owner/repo`), set the repo explicitly:
97
-
98
- ```bash
99
- export GH_REPO=owner/repo
100
- ```
101
-
102
- **Google Fonts**: Container egress proxies typically block `fonts.googleapis.com`.
103
- Screenshots will render with system font fallbacks. This is cosmetic only —
104
- `document.fonts.ready` still resolves and layout is preserved.
3
+ Before/after screenshots for pull requests. One command detects the routes your branch
4
+ changed, captures them on production ("Pre") and on your dev server ("Post"), pixel-diffs
5
+ them, uploads the images to GitHub, and posts a single comment on the PR that a reviewer
6
+ can judge at a glance.
7
+
8
+ > Originally forked from [before-and-after](https://github.com/vercel-labs/before-and-after) by James Clements / Vercel Labs.
9
+
10
+ ```
11
+ $ npx -y @juangadm/pre-post@latest pr
12
+
13
+ Routes (nextjs-app, 41ms): /, /pricing
14
+ / medium src/app/page.tsx imports src/components/ui/button.tsx (2 hops)
15
+ /pricing medium src/app/pricing/page.tsx imports src/components/ui/button.tsx (2 hops)
16
+ Capturing 8 screenshots (2 route(s) × 2 viewport(s)) ...
17
+ changed /pricing @ mobile (1.42%, 1811ms)
18
+ changed /pricing @ desktop (0.64%, 2036ms)
19
+ same / @ mobile (0.00%, 1990ms)
20
+ same / @ desktop (0.00%, 2211ms)
21
+ Publishing 10 image(s) to acme/web@pre-post-assets ...
22
+ Updated PR comment: https://github.com/acme/web/pull/42#issuecomment-1
23
+ pre-post · PR #42 · 2 route(s) · 2 viewport(s) · 6.8s
24
+ / desktop no change
25
+ / mobile no change
26
+ /pricing desktop 0.64% changed
27
+ /pricing mobile 1.4% changed
28
+ Comment: https://github.com/acme/web/pull/42#issuecomment-1
29
+ ```
30
+
31
+ ## How it works
32
+
33
+ 1. **Routes.** Diffs the branch against the merge base with `main`, then follows the import
34
+ graph: a change to `components/ui/button.tsx` marks every page that imports it. Next.js
35
+ App Router and Pages Router, Vite apps (React Router, file-based `src/pages`), and a
36
+ generic fallback. Monorepos are handled by picking the app that owns the changed files.
37
+ 2. **Capture.** Playwright + Chromium headless shell. Fixed clock, reduced motion,
38
+ animations finished, caret hidden, fonts and images settled, layout stable across frames,
39
+ lazy content primed. 2x device scale, full page (capped at 2400 CSS px), desktop + mobile.
40
+ All routes and viewports run concurrently.
41
+ 3. **Diff.** Pure-JS pixel comparison in worker threads. Reports the percentage changed,
42
+ the bounding box, a red-highlight image, and a tight crop of the changed region.
43
+ 4. **Publish.** Images go to a `pre-post-assets` branch in the same repository via the GitHub
44
+ API, as one commit per run. Nothing is committed to the PR branch, no CI is triggered,
45
+ and the blob URLs render on private repos. `pre-post prune` removes images for PRs
46
+ closed more than 90 days ago.
47
+ 5. **Comment.** One sticky comment per PR, updated in place on every run. Changed routes show
48
+ a Pre/Post crop with the full page and diff collapsed underneath; unchanged routes fold
49
+ into a single line.
105
50
 
106
51
  ## Install
107
52
 
108
- ```bash
109
- npm install -D @juangadm/pre-post
110
- ```
111
-
112
- ## Basic Use
113
-
114
- ### As a Claude Code Skill (recommended)
115
-
116
- After making visual UI changes, say `/pre-post` or "take pre and post screenshots". Claude will:
117
-
118
- 1. Detect affected routes from your git diff
119
- 2. Propose routes for your approval
120
- 3. Capture desktop + mobile screenshots (production vs localhost)
121
- 4. Show you the screenshots for approval
122
- 5. Upload and append markdown to your PR
123
-
124
- ### From the CLI
125
-
126
- Capture any two URLs:
127
-
128
- ```bash
129
- pre-post site.com localhost:3000
130
- ```
131
-
132
- Use existing images:
133
-
134
- ```bash
135
- pre-post before.png after.png
136
- ```
137
-
138
- ## CLI Subcommands
139
-
140
- ### `detect` -- Route Detection
141
-
142
- Detect affected routes from git changes:
143
-
144
- ```bash
145
- pre-post detect # Auto-detect framework
146
- pre-post detect --framework nextjs-app # Force framework
147
- ```
148
-
149
- Outputs JSON with route paths, confidence levels, and source files.
150
-
151
- ### `compare` -- URL Comparison
53
+ Nothing to install. `npx -y @juangadm/pre-post@latest pr` downloads the CLI and, on first
54
+ use, the Chromium headless shell (~80 MB). You need Node 20+ and a GitHub token: either
55
+ `gh auth login` or `GH_TOKEN`.
152
56
 
153
- Compare pre/post states across routes:
57
+ As a Claude Code skill:
154
58
 
155
59
  ```bash
156
- pre-post compare --before-base https://prod.com --after-base http://localhost:3000
157
- pre-post compare --before-base URL --after-base URL --routes /dashboard,/settings
158
- pre-post compare --before-base URL --after-base URL --responsive # Desktop + mobile
60
+ npx skills add juangadm/pre-post -y
159
61
  ```
160
62
 
161
- ### `run` -- Full Auto
162
-
163
- Combines `detect` + `compare`:
164
-
165
- ```bash
166
- pre-post run --before-base https://prod.com --after-base http://localhost:3000
167
- ```
168
-
169
- ## Options
170
-
171
- Capture a specific element using a CSS selector:
172
-
173
- ```bash
174
- pre-post url1 url2 ".hero"
175
- ```
63
+ Then say `/pre-post` after making UI changes.
176
64
 
177
- Use different selectors for pre and post:
65
+ ## Usage
178
66
 
179
67
  ```bash
180
- pre-post url1 url2 ".old" ".new"
181
- ```
182
-
183
- Capture at mobile (375x812), tablet (768x1024), or custom viewport:
68
+ pre-post pr # everything, on the current branch's PR
69
+ pre-post pr --before https://acme.com # first run in a repo (saved to .pre-post.json)
70
+ pre-post pr --routes /pricing,/docs # explicit routes
71
+ pre-post pr --viewports desktop,1440x900 # custom viewports
72
+ pre-post pr --dry-run # capture + diff locally, post nothing
73
+ pre-post pr --json # machine-readable output
184
74
 
185
- ```bash
186
- pre-post url1 url2 --mobile
187
- pre-post url1 url2 --size 1920x1080
75
+ pre-post https://acme.com http://localhost:3000 --routes /pricing # ad-hoc comparison
76
+ pre-post before.png after.png # diff two images
77
+ pre-post detect # which routes does this branch touch?
78
+ pre-post login https://staging.acme.com # sign in once; the session is reused
79
+ pre-post prune --days 90 # clean up the assets branch
80
+ pre-post doctor # browser, token, dev server, config
188
81
  ```
189
82
 
190
- Capture the entire scrollable page:
83
+ When something needs a human, the CLI exits with code 3 and one sentence saying what to do
84
+ (log in, start the dev server, pass `--before`). Re-running picks up where it left off.
191
85
 
192
- ```bash
193
- pre-post url1 url2 --full
194
- ```
86
+ ## Configuration
195
87
 
196
- Output a markdown table for PR descriptions:
88
+ Optional `.pre-post.json` in the repo root:
197
89
 
198
- ```bash
199
- pre-post url1 url2 --markdown
90
+ ```json
91
+ {
92
+ "before": "https://acme.com",
93
+ "routes": ["/"],
94
+ "samples": { "/blog/[slug]": "/blog/hello-world" },
95
+ "viewports": ["desktop", "mobile"],
96
+ "fullPage": true,
97
+ "maxHeight": 2400,
98
+ "scale": 2,
99
+ "threshold": 0.001,
100
+ "minChangedPixels": 40,
101
+ "maxRoutes": 6,
102
+ "ignore": ["apps/docs"],
103
+ "headers": {},
104
+ "assetsBranch": "pre-post-assets"
105
+ }
200
106
  ```
201
107
 
202
- Save to a custom location:
108
+ Environment:
203
109
 
204
- ```bash
205
- pre-post url1 url2 --output ./screenshots
206
- ```
110
+ | Variable | Purpose |
111
+ |---|---|
112
+ | `GH_TOKEN` / `GITHUB_TOKEN` | GitHub token (default: `gh auth token`) |
113
+ | `VERCEL_AUTOMATION_BYPASS_SECRET` | Bypass Vercel Deployment Protection on the production URL |
114
+ | `PRE_POST_CONCURRENCY` | Parallel pages (default 6) |
115
+ | `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` | Use a specific Chromium binary |
116
+ | `GH_REPO` | `owner/repo` when the remote URL cannot be parsed |
207
117
 
208
- Upload to a custom image storage service:
118
+ ## Library
209
119
 
210
- ```bash
211
- pre-post url1 url2 --markdown --upload-url https://my-s3-bucket.amazonaws.com
120
+ ```ts
121
+ import { runPr, captureScreenshot, diffImages, detectRoutesForRepo } from '@juangadm/pre-post';
212
122
  ```
213
123
 
214
- By default, `--markdown` commits screenshots to the PR branch (under `.pre-post/`) and serves them via GitHub blob URLs pinned to the commit SHA. This works for both public and private repos. Use `--upload-url` to point at your own storage instead. It auto-detects the protocol for 0x0.st, Vercel Blob, and any generic PUT endpoint (like S3). Screenshots auto-append to the PR body, newest on top.
215
-
216
- ## Route Detection
217
-
218
- Pre-post automatically maps `git diff --name-only` to affected UI routes:
219
-
220
- | Changed File | Detected Route | Confidence |
221
- |---|---|---|
222
- | `app/page.tsx` | `/` | high |
223
- | `app/dashboard/page.tsx` | `/dashboard` | high |
224
- | `app/(marketing)/about/page.tsx` | `/about` (strips route groups) | high |
225
- | `app/blog/[slug]/page.tsx` | `/blog/[slug]` | high |
226
- | `app/dashboard/layout.tsx` | `/dashboard` | medium |
227
- | `app/dashboard/components/Chart.tsx` | `/dashboard` | medium |
228
- | `globals.css`, `tailwind.config.ts` | `/` | low |
229
- | `app/api/*`, `middleware.ts` | Skipped (no visual) | -- |
230
-
231
- Supports:
232
- - **Next.js App Router** (route groups, dynamic segments, parallel routes, catch-all)
233
- - **Next.js Pages Router** (`pages/`, `_app.tsx`, `_document.tsx`)
234
- - **Remix** (`routes/` directory)
235
- - **SvelteKit** (`src/routes/+page.svelte`)
236
- - **Generic fallback** (defaults to `/`)
237
-
238
- ## Add Skill
239
-
240
- Install as a Claude Code skill:
124
+ ## Development
241
125
 
242
126
  ```bash
243
- npx skills add juangadm/pre-post
127
+ pnpm install
128
+ pnpm build
129
+ pnpm test:unit
130
+ TEST_BROWSER=true pnpm test # needs a Chromium; npx playwright-core install chromium-headless-shell
244
131
  ```
245
132
 
246
- The skill uses `gh` to detect the associated PR and Playwright for screenshots.
247
-
248
- ## Credits
249
-
250
- - Original [before-and-after](https://github.com/vercel-labs/before-and-after) by [James Clements](https://github.com/jamesclement) at [Vercel Labs](https://github.com/vercel-labs)
251
- - Browser automation powered by [Playwright](https://playwright.dev/)
252
-
253
133
  ## License
254
134
 
255
135
  MIT