@juangadm/pre-post 1.0.0 → 1.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/README.md +99 -20
- package/dist/baseline.d.ts +208 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +413 -0
- package/dist/baseline.js.map +1 -0
- package/dist/bin/cli.js +87 -42
- package/dist/bin/cli.js.map +1 -1
- package/dist/browser.d.ts +31 -3
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +291 -97
- package/dist/browser.js.map +1 -1
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +21 -3
- package/dist/commands/compare.js.map +1 -1
- package/dist/commands/detect.d.ts +5 -0
- package/dist/commands/detect.d.ts.map +1 -1
- package/dist/commands/detect.js +4 -1
- package/dist/commands/detect.js.map +1 -1
- package/dist/commands/doctor.d.ts +32 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +90 -9
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/pr.d.ts +4 -0
- package/dist/commands/pr.d.ts.map +1 -1
- package/dist/commands/pr.js +157 -51
- package/dist/commands/pr.js.map +1 -1
- package/dist/commands/prune.js +1 -1
- package/dist/commands/prune.js.map +1 -1
- package/dist/comparison.d.ts +104 -0
- package/dist/comparison.d.ts.map +1 -0
- package/dist/comparison.js +241 -0
- package/dist/comparison.js.map +1 -0
- package/dist/config.d.ts +12 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +25 -3
- package/dist/config.js.map +1 -1
- package/dist/deployments.d.ts +71 -0
- package/dist/deployments.d.ts.map +1 -0
- package/dist/deployments.js +204 -0
- package/dist/deployments.js.map +1 -0
- package/dist/diff-pool.d.ts.map +1 -1
- package/dist/diff-pool.js +5 -2
- package/dist/diff-pool.js.map +1 -1
- package/dist/diff-worker.d.ts +3 -0
- package/dist/diff-worker.d.ts.map +1 -1
- package/dist/diff-worker.js +1 -0
- package/dist/diff-worker.js.map +1 -1
- package/dist/diff.d.ts +10 -0
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +117 -7
- package/dist/diff.js.map +1 -1
- package/dist/doctor.d.ts +42 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +73 -7
- package/dist/doctor.js.map +1 -1
- package/dist/git.d.ts +41 -3
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +103 -7
- package/dist/git.js.map +1 -1
- package/dist/github.d.ts +92 -2
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +191 -20
- package/dist/github.js.map +1 -1
- package/dist/landing.d.ts +48 -0
- package/dist/landing.d.ts.map +1 -0
- package/dist/landing.js +93 -0
- package/dist/landing.js.map +1 -0
- package/dist/pkg.d.ts +9 -0
- package/dist/pkg.d.ts.map +1 -1
- package/dist/pkg.js +14 -0
- package/dist/pkg.js.map +1 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +59 -28
- package/dist/report.js.map +1 -1
- package/dist/routes.d.ts +27 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +98 -23
- package/dist/routes.js.map +1 -1
- package/dist/run.d.ts +88 -8
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +224 -28
- package/dist/run.js.map +1 -1
- package/dist/sameness.d.ts +91 -0
- package/dist/sameness.d.ts.map +1 -0
- package/dist/sameness.js +157 -0
- package/dist/sameness.js.map +1 -0
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +7 -1
- package/dist/sessions.js.map +1 -1
- package/dist/shift.d.ts +67 -0
- package/dist/shift.d.ts.map +1 -0
- package/dist/shift.js +184 -0
- package/dist/shift.js.map +1 -0
- package/dist/types.d.ts +83 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -1
- package/dist/url.d.ts +12 -0
- package/dist/url.d.ts.map +1 -0
- package/dist/url.js +30 -0
- package/dist/url.js.map +1 -0
- package/package.json +1 -1
- package/skill/SKILL.md +40 -7
package/dist/types.d.ts
CHANGED
|
@@ -48,6 +48,14 @@ export interface CaptureResult {
|
|
|
48
48
|
selector?: string;
|
|
49
49
|
/** HTTP status of the main document */
|
|
50
50
|
status?: number;
|
|
51
|
+
/** URL the browser ended on, which is not the requested one after a redirect */
|
|
52
|
+
finalUrl?: string;
|
|
53
|
+
/** Document title, used to recognise a sign-in wall that answered with 200 */
|
|
54
|
+
title?: string;
|
|
55
|
+
/** Visible text, used to tell "the same site, changed" from "a different site" */
|
|
56
|
+
text?: string;
|
|
57
|
+
/** Response looked like it came from Vercel (deployment protection) */
|
|
58
|
+
vercel?: boolean;
|
|
51
59
|
/** Wall-clock milliseconds for navigation + settle + screenshot */
|
|
52
60
|
durationMs: number;
|
|
53
61
|
}
|
|
@@ -87,6 +95,23 @@ export interface DiffResult {
|
|
|
87
95
|
after: Buffer;
|
|
88
96
|
region: DiffRegion;
|
|
89
97
|
};
|
|
98
|
+
/** Vertical displacement explaining most of the difference, when one does */
|
|
99
|
+
shift?: ShiftSummary;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* A layout shift: Post content moved down (or up) by a constant amount from a
|
|
103
|
+
* given row, and what remains different once the two sides are put back in
|
|
104
|
+
* register. Plain numbers, so it survives the worker-thread boundary.
|
|
105
|
+
*/
|
|
106
|
+
export interface ShiftSummary {
|
|
107
|
+
/** Device pixels Post content moved down by; negative means up. */
|
|
108
|
+
dy: number;
|
|
109
|
+
/** First row, in Pre coordinates, that moved. Rows above it stayed put. */
|
|
110
|
+
from: number;
|
|
111
|
+
/** Changed pixels once Post is aligned with Pre. */
|
|
112
|
+
alignedChangedPixels: number;
|
|
113
|
+
/** Aligned changed pixels as a fraction of the canvas. */
|
|
114
|
+
alignedChangedRatio: number;
|
|
90
115
|
}
|
|
91
116
|
export type Framework = 'nextjs-app' | 'nextjs-pages' | 'vite' | 'generic';
|
|
92
117
|
export interface DetectedRoute {
|
|
@@ -104,6 +129,8 @@ export interface RouteDetectionOptions {
|
|
|
104
129
|
framework?: Framework;
|
|
105
130
|
/** Maximum number of routes to return (default: 6) */
|
|
106
131
|
maxRoutes?: number;
|
|
132
|
+
/** Where warnings go. Left unset, they are silent. */
|
|
133
|
+
log?: (msg: string) => void;
|
|
107
134
|
}
|
|
108
135
|
export interface PrePostConfig {
|
|
109
136
|
/** Production base URL — the "before" state */
|
|
@@ -114,13 +141,16 @@ export interface PrePostConfig {
|
|
|
114
141
|
routes?: string[];
|
|
115
142
|
/** Sample URLs for dynamic routes, e.g. { "/blog/[slug]": "/blog/hello" } */
|
|
116
143
|
samples?: Record<string, string>;
|
|
117
|
-
/** Viewports to capture. Default: ["desktop"
|
|
144
|
+
/** Viewports to capture. Default: ["desktop"] */
|
|
118
145
|
viewports?: Array<ViewportPreset | string>;
|
|
119
146
|
/** Extra headers for every request */
|
|
120
147
|
headers?: Record<string, string>;
|
|
121
148
|
/** Change ratio (fraction 0..1) at or above which a route counts as changed. Default 0.001 */
|
|
122
149
|
threshold?: number;
|
|
123
150
|
/** Absolute changed-pixel floor at or above which a route counts as changed, so small edits on tall pages register. Default 40 */
|
|
151
|
+
/** Smallest painted change that counts, in CSS pixels². */
|
|
152
|
+
minChangedArea?: number;
|
|
153
|
+
/** @deprecated device pixels; use minChangedArea. Converted at the capture scale. */
|
|
124
154
|
minChangedPixels?: number;
|
|
125
155
|
/** Max detected routes. Default 6 */
|
|
126
156
|
maxRoutes?: number;
|
|
@@ -137,32 +167,80 @@ export interface PrePostConfig {
|
|
|
137
167
|
}
|
|
138
168
|
/** Pre, post, and (when there was a change) diff and crop images, as local paths or URLs. */
|
|
139
169
|
export interface ArtifactSet {
|
|
140
|
-
|
|
141
|
-
|
|
170
|
+
/** Absent when the route has no baseline (a page this branch adds). */
|
|
171
|
+
before?: string;
|
|
172
|
+
/** Absent when the branch removed the route. */
|
|
173
|
+
after?: string;
|
|
142
174
|
diff?: string;
|
|
143
175
|
cropBefore?: string;
|
|
144
176
|
cropAfter?: string;
|
|
145
177
|
}
|
|
146
178
|
export declare const ARTIFACT_KINDS: readonly ["before", "after", "diff", "cropBefore", "cropAfter"];
|
|
179
|
+
export type ArtifactKind = typeof ARTIFACT_KINDS[number];
|
|
180
|
+
/**
|
|
181
|
+
* The filename segment for an artifact kind, e.g. `home-desktop-<segment>.png`.
|
|
182
|
+
*
|
|
183
|
+
* One mapping, because two of them is what went wrong: the capture wrote
|
|
184
|
+
* `-pre`/`-post` while the assets branch published `-before`/`-after`, so the
|
|
185
|
+
* file on disk and the image in the PR had different names for the same
|
|
186
|
+
* screenshot. Renaming the literals on one side would only have moved the
|
|
187
|
+
* seam — the crops would still have been `-before-crop` locally and
|
|
188
|
+
* `-cropBefore` published.
|
|
189
|
+
*/
|
|
190
|
+
export declare function artifactSuffix(kind: ArtifactKind): string;
|
|
147
191
|
export interface RouteCaptureOutcome {
|
|
148
192
|
route: string;
|
|
149
193
|
/** Route actually requested (after sample substitution) */
|
|
150
194
|
resolvedRoute: string;
|
|
151
195
|
viewport: string;
|
|
152
|
-
status: 'changed' | 'unchanged' | 'error';
|
|
196
|
+
status: 'changed' | 'unchanged' | 'added' | 'removed' | 'error';
|
|
153
197
|
changedRatio?: number;
|
|
154
198
|
sizeChanged?: boolean;
|
|
155
199
|
error?: string;
|
|
156
200
|
files?: ArtifactSet;
|
|
157
201
|
urls?: ArtifactSet;
|
|
158
202
|
durationMs?: number;
|
|
159
|
-
/**
|
|
203
|
+
/** sha1 of the baseline capture, for spotting a host that serves one page for every route */
|
|
204
|
+
baselineHash?: string;
|
|
205
|
+
/** Extra context, e.g. "new page — no baseline (example.com returned 404)" */
|
|
160
206
|
note?: string;
|
|
207
|
+
/** Vertical displacement of Post against Pre, when one explains the change */
|
|
208
|
+
shift?: RouteShift;
|
|
209
|
+
/** A side answered with a sign-in wall, so nothing was really compared */
|
|
210
|
+
blocked?: BlockedSide;
|
|
211
|
+
/**
|
|
212
|
+
* How much of the two sides' wording is shared, or null when neither page
|
|
213
|
+
* had enough text to judge. Near zero on every route means the two sides are
|
|
214
|
+
* different sites, which a pixel ratio cannot tell you — see `sameness.ts`.
|
|
215
|
+
*/
|
|
216
|
+
textOverlap?: number | null;
|
|
217
|
+
/**
|
|
218
|
+
* The same measure over the two titles. A title is where a site names
|
|
219
|
+
* itself, so it corroborates a run that only has one route to judge.
|
|
220
|
+
*/
|
|
221
|
+
titleOverlap?: number | null;
|
|
222
|
+
}
|
|
223
|
+
export interface BlockedSide {
|
|
224
|
+
side: 'before' | 'after';
|
|
225
|
+
/** The sign-in page the capture landed on */
|
|
226
|
+
finalUrl: string;
|
|
227
|
+
/** Deployment protection, so the bypass secret is the fix */
|
|
228
|
+
vercel: boolean;
|
|
229
|
+
}
|
|
230
|
+
export interface RouteShift {
|
|
231
|
+
/** CSS pixels the content moved down by; negative means up. */
|
|
232
|
+
px: number;
|
|
233
|
+
/** Whether anything changed beyond the move, judged by the same rule as any other capture. */
|
|
234
|
+
otherChange: boolean;
|
|
235
|
+
/** Changed share once the move is undone; `changedRatio` is the raw figure. */
|
|
236
|
+
residualRatio: number;
|
|
161
237
|
}
|
|
162
238
|
export interface PrRunResult {
|
|
163
239
|
repo: string;
|
|
164
240
|
prNumber?: number;
|
|
165
241
|
commentUrl?: string;
|
|
242
|
+
/** Whether `commentUrl` points at the PR description or at a comment. */
|
|
243
|
+
commentKind?: 'description' | 'comment';
|
|
166
244
|
beforeBase: string;
|
|
167
245
|
afterBase: string;
|
|
168
246
|
outcomes: RouteCaptureOutcome[];
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE7D,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,YAAY,CAAC;AAE3D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,cAAc,EAAE,YAAY,CAIjE,CAAC;AAMF,MAAM,WAAW,WAAW;IAC1B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,wCAAwC;IACxC,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChG;AAED,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,QAAQ,EAAE,YAAY,CAAC;IACvB,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,cAAc,GAAG,MAAM,CAAC;IAChC,KAAK,EAAE,cAAc,GAAG,MAAM,CAAC;IAC/B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,aAAa,CAAC;CACtB;AAMD,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,sDAAsD;IACtD,WAAW,EAAE,OAAO,CAAC;IACrB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -7,4 +7,21 @@ export const VIEWPORT_PRESETS = {
|
|
|
7
7
|
mobile: { width: 375, height: 812 },
|
|
8
8
|
};
|
|
9
9
|
export const ARTIFACT_KINDS = ['before', 'after', 'diff', 'cropBefore', 'cropAfter'];
|
|
10
|
+
/**
|
|
11
|
+
* The filename segment for an artifact kind, e.g. `home-desktop-<segment>.png`.
|
|
12
|
+
*
|
|
13
|
+
* One mapping, because two of them is what went wrong: the capture wrote
|
|
14
|
+
* `-pre`/`-post` while the assets branch published `-before`/`-after`, so the
|
|
15
|
+
* file on disk and the image in the PR had different names for the same
|
|
16
|
+
* screenshot. Renaming the literals on one side would only have moved the
|
|
17
|
+
* seam — the crops would still have been `-before-crop` locally and
|
|
18
|
+
* `-cropBefore` published.
|
|
19
|
+
*/
|
|
20
|
+
export function artifactSuffix(kind) {
|
|
21
|
+
switch (kind) {
|
|
22
|
+
case 'cropBefore': return 'before-crop';
|
|
23
|
+
case 'cropAfter': return 'after-crop';
|
|
24
|
+
default: return kind;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
10
27
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,WAAW;AACX,+DAA+D;AAW/D,MAAM,CAAC,MAAM,gBAAgB,GAAyC;IACpE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IACrC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IACpC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;CACpC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,WAAW;AACX,+DAA+D;AAW/D,MAAM,CAAC,MAAM,gBAAgB,GAAyC;IACpE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IACrC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IACpC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;CACpC,CAAC;AAmMF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,CAAU,CAAC;AAI9F;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,IAAkB;IAC/C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,YAAY,CAAC,CAAC,OAAO,aAAa,CAAC;QACxC,KAAK,WAAW,CAAC,CAAC,OAAO,YAAY,CAAC;QACtC,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC;IACvB,CAAC;AACH,CAAC"}
|
package/dist/url.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL helpers shared by the capture layer and the command pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of run.ts so browser.ts can ask "is this loopback?" without
|
|
5
|
+
* importing the module that imports it.
|
|
6
|
+
*/
|
|
7
|
+
/** Is this URL served from the machine running the command? */
|
|
8
|
+
export declare function isLocalUrl(url: string): boolean;
|
|
9
|
+
export declare function normalizeUrl(url: string): string;
|
|
10
|
+
export declare function hostOf(url: string): string;
|
|
11
|
+
export declare function joinUrl(base: string, route: string): string;
|
|
12
|
+
//# sourceMappingURL=url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM1C;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3D"}
|
package/dist/url.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL helpers shared by the capture layer and the command pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of run.ts so browser.ts can ask "is this loopback?" without
|
|
5
|
+
* importing the module that imports it.
|
|
6
|
+
*/
|
|
7
|
+
/** Add a scheme to a bare URL (http for loopback hosts, https otherwise) and drop trailing slashes. */
|
|
8
|
+
const LOOPBACK = /^(?:(?:https?|file):\/\/)?(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(:|\/|$)/i;
|
|
9
|
+
/** Is this URL served from the machine running the command? */
|
|
10
|
+
export function isLocalUrl(url) {
|
|
11
|
+
return LOOPBACK.test(url);
|
|
12
|
+
}
|
|
13
|
+
export function normalizeUrl(url) {
|
|
14
|
+
const withScheme = /^(https?|file):\/\//i.test(url)
|
|
15
|
+
? url
|
|
16
|
+
: isLocalUrl(url) ? `http://${url}` : `https://${url}`;
|
|
17
|
+
return withScheme.replace(/\/+$/, '');
|
|
18
|
+
}
|
|
19
|
+
export function hostOf(url) {
|
|
20
|
+
try {
|
|
21
|
+
return new URL(url).host;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return url;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function joinUrl(base, route) {
|
|
28
|
+
return base.replace(/\/+$/, '') + (route.startsWith('/') ? route : `/${route}`);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=url.js.map
|
package/dist/url.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url.js","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,uGAAuG;AACvG,MAAM,QAAQ,GAAG,gFAAgF,CAAC;AAElG,+DAA+D;AAC/D,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC;QACjD,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,EAAE,CAAC;IACzD,OAAO,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,KAAa;IACjD,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;AAClF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juangadm/pre-post",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Before/after screenshots for pull requests: detect changed routes, capture, pixel-diff, and post a sticky PR comment",
|
|
5
5
|
"author": "Juan Gabriel Delgado (forked from James Clements)",
|
|
6
6
|
"license": "MIT",
|
package/skill/SKILL.md
CHANGED
|
@@ -10,9 +10,31 @@ allowed-tools:
|
|
|
10
10
|
# pre-post
|
|
11
11
|
|
|
12
12
|
One command does everything: detects the routes this branch changed, screenshots them on
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
desktop, pixel-diffs them, uploads the images to a `pre-post-assets` branch, and
|
|
14
|
+
posts or updates a single comment on the open PR. The human reviews on GitHub.
|
|
15
|
+
|
|
16
|
+
It picks both sides itself:
|
|
17
|
+
|
|
18
|
+
- **Post** (this branch) — the PR's preview deployment when one exists, read from the GitHub
|
|
19
|
+
Deployments API or, for providers that only comment (Vercel's GitHub app does), from the
|
|
20
|
+
deployment bot's PR comment. Otherwise a dev server: one already running, or one it starts
|
|
21
|
+
and stops itself.
|
|
22
|
+
- **Pre** (the baseline) — `before` from `.pre-post.json`, otherwise the production
|
|
23
|
+
deployment for the commit this branch forked from, otherwise that base commit itself,
|
|
24
|
+
checked out into a throwaway worktree and served locally.
|
|
25
|
+
|
|
26
|
+
Both sides always come from the same kind of environment. Pairing a deployment against a
|
|
27
|
+
dev server would compare different builds — a dev server renders Next.js's dev badge that
|
|
28
|
+
production never shows — so a diff would carry changes the branch never made.
|
|
29
|
+
|
|
30
|
+
So on a PR with a preview deployment, no dev server and no checkout are needed — anyone on
|
|
31
|
+
the team can run it against anyone's PR. With nothing deployed and nothing running, it
|
|
32
|
+
serves both sides itself.
|
|
33
|
+
|
|
34
|
+
The last baseline needs no network at all, so the tool still works inside a sandbox, a CI
|
|
35
|
+
container, or behind an egress allowlist where no deployment URL is reachable. It also
|
|
36
|
+
compares against exactly what the branch forked from, rendered in the same environment as
|
|
37
|
+
the Post side. Pass `--no-local-baseline` to turn it off.
|
|
16
38
|
|
|
17
39
|
## Run
|
|
18
40
|
|
|
@@ -20,14 +42,25 @@ comment on the open PR. The human reviews on GitHub.
|
|
|
20
42
|
npx -y @juangadm/pre-post@latest pr
|
|
21
43
|
```
|
|
22
44
|
|
|
23
|
-
Add `--
|
|
24
|
-
|
|
45
|
+
Add `--routes /a,/b` when the user names pages explicitly. Add
|
|
46
|
+
`--before https://production-url` only if the run reports it cannot work out the baseline
|
|
47
|
+
(it is then saved to `.pre-post.json` for next time).
|
|
48
|
+
|
|
49
|
+
## What it posts
|
|
50
|
+
|
|
51
|
+
The visual changes go at the **top of the PR description**, in a delimited block that
|
|
52
|
+
re-runs replace in place — the author's own text is never touched. If the PR cannot be
|
|
53
|
+
edited (a fork, a read-only token) it falls back to a single sticky comment.
|
|
54
|
+
|
|
55
|
+
Each changed route shows **Pre beside Post**, per viewport, full pages in a `<details>`. No
|
|
56
|
+
overlay, no percentage. A page that moved says `Content shifted down 48px`; relay as written.
|
|
25
57
|
|
|
26
58
|
## Rules
|
|
27
59
|
|
|
28
60
|
- Run the command once. Do not open, read, or describe the screenshot files; the PR
|
|
29
61
|
comment is the deliverable. Report the summary the command prints, plus the comment link.
|
|
30
|
-
- Do not start dev servers,
|
|
62
|
+
- Do not switch branches, start dev servers, or use a browser tool yourself. The command
|
|
63
|
+
handles all three.
|
|
31
64
|
- Exit code 3 means a human must do one thing (log in, start the dev server, pass
|
|
32
65
|
`--before`). Relay that one sentence verbatim and stop.
|
|
33
66
|
- Do not use `--dry-run` unless the user asks to preview without posting.
|
|
@@ -39,7 +72,7 @@ Add `--before https://production-url` the first time in a repo (it is saved to
|
|
|
39
72
|
| Flag | Use when |
|
|
40
73
|
|------|----------|
|
|
41
74
|
| `--routes /a,/b` | The user names the pages |
|
|
42
|
-
| `--
|
|
75
|
+
| `-r`, `--responsive` | Desktop and mobile (default is desktop only) |
|
|
43
76
|
| `--viewport-only` | First screen only instead of full page |
|
|
44
77
|
| `--pr <n>` | The branch has several PRs or the lookup fails |
|
|
45
78
|
| `--dry-run` | Preview locally, post nothing |
|