@juxtapose/core 0.4.0 → 0.6.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 (153) hide show
  1. package/dist/agent/handoff.d.ts +8 -1
  2. package/dist/agent/handoff.js +75 -7
  3. package/dist/agent/handoff.js.map +1 -1
  4. package/dist/analysis/affected.d.ts +37 -0
  5. package/dist/analysis/affected.js +97 -22
  6. package/dist/analysis/affected.js.map +1 -1
  7. package/dist/analysis/cause.d.ts +32 -0
  8. package/dist/analysis/cause.js +187 -0
  9. package/dist/analysis/cause.js.map +1 -0
  10. package/dist/baseline/approve.d.ts +24 -0
  11. package/dist/baseline/approve.js +54 -0
  12. package/dist/baseline/approve.js.map +1 -0
  13. package/dist/baseline/git-store.d.ts +4 -0
  14. package/dist/baseline/git-store.js +22 -0
  15. package/dist/baseline/git-store.js.map +1 -1
  16. package/dist/browser/acquire.d.ts +15 -0
  17. package/dist/browser/acquire.js +26 -0
  18. package/dist/browser/acquire.js.map +1 -0
  19. package/dist/browser/browser.d.ts +53 -0
  20. package/dist/browser/browser.js +122 -0
  21. package/dist/browser/browser.js.map +1 -0
  22. package/dist/browser/cdp.d.ts +81 -0
  23. package/dist/browser/cdp.js +230 -0
  24. package/dist/browser/cdp.js.map +1 -0
  25. package/dist/browser/daemon/client.d.ts +145 -0
  26. package/dist/browser/daemon/client.js +764 -0
  27. package/dist/browser/daemon/client.js.map +1 -0
  28. package/dist/browser/daemon/state.d.ts +99 -0
  29. package/dist/browser/daemon/state.js +297 -0
  30. package/dist/browser/daemon/state.js.map +1 -0
  31. package/dist/browser/daemon/supervisor-main.d.ts +1 -0
  32. package/dist/browser/daemon/supervisor-main.js +54 -0
  33. package/dist/browser/daemon/supervisor-main.js.map +1 -0
  34. package/dist/browser/daemon/supervisor.d.ts +37 -0
  35. package/dist/browser/daemon/supervisor.js +777 -0
  36. package/dist/browser/daemon/supervisor.js.map +1 -0
  37. package/dist/{capture/launch.d.ts → browser/flags.d.ts} +19 -1
  38. package/dist/browser/flags.js +146 -0
  39. package/dist/browser/flags.js.map +1 -0
  40. package/dist/browser/index.d.ts +14 -0
  41. package/dist/browser/index.js +14 -0
  42. package/dist/browser/index.js.map +1 -0
  43. package/dist/browser/install.d.ts +33 -0
  44. package/dist/browser/install.js +167 -0
  45. package/dist/browser/install.js.map +1 -0
  46. package/dist/browser/launch.d.ts +37 -0
  47. package/dist/browser/launch.js +254 -0
  48. package/dist/browser/launch.js.map +1 -0
  49. package/dist/browser/page.d.ts +125 -0
  50. package/dist/browser/page.js +564 -0
  51. package/dist/browser/page.js.map +1 -0
  52. package/dist/browser/pins.d.ts +12 -0
  53. package/dist/browser/pins.js +57 -0
  54. package/dist/browser/pins.js.map +1 -0
  55. package/dist/browser/private-dir.d.ts +7 -0
  56. package/dist/browser/private-dir.js +24 -0
  57. package/dist/browser/private-dir.js.map +1 -0
  58. package/dist/browser/resolve.d.ts +31 -0
  59. package/dist/browser/resolve.js +126 -0
  60. package/dist/browser/resolve.js.map +1 -0
  61. package/dist/browser/selectors.d.ts +10 -0
  62. package/dist/browser/selectors.js +60 -0
  63. package/dist/browser/selectors.js.map +1 -0
  64. package/dist/browser/transport.d.ts +51 -0
  65. package/dist/browser/transport.js +124 -0
  66. package/dist/browser/transport.js.map +1 -0
  67. package/dist/browser/types.d.ts +4 -0
  68. package/dist/browser/types.js +2 -0
  69. package/dist/browser/types.js.map +1 -0
  70. package/dist/browser/zip.d.ts +27 -0
  71. package/dist/browser/zip.js +241 -0
  72. package/dist/browser/zip.js.map +1 -0
  73. package/dist/capture/capture.d.ts +7 -1
  74. package/dist/capture/capture.js +25 -8
  75. package/dist/capture/capture.js.map +1 -1
  76. package/dist/capture/env.d.ts +1 -1
  77. package/dist/capture/pool.d.ts +1 -1
  78. package/dist/capture/pool.js +41 -8
  79. package/dist/capture/pool.js.map +1 -1
  80. package/dist/capture/settle.d.ts +1 -1
  81. package/dist/capture/settle.js +2 -0
  82. package/dist/capture/settle.js.map +1 -1
  83. package/dist/capture/snap.d.ts +43 -0
  84. package/dist/capture/snap.js +103 -0
  85. package/dist/capture/snap.js.map +1 -0
  86. package/dist/capture/structure.d.ts +77 -0
  87. package/dist/capture/structure.js +498 -0
  88. package/dist/capture/structure.js.map +1 -0
  89. package/dist/diff/compare.d.ts +19 -0
  90. package/dist/diff/compare.js +19 -0
  91. package/dist/diff/compare.js.map +1 -0
  92. package/dist/diff/crops.d.ts +26 -0
  93. package/dist/diff/crops.js +92 -0
  94. package/dist/diff/crops.js.map +1 -0
  95. package/dist/diff/structural/classify.d.ts +29 -0
  96. package/dist/diff/structural/classify.js +113 -0
  97. package/dist/diff/structural/classify.js.map +1 -0
  98. package/dist/diff/structural/coverage.d.ts +11 -0
  99. package/dist/diff/structural/coverage.js +37 -0
  100. package/dist/diff/structural/coverage.js.map +1 -0
  101. package/dist/diff/structural/deltas.d.ts +29 -0
  102. package/dist/diff/structural/deltas.js +218 -0
  103. package/dist/diff/structural/deltas.js.map +1 -0
  104. package/dist/diff/structural/disambiguate.d.ts +3 -0
  105. package/dist/diff/structural/disambiguate.js +89 -0
  106. package/dist/diff/structural/disambiguate.js.map +1 -0
  107. package/dist/diff/structural/label.d.ts +15 -0
  108. package/dist/diff/structural/label.js +64 -0
  109. package/dist/diff/structural/label.js.map +1 -0
  110. package/dist/diff/structural/match.d.ts +13 -0
  111. package/dist/diff/structural/match.js +135 -0
  112. package/dist/diff/structural/match.js.map +1 -0
  113. package/dist/diff/structural/shift.d.ts +2 -0
  114. package/dist/diff/structural/shift.js +144 -0
  115. package/dist/diff/structural/shift.js.map +1 -0
  116. package/dist/diff/structural/summary.d.ts +31 -0
  117. package/dist/diff/structural/summary.js +420 -0
  118. package/dist/diff/structural/summary.js.map +1 -0
  119. package/dist/diff/structural.d.ts +40 -0
  120. package/dist/diff/structural.js +219 -0
  121. package/dist/diff/structural.js.map +1 -0
  122. package/dist/index.d.ts +28 -4
  123. package/dist/index.js +32 -3
  124. package/dist/index.js.map +1 -1
  125. package/dist/platform.d.ts +1 -1
  126. package/dist/platforms/urls.d.ts +3 -0
  127. package/dist/platforms/urls.js +89 -0
  128. package/dist/platforms/urls.js.map +1 -0
  129. package/dist/report/comment.js +9 -3
  130. package/dist/report/comment.js.map +1 -1
  131. package/dist/report/format.d.ts +18 -0
  132. package/dist/report/format.js +20 -0
  133. package/dist/report/format.js.map +1 -1
  134. package/dist/report/html.js +2 -2
  135. package/dist/report/html.js.map +1 -1
  136. package/dist/run/groups.d.ts +2 -0
  137. package/dist/run/groups.js +45 -0
  138. package/dist/run/groups.js.map +1 -0
  139. package/dist/run/run.d.ts +6 -2
  140. package/dist/run/run.js +74 -6
  141. package/dist/run/run.js.map +1 -1
  142. package/dist/shell-quote.d.ts +2 -0
  143. package/dist/shell-quote.js +10 -0
  144. package/dist/shell-quote.js.map +1 -0
  145. package/dist/types.d.ts +201 -5
  146. package/dist/types.js +0 -2
  147. package/dist/types.js.map +1 -1
  148. package/dist/url-platform.d.ts +2 -2
  149. package/dist/url-platform.js +2 -2
  150. package/dist/url-platform.js.map +1 -1
  151. package/package.json +6 -10
  152. package/dist/capture/launch.js +0 -56
  153. package/dist/capture/launch.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/report/format.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,4EAA4E;AAE5E,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC7C,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/report/format.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,4EAA4E;AAE5E,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC7C,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,CAI9B;IACC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,cAAc,KAAK,CAAC,IAAI,CAAC,CAAC,eAAe,KAAK,CAAC,CAAC;AACvE,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,iBAAiB,CAAC,CAAuC;IACvE,OAAO,cAAc,CAAC,CAAC,CAAC;QACtB,CAAC,CAAC,qCAAqC;QACvC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,UAAU,CAAC;AACpD,CAAC"}
@@ -8,7 +8,7 @@
8
8
  // This complements rather than duplicates the addon panel. The panel is for
9
9
  // local review with a dev server running; this is for a reviewer looking at a
10
10
  // pull request who has checked nothing out.
11
- import { formatPercent } from './format.js';
11
+ import { describeMagnitude } from './format.js';
12
12
  export function buildHtmlReport({ report, images }) {
13
13
  const needsReview = report.results.filter((r) => r.status === 'fail' || r.status === 'new' || r.status === 'stale');
14
14
  const s = report.summary;
@@ -58,7 +58,7 @@ function storySection(result, imgs) {
58
58
  <h2>
59
59
  <span class="badge ${result.status}">${statusLabel(result.status)}</span>
60
60
  ${escapeHtml(result.storyId)}
61
- ${result.status === 'fail' ? `<span class="pct">${escapeHtml(formatPercent(result.mismatchPercent))} changed</span>` : ''}
61
+ ${result.status === 'fail' ? `<span class="pct">${escapeHtml(describeMagnitude(result))}</span>` : ''}
62
62
  </h2>
63
63
  ${result.error ? `<p class="error">${escapeHtml(result.error)}</p>` : ''}
64
64
  ${comparable
@@ -1 +1 @@
1
- {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/report/html.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/report/html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { DiffResult, RunGroup } from '../types.js';
2
+ export declare function computeGroups(results: DiffResult[]): RunGroup[];
@@ -0,0 +1,45 @@
1
+ // Which failing stories changed the same way. The verdict's signature
2
+ // already abstracts the element to role|tag and keeps the values, so "every
3
+ // button background #2563eb→#1d4ed8" hashes alike on every page that made
4
+ // that change; grouping is a bucket sort on it. Cold path: runs once per
5
+ // report, after every story is judged.
6
+ import { compareCodeUnits } from '../diff/structural/deltas.js';
7
+ export function computeGroups(results) {
8
+ const bySignature = new Map();
9
+ for (const r of results) {
10
+ // A verdict with no deltas has a signature that depends on the
11
+ // classification alone: unrelated identical, drifting or resized
12
+ // stories would "share" it, and there is no change to state.
13
+ if (r.status !== 'fail' || !r.structural || r.structural.deltaCount === 0)
14
+ continue;
15
+ const { signature, change, summary } = r.structural;
16
+ const text = change ?? summary;
17
+ const g = bySignature.get(signature);
18
+ if (!g)
19
+ bySignature.set(signature, { ids: [r.storyId], first: r.storyId, change: text });
20
+ else {
21
+ g.ids.push(r.storyId);
22
+ // The wording of the first story in code-unit order, whatever the
23
+ // input order: two verdicts of one signature can word it differently.
24
+ if (compareCodeUnits(r.storyId, g.first) < 0) {
25
+ g.first = r.storyId;
26
+ g.change = text;
27
+ }
28
+ }
29
+ }
30
+ // Collected through a Map, emitted through a sort: insertion order never
31
+ // reaches the report.
32
+ const groups = [];
33
+ for (const [signature, g] of bySignature) {
34
+ if (g.ids.length < 2)
35
+ continue;
36
+ const storyIds = [...g.ids].sort(compareCodeUnits);
37
+ groups.push({
38
+ signature,
39
+ summary: `${g.change} — ${storyIds.length} stories`,
40
+ storyIds,
41
+ });
42
+ }
43
+ return groups.sort((x, y) => y.storyIds.length - x.storyIds.length || compareCodeUnits(x.signature, y.signature));
44
+ }
45
+ //# sourceMappingURL=groups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups.js","sourceRoot":"","sources":["../../src/run/groups.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,4EAA4E;AAC5E,0EAA0E;AAC1E,yEAAyE;AACzE,uCAAuC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,MAAM,UAAU,aAAa,CAAC,OAAqB;IACjD,MAAM,WAAW,GAAG,IAAI,GAAG,EAA4D,CAAC;IACxF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,+DAA+D;QAC/D,iEAAiE;QACjE,6DAA6D;QAC7D,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,UAAU,CAAC,UAAU,KAAK,CAAC;YAAE,SAAS;QACpF,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC;QACpD,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAC;QAC/B,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,CAAC,CAAC;YACJ,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;aAC9E,CAAC;YACJ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACtB,kEAAkE;YAClE,sEAAsE;YACtE,IAAI,gBAAgB,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7C,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC;gBACpB,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IACD,yEAAyE;IACzE,sBAAsB;IACtB,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC;QACzC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAC/B,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC;YACV,SAAS;YACT,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,MAAM,QAAQ,CAAC,MAAM,UAAU;YACnD,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAChB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,IAAI,gBAAgB,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,CACtF,CAAC;AACJ,CAAC"}
package/dist/run/run.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import type { Browser } from 'playwright';
1
+ import type { Browser } from '../browser/browser.js';
2
2
  import type { Platform } from '../platform.js';
3
- import type { BaselineStore, DiffStatus, ProjectConfig, RunReport, StoryManifest, Viewport } from '../types.js';
3
+ import type { BaselineStore, DiffStatus, ProjectConfig, RunReport, StoryManifest, StructureSnapshot, Viewport } from '../types.js';
4
4
  import { type AncestryCheck } from '../baseline/status.js';
5
5
  import { type Phases } from './phases.js';
6
+ import type { CauseIndex } from '../analysis/cause.js';
6
7
  export declare const DEFAULT_VIEWPORT: Viewport;
7
8
  export interface RunOptions {
8
9
  browser: Browser;
@@ -24,11 +25,14 @@ export interface RunOptions {
24
25
  /** Collects per-phase wall time. Pass one to fold in phases the caller timed
25
26
  * itself (enumerate, affected, launch); omit and one is made internally. */
26
27
  phases?: Phases;
28
+ /** From `jux run --since`: consulted only for a story that failed. */
29
+ cause?: CauseIndex;
27
30
  }
28
31
  export interface RunArtifact {
29
32
  storyId: string;
30
33
  status: DiffStatus;
31
34
  current: Buffer;
32
35
  diff?: Buffer;
36
+ structure?: StructureSnapshot;
33
37
  }
34
38
  export declare function runCapture(opts: RunOptions): Promise<RunReport>;
package/dist/run/run.js CHANGED
@@ -7,8 +7,13 @@
7
7
  import { captureEnv } from '../capture/env.js';
8
8
  import { capturePool } from '../capture/pool.js';
9
9
  import { resolveStatus, toDiffStatus } from '../baseline/status.js';
10
- import { diffImages, resolveThreshold, resolveMinDiffPercent } from '../diff/diff.js';
10
+ import { decodeStructure } from '../capture/structure.js';
11
+ import { structuralDiff } from '../diff/structural.js';
12
+ import { compareCodeUnits } from '../diff/structural/deltas.js';
13
+ import { computeGroups } from './groups.js';
14
+ import { diffImages, resolveThreshold, resolveMinDiffPercent, } from '../diff/diff.js';
11
15
  import { phases } from './phases.js';
16
+ import { shellQuote } from '../shell-quote.js';
12
17
  export const DEFAULT_VIEWPORT = { width: 1280, height: 800 };
13
18
  export async function runCapture(opts) {
14
19
  const startedAt = new Date();
@@ -57,9 +62,14 @@ export async function runCapture(opts) {
57
62
  }
58
63
  results.push(await judge(outcome.snapshot, outcome.story, manifest, opts, p));
59
64
  }
60
- // Diffing happens inside the loop, so subtract it to leave capture alone.
61
- p.add('capture', Date.now() - captureStarted - (p.timings.diff ?? 0));
65
+ // Diffing and cause tracing happen inside the loop; subtract both to
66
+ // leave capture alone.
67
+ p.add('capture', Date.now() - captureStarted - (p.timings.diff ?? 0) - (p.timings.cause ?? 0));
62
68
  const summary = tally(results);
69
+ // Code-unit order: the report is byte-stable across machines, and
70
+ // localeCompare is not.
71
+ results.sort((a, b) => compareCodeUnits(a.storyId, b.storyId));
72
+ const groups = computeGroups(results);
63
73
  return {
64
74
  runId: opts.runId,
65
75
  branch: opts.branch,
@@ -70,8 +80,9 @@ export async function runCapture(opts) {
70
80
  env: captureEnv(opts.browser),
71
81
  capturedCount: opts.stories.length,
72
82
  totalCount: opts.totalCount,
73
- results: results.sort((a, b) => a.storyId.localeCompare(b.storyId)),
83
+ results,
74
84
  summary,
85
+ ...(groups.length > 0 ? { groups } : {}),
75
86
  durationMs: Date.now() - started,
76
87
  startedAt: startedAt.toISOString(),
77
88
  };
@@ -95,13 +106,23 @@ async function judge(snapshot, story, manifest, opts, p) {
95
106
  // pass / new / stale need no pixel work: there is either nothing to explain
96
107
  // or nothing to compare against.
97
108
  if (status !== 'fail') {
98
- await opts.onArtifact?.({ storyId: story.storyId, status, current: snapshot.image });
109
+ await opts.onArtifact?.({
110
+ storyId: story.storyId,
111
+ status,
112
+ current: snapshot.image,
113
+ structure: snapshot.structure,
114
+ });
99
115
  return base;
100
116
  }
101
117
  const baseline = await opts.store.get(story.storyId);
102
118
  if (!baseline) {
103
119
  // The manifest claimed a baseline the store can't produce.
104
- await opts.onArtifact?.({ storyId: story.storyId, status, current: snapshot.image });
120
+ await opts.onArtifact?.({
121
+ storyId: story.storyId,
122
+ status,
123
+ current: snapshot.image,
124
+ structure: snapshot.structure,
125
+ });
105
126
  return { ...base, error: 'baseline missing from store' };
106
127
  }
107
128
  // Counted as well as timed: under a byte-exact hash the number of diffs is
@@ -116,15 +137,62 @@ async function judge(snapshot, story, manifest, opts, p) {
116
137
  status,
117
138
  current: snapshot.image,
118
139
  diff: diff.diffImage,
140
+ structure: snapshot.structure,
119
141
  });
142
+ // Structure explains the failure after the pixels have decided it. The
143
+ // baseline sidecar is read only here, so a green run never touches one. A
144
+ // manifest hash is not a file: read the store, and treat anything
145
+ // unreadable as absent. This code runs only on a hash mismatch.
146
+ const structural = await tryStructural(opts, story, snapshot, diff, p);
120
147
  return {
121
148
  ...base,
122
149
  mismatchPixels: diff.mismatchPixels,
123
150
  mismatchPercent: diff.mismatchPercent,
124
151
  changedRegions: diff.changedRegions,
125
152
  error: diff.dimensionMismatch ? 'viewport size changed since baseline' : undefined,
153
+ ...(structural ? { structural } : {}),
126
154
  };
127
155
  }
156
+ /** A sidecar that is absent or unreadable is simply no baseline structure. */
157
+ async function readBaselineStructure(store, storyId) {
158
+ try {
159
+ const gz = store.getStructure ? await store.getStructure(storyId) : null;
160
+ return gz ? decodeStructure(gz) : undefined;
161
+ }
162
+ catch {
163
+ return undefined;
164
+ }
165
+ }
166
+ /** Structure explains a failure, never decides one, so nothing in here may
167
+ * fail the story: a missing, corrupt or malformed sidecar, a cause index
168
+ * that throws, or a bug in the diff, yields no verdict (or one without a
169
+ * cause) and the pixel result stands. */
170
+ async function tryStructural(opts, story, snapshot, pixels, p) {
171
+ if (!snapshot.structure)
172
+ return undefined;
173
+ let cause;
174
+ if (opts.cause) {
175
+ try {
176
+ cause = await p.time('cause', () => opts.cause.causeFor(story.componentPath));
177
+ }
178
+ catch {
179
+ cause = undefined;
180
+ }
181
+ }
182
+ try {
183
+ return structuralDiff({
184
+ baseline: await readBaselineStructure(opts.store, story.storyId),
185
+ current: snapshot.structure,
186
+ imagesIdentical: false,
187
+ pixels,
188
+ escalate: { command: `jux handoff ${shellQuote(story.storyId)}` },
189
+ ...(cause ? { cause } : {}),
190
+ });
191
+ }
192
+ catch {
193
+ return undefined;
194
+ }
195
+ }
128
196
  function tally(results) {
129
197
  const summary = {
130
198
  pass: 0,
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/run/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/run/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** Single-quote a value for a POSIX shell unless it is plainly safe. */
2
+ export declare function shellQuote(v: string): string;
@@ -0,0 +1,10 @@
1
+ // Every hint that prints a command prints one an agent can paste. A snap
2
+ // name with a space (`jux diff 'a b' x`) printed bare made the suggested
3
+ // `jux snap <url> --as a b` a different command. In core so the verdict's
4
+ // `escalate.command` and the CLI's hints share one implementation.
5
+ const SHELL_SAFE = /^[A-Za-z0-9_@%+=:,./-]+$/;
6
+ /** Single-quote a value for a POSIX shell unless it is plainly safe. */
7
+ export function shellQuote(v) {
8
+ return SHELL_SAFE.test(v) ? v : `'${v.replaceAll("'", "'\\''")}'`;
9
+ }
10
+ //# sourceMappingURL=shell-quote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-quote.js","sourceRoot":"","sources":["../src/shell-quote.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,yEAAyE;AACzE,0EAA0E;AAC1E,mEAAmE;AAEnE,MAAM,UAAU,GAAG,0BAA0B,CAAC;AAE9C,wEAAwE;AACxE,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC;AACpE,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Viewport } from './browser/types.js';
1
2
  /** Per-story tuning, read from the platform's story parameters. */
2
3
  export interface StoryParams {
3
4
  /** Exclude this story from capture entirely. */
@@ -27,10 +28,7 @@ export interface StoryParams {
27
28
  * cost more than it returns. Default true. */
28
29
  liveCapture?: boolean;
29
30
  }
30
- export interface Viewport {
31
- width: number;
32
- height: number;
33
- }
31
+ export type { Viewport } from './browser/types.js';
34
32
  /** One capturable story, normalised across platforms. */
35
33
  export interface StoryManifest {
36
34
  /** Stable, URL-safe. Platform-native id (Storybook's `id`, Ladle's key). */
@@ -52,6 +50,49 @@ export interface Snapshot {
52
50
  capturedAt: string;
53
51
  /** Wall time for this story's capture, ms. */
54
52
  durationMs: number;
53
+ /** Visible elements and their styles, from the same frame as `image`.
54
+ * Absent when structure capture failed or was disabled — it explains a
55
+ * failure, it never decides one. */
56
+ structure?: StructureSnapshot;
57
+ }
58
+ export interface StructureRect {
59
+ x: number;
60
+ y: number;
61
+ w: number;
62
+ h: number;
63
+ }
64
+ export interface StructureElement {
65
+ /** tag + (#id | [data-testid] | :nth-of-type) chain from <html>. */
66
+ path: string;
67
+ /** Index of the nearest kept ancestor in `elements`, null at the root. */
68
+ parent: number | null;
69
+ tag: string;
70
+ id?: string;
71
+ testId?: string;
72
+ classes?: string[];
73
+ role?: string;
74
+ name?: string;
75
+ text?: string;
76
+ src?: string;
77
+ rect: StructureRect;
78
+ paintOrder: number;
79
+ /** Compact: see effectiveStyle() in capture/structure.ts. */
80
+ styles: Record<string, string>;
81
+ }
82
+ export interface StructureSnapshot {
83
+ schema: 'juxtapose.structure/v1';
84
+ viewport: Viewport;
85
+ /** sha256 of the canonical JSON of `elements`. Equal ⇒ identical structure
86
+ * and styles, so a pixel difference is render drift. */
87
+ structureHash: string;
88
+ /** Full document height, from CDP. Greater than viewport.height means part
89
+ * of the page was never captured — PR (b)'s `below-fold` flag reads this. */
90
+ contentHeight: number;
91
+ elements: StructureElement[];
92
+ truncated?: {
93
+ kept: number;
94
+ total: number;
95
+ };
55
96
  }
56
97
  export interface ChangedRegion {
57
98
  x: number;
@@ -59,6 +100,126 @@ export interface ChangedRegion {
59
100
  width: number;
60
101
  height: number;
61
102
  }
103
+ /** One changed fact between two structure snapshots. `el` is a short human
104
+ * label (`button[name="Save"]`, `div#row-1`, `div.card`, or a trimmed path). */
105
+ export type Delta = {
106
+ kind: 'text';
107
+ el: string;
108
+ from: string;
109
+ to: string;
110
+ } | {
111
+ kind: 'style';
112
+ el: string;
113
+ prop: string;
114
+ from: string;
115
+ to: string;
116
+ } | {
117
+ kind: 'attr';
118
+ el: string;
119
+ attr: 'src' | 'role' | 'name';
120
+ from: string;
121
+ to: string;
122
+ } | {
123
+ kind: 'added';
124
+ el: string;
125
+ rect: StructureRect;
126
+ } | {
127
+ kind: 'removed';
128
+ el: string;
129
+ rect: StructureRect;
130
+ } | {
131
+ kind: 'moved';
132
+ el: string;
133
+ dx: number;
134
+ dy: number;
135
+ } | {
136
+ kind: 'resized';
137
+ el: string;
138
+ dw: number;
139
+ dh: number;
140
+ }
141
+ /** ≥3 contiguous elements after `after` moved by the same (dx, dy). */
142
+ | {
143
+ kind: 'shift';
144
+ after: string;
145
+ dx: number;
146
+ dy: number;
147
+ count: number;
148
+ };
149
+ export type Classification = 'identical' | 'render-drift' | 'dimension-change' | 'element-added' | 'element-removed' | 'reflow' | 'geometry' | 'text-only' | 'style-only' | 'attr-only' | 'mixed' | 'unknown';
150
+ /** Sub-tags of `style-only`, so "colour tweak" and "spacing change" read
151
+ * differently at a glance. */
152
+ export type StyleTag = 'color' | 'typography' | 'spacing' | 'border' | 'effects';
153
+ export type Flag = 'element-removed' | 'text-changed' | 'large-reflow' | 'unexplained-pixels'
154
+ /** The images differ but the pixel diff marked nothing: the change is below
155
+ * its tolerance, and the structural deltas are the change. */
156
+ | 'sub-threshold' | 'structure-truncated' | 'no-baseline-structure' | 'no-current-structure'
157
+ /** Either side's content is taller than the viewport: changes below the
158
+ * fold are invisible to both pixels and structure. */
159
+ | 'below-fold';
160
+ export type CauseKind =
161
+ /** At least one changed file is in the story's import closure. */
162
+ 'in-closure'
163
+ /** A changed file reaches every story: a root lockfile or a platform config dir. */
164
+ | 'config'
165
+ /** The closure was traced and no changed file is in it: the strongest
166
+ * "this is not your code" the tool can give, especially beside render-drift. */
167
+ | 'none-in-closure'
168
+ /** No --since, no manifest, git failed, or the story is not in the graph. */
169
+ | 'unknown';
170
+ /** Why this story changed: the cheap link only (story → import closure →
171
+ * changed files). Matched CSS rules and source lines are later rows. */
172
+ export interface Cause {
173
+ kind: CauseKind;
174
+ /** At most 5, nearest first; posix paths relative to the project root. */
175
+ files: Array<{
176
+ path: string;
177
+ distance: number;
178
+ }>;
179
+ /** `in-closure` only: the closure was not fully traced (a bundled chunk
180
+ * with no src, or a changed file the manifest never names), so the cause
181
+ * may be a file not listed. Absent, never false, when the trace was full. */
182
+ partial?: true;
183
+ }
184
+ /** Tier-0: what changed, in a few hundred characters, with whether it
185
+ * explains every changed pixel. The whole output of `jux diff`. */
186
+ export interface StructuralVerdict {
187
+ schema: 'juxtapose.verdict/v1';
188
+ classification: Classification;
189
+ /** Empty unless classification is `style-only` or `mixed`. */
190
+ styleTags: StyleTag[];
191
+ /** Templated, deterministic, ≤ 300 chars. */
192
+ summary: string;
193
+ /** The change with every element reduced to role|tag and no per-story
194
+ * tail, ≤ 160 chars: what stories sharing a `signature` have in common.
195
+ * Absent when there are no deltas. */
196
+ change?: string;
197
+ /** At most 20, and only the prefix that keeps the whole verdict within
198
+ * 1,500 chars; `deltaCount` is the total. */
199
+ deltas: Delta[];
200
+ /** Counted after suppression: a child that only followed its parent's
201
+ * move or resize, and a style inherited from where it originated, are not
202
+ * deltas, nor is an added/removed element hidden by the other side's
203
+ * truncation; a shift run counts once. */
204
+ deltaCount: number;
205
+ /** Fraction of changed-region area intersecting some delta's element. */
206
+ coverage: number;
207
+ /** ≥ 0.98 | ≥ 0.5 | below. */
208
+ explained: 'full' | 'partial' | 'none';
209
+ /** The prefix that fits the 1,500-char verdict; `coverage` covers all. */
210
+ unexplainedRegions: ChangedRegion[];
211
+ flags: Flag[];
212
+ /** Present only in `jux run --since`; absent from `jux diff`. */
213
+ cause?: Cause;
214
+ /** sha256 over the classification and the delta set with elements
215
+ * abstracted to role|tag, so two pages with the same change share one.
216
+ * Over the same post-suppression facts `deltaCount` counts. */
217
+ signature: string;
218
+ /** The exact command for tier-3 pixels. */
219
+ escalate: {
220
+ command: string;
221
+ };
222
+ }
62
223
  export type DiffStatus = 'pass' | 'fail' | 'new' | 'stale' | 'skip';
63
224
  export interface DiffResult {
64
225
  storyId: string;
@@ -76,8 +237,22 @@ export interface DiffResult {
76
237
  viewport?: Viewport;
77
238
  /** Set when the capture or diff threw. status is 'fail' in that case. */
78
239
  error?: string;
240
+ /** Tier-0 explanation of a failure. Present only when status is 'fail' and
241
+ * the current capture produced a structure; never consulted on pass. */
242
+ structural?: StructuralVerdict;
79
243
  durationMs: number;
80
244
  }
245
+ /** One change seen on several stories: the same signature on ≥2 failing
246
+ * results. Listing them is what turns 40 handoffs into one decision;
247
+ * approving by group is a later row. */
248
+ export interface RunGroup {
249
+ signature: string;
250
+ /** The shared change, as `<change> — N stories`: the verdict's `change`
251
+ * (elements as role|tag), not one page's labelled summary. */
252
+ summary: string;
253
+ /** ≥ 2, code-unit sorted. */
254
+ storyIds: string[];
255
+ }
81
256
  export interface RunReport {
82
257
  runId: string;
83
258
  branch: string;
@@ -90,6 +265,8 @@ export interface RunReport {
90
265
  totalCount: number;
91
266
  results: DiffResult[];
92
267
  summary: Record<DiffStatus, number>;
268
+ /** Present when at least one signature is shared by ≥2 failing stories. */
269
+ groups?: RunGroup[];
93
270
  durationMs: number;
94
271
  startedAt: string;
95
272
  }
@@ -114,6 +291,9 @@ export interface ApprovalMeta {
114
291
  /** Absent on entries approved before this was recorded. Absent must not read
115
292
  * as "matches": an unknown origin is unknown, not current. */
116
293
  env?: CaptureEnv;
294
+ /** structureHash of the approved capture's sidecar. Absent when the capture
295
+ * had no structure, or was approved before sidecars existed. */
296
+ structureHash?: string;
117
297
  }
118
298
  export interface BaselineEntry extends ApprovalMeta {
119
299
  /** sha256 of the baseline image bytes. Detects drift between manifest
@@ -126,10 +306,20 @@ export interface BaselineManifest {
126
306
  version: 1;
127
307
  baselines: Record<string, BaselineEntry>;
128
308
  }
309
+ /** One page for the `urls` platform. */
310
+ export interface UrlEntry {
311
+ /** Stable id; used as the story id and for file names. */
312
+ id: string;
313
+ /** Absolute, or relative to --origin. */
314
+ url: string;
315
+ params?: StoryParams;
316
+ }
129
317
  /** Project config, from juxtapose.config.{ts,js,json} or package.json#juxtapose. */
130
318
  export interface ProjectConfig {
131
319
  /** Which workbench. Autodetected when omitted. */
132
- platform?: 'storybook' | 'ladle';
320
+ platform?: 'storybook' | 'ladle' | 'urls';
321
+ /** Pages to capture when `platform` is 'urls'. */
322
+ urls?: UrlEntry[];
133
323
  /** Where the built static workbench lives. */
134
324
  buildDir?: string;
135
325
  /** Capture against an already-running dev server instead of building. */
@@ -167,4 +357,10 @@ export interface BaselineStore {
167
357
  remove(storyId: string): Promise<void>;
168
358
  readManifest(): Promise<BaselineManifest>;
169
359
  writeManifest(manifest: BaselineManifest): Promise<void>;
360
+ /** Optional: stores that can hold the gzipped structure sidecar. */
361
+ putStructure?(storyId: string, gz: Buffer): Promise<void>;
362
+ getStructure?(storyId: string): Promise<Buffer | null>;
363
+ /** Optional: where the baseline image lives on disk, for stores that keep
364
+ * one. The handoff hands it to `jux diff … --crops`. */
365
+ locate?(storyId: string): string | undefined;
170
366
  }
package/dist/types.js CHANGED
@@ -1,4 +1,2 @@
1
- // Core data model. Deliberately free of any platform (Storybook/Ladle) types —
2
- // adapters map their world onto these.
3
1
  export {};
4
2
  //# 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,+EAA+E;AAC/E,uCAAuC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -1,8 +1,8 @@
1
- import type { Page } from 'playwright';
1
+ import type { Page } from './browser/page.js';
2
2
  /**
3
3
  * Build a `showStory` implementation from a URL builder.
4
4
  *
5
- * Note `waitUntil: 'load'` rather than `networkidle`: the platform's own
5
+ * `page.goto` resolves on the main frame's `load`, not network idle: the platform's own
6
6
  * render signal and core's settle pipeline decide when the page is actually
7
7
  * ready. Waiting for network idle here would be both slower and less reliable
8
8
  * — a story that polls would never satisfy it.
@@ -9,14 +9,14 @@
9
9
  /**
10
10
  * Build a `showStory` implementation from a URL builder.
11
11
  *
12
- * Note `waitUntil: 'load'` rather than `networkidle`: the platform's own
12
+ * `page.goto` resolves on the main frame's `load`, not network idle: the platform's own
13
13
  * render signal and core's settle pipeline decide when the page is actually
14
14
  * ready. Waiting for network idle here would be both slower and less reliable
15
15
  * — a story that polls would never satisfy it.
16
16
  */
17
17
  export function navigateToStory(storyUrl) {
18
18
  return async (page, storyId, baseUrl) => {
19
- await page.goto(storyUrl(baseUrl, storyId), { waitUntil: 'load' });
19
+ await page.goto(storyUrl(baseUrl, storyId));
20
20
  };
21
21
  }
22
22
  //# sourceMappingURL=url-platform.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"url-platform.js","sourceRoot":"","sources":["../src/url-platform.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,8CAA8C;AAC9C,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AAIpE;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAsD;IAEtD,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QACtC,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"url-platform.js","sourceRoot":"","sources":["../src/url-platform.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,8CAA8C;AAC9C,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AAIpE;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAsD;IAEtD,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QACtC,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC;AACJ,CAAC"}