@juangadm/pre-post 1.0.0 → 1.1.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 (103) hide show
  1. package/README.md +99 -20
  2. package/dist/baseline.d.ts +119 -0
  3. package/dist/baseline.d.ts.map +1 -0
  4. package/dist/baseline.js +316 -0
  5. package/dist/baseline.js.map +1 -0
  6. package/dist/bin/cli.js +80 -41
  7. package/dist/bin/cli.js.map +1 -1
  8. package/dist/browser.d.ts +31 -3
  9. package/dist/browser.d.ts.map +1 -1
  10. package/dist/browser.js +239 -97
  11. package/dist/browser.js.map +1 -1
  12. package/dist/commands/compare.d.ts.map +1 -1
  13. package/dist/commands/compare.js +21 -3
  14. package/dist/commands/compare.js.map +1 -1
  15. package/dist/commands/detect.d.ts +5 -0
  16. package/dist/commands/detect.d.ts.map +1 -1
  17. package/dist/commands/detect.js +4 -1
  18. package/dist/commands/detect.js.map +1 -1
  19. package/dist/commands/doctor.d.ts +32 -0
  20. package/dist/commands/doctor.d.ts.map +1 -1
  21. package/dist/commands/doctor.js +90 -9
  22. package/dist/commands/doctor.js.map +1 -1
  23. package/dist/commands/login.js +1 -1
  24. package/dist/commands/pr.d.ts +4 -0
  25. package/dist/commands/pr.d.ts.map +1 -1
  26. package/dist/commands/pr.js +150 -50
  27. package/dist/commands/pr.js.map +1 -1
  28. package/dist/commands/prune.js +1 -1
  29. package/dist/commands/prune.js.map +1 -1
  30. package/dist/comparison.d.ts +104 -0
  31. package/dist/comparison.d.ts.map +1 -0
  32. package/dist/comparison.js +236 -0
  33. package/dist/comparison.js.map +1 -0
  34. package/dist/config.d.ts +12 -2
  35. package/dist/config.d.ts.map +1 -1
  36. package/dist/config.js +25 -3
  37. package/dist/config.js.map +1 -1
  38. package/dist/deployments.d.ts +71 -0
  39. package/dist/deployments.d.ts.map +1 -0
  40. package/dist/deployments.js +204 -0
  41. package/dist/deployments.js.map +1 -0
  42. package/dist/diff-pool.d.ts.map +1 -1
  43. package/dist/diff-pool.js +5 -2
  44. package/dist/diff-pool.js.map +1 -1
  45. package/dist/diff-worker.d.ts +3 -0
  46. package/dist/diff-worker.d.ts.map +1 -1
  47. package/dist/diff-worker.js +1 -0
  48. package/dist/diff-worker.js.map +1 -1
  49. package/dist/diff.d.ts +10 -0
  50. package/dist/diff.d.ts.map +1 -1
  51. package/dist/diff.js +117 -7
  52. package/dist/diff.js.map +1 -1
  53. package/dist/doctor.d.ts +42 -1
  54. package/dist/doctor.d.ts.map +1 -1
  55. package/dist/doctor.js +73 -7
  56. package/dist/doctor.js.map +1 -1
  57. package/dist/git.d.ts +41 -3
  58. package/dist/git.d.ts.map +1 -1
  59. package/dist/git.js +103 -7
  60. package/dist/git.js.map +1 -1
  61. package/dist/github.d.ts +92 -2
  62. package/dist/github.d.ts.map +1 -1
  63. package/dist/github.js +191 -20
  64. package/dist/github.js.map +1 -1
  65. package/dist/landing.d.ts +48 -0
  66. package/dist/landing.d.ts.map +1 -0
  67. package/dist/landing.js +93 -0
  68. package/dist/landing.js.map +1 -0
  69. package/dist/pkg.d.ts +9 -0
  70. package/dist/pkg.d.ts.map +1 -1
  71. package/dist/pkg.js +14 -0
  72. package/dist/pkg.js.map +1 -1
  73. package/dist/report.d.ts.map +1 -1
  74. package/dist/report.js +49 -26
  75. package/dist/report.js.map +1 -1
  76. package/dist/routes.d.ts +27 -0
  77. package/dist/routes.d.ts.map +1 -1
  78. package/dist/routes.js +98 -23
  79. package/dist/routes.js.map +1 -1
  80. package/dist/run.d.ts +88 -8
  81. package/dist/run.d.ts.map +1 -1
  82. package/dist/run.js +214 -26
  83. package/dist/run.js.map +1 -1
  84. package/dist/sameness.d.ts +91 -0
  85. package/dist/sameness.d.ts.map +1 -0
  86. package/dist/sameness.js +157 -0
  87. package/dist/sameness.js.map +1 -0
  88. package/dist/sessions.d.ts.map +1 -1
  89. package/dist/sessions.js +7 -1
  90. package/dist/sessions.js.map +1 -1
  91. package/dist/shift.d.ts +67 -0
  92. package/dist/shift.d.ts.map +1 -0
  93. package/dist/shift.js +184 -0
  94. package/dist/shift.js.map +1 -0
  95. package/dist/types.d.ts +67 -5
  96. package/dist/types.d.ts.map +1 -1
  97. package/dist/types.js.map +1 -1
  98. package/dist/url.d.ts +12 -0
  99. package/dist/url.d.ts.map +1 -0
  100. package/dist/url.js +30 -0
  101. package/dist/url.js.map +1 -0
  102. package/package.json +1 -1
  103. package/skill/SKILL.md +40 -7
package/dist/github.js CHANGED
@@ -11,24 +11,36 @@ import { execFileSync } from 'child_process';
11
11
  import { GitHubError, NeedsHumanError, GH_LOGIN_HINT } from './errors.js';
12
12
  export { GitHubError } from './errors.js';
13
13
  export const API_BASE = process.env.GITHUB_API_URL || 'https://api.github.com';
14
- export function getToken() {
15
- const env = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
16
- if (env)
17
- return env;
14
+ /**
15
+ * The token this run will use, and where it came from.
16
+ *
17
+ * The source is not bookkeeping: the env vars take precedence over the `gh`
18
+ * CLI, so advice aimed at the wrong one is advice that cannot work. Someone
19
+ * whose `GH_TOKEN` is refused gains nothing from `gh auth login`, because the
20
+ * variable still wins on the next run.
21
+ */
22
+ export function findToken() {
23
+ if (process.env.GH_TOKEN)
24
+ return { token: process.env.GH_TOKEN, source: 'GH_TOKEN' };
25
+ if (process.env.GITHUB_TOKEN)
26
+ return { token: process.env.GITHUB_TOKEN, source: 'GITHUB_TOKEN' };
18
27
  try {
19
28
  const out = execFileSync('gh', ['auth', 'token'], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
20
- return out || null;
29
+ return out ? { token: out, source: 'gh' } : null;
21
30
  }
22
31
  catch {
23
32
  return null;
24
33
  }
25
34
  }
26
- /** A token, or the one sentence telling the human how to get one. */
35
+ export function getToken() {
36
+ return findToken()?.token ?? null;
37
+ }
38
+ /** A token and its source, or the one sentence telling the human how to get one. */
27
39
  export function requireToken(purpose = 'publish screenshots') {
28
- const token = getToken();
29
- if (!token)
40
+ const found = findToken();
41
+ if (!found)
30
42
  throw new NeedsHumanError(`GitHub access is needed to ${purpose}. ${GH_LOGIN_HINT}`);
31
- return token;
43
+ return found;
32
44
  }
33
45
  export class GitHub {
34
46
  token;
@@ -67,6 +79,80 @@ export class GitHub {
67
79
  return json;
68
80
  }
69
81
  }
82
+ /**
83
+ * Can this token write to `ownerRepo`?
84
+ *
85
+ * `getToken()` checks that a token exists, which is a different question. A
86
+ * GitHub Actions job that maps `secrets.GITHUB_TOKEN` gets one that reads
87
+ * everything this tool reads and writes nothing: measured on this repository,
88
+ * `GET /repos/juangadm/pre-post` answers 200 with `permissions.push: false`
89
+ * and `POST .../git/blobs` answers 403. Those reads are the ones `pr` makes
90
+ * before it captures, so without this the run spends its screenshots first and
91
+ * discovers the refusal after.
92
+ *
93
+ * The probe is the first write `publishAssets` makes, on the one piece of
94
+ * content that cannot add anything: the empty blob already exists in every
95
+ * repository, so a successful call stores nothing new. A read cannot stand in
96
+ * for it — `permissions.push` describes the account's access to the repository,
97
+ * not the scopes the token carries, so it can report `true` for a credential
98
+ * the write still refuses. That is the confident all-clear this check exists to
99
+ * avoid, which is why it writes.
100
+ *
101
+ * What it proves is bounded: the token may write objects. Creating the assets
102
+ * *ref* is a separate permission a ruleset can refuse, so `writable: true` is
103
+ * "not this failure", never "the publish will work".
104
+ */
105
+ export async function checkWriteAccess(gh, ownerRepo) {
106
+ try {
107
+ await gh.request('POST', `/repos/${ownerRepo}/git/blobs`, { content: '', encoding: 'utf-8' });
108
+ return { writable: true };
109
+ }
110
+ catch (err) {
111
+ // 401/403 arrive as NeedsHumanError from `request`; a repository an
112
+ // installation cannot write is often hidden as 404 rather than refused.
113
+ if (err instanceof NeedsHumanError)
114
+ return { writable: false, reason: 'rejected' };
115
+ if (err instanceof GitHubError) {
116
+ if (err.status === 404)
117
+ return { writable: false, reason: 'rejected' };
118
+ return { writable: false, reason: 'unknown', detail: `GitHub answered ${err.status}` };
119
+ }
120
+ return { writable: false, reason: 'unknown', detail: err instanceof Error ? err.message : String(err) };
121
+ }
122
+ }
123
+ /**
124
+ * The one thing to do about a token that cannot publish.
125
+ *
126
+ * It follows the credential that was actually chosen, not just the
127
+ * environment. Being inside a runner does not make `permissions:` the fix: a
128
+ * workflow that sets `GH_TOKEN` to a PAT is refused by that PAT, and rewriting
129
+ * the job's permissions changes only the `GITHUB_TOKEN` the run never reaches.
130
+ * The same holds the other way round on a laptop, where `gh auth login` cannot
131
+ * help while an env var is shadowing it.
132
+ *
133
+ * The runner sentence names both permissions, though only `contents` is what
134
+ * this check tested. Naming `contents` alone would be advice that fails on its
135
+ * own terms: a `permissions:` block sets every scope it omits to none, so
136
+ * following it leaves a token that uploads the screenshots and is then refused
137
+ * the PR description — measured on this repository, `PATCH /pulls/23` answers
138
+ * 403 with only `contents: write` and 200 with `pull-requests: write` beside it.
139
+ * A second trip through a full capture is not worth the tighter sentence.
140
+ */
141
+ export function cannotPublishHint(ownerRepo, source) {
142
+ const inActions = process.env.GITHUB_ACTIONS === 'true';
143
+ const perms = '"permissions: { contents: write, pull-requests: write }"';
144
+ const nowhere = `cannot write to ${ownerRepo}, so the screenshots would have nowhere to go`;
145
+ if (source === 'gh') {
146
+ return `The gh CLI login ${nowhere}: run gh auth login as someone with write access, or set GH_TOKEN to a token carrying repo scope.`;
147
+ }
148
+ if (inActions && source === 'GITHUB_TOKEN') {
149
+ return `This workflow's GITHUB_TOKEN ${nowhere}: give the job ${perms} and re-run.`;
150
+ }
151
+ if (inActions) {
152
+ return `The GH_TOKEN this workflow sets ${nowhere}: give that credential write access, or unset it so the job's own GITHUB_TOKEN is used with ${perms}.`;
153
+ }
154
+ return `The ${source} set in this environment ${nowhere}: set it to a token carrying repo scope, or unset it to fall back on your gh CLI login.`;
155
+ }
70
156
  export async function findOpenPr(gh, ownerRepo, branch) {
71
157
  const owner = ownerRepo.split('/')[0];
72
158
  const prs = await gh.request('GET', `/repos/${ownerRepo}/pulls?state=open&head=${encodeURIComponent(`${owner}:${branch}`)}&per_page=1`);
@@ -168,6 +254,47 @@ export async function upsertStickyComment(gh, ownerRepo, prNumber, body, marker)
168
254
  const created = await gh.request('POST', `/repos/${ownerRepo}/issues/${prNumber}/comments`, { body });
169
255
  return { html_url: created.html_url, created: true };
170
256
  }
257
+ /**
258
+ * Write `body` into a marked block in the PR description, replacing the block
259
+ * from a previous run. The description is where reviewers look first, so this
260
+ * is preferred over a comment.
261
+ *
262
+ * Returns updated: false when the token cannot edit the PR (a fork, or no write
263
+ * access), so the caller can fall back to a comment instead of failing.
264
+ */
265
+ export async function upsertPrDescription(gh, ownerRepo, prNumber, body, marker) {
266
+ const open = `<!-- ${marker}:start -->`;
267
+ const close = `<!-- ${marker}:end -->`;
268
+ const pr = await gh.request('GET', `/repos/${ownerRepo}/pulls/${prNumber}`);
269
+ const section = `${open}\n${body}\n${close}`;
270
+ const existing = pr.body ?? '';
271
+ const start = existing.indexOf(open);
272
+ const end = existing.indexOf(close);
273
+ // Prepend: the screenshots are the first thing a reviewer should see.
274
+ const next = start !== -1 && end > start
275
+ ? existing.slice(0, start) + section + existing.slice(end + close.length)
276
+ : section + (existing.trim() ? '\n\n' + existing.trimStart() : '');
277
+ if (next === existing)
278
+ return { html_url: pr.html_url, updated: true };
279
+ try {
280
+ await gh.request('PATCH', `/repos/${ownerRepo}/pulls/${prNumber}`, { body: next });
281
+ }
282
+ catch {
283
+ return { html_url: pr.html_url, updated: false };
284
+ }
285
+ return { html_url: pr.html_url, updated: true };
286
+ }
287
+ const ASSETS_README_PATH = 'README.md';
288
+ /** Kept so pruning the last folder does not ask the API for an empty tree. */
289
+ const ASSETS_README = `# pre-post assets
290
+
291
+ Screenshots published by [pre-post](https://github.com/juangadm/pre-post), one folder per
292
+ pull request (\`pr-<number>/\`). Nothing here is edited by hand.
293
+
294
+ \`pre-post prune\` removes folders for pull requests closed more than \`pruneDays\` ago. This
295
+ file is what keeps the branch from becoming an empty tree, which the GitHub tree API
296
+ refuses to create.
297
+ `;
171
298
  /**
172
299
  * Remove `pr-<n>/` folders on the assets branch whose PR closed more than
173
300
  * `olderThanDays` ago. One commit; no history rewrite.
@@ -225,16 +352,60 @@ export async function pruneAssets(gh, ownerRepo, branch, olderThanDays, dryRun =
225
352
  });
226
353
  if (dryRun || deletions.length === 0)
227
354
  return { removed, kept };
228
- const newTree = await gh.request('POST', `/repos/${ownerRepo}/git/trees`, {
229
- base_tree: commit.tree.sha,
230
- tree: deletions.map(p => ({ path: p, mode: '100644', type: 'blob', sha: null })),
231
- });
232
- const newCommit = await gh.request('POST', `/repos/${ownerRepo}/git/commits`, {
233
- message: `Prune screenshots for ${removed.length} closed PR(s)`,
234
- tree: newTree.sha,
235
- parents: [headSha],
236
- });
237
- await gh.request('PATCH', `/repos/${ownerRepo}/git/refs/${encodeURIComponent(`heads/${branch}`)}`, { sha: newCommit.sha });
238
- return { removed, kept, sha: newCommit.sha };
355
+ // Deleting every blob would leave an empty tree, and git's empty tree is not
356
+ // something the API will build: `tree: []` is refused as "Invalid tree info"
357
+ // (422), and the canonical empty-tree SHA is not resolvable through the REST
358
+ // API either (404) even though every repository contains that object. So the
359
+ // last folder could never be removed -- prune worked in every case except the
360
+ // one that finishes the job.
361
+ //
362
+ // The branch therefore keeps one file. `README.md` is chosen over an empty
363
+ // marker because the branch is otherwise undocumented, and it is inert on
364
+ // both sides: prune only ever counts `pr-<n>/` paths, and publish adds to
365
+ // whatever tree it finds.
366
+ const doomed = new Set(deletions);
367
+ const survivors = tree.tree.filter(e => e.type === 'blob' && !doomed.has(e.path));
368
+ // Rebuilding from scratch is only safe on a complete listing. A truncated one
369
+ // does not show every entry, so "nothing survives" would be a statement about
370
+ // the page that came back rather than about the branch, and the rebuild would
371
+ // silently drop whatever GitHub left out. Subtracting from `base_tree` is the
372
+ // safe answer there, and it cannot empty the tree either: truncation means
373
+ // there are more entries than the ones being removed.
374
+ const rebuild = survivors.length === 0 && !tree.truncated;
375
+ try {
376
+ const newTree = await gh.request('POST', `/repos/${ownerRepo}/git/trees`, rebuild
377
+ // No base_tree: the surviving tree is this file and nothing else.
378
+ ? { tree: [{ path: ASSETS_README_PATH, mode: '100644', type: 'blob', content: ASSETS_README }] }
379
+ : {
380
+ base_tree: commit.tree.sha,
381
+ tree: deletions.map(p => ({ path: p, mode: '100644', type: 'blob', sha: null })),
382
+ });
383
+ const newCommit = await gh.request('POST', `/repos/${ownerRepo}/git/commits`, {
384
+ message: `Prune screenshots for ${removed.length} closed PR(s)`,
385
+ tree: newTree.sha,
386
+ parents: [headSha],
387
+ });
388
+ await gh.request('PATCH', `/repos/${ownerRepo}/git/refs/${encodeURIComponent(`heads/${branch}`)}`, { sha: newCommit.sha });
389
+ return { removed, kept, sha: newCommit.sha };
390
+ }
391
+ catch (err) {
392
+ // Everything above this point was a read, so a write that fails here has
393
+ // left the branch untouched and the run is always safe to repeat. What
394
+ // changes is what the human should do about it, and naming the wrong cause
395
+ // is worse than naming none: `request` has already turned 401 and 403 into
396
+ // NeedsHumanError, so what reaches here is a refusal disguised as a 404, a
397
+ // race, or GitHub being unwell -- and only the first is about permissions.
398
+ if (err instanceof GitHubError) {
399
+ if (err.status === 409 || err.status === 422) {
400
+ throw new NeedsHumanError(`Another run moved ${branch} while prune was working on it; nothing was changed, so run pre-post prune again.`);
401
+ }
402
+ if (err.status === 429 || err.status >= 500) {
403
+ throw new NeedsHumanError(`GitHub could not finish pruning ${branch} (it answered ${err.status}); nothing was changed, so run pre-post prune again in a few minutes.`);
404
+ }
405
+ throw new NeedsHumanError(`Could not update the ${branch} branch to prune ${removed.length} folder(s) (GitHub answered ${err.status}); ` +
406
+ `check that your token still has contents: write on ${ownerRepo}, then run pre-post prune again.`);
407
+ }
408
+ throw err;
409
+ }
239
410
  }
240
411
  //# sourceMappingURL=github.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,wBAAwB,CAAC;AAU/E;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;QAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACrF,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;QAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IACjG,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACrH,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,SAAS,EAAE,EAAE,KAAK,IAAI,IAAI,CAAC;AACpC,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,YAAY,CAAC,OAAO,GAAG,qBAAqB;IAC1D,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,eAAe,CAAC,8BAA8B,OAAO,KAAK,aAAa,EAAE,CAAC,CAAC;IACjG,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,OAAO,MAAM;IACY;IAAgC;IAA7D,YAA6B,KAAa,EAAmB,OAAO,QAAQ;QAA/C,UAAK,GAAL,KAAK,CAAQ;QAAmB,SAAI,GAAJ,IAAI,CAAW;IAAG,CAAC;IAEhF,KAAK,CAAC,OAAO,CAAU,MAAc,EAAE,IAAY,EAAE,IAAc;QACjE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,EAAE,EAAE;YAC7C,MAAM;YACN,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE;gBACrC,MAAM,EAAE,6BAA6B;gBACrC,sBAAsB,EAAE,YAAY;gBACpC,YAAY,EAAE,UAAU;gBACxB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACxD;YACD,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SAC9C,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,SAAc,CAAC;QAC9C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,IAAI,GAAQ,IAAI,CAAC;QACrB,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;QAC1B,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YAC3F,MAAM,IAAI,eAAe,CAAC,8BAA8B,GAAG,CAAC,MAAM,MAAM,aAAa,EAAE,CAAC,CAAC;QAC3F,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,IAAI,EAAE,OAAO,IAAI,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC;YACpD,MAAM,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,MAAM,IAAI,IAAI,MAAM,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,IAAS,CAAC;IACnB,CAAC;CACF;AAWD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EAAU,EAAE,SAAiB;IAClE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,SAAS,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9F,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,oEAAoE;QACpE,wEAAwE;QACxE,IAAI,GAAG,YAAY,eAAe;YAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QACnF,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;YAC/B,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;YACvE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,mBAAmB,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;QACzF,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1G,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,MAAmB;IACtE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,MAAM,CAAC;IACxD,MAAM,KAAK,GAAG,0DAA0D,CAAC;IACzE,MAAM,OAAO,GAAG,mBAAmB,SAAS,+CAA+C,CAAC;IAC5F,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,oBAAoB,OAAO,mGAAmG,CAAC;IACxI,CAAC;IACD,IAAI,SAAS,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC3C,OAAO,gCAAgC,OAAO,kBAAkB,KAAK,cAAc,CAAC;IACtF,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,mCAAmC,OAAO,+FAA+F,KAAK,GAAG,CAAC;IAC3J,CAAC;IACD,OAAO,OAAO,MAAM,4BAA4B,OAAO,yFAAyF,CAAC;AACnJ,CAAC;AAUD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,EAAU,EAAE,SAAiB,EAAE,MAAc;IAC5E,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAC1B,KAAK,EACL,UAAU,SAAS,0BAA0B,kBAAkB,CAAC,GAAG,KAAK,IAAI,MAAM,EAAE,CAAC,aAAa,CACnG,CAAC;IACF,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,EAAU,EAAE,SAAiB,EAAE,MAAc;IACvE,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,SAAS,UAAU,MAAM,EAAE,CAAC,CAAC;AAClE,CAAC;AAcD,MAAM,UAAU,OAAO,CAAC,SAAiB,EAAE,GAAW,EAAE,QAAgB;IACtE,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtE,OAAO,sBAAsB,SAAS,SAAS,GAAG,IAAI,OAAO,WAAW,CAAC;AAC3E,CAAC;AAED,KAAK,UAAU,QAAQ,CAAO,KAAU,EAAE,KAAa,EAAE,EAA2B;IAClF,MAAM,OAAO,GAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;QAC/E,OAAO,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,EAAU,EACV,SAAiB,EACjB,MAAc,EACd,KAAkB,EAClB,OAAe;IAEf,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAEnE,uFAAuF;IACvF,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;QAC/C,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAkB,MAAM,EAAE,UAAU,SAAS,YAAY,EAAE;YACrF,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACrC,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7C,iDAAiD;QACjD,IAAI,SAAS,GAAkB,IAAI,CAAC;QACpC,IAAI,QAA4B,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAA8B,KAAK,EAAE,UAAU,SAAS,YAAY,kBAAkB,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YACzI,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAA4B,KAAK,EAAE,UAAU,SAAS,gBAAgB,SAAS,EAAE,CAAC,CAAC;YAClH,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,CAAC,GAAG,YAAY,WAAW,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,MAAM,GAAG,CAAC;QACrE,CAAC;QAED,2BAA2B;QAC3B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAkB,MAAM,EAAE,UAAU,SAAS,YAAY,EAAE;YACtF,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;SACnF,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAkB,MAAM,EAAE,UAAU,SAAS,cAAc,EAAE;YAC1F,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,GAAG;YACd,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;SACtC,CAAC,CAAC;QAEH,uFAAuF;QACvF,IAAI,CAAC;YACH,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,SAAS,aAAa,kBAAkB,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACxI,CAAC;iBAAM,CAAC;gBACN,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,SAAS,WAAW,EAAE,EAAE,GAAG,EAAE,cAAc,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YAC7G,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,WAAW,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC;gBAAE,SAAS;YACtG,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;QACvC,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAChF,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,sCAAsC,CAAC,CAAC;AACpF,CAAC;AAOD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAU,EACV,SAAiB,EACjB,QAAgB,EAChB,IAAY,EACZ,MAAc;IAEd,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,OAAO,CAC/B,KAAK,EACL,UAAU,SAAS,WAAW,QAAQ,+BAA+B,IAAI,EAAE,CAC5E,CAAC;QACF,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAmC,OAAO,EAAE,UAAU,SAAS,oBAAoB,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5I,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACxD,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG;YAAE,MAAM;IACnC,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAmC,MAAM,EAAE,UAAU,SAAS,WAAW,QAAQ,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACxI,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvD,CAAC;AAQD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAU,EACV,SAAiB,EACjB,QAAgB,EAChB,IAAY,EACZ,MAAc;IAEd,MAAM,IAAI,GAAG,QAAQ,MAAM,YAAY,CAAC;IACxC,MAAM,KAAK,GAAG,QAAQ,MAAM,UAAU,CAAC;IACvC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,OAAO,CAA4C,KAAK,EAAE,UAAU,SAAS,UAAU,QAAQ,EAAE,CAAC,CAAC;IACvH,MAAM,OAAO,GAAG,GAAG,IAAI,KAAK,IAAI,KAAK,KAAK,EAAE,CAAC;IAC7C,MAAM,QAAQ,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACpC,sEAAsE;IACtE,MAAM,IAAI,GAAG,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK;QACtC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;QACzE,CAAC,CAAC,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrE,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACvE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,SAAS,UAAU,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAClD,CAAC;AAQD,MAAM,kBAAkB,GAAG,WAAW,CAAC;AAEvC,8EAA8E;AAC9E,MAAM,aAAa,GAAG;;;;;;;;CAQrB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,EAAU,EACV,SAAiB,EACjB,MAAc,EACd,aAAqB,EACrB,MAAM,GAAG,KAAK;IAEd,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAA8B,KAAK,EAAE,UAAU,SAAS,YAAY,kBAAkB,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACzI,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,WAAW,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QACvF,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAA4B,KAAK,EAAE,UAAU,SAAS,gBAAgB,OAAO,EAAE,CAAC,CAAC;IAChH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAC3B,KAAK,EACL,UAAU,SAAS,cAAc,MAAM,CAAC,IAAI,CAAC,GAAG,cAAc,CAC/D,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC5C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACvB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,IAAI;gBAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;;gBAAM,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,GAAG,UAAU,CAAC;IACvD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1D,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,SAAS,CAAC;YAC9C,OAAO,EAAE,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,QAAS,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC;QAC9F,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,WAAW,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAC;YAClE,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE;QAChC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,SAAS,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,MAAM,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAE/D,6EAA6E;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,6BAA6B;IAC7B,EAAE;IACF,2EAA2E;IAC3E,0EAA0E;IAC1E,0EAA0E;IAC1E,0BAA0B;IAC1B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAElF,8EAA8E;IAC9E,8EAA8E;IAC9E,8EAA8E;IAC9E,8EAA8E;IAC9E,2EAA2E;IAC3E,sDAAsD;IACtD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;IAE1D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAkB,MAAM,EAAE,UAAU,SAAS,YAAY,EAAE,OAAO;YAChG,kEAAkE;YAClE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE;YAChG,CAAC,CAAC;gBACA,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG;gBAC1B,IAAI,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;aACjF,CAAC,CAAC;QACL,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,OAAO,CAAkB,MAAM,EAAE,UAAU,SAAS,cAAc,EAAE;YAC7F,OAAO,EAAE,yBAAyB,OAAO,CAAC,MAAM,eAAe;YAC/D,IAAI,EAAE,OAAO,CAAC,GAAG;YACjB,OAAO,EAAE,CAAC,OAAO,CAAC;SACnB,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,SAAS,aAAa,kBAAkB,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3H,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,yEAAyE;QACzE,uEAAuE;QACvE,2EAA2E;QAC3E,2EAA2E;QAC3E,2EAA2E;QAC3E,2EAA2E;QAC3E,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;YAC/B,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC7C,MAAM,IAAI,eAAe,CAAC,qBAAqB,MAAM,mFAAmF,CAAC,CAAC;YAC5I,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;gBAC5C,MAAM,IAAI,eAAe,CAAC,mCAAmC,MAAM,iBAAiB,GAAG,CAAC,MAAM,uEAAuE,CAAC,CAAC;YACzK,CAAC;YACD,MAAM,IAAI,eAAe,CACvB,wBAAwB,MAAM,oBAAoB,OAAO,CAAC,MAAM,+BAA+B,GAAG,CAAC,MAAM,KAAK;gBAC9G,sDAAsD,SAAS,kCAAkC,CAClG,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Did a capture reach the page it asked for, or land somewhere else?
3
+ *
4
+ * Deployment protection, corporate SSO and IP allow-lists answer a request for
5
+ * a page with a sign-in screen, and they do it with HTTP 200 after a redirect —
6
+ * so the 401/403 guard in `browser.ts` never sees them. Screenshotting that and
7
+ * publishing the difference as a visual change is the worst failure this tool
8
+ * has: confident, and wrong. It happened on a real run, twice, before anyone
9
+ * noticed the "Post" screenshot was a login form.
10
+ *
11
+ * The test is deliberately narrow. A redirect on its own proves nothing — a
12
+ * site legitimately sends `example.xyz` to `example.org`, or apex to `www` —
13
+ * so only a redirect that ends somewhere *sign-in shaped* counts. Missing an
14
+ * exotic auth wall is recoverable; refusing to run against a site that redirects
15
+ * for ordinary reasons is not.
16
+ */
17
+ /**
18
+ * The registrable-ish part of a host, so `www.example.com` and `example.com`
19
+ * read as one site. Two labels is a heuristic — it treats `a.co.uk` and
20
+ * `b.co.uk` as the same site — but it is only ever used to make the sign-in
21
+ * test *stricter*, never to reject anything on its own.
22
+ */
23
+ export declare function siteOf(url: string): string;
24
+ /** Did the navigation end up on a different site than the one requested? */
25
+ export declare function leftTheSite(requested: string, final: string): boolean;
26
+ /** Does this URL and title read as a sign-in page rather than a site's own page? */
27
+ export declare function looksLikeSignIn(url: string, title?: string): boolean;
28
+ export interface Landing {
29
+ /** Where the browser actually ended up. */
30
+ finalUrl: string;
31
+ /** True when the capture is of a sign-in wall, not of the requested page. */
32
+ blocked: boolean;
33
+ /** The wall is on another site entirely — usually an identity provider. */
34
+ offSite: boolean;
35
+ }
36
+ /**
37
+ * Judge where a capture landed.
38
+ *
39
+ * Blocked requires *both* that the browser moved and that where it moved to is
40
+ * sign-in shaped: asking for `/login` and getting `/login` is not a wall, and
41
+ * neither is a plain canonical-domain redirect.
42
+ */
43
+ export declare function checkLanding(requested: string, finalUrl: string, title?: string): Landing;
44
+ /**
45
+ * The one sentence a human needs. Names the fix, not the symptom.
46
+ */
47
+ export declare function signInHint(url: string, vercel: boolean): string;
48
+ //# sourceMappingURL=landing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landing.d.ts","sourceRoot":"","sources":["../src/landing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQ1C;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAIrE;AAMD,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAShE;AAED,MAAM,WAAW,OAAO;IACtB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAOrF;AAcD;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAO/D"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Did a capture reach the page it asked for, or land somewhere else?
3
+ *
4
+ * Deployment protection, corporate SSO and IP allow-lists answer a request for
5
+ * a page with a sign-in screen, and they do it with HTTP 200 after a redirect —
6
+ * so the 401/403 guard in `browser.ts` never sees them. Screenshotting that and
7
+ * publishing the difference as a visual change is the worst failure this tool
8
+ * has: confident, and wrong. It happened on a real run, twice, before anyone
9
+ * noticed the "Post" screenshot was a login form.
10
+ *
11
+ * The test is deliberately narrow. A redirect on its own proves nothing — a
12
+ * site legitimately sends `example.xyz` to `example.org`, or apex to `www` —
13
+ * so only a redirect that ends somewhere *sign-in shaped* counts. Missing an
14
+ * exotic auth wall is recoverable; refusing to run against a site that redirects
15
+ * for ordinary reasons is not.
16
+ */
17
+ /**
18
+ * The registrable-ish part of a host, so `www.example.com` and `example.com`
19
+ * read as one site. Two labels is a heuristic — it treats `a.co.uk` and
20
+ * `b.co.uk` as the same site — but it is only ever used to make the sign-in
21
+ * test *stricter*, never to reject anything on its own.
22
+ */
23
+ export function siteOf(url) {
24
+ try {
25
+ const { hostname } = new URL(url);
26
+ const labels = hostname.split('.');
27
+ return labels.length <= 2 ? hostname : labels.slice(-2).join('.');
28
+ }
29
+ catch {
30
+ return '';
31
+ }
32
+ }
33
+ /** Did the navigation end up on a different site than the one requested? */
34
+ export function leftTheSite(requested, final) {
35
+ const from = siteOf(requested);
36
+ const to = siteOf(final);
37
+ return Boolean(from && to && from !== to);
38
+ }
39
+ /** Words that appear in the URL or title of a sign-in page and little else. */
40
+ const SIGN_IN_URL = /(login|log-in|signin|sign-in|sso|oauth|authorize|authenticate)/i;
41
+ const SIGN_IN_TITLE = /(sign[ -]?in|log[ -]?in|authentication required|authorization required|access denied)/i;
42
+ /** Does this URL and title read as a sign-in page rather than a site's own page? */
43
+ export function looksLikeSignIn(url, title = '') {
44
+ let path = '';
45
+ try {
46
+ const u = new URL(url);
47
+ path = u.pathname + u.search;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ return SIGN_IN_URL.test(path) || SIGN_IN_TITLE.test(title);
53
+ }
54
+ /**
55
+ * Judge where a capture landed.
56
+ *
57
+ * Blocked requires *both* that the browser moved and that where it moved to is
58
+ * sign-in shaped: asking for `/login` and getting `/login` is not a wall, and
59
+ * neither is a plain canonical-domain redirect.
60
+ */
61
+ export function checkLanding(requested, finalUrl, title = '') {
62
+ const moved = normalize(finalUrl) !== normalize(requested);
63
+ return {
64
+ finalUrl,
65
+ blocked: moved && looksLikeSignIn(finalUrl, title),
66
+ offSite: leftTheSite(requested, finalUrl),
67
+ };
68
+ }
69
+ /** Ignore the trailing-slash and fragment differences a redirect adds for free. */
70
+ function normalize(url) {
71
+ try {
72
+ const u = new URL(url);
73
+ u.hash = '';
74
+ if (u.pathname.endsWith('/') && u.pathname !== '/')
75
+ u.pathname = u.pathname.slice(0, -1);
76
+ return u.toString();
77
+ }
78
+ catch {
79
+ return url;
80
+ }
81
+ }
82
+ /**
83
+ * The one sentence a human needs. Names the fix, not the symptom.
84
+ */
85
+ export function signInHint(url, vercel) {
86
+ if (vercel) {
87
+ return `${url} answered with a sign-in page, so the site was never captured. ` +
88
+ 'Set VERCEL_AUTOMATION_BYPASS_SECRET (Vercel → Project → Settings → Deployment Protection → Protection Bypass for Automation) and re-run.';
89
+ }
90
+ return `${url} answered with a sign-in page, so the site was never captured. ` +
91
+ `Run: npx pre-post login ${url} (opens a browser once, saves the session locally)`;
92
+ }
93
+ //# sourceMappingURL=landing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landing.js","sourceRoot":"","sources":["../src/landing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnC,OAAO,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,KAAa;IAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACzB,OAAO,OAAO,CAAC,IAAI,IAAI,EAAE,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,+EAA+E;AAC/E,MAAM,WAAW,GAAG,iEAAiE,CAAC;AACtF,MAAM,aAAa,GAAG,wFAAwF,CAAC;AAE/G,oFAAoF;AACpF,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,KAAK,GAAG,EAAE;IACrD,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAWD;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,QAAgB,EAAE,KAAK,GAAG,EAAE;IAC1E,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,SAAS,CAAC,CAAC;IAC3D,OAAO;QACL,QAAQ;QACR,OAAO,EAAE,KAAK,IAAI,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC;QAClD,OAAO,EAAE,WAAW,CAAC,SAAS,EAAE,QAAQ,CAAC;KAC1C,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;QACZ,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,GAAG;YAAE,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACzF,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,MAAe;IACrD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,GAAG,GAAG,iEAAiE;YAC5E,0IAA0I,CAAC;IAC/I,CAAC;IACD,OAAO,GAAG,GAAG,iEAAiE;QAC5E,2BAA2B,GAAG,sDAAsD,CAAC;AACzF,CAAC"}
package/dist/pkg.d.ts CHANGED
@@ -5,4 +5,13 @@
5
5
  */
6
6
  export declare function readPackage(root: string): Record<string, any> | null;
7
7
  export declare function hasDependency(root: string, name: string): boolean;
8
+ /**
9
+ * The script that starts a dev server for this package, preferring `dev`.
10
+ *
11
+ * This is the test for "is this directory an app we could actually serve?",
12
+ * used both when picking the app root to detect routes for and when serving a
13
+ * base commit. The two must agree: a directory that cannot be served is not
14
+ * the app a PR changed, however many of its files the diff touched.
15
+ */
16
+ export declare function devScript(dir: string): string | null;
8
17
  //# sourceMappingURL=pkg.d.ts.map
package/dist/pkg.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pkg.d.ts","sourceRoot":"","sources":["../src/pkg.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAkBpE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGjE"}
1
+ {"version":3,"file":"pkg.d.ts","sourceRoot":"","sources":["../src/pkg.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAkBpE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGjE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIpD"}
package/dist/pkg.js CHANGED
@@ -32,4 +32,18 @@ export function hasDependency(root, name) {
32
32
  const pkg = readPackage(root);
33
33
  return Boolean(pkg?.dependencies?.[name] || pkg?.devDependencies?.[name]);
34
34
  }
35
+ /**
36
+ * The script that starts a dev server for this package, preferring `dev`.
37
+ *
38
+ * This is the test for "is this directory an app we could actually serve?",
39
+ * used both when picking the app root to detect routes for and when serving a
40
+ * base commit. The two must agree: a directory that cannot be served is not
41
+ * the app a PR changed, however many of its files the diff touched.
42
+ */
43
+ export function devScript(dir) {
44
+ const scripts = readPackage(dir)?.scripts;
45
+ if (!scripts)
46
+ return null;
47
+ return ['dev', 'start:dev', 'serve', 'start'].find(name => typeof scripts[name] === 'string') ?? null;
48
+ }
35
49
  //# sourceMappingURL=pkg.js.map
package/dist/pkg.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pkg.js","sourceRoot":"","sources":["../src/pkg.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAgE,CAAC;AAEtF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAC7C,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,KAAK,OAAO;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC;IACnD,IAAI,GAAG,GAA+B,IAAI,CAAC;IAC3C,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,GAAG,IAAI,CAAC;IACb,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IAClC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAY;IACtD,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC,GAAG,EAAE,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,eAAe,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5E,CAAC"}
1
+ {"version":3,"file":"pkg.js","sourceRoot":"","sources":["../src/pkg.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAgE,CAAC;AAEtF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAC7C,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,KAAK,OAAO;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC;IACnD,IAAI,GAAG,GAA+B,IAAI,CAAC;IAC3C,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,GAAG,IAAI,CAAC;IACb,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IAClC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAY;IACtD,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC,GAAG,EAAE,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,eAAe,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,OAA6C,CAAC;IAChF,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,IAAI,IAAI,CAAC;AACxG,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAuB,MAAM,YAAY,CAAC;AAG9D,eAAO,MAAM,aAAa,qCAAqC,CAAC;AAuBhE,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,cAAmB,GAAG,MAAM,CAqDtF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAyBxD"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAuB,MAAM,YAAY,CAAC;AAI9D,eAAO,MAAM,aAAa,qCAAqC,CAAC;AAgBhE,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,cAAmB,GAAG,MAAM,CA+EtF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CA6BxD"}
package/dist/report.js CHANGED
@@ -2,17 +2,9 @@
2
2
  * Output formatting: the PR comment (for humans) and the terminal summary
3
3
  * (for the developer or the agent that invoked the CLI).
4
4
  */
5
- import { hostOf } from './run.js';
5
+ import { describeShift } from './run.js';
6
+ import { hostOf, isLocalUrl } from './url.js';
6
7
  export const STICKY_MARKER = '<!-- pre-post:visual-changes -->';
7
- function pct(ratio) {
8
- if (ratio === undefined)
9
- return '';
10
- if (ratio === 0)
11
- return '0%';
12
- if (ratio < 0.0001)
13
- return '<0.01%';
14
- return `${(ratio * 100).toFixed(ratio < 0.01 ? 2 : 1)}%`;
15
- }
16
8
  function code(s) {
17
9
  return `\`${s}\``;
18
10
  }
@@ -31,31 +23,61 @@ function groupByRoute(outcomes) {
31
23
  export function buildComment(result, options = {}) {
32
24
  const lines = [STICKY_MARKER, '## Visual changes', ''];
33
25
  const routes = groupByRoute(result.outcomes);
34
- const viewportCount = new Set(result.outcomes.map(o => o.viewport)).size;
35
26
  const changed = result.outcomes.filter(o => o.status === 'changed');
36
27
  const unchanged = result.outcomes.filter(o => o.status === 'unchanged');
37
28
  const errors = result.outcomes.filter(o => o.status === 'error');
38
- const summary = changed.length === 0
39
- ? `No visual changes detected across ${routes.size} route${routes.size === 1 ? '' : 's'} and ${viewportCount} viewport${viewportCount === 1 ? '' : 's'}.`
40
- : `${changed.length} of ${result.outcomes.length} captures changed across ${routes.size} route${routes.size === 1 ? '' : 's'}.`;
41
- lines.push(`**Pre** = ${hostOf(result.beforeBase)} · **Post** = this branch · ${summary}`, '');
29
+ // A page that only one side has is still something a reviewer must see, so it
30
+ // counts as a change for "did anything happen" — but it is shown as one
31
+ // screenshot, never as a Pre/Post pair, because there is no pair.
32
+ const oneSided = result.outcomes.filter(o => (o.status === 'added' || o.status === 'removed') && (o.urls || o.files));
33
+ // Both sides can now be a deployment, so name the actual hosts rather than
34
+ // assuming Post is the reader's own checkout.
35
+ const postLabel = isLocalUrl(result.afterBase) ? 'this branch (local)' : hostOf(result.afterBase);
36
+ const sha = options.headSha ? ` @ ${code(options.headSha.slice(0, 7))}` : '';
37
+ lines.push(`**Pre** = ${hostOf(result.beforeBase)} · **Post** = ${postLabel}${sha} · <a href="https://github.com/juangadm/pre-post">pre-post</a>`, '');
38
+ if (changed.length === 0 && oneSided.length === 0)
39
+ lines.push('No visual changes.', '');
42
40
  for (const [route, outcomes] of routes) {
43
41
  const changedHere = outcomes.filter(o => o.status === 'changed' && (o.urls || o.files));
44
42
  if (changedHere.length === 0)
45
43
  continue;
46
44
  for (const o of changedHere) {
47
45
  const u = o.urls ?? o.files;
48
- const note = [o.sizeChanged ? 'page height changed' : '', o.note || ''].filter(Boolean).map(n => ` · ${n}`).join('');
49
- lines.push(`### ${code(route)} — ${viewportLabel(o.viewport)} · ${pct(o.changedRatio)} of pixels changed${note}`, '');
46
+ lines.push(`### ${code(route)} — ${viewportLabel(o.viewport)}`, '');
47
+ // A move repaints everything below it, so the percentage says nothing a
48
+ // reviewer can use. Say how far it moved instead, and whether the branch
49
+ // changed anything else.
50
+ if (o.shift) {
51
+ lines.push(o.shift.otherChange
52
+ ? `Content ${describeShift(o.shift.px)}. The pair below is aligned on that move, so it shows what changed besides it.`
53
+ : `Content ${describeShift(o.shift.px)}. Nothing else changed.`, '');
54
+ }
55
+ const cropped = Boolean(u.cropBefore && u.cropAfter);
50
56
  const pre = u.cropBefore ?? u.before;
51
57
  const post = u.cropAfter ?? u.after;
52
58
  lines.push('| Pre | Post |', '|:---:|:---:|', `| ![Pre](${pre}) | ![Post](${post}) |`, '');
53
- lines.push('<details>', `<summary>Full page and diff</summary>`, '');
54
- const diffCol = u.diff ? ` ![Diff](${u.diff}) |` : '';
55
- lines.push(`| Pre (full) | Post (full) |${u.diff ? ' Diff |' : ''}`, `|:---:|:---:|${u.diff ? ':---:|' : ''}`, `| ![Pre full](${u.before}) | ![Post full](${u.after}) |${diffCol}`, '');
56
- lines.push('</details>', '');
59
+ // Without a crop the pair above is already the full page; repeating it
60
+ // under a fold gives a reviewer two more identical images to scroll past.
61
+ if (cropped) {
62
+ lines.push('<details>', `<summary>Full page</summary>`, '');
63
+ lines.push('| Pre (full) | Post (full) |', '|:---:|:---:|', `| ![Pre full](${u.before}) | ![Post full](${u.after}) |`, '');
64
+ lines.push('</details>', '');
65
+ }
57
66
  }
58
67
  }
68
+ for (const o of oneSided) {
69
+ const u = o.urls ?? o.files;
70
+ const image = o.status === 'added' ? u.after : u.before;
71
+ if (!image)
72
+ continue;
73
+ const what = o.status === 'added' ? 'New page' : 'Page removed';
74
+ const side = o.status === 'added' ? 'Post' : 'Pre';
75
+ lines.push(`### ${code(o.route)} — ${viewportLabel(o.viewport)} · ${what}`, '');
76
+ lines.push(o.status === 'added'
77
+ ? `This route has no baseline — ${hostOf(result.beforeBase)} returns 404 for it — so there is no "before" to show and no percentage to quote. ${side} only:`
78
+ : `This route is gone on this branch, so there is no "after". ${side} only:`, '');
79
+ lines.push(`![${side}](${image})`, '');
80
+ }
59
81
  if (unchanged.length) {
60
82
  const byRoute = groupByRoute(unchanged);
61
83
  const parts = Array.from(byRoute.entries()).map(([route, os]) => `${code(route)} (${os.map(o => o.viewport).join(', ')})`);
@@ -70,9 +92,6 @@ export function buildComment(result, options = {}) {
70
92
  if (result.skippedDynamic.length) {
71
93
  lines.push(`**Needs a sample URL:** ${result.skippedDynamic.map(code).join(', ')} — add them under ${code('"samples"')} in ${code('.pre-post.json')}.`, '');
72
94
  }
73
- const stamp = (options.now ?? new Date()).toISOString().replace('T', ' ').slice(0, 16) + ' UTC';
74
- const sha = options.headSha ? ` · ${code(options.headSha.slice(0, 7))}` : '';
75
- lines.push('---', `<sub>Captured by <a href="https://github.com/juangadm/pre-post">pre-post</a>${options.version ? ` v${options.version}` : ''}${sha} · ${stamp} · ${(result.durationMs / 1000).toFixed(1)}s</sub>`);
76
95
  return lines.join('\n');
77
96
  }
78
97
  /**
@@ -90,8 +109,12 @@ export function buildSummary(result) {
90
109
  const rows = result.outcomes.map(o => [
91
110
  o.route,
92
111
  o.viewport,
93
- o.status === 'error' ? 'error' : o.status === 'changed' ? `${pct(o.changedRatio)} changed` : 'no change',
94
- o.status === 'error' ? (o.error ?? '') : [o.sizeChanged ? 'height changed' : '', o.note || ''].filter(Boolean).join(', '),
112
+ o.status === 'error' ? 'error'
113
+ : o.status === 'changed' ? 'changed'
114
+ : o.status === 'added' ? 'new page'
115
+ : o.status === 'removed' ? 'removed'
116
+ : 'no change',
117
+ o.status === 'error' ? (o.error ?? '') : (o.note || ''),
95
118
  ]);
96
119
  const widths = [0, 1, 2].map(i => Math.max(...rows.map(r => r[i].length), 0));
97
120
  for (const r of rows) {