perfgraph 0.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 (263) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -0
  3. package/dist/causal/builder.d.ts +34 -0
  4. package/dist/causal/builder.d.ts.map +1 -0
  5. package/dist/causal/builder.js +132 -0
  6. package/dist/causal/builder.js.map +1 -0
  7. package/dist/causal/index.d.ts +11 -0
  8. package/dist/causal/index.d.ts.map +1 -0
  9. package/dist/causal/index.js +10 -0
  10. package/dist/causal/index.js.map +1 -0
  11. package/dist/causal/rules/js.d.ts +49 -0
  12. package/dist/causal/rules/js.d.ts.map +1 -0
  13. package/dist/causal/rules/js.js +209 -0
  14. package/dist/causal/rules/js.js.map +1 -0
  15. package/dist/causal/rules/layout.d.ts +39 -0
  16. package/dist/causal/rules/layout.d.ts.map +1 -0
  17. package/dist/causal/rules/layout.js +169 -0
  18. package/dist/causal/rules/layout.js.map +1 -0
  19. package/dist/causal/rules/lcp.d.ts +49 -0
  20. package/dist/causal/rules/lcp.d.ts.map +1 -0
  21. package/dist/causal/rules/lcp.js +250 -0
  22. package/dist/causal/rules/lcp.js.map +1 -0
  23. package/dist/causal/rules/network.d.ts +39 -0
  24. package/dist/causal/rules/network.d.ts.map +1 -0
  25. package/dist/causal/rules/network.js +140 -0
  26. package/dist/causal/rules/network.js.map +1 -0
  27. package/dist/causal/types.d.ts +142 -0
  28. package/dist/causal/types.d.ts.map +1 -0
  29. package/dist/causal/types.js +88 -0
  30. package/dist/causal/types.js.map +1 -0
  31. package/dist/cli/analyze.d.ts +33 -0
  32. package/dist/cli/analyze.d.ts.map +1 -0
  33. package/dist/cli/analyze.js +137 -0
  34. package/dist/cli/analyze.js.map +1 -0
  35. package/dist/cli/collect.d.ts +28 -0
  36. package/dist/cli/collect.d.ts.map +1 -0
  37. package/dist/cli/collect.js +125 -0
  38. package/dist/cli/collect.js.map +1 -0
  39. package/dist/cli/extract.d.ts +31 -0
  40. package/dist/cli/extract.d.ts.map +1 -0
  41. package/dist/cli/extract.js +135 -0
  42. package/dist/cli/extract.js.map +1 -0
  43. package/dist/cli/mcp.d.ts +14 -0
  44. package/dist/cli/mcp.d.ts.map +1 -0
  45. package/dist/cli/mcp.js +53 -0
  46. package/dist/cli/mcp.js.map +1 -0
  47. package/dist/cli/normalize.d.ts +58 -0
  48. package/dist/cli/normalize.d.ts.map +1 -0
  49. package/dist/cli/normalize.js +179 -0
  50. package/dist/cli/normalize.js.map +1 -0
  51. package/dist/cli/report.d.ts +33 -0
  52. package/dist/cli/report.d.ts.map +1 -0
  53. package/dist/cli/report.js +137 -0
  54. package/dist/cli/report.js.map +1 -0
  55. package/dist/cli/run.d.ts +49 -0
  56. package/dist/cli/run.d.ts.map +1 -0
  57. package/dist/cli/run.js +243 -0
  58. package/dist/cli/run.js.map +1 -0
  59. package/dist/collect/buffer-monitor.d.ts +25 -0
  60. package/dist/collect/buffer-monitor.d.ts.map +1 -0
  61. package/dist/collect/buffer-monitor.js +69 -0
  62. package/dist/collect/buffer-monitor.js.map +1 -0
  63. package/dist/collect/console.d.ts +25 -0
  64. package/dist/collect/console.d.ts.map +1 -0
  65. package/dist/collect/console.js +82 -0
  66. package/dist/collect/console.js.map +1 -0
  67. package/dist/collect/coverage.d.ts +26 -0
  68. package/dist/collect/coverage.d.ts.map +1 -0
  69. package/dist/collect/coverage.js +99 -0
  70. package/dist/collect/coverage.js.map +1 -0
  71. package/dist/collect/dom.d.ts +37 -0
  72. package/dist/collect/dom.d.ts.map +1 -0
  73. package/dist/collect/dom.js +118 -0
  74. package/dist/collect/dom.js.map +1 -0
  75. package/dist/collect/lighthouse.d.ts +41 -0
  76. package/dist/collect/lighthouse.d.ts.map +1 -0
  77. package/dist/collect/lighthouse.js +111 -0
  78. package/dist/collect/lighthouse.js.map +1 -0
  79. package/dist/collect/network.d.ts +32 -0
  80. package/dist/collect/network.d.ts.map +1 -0
  81. package/dist/collect/network.js +236 -0
  82. package/dist/collect/network.js.map +1 -0
  83. package/dist/collect/orchestrator.d.ts +23 -0
  84. package/dist/collect/orchestrator.d.ts.map +1 -0
  85. package/dist/collect/orchestrator.js +350 -0
  86. package/dist/collect/orchestrator.js.map +1 -0
  87. package/dist/collect/performance.d.ts +28 -0
  88. package/dist/collect/performance.d.ts.map +1 -0
  89. package/dist/collect/performance.js +108 -0
  90. package/dist/collect/performance.js.map +1 -0
  91. package/dist/collect/runtime.d.ts +26 -0
  92. package/dist/collect/runtime.d.ts.map +1 -0
  93. package/dist/collect/runtime.js +81 -0
  94. package/dist/collect/runtime.js.map +1 -0
  95. package/dist/collect/session.d.ts +58 -0
  96. package/dist/collect/session.d.ts.map +1 -0
  97. package/dist/collect/session.js +162 -0
  98. package/dist/collect/session.js.map +1 -0
  99. package/dist/collect/trace.d.ts +40 -0
  100. package/dist/collect/trace.d.ts.map +1 -0
  101. package/dist/collect/trace.js +127 -0
  102. package/dist/collect/trace.js.map +1 -0
  103. package/dist/collect/types.d.ts +317 -0
  104. package/dist/collect/types.d.ts.map +1 -0
  105. package/dist/collect/types.js +12 -0
  106. package/dist/collect/types.js.map +1 -0
  107. package/dist/distill/insights.d.ts +67 -0
  108. package/dist/distill/insights.d.ts.map +1 -0
  109. package/dist/distill/insights.js +317 -0
  110. package/dist/distill/insights.js.map +1 -0
  111. package/dist/distill/summaries.d.ts +71 -0
  112. package/dist/distill/summaries.d.ts.map +1 -0
  113. package/dist/distill/summaries.js +165 -0
  114. package/dist/distill/summaries.js.map +1 -0
  115. package/dist/extract/critical-path.d.ts +17 -0
  116. package/dist/extract/critical-path.d.ts.map +1 -0
  117. package/dist/extract/critical-path.js +95 -0
  118. package/dist/extract/critical-path.js.map +1 -0
  119. package/dist/extract/index.d.ts +16 -0
  120. package/dist/extract/index.d.ts.map +1 -0
  121. package/dist/extract/index.js +32 -0
  122. package/dist/extract/index.js.map +1 -0
  123. package/dist/extract/js-hotspots.d.ts +15 -0
  124. package/dist/extract/js-hotspots.d.ts.map +1 -0
  125. package/dist/extract/js-hotspots.js +22 -0
  126. package/dist/extract/js-hotspots.js.map +1 -0
  127. package/dist/extract/layout-shifts.d.ts +19 -0
  128. package/dist/extract/layout-shifts.d.ts.map +1 -0
  129. package/dist/extract/layout-shifts.js +47 -0
  130. package/dist/extract/layout-shifts.js.map +1 -0
  131. package/dist/extract/lcp-breakdown.d.ts +19 -0
  132. package/dist/extract/lcp-breakdown.d.ts.map +1 -0
  133. package/dist/extract/lcp-breakdown.js +110 -0
  134. package/dist/extract/lcp-breakdown.js.map +1 -0
  135. package/dist/extract/main-thread.d.ts +16 -0
  136. package/dist/extract/main-thread.d.ts.map +1 -0
  137. package/dist/extract/main-thread.js +41 -0
  138. package/dist/extract/main-thread.js.map +1 -0
  139. package/dist/extract/render-blocking.d.ts +16 -0
  140. package/dist/extract/render-blocking.d.ts.map +1 -0
  141. package/dist/extract/render-blocking.js +79 -0
  142. package/dist/extract/render-blocking.js.map +1 -0
  143. package/dist/extract/third-party.d.ts +15 -0
  144. package/dist/extract/third-party.d.ts.map +1 -0
  145. package/dist/extract/third-party.js +127 -0
  146. package/dist/extract/third-party.js.map +1 -0
  147. package/dist/extract/types.d.ts +183 -0
  148. package/dist/extract/types.d.ts.map +1 -0
  149. package/dist/extract/types.js +118 -0
  150. package/dist/extract/types.js.map +1 -0
  151. package/dist/index.d.ts +20 -0
  152. package/dist/index.d.ts.map +1 -0
  153. package/dist/index.js +188 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/mcp/handlers.d.ts +72 -0
  156. package/dist/mcp/handlers.d.ts.map +1 -0
  157. package/dist/mcp/handlers.js +285 -0
  158. package/dist/mcp/handlers.js.map +1 -0
  159. package/dist/mcp/progress.d.ts +37 -0
  160. package/dist/mcp/progress.d.ts.map +1 -0
  161. package/dist/mcp/progress.js +51 -0
  162. package/dist/mcp/progress.js.map +1 -0
  163. package/dist/mcp/prompts.d.ts +57 -0
  164. package/dist/mcp/prompts.d.ts.map +1 -0
  165. package/dist/mcp/prompts.js +225 -0
  166. package/dist/mcp/prompts.js.map +1 -0
  167. package/dist/mcp/resources.d.ts +48 -0
  168. package/dist/mcp/resources.d.ts.map +1 -0
  169. package/dist/mcp/resources.js +149 -0
  170. package/dist/mcp/resources.js.map +1 -0
  171. package/dist/mcp/server.d.ts +34 -0
  172. package/dist/mcp/server.d.ts.map +1 -0
  173. package/dist/mcp/server.js +452 -0
  174. package/dist/mcp/server.js.map +1 -0
  175. package/dist/mcp/types.d.ts +47 -0
  176. package/dist/mcp/types.d.ts.map +1 -0
  177. package/dist/mcp/types.js +67 -0
  178. package/dist/mcp/types.js.map +1 -0
  179. package/dist/normalize/clock.d.ts +40 -0
  180. package/dist/normalize/clock.d.ts.map +1 -0
  181. package/dist/normalize/clock.js +96 -0
  182. package/dist/normalize/clock.js.map +1 -0
  183. package/dist/normalize/dom-ir.d.ts +16 -0
  184. package/dist/normalize/dom-ir.d.ts.map +1 -0
  185. package/dist/normalize/dom-ir.js +48 -0
  186. package/dist/normalize/dom-ir.js.map +1 -0
  187. package/dist/normalize/index.d.ts +23 -0
  188. package/dist/normalize/index.d.ts.map +1 -0
  189. package/dist/normalize/index.js +118 -0
  190. package/dist/normalize/index.js.map +1 -0
  191. package/dist/normalize/lighthouse-insights.d.ts +27 -0
  192. package/dist/normalize/lighthouse-insights.d.ts.map +1 -0
  193. package/dist/normalize/lighthouse-insights.js +318 -0
  194. package/dist/normalize/lighthouse-insights.js.map +1 -0
  195. package/dist/normalize/lighthouse-ir.d.ts +25 -0
  196. package/dist/normalize/lighthouse-ir.d.ts.map +1 -0
  197. package/dist/normalize/lighthouse-ir.js +151 -0
  198. package/dist/normalize/lighthouse-ir.js.map +1 -0
  199. package/dist/normalize/network-ir.d.ts +23 -0
  200. package/dist/normalize/network-ir.d.ts.map +1 -0
  201. package/dist/normalize/network-ir.js +180 -0
  202. package/dist/normalize/network-ir.js.map +1 -0
  203. package/dist/normalize/runtime-ir.d.ts +18 -0
  204. package/dist/normalize/runtime-ir.d.ts.map +1 -0
  205. package/dist/normalize/runtime-ir.js +114 -0
  206. package/dist/normalize/runtime-ir.js.map +1 -0
  207. package/dist/normalize/trace-ir.d.ts +20 -0
  208. package/dist/normalize/trace-ir.d.ts.map +1 -0
  209. package/dist/normalize/trace-ir.js +224 -0
  210. package/dist/normalize/trace-ir.js.map +1 -0
  211. package/dist/normalize/types.d.ts +536 -0
  212. package/dist/normalize/types.d.ts.map +1 -0
  213. package/dist/normalize/types.js +242 -0
  214. package/dist/normalize/types.js.map +1 -0
  215. package/dist/output/manifest.d.ts +44 -0
  216. package/dist/output/manifest.d.ts.map +1 -0
  217. package/dist/output/manifest.js +232 -0
  218. package/dist/output/manifest.js.map +1 -0
  219. package/dist/output/toon.d.ts +19 -0
  220. package/dist/output/toon.d.ts.map +1 -0
  221. package/dist/output/toon.js +22 -0
  222. package/dist/output/toon.js.map +1 -0
  223. package/dist/output/writer.d.ts +31 -0
  224. package/dist/output/writer.d.ts.map +1 -0
  225. package/dist/output/writer.js +51 -0
  226. package/dist/output/writer.js.map +1 -0
  227. package/dist/report/analyzer.d.ts +29 -0
  228. package/dist/report/analyzer.d.ts.map +1 -0
  229. package/dist/report/analyzer.js +330 -0
  230. package/dist/report/analyzer.js.map +1 -0
  231. package/dist/report/index.d.ts +13 -0
  232. package/dist/report/index.d.ts.map +1 -0
  233. package/dist/report/index.js +12 -0
  234. package/dist/report/index.js.map +1 -0
  235. package/dist/report/markdown.d.ts +21 -0
  236. package/dist/report/markdown.d.ts.map +1 -0
  237. package/dist/report/markdown.js +182 -0
  238. package/dist/report/markdown.js.map +1 -0
  239. package/dist/report/remediations.d.ts +42 -0
  240. package/dist/report/remediations.d.ts.map +1 -0
  241. package/dist/report/remediations.js +179 -0
  242. package/dist/report/remediations.js.map +1 -0
  243. package/dist/report/scorer.d.ts +35 -0
  244. package/dist/report/scorer.d.ts.map +1 -0
  245. package/dist/report/scorer.js +72 -0
  246. package/dist/report/scorer.js.map +1 -0
  247. package/dist/report/types.d.ts +201 -0
  248. package/dist/report/types.d.ts.map +1 -0
  249. package/dist/report/types.js +149 -0
  250. package/dist/report/types.js.map +1 -0
  251. package/dist/shared/fs-utils.d.ts +12 -0
  252. package/dist/shared/fs-utils.d.ts.map +1 -0
  253. package/dist/shared/fs-utils.js +44 -0
  254. package/dist/shared/fs-utils.js.map +1 -0
  255. package/dist/shared/types.d.ts +69 -0
  256. package/dist/shared/types.d.ts.map +1 -0
  257. package/dist/shared/types.js +18 -0
  258. package/dist/shared/types.js.map +1 -0
  259. package/dist/shared/utils.d.ts +6 -0
  260. package/dist/shared/utils.d.ts.map +1 -0
  261. package/dist/shared/utils.js +9 -0
  262. package/dist/shared/utils.js.map +1 -0
  263. package/package.json +67 -0
@@ -0,0 +1,317 @@
1
+ /**
2
+ * Agent-optimized summary layer that fuses Lighthouse insights,
3
+ * extracted features, and evidence data into a compact Insights structure.
4
+ *
5
+ * The result can be serialized to `insights.toon` (~5-15 KB for a typical SPA).
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import { buildLighthouseInsights } from '../normalize/lighthouse-insights.js';
10
+ // ---------------------------------------------------------------------------
11
+ // Helpers
12
+ // ---------------------------------------------------------------------------
13
+ function isRecord(value) {
14
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
15
+ }
16
+ function safeNumber(value) {
17
+ return typeof value === 'number' ? value : undefined;
18
+ }
19
+ /** Navigate to the LHR root — handles { lhr: {...} } wrapper used by LighthouseRawData. */
20
+ function getLHRRoot(raw) {
21
+ if (!isRecord(raw))
22
+ return {};
23
+ if (isRecord(raw.lhr))
24
+ return raw.lhr;
25
+ return raw;
26
+ }
27
+ /** Extract numericValue from a Lighthouse audit by ID. */
28
+ function getAuditNumericValue(lhr, auditId) {
29
+ const audits = isRecord(lhr.audits) ? lhr.audits : {};
30
+ const audit = isRecord(audits[auditId])
31
+ ? audits[auditId]
32
+ : undefined;
33
+ return safeNumber(audit?.numericValue);
34
+ }
35
+ /** Extract category scores from Lighthouse. */
36
+ function extractScores(raw) {
37
+ const lhr = getLHRRoot(raw);
38
+ const categories = isRecord(lhr.categories) ? lhr.categories : {};
39
+ const getScore = (name) => {
40
+ const cat = categories[name];
41
+ return isRecord(cat) ? safeNumber(cat.score) : undefined;
42
+ };
43
+ return {
44
+ performance: getScore('performance'),
45
+ accessibility: getScore('accessibility'),
46
+ bestPractices: getScore('best-practices'),
47
+ seo: getScore('seo'),
48
+ };
49
+ }
50
+ // ---------------------------------------------------------------------------
51
+ // Build helpers
52
+ // ---------------------------------------------------------------------------
53
+ /** Build lcpElement from Lighthouse insights + features. */
54
+ function buildLcpElement(insights, features) {
55
+ const lb = insights.lcpBreakdown;
56
+ if (!lb)
57
+ return undefined;
58
+ return {
59
+ selector: lb.lcpElementSelector ?? '',
60
+ snippet: lb.lcpElementSnippet,
61
+ nodeLabel: lb.lcpElementNodeLabel,
62
+ renderDelayMs: lb.elementRenderDelay,
63
+ resourceLoadDelayMs: features.lcpBreakdown?.resourceLoadDelay,
64
+ resourceLoadTimeMs: features.lcpBreakdown?.resourceLoadTime,
65
+ ttfbMs: lb.timeToFirstByte,
66
+ };
67
+ }
68
+ /** Build renderBlocking array from Lighthouse insights. */
69
+ function buildRenderBlocking(insights) {
70
+ const rb = insights.renderBlocking;
71
+ if (!rb || !rb.resources)
72
+ return [];
73
+ return rb.resources.map((r) => ({
74
+ url: r.url,
75
+ bytes: r.totalBytes,
76
+ wastedMs: r.wastedMs,
77
+ }));
78
+ }
79
+ /** Convert a NetworkChainNode to a CriticalPathNode. */
80
+ function convertChainNode(node) {
81
+ const result = {
82
+ url: node.url,
83
+ durationMs: node.navStartToEndTime,
84
+ };
85
+ if (node.children) {
86
+ const children = Object.values(node.children).map(convertChainNode);
87
+ if (children.length > 0) {
88
+ result.children = children;
89
+ }
90
+ }
91
+ return result;
92
+ }
93
+ /** Build criticalPath from features + Lighthouse insights. */
94
+ function buildCriticalPath(features, insights) {
95
+ const cp = features.criticalPath;
96
+ const ndt = insights.networkDependencyTree;
97
+ if (!cp && !ndt)
98
+ return undefined;
99
+ let tree;
100
+ if (ndt?.chains) {
101
+ const entries = Object.values(ndt.chains);
102
+ if (entries.length > 0) {
103
+ tree = convertChainNode(entries[0]);
104
+ }
105
+ }
106
+ return {
107
+ depth: cp?.deepestChainDepth ?? 0,
108
+ longestChainMs: ndt?.longestChainDuration ?? cp?.longestSingleRequest,
109
+ tree,
110
+ };
111
+ }
112
+ /** Collect warnings from multiple sources. */
113
+ function buildWarnings(lighthouseJson) {
114
+ const warnings = [];
115
+ // From LighthouseRawData.warnings (collection-level warnings)
116
+ const raw = lighthouseJson;
117
+ if (Array.isArray(raw.warnings)) {
118
+ for (const w of raw.warnings) {
119
+ if (typeof w === 'string')
120
+ warnings.push(w);
121
+ }
122
+ }
123
+ // From LHR runtime warnings
124
+ const lhr = getLHRRoot(lighthouseJson);
125
+ if (Array.isArray(lhr.warnings)) {
126
+ for (const w of lhr.warnings) {
127
+ if (typeof w === 'string')
128
+ warnings.push(w);
129
+ }
130
+ }
131
+ return warnings;
132
+ }
133
+ function buildRecommendations(input) {
134
+ const recs = [];
135
+ // Critical: LCP > 4000ms
136
+ if (input.lcpMs !== undefined && input.lcpMs > 4000) {
137
+ recs.push({
138
+ priority: 'critical',
139
+ title: 'Optimize Largest Contentful Paint',
140
+ action: 'Reduce LCP by optimizing server response time, eliminating render-blocking resources, and optimizing images.',
141
+ evidence: [`LCP: ${input.lcpMs}ms`],
142
+ });
143
+ }
144
+ // Critical: TBT > 600ms
145
+ if (input.tbtMs !== undefined && input.tbtMs > 600) {
146
+ recs.push({
147
+ priority: 'critical',
148
+ title: 'Reduce Total Blocking Time',
149
+ action: 'Break up long tasks, reduce JavaScript execution time, and consider code splitting.',
150
+ evidence: [`TBT: ${input.tbtMs}ms`],
151
+ });
152
+ }
153
+ // Critical: CLS > 0.25
154
+ if (input.cls !== undefined && input.cls > 0.25) {
155
+ recs.push({
156
+ priority: 'critical',
157
+ title: 'Reduce Cumulative Layout Shift',
158
+ action: 'Set explicit dimensions on images and embeds, avoid inserting content above existing content.',
159
+ evidence: [`CLS: ${input.cls}`],
160
+ });
161
+ }
162
+ // High: LCP > 2500ms (not already critical)
163
+ if (input.lcpMs !== undefined &&
164
+ input.lcpMs > 2500 &&
165
+ input.lcpMs <= 4000) {
166
+ recs.push({
167
+ priority: 'high',
168
+ title: 'Improve LCP to meet 2.5s threshold',
169
+ action: 'Optimize server response time (TTFB), preload key resources, and optimize the LCP element.',
170
+ evidence: [`LCP: ${input.lcpMs}ms`],
171
+ });
172
+ }
173
+ // High: render blocking resources exist
174
+ if (input.renderBlocking.length > 0) {
175
+ const totalWasted = input.renderBlocking.reduce((s, r) => s + (r.wastedMs ?? 0), 0);
176
+ const evidence = [
177
+ `${input.renderBlocking.length} render-blocking resources`,
178
+ ];
179
+ if (totalWasted > 0) {
180
+ evidence.push(`Potential savings: ${totalWasted}ms`);
181
+ }
182
+ recs.push({
183
+ priority: 'high',
184
+ title: 'Reduce render-blocking resources',
185
+ action: 'Defer non-critical CSS and JavaScript, inline critical styles, and use preload for key resources.',
186
+ evidence,
187
+ });
188
+ }
189
+ // High: deep critical chain
190
+ if (input.criticalPath && input.criticalPath.depth > 5) {
191
+ recs.push({
192
+ priority: 'high',
193
+ title: 'Optimize critical request chain',
194
+ action: 'Reduce sequential network requests by inlining critical resources, using HTTP/2, and preloading key assets.',
195
+ evidence: [`Critical chain depth: ${input.criticalPath.depth}`],
196
+ });
197
+ }
198
+ // Medium: high FCP
199
+ if (input.fcpMs !== undefined && input.fcpMs > 3000) {
200
+ recs.push({
201
+ priority: 'medium',
202
+ title: 'Improve First Contentful Paint',
203
+ action: 'Reduce server response time and eliminate render-blocking resources above the fold.',
204
+ evidence: [`FCP: ${input.fcpMs}ms`],
205
+ });
206
+ }
207
+ // Medium: third-party overhead
208
+ const tp = input.features.thirdPartyOverhead;
209
+ if (tp && tp.thirdPartyRatio > 0.3) {
210
+ recs.push({
211
+ priority: 'medium',
212
+ title: 'Reduce third-party code overhead',
213
+ action: 'Audit third-party scripts for necessity, defer non-critical ones, use async loading.',
214
+ evidence: [
215
+ `Third-party ratio: ${(tp.thirdPartyRatio * 100).toFixed(1)}%`,
216
+ ],
217
+ });
218
+ }
219
+ // Medium: many long tasks
220
+ const js = input.features.jsHotspots;
221
+ if (js && js.longTaskCount > 10) {
222
+ recs.push({
223
+ priority: 'medium',
224
+ title: 'Reduce JavaScript long tasks',
225
+ action: 'Break up JavaScript execution into smaller chunks, use requestIdleCallback, consider web workers.',
226
+ evidence: [`${js.longTaskCount} long tasks detected`],
227
+ });
228
+ }
229
+ return recs;
230
+ }
231
+ // ---------------------------------------------------------------------------
232
+ // Public API
233
+ // ---------------------------------------------------------------------------
234
+ /**
235
+ * Build a compact Insights structure from extracted features and raw
236
+ * Lighthouse data.
237
+ *
238
+ * The result is designed to be serialized as `insights.toon` (~5-15 KB)
239
+ * and consumed by AI agents for quick performance diagnosis.
240
+ *
241
+ * @param features - Extracted feature set from `extract()`
242
+ * @param lighthouseJson - Raw Lighthouse JSON (LighthouseRawData or plain LHR)
243
+ * @returns A compact Insights structure
244
+ */
245
+ export function buildInsights(features, lighthouseJson) {
246
+ // 1. Parse Lighthouse insight audits
247
+ const lighthouseInsights = buildLighthouseInsights(lighthouseJson);
248
+ // 2. Lighthouse scores block
249
+ const scores = extractScores(lighthouseJson);
250
+ // 3. Navigate to LHR audit container
251
+ const lhr = getLHRRoot(lighthouseJson);
252
+ // 4. Metrics from Lighthouse audits (fallback chain)
253
+ const lcpAuditMs = getAuditNumericValue(lhr, 'largest-contentful-paint');
254
+ const fcpMs = getAuditNumericValue(lhr, 'first-contentful-paint');
255
+ const clsAudit = getAuditNumericValue(lhr, 'cumulative-layout-shift');
256
+ const tbtAudit = getAuditNumericValue(lhr, 'total-blocking-time');
257
+ // LCP: prefer FeatureSet breakdown total, then Lighthouse insight
258
+ // composite, then raw audit
259
+ const lcpMs = features.lcpBreakdown?.totalLCP ??
260
+ (lighthouseInsights.lcpBreakdown
261
+ ? lighthouseInsights.lcpBreakdown.timeToFirstByte +
262
+ lighthouseInsights.lcpBreakdown.elementRenderDelay
263
+ : undefined) ??
264
+ lcpAuditMs;
265
+ // CLS: prefer FeatureSet, then raw audit
266
+ const cls = features.layoutShifts?.cls ?? clsAudit;
267
+ // TBT: prefer Lighthouse audit (the real TBT metric) when it's sane,
268
+ // otherwise use FeatureSet busyMs, or undefined if both are absurd.
269
+ // In headless/automated environments Lighthouse TBT can be wildly inflated
270
+ // (e.g. 151s) due to CDP overhead or browser throttling — we cap at 60s
271
+ // and fall back to busyMs as a best-effort proxy.
272
+ const TBT_SANE_MAX = 60_000; // 60 seconds — anything above is an artifact
273
+ const tbtMs = tbtAudit !== undefined && tbtAudit >= 0 && tbtAudit <= TBT_SANE_MAX
274
+ ? tbtAudit
275
+ : features.mainThreadBlocking?.busyMs !== undefined &&
276
+ features.mainThreadBlocking?.busyMs <= TBT_SANE_MAX
277
+ ? features.mainThreadBlocking?.busyMs
278
+ : undefined;
279
+ // 5. LCP element
280
+ const lcpElement = buildLcpElement(lighthouseInsights, features);
281
+ // 6. Render-blocking resources
282
+ const renderBlocking = buildRenderBlocking(lighthouseInsights);
283
+ // 7. Critical path
284
+ const criticalPath = buildCriticalPath(features, lighthouseInsights);
285
+ // 8. Warnings
286
+ const warnings = buildWarnings(lighthouseJson);
287
+ // 9. Data-driven recommendations
288
+ const topRecommendations = buildRecommendations({
289
+ lcpMs,
290
+ fcpMs,
291
+ cls,
292
+ tbtMs,
293
+ renderBlocking,
294
+ criticalPath,
295
+ features,
296
+ });
297
+ return {
298
+ url: features.url ?? '',
299
+ analyzedAt: new Date().toISOString(),
300
+ lighthouse: {
301
+ performance: scores.performance,
302
+ accessibility: scores.accessibility,
303
+ bestPractices: scores.bestPractices,
304
+ seo: scores.seo,
305
+ lcpMs,
306
+ fcpMs,
307
+ cls,
308
+ tbtMs,
309
+ },
310
+ lcpElement,
311
+ renderBlocking,
312
+ criticalPath,
313
+ warnings,
314
+ topRecommendations,
315
+ };
316
+ }
317
+ //# sourceMappingURL=insights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insights.js","sourceRoot":"","sources":["../../src/distill/insights.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAyD9E,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,2FAA2F;AAC3F,SAAS,UAAU,CAAC,GAAY;IAC9B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9B,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC;IACtC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,0DAA0D;AAC1D,SAAS,oBAAoB,CAC3B,GAA4B,EAC5B,OAAe;IAEf,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC,CAAE,MAAM,CAAC,OAAO,CAA6B;QAC9C,CAAC,CAAC,SAAS,CAAC;IACd,OAAO,UAAU,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;AACzC,CAAC;AAED,+CAA+C;AAC/C,SAAS,aAAa,CAAC,GAAY;IAMjC,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAElE,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAsB,EAAE;QACpD,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAC7B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3D,CAAC,CAAC;IAEF,OAAO;QACL,WAAW,EAAE,QAAQ,CAAC,aAAa,CAAC;QACpC,aAAa,EAAE,QAAQ,CAAC,eAAe,CAAC;QACxC,aAAa,EAAE,QAAQ,CAAC,gBAAgB,CAAC;QACzC,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC;KACrB,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,4DAA4D;AAC5D,SAAS,eAAe,CACtB,QAA4B,EAC5B,QAAoB;IAEpB,MAAM,EAAE,GAAG,QAAQ,CAAC,YAAY,CAAC;IACjC,IAAI,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAE1B,OAAO;QACL,QAAQ,EAAE,EAAE,CAAC,kBAAkB,IAAI,EAAE;QACrC,OAAO,EAAE,EAAE,CAAC,iBAAiB;QAC7B,SAAS,EAAE,EAAE,CAAC,mBAAmB;QACjC,aAAa,EAAE,EAAE,CAAC,kBAAkB;QACpC,mBAAmB,EAAE,QAAQ,CAAC,YAAY,EAAE,iBAAiB;QAC7D,kBAAkB,EAAE,QAAQ,CAAC,YAAY,EAAE,gBAAgB;QAC3D,MAAM,EAAE,EAAE,CAAC,eAAe;KAC3B,CAAC;AACJ,CAAC;AAED,2DAA2D;AAC3D,SAAS,mBAAmB,CAC1B,QAA4B;IAE5B,MAAM,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC;IACnC,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAEpC,OAAO,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9B,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,KAAK,EAAE,CAAC,CAAC,UAAU;QACnB,QAAQ,EAAE,CAAC,CAAC,QAAQ;KACrB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,wDAAwD;AACxD,SAAS,gBAAgB,CAAC,IAAsB;IAC9C,MAAM,MAAM,GAAqB;QAC/B,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,UAAU,EAAE,IAAI,CAAC,iBAAiB;KACnC,CAAC;IAEF,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACpE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8DAA8D;AAC9D,SAAS,iBAAiB,CACxB,QAAoB,EACpB,QAA4B;IAE5B,MAAM,EAAE,GAAG,QAAQ,CAAC,YAAY,CAAC;IACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IAE3C,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAElC,IAAI,IAAkC,CAAC;IAEvC,IAAI,GAAG,EAAE,MAAM,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,EAAE,EAAE,iBAAiB,IAAI,CAAC;QACjC,cAAc,EAAE,GAAG,EAAE,oBAAoB,IAAI,EAAE,EAAE,oBAAoB;QACrE,IAAI;KACL,CAAC;AACJ,CAAC;AAED,8CAA8C;AAC9C,SAAS,aAAa,CAAC,cAAuB;IAC5C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,8DAA8D;IAC9D,MAAM,GAAG,GAAG,cAAyC,CAAC;IACtD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC7B,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,MAAM,GAAG,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IACvC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC7B,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAgBD,SAAS,oBAAoB,CAC3B,KAA0B;IAE1B,MAAM,IAAI,GAAmC,EAAE,CAAC;IAEhD,yBAAyB;IACzB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,GAAG,IAAI,EAAE,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,mCAAmC;YAC1C,MAAM,EACJ,8GAA8G;YAChH,QAAQ,EAAE,CAAC,QAAQ,KAAK,CAAC,KAAK,IAAI,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAED,wBAAwB;IACxB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC;QACnD,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,4BAA4B;YACnC,MAAM,EACJ,qFAAqF;YACvF,QAAQ,EAAE,CAAC,QAAQ,KAAK,CAAC,KAAK,IAAI,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAED,uBAAuB;IACvB,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,gCAAgC;YACvC,MAAM,EACJ,+FAA+F;YACjG,QAAQ,EAAE,CAAC,QAAQ,KAAK,CAAC,GAAG,EAAE,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;IAED,4CAA4C;IAC5C,IACE,KAAK,CAAC,KAAK,KAAK,SAAS;QACzB,KAAK,CAAC,KAAK,GAAG,IAAI;QAClB,KAAK,CAAC,KAAK,IAAI,IAAI,EACnB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,oCAAoC;YAC3C,MAAM,EACJ,4FAA4F;YAC9F,QAAQ,EAAE,CAAC,QAAQ,KAAK,CAAC,KAAK,IAAI,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAED,wCAAwC;IACxC,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAC7C,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAC/B,CAAC,CACF,CAAC;QACF,MAAM,QAAQ,GAAa;YACzB,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,4BAA4B;SAC3D,CAAC;QACF,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;YACpB,QAAQ,CAAC,IAAI,CAAC,sBAAsB,WAAW,IAAI,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,kCAAkC;YACzC,MAAM,EACJ,mGAAmG;YACrG,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED,4BAA4B;IAC5B,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,iCAAiC;YACxC,MAAM,EACJ,6GAA6G;YAC/G,QAAQ,EAAE,CAAC,yBAAyB,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;SAChE,CAAC,CAAC;IACL,CAAC;IAED,mBAAmB;IACnB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,GAAG,IAAI,EAAE,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,gCAAgC;YACvC,MAAM,EACJ,qFAAqF;YACvF,QAAQ,EAAE,CAAC,QAAQ,KAAK,CAAC,KAAK,IAAI,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAED,+BAA+B;IAC/B,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IAC7C,IAAI,EAAE,IAAI,EAAE,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,kCAAkC;YACzC,MAAM,EACJ,sFAAsF;YACxF,QAAQ,EAAE;gBACR,sBAAsB,CAAC,EAAE,CAAC,eAAe,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;aAC/D;SACF,CAAC,CAAC;IACL,CAAC;IAED,0BAA0B;IAC1B,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;IACrC,IAAI,EAAE,IAAI,EAAE,CAAC,aAAa,GAAG,EAAE,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,8BAA8B;YACrC,MAAM,EACJ,mGAAmG;YACrG,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,aAAa,sBAAsB,CAAC;SACtD,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,QAAoB,EACpB,cAAuB;IAEvB,qCAAqC;IACrC,MAAM,kBAAkB,GAAG,uBAAuB,CAAC,cAAc,CAAC,CAAC;IAEnE,6BAA6B;IAC7B,MAAM,MAAM,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;IAE7C,qCAAqC;IACrC,MAAM,GAAG,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAEvC,qDAAqD;IACrD,MAAM,UAAU,GAAG,oBAAoB,CAAC,GAAG,EAAE,0BAA0B,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,oBAAoB,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;IAElE,kEAAkE;IAClE,4BAA4B;IAC5B,MAAM,KAAK,GACT,QAAQ,CAAC,YAAY,EAAE,QAAQ;QAC/B,CAAC,kBAAkB,CAAC,YAAY;YAC9B,CAAC,CAAC,kBAAkB,CAAC,YAAY,CAAC,eAAe;gBAC/C,kBAAkB,CAAC,YAAY,CAAC,kBAAkB;YACpD,CAAC,CAAC,SAAS,CAAC;QACd,UAAU,CAAC;IAEb,yCAAyC;IACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,EAAE,GAAG,IAAI,QAAQ,CAAC;IAEnD,qEAAqE;IACrE,oEAAoE;IACpE,2EAA2E;IAC3E,wEAAwE;IACxE,kDAAkD;IAClD,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,6CAA6C;IAC1E,MAAM,KAAK,GACT,QAAQ,KAAK,SAAS,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ,IAAI,YAAY;QACjE,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,KAAK,SAAS;YAC/C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,IAAI,YAAY;YACrD,CAAC,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM;YACrC,CAAC,CAAC,SAAS,CAAC;IAElB,iBAAiB;IACjB,MAAM,UAAU,GAAG,eAAe,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;IAEjE,+BAA+B;IAC/B,MAAM,cAAc,GAAG,mBAAmB,CAAC,kBAAkB,CAAC,CAAC;IAE/D,mBAAmB;IACnB,MAAM,YAAY,GAAG,iBAAiB,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IAErE,cAAc;IACd,MAAM,QAAQ,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;IAE/C,iCAAiC;IACjC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;QAC9C,KAAK;QACL,KAAK;QACL,GAAG;QACH,KAAK;QACL,cAAc;QACd,YAAY;QACZ,QAAQ;KACT,CAAC,CAAC;IAEH,OAAO;QACL,GAAG,EAAE,QAAQ,CAAC,GAAG,IAAI,EAAE;QACvB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,UAAU,EAAE;YACV,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,KAAK;YACL,KAAK;YACL,GAAG;YACH,KAAK;SACN;QACD,UAAU;QACV,cAAc;QACd,YAAY;QACZ,QAAQ;QACR,kBAAkB;KACnB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Compact summary builders for large raw data files.
3
+ *
4
+ * Each function takes a raw data structure (network.json, lighthouse.json,
5
+ * coverage.json) and returns a small summary object that can be written
6
+ * as a companion file (~1-5 KB) for agent consumption.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ import type { NetworkRawData, LighthouseRawData, CoverageRawData } from '../collect/types.js';
11
+ export interface NetworkSummary {
12
+ totalRequests: number;
13
+ totalBytes: number;
14
+ topRequestsByDuration: Array<{
15
+ url: string;
16
+ duration: number;
17
+ resourceType: string;
18
+ bytes: number;
19
+ }>;
20
+ blockingResources: Array<{
21
+ url: string;
22
+ resourceType: string;
23
+ }>;
24
+ initiatorChains: Array<{
25
+ url: string;
26
+ depth: number;
27
+ }>;
28
+ }
29
+ export interface LighthouseSummary {
30
+ categories: Record<string, number>;
31
+ failedInsightAudits: Array<{
32
+ id: string;
33
+ title: string;
34
+ score: number;
35
+ }>;
36
+ }
37
+ export interface CoverageSummary {
38
+ unusedBytesByUrl: Array<{
39
+ url: string;
40
+ totalBytes: number;
41
+ unusedBytes: number;
42
+ unusedPercentage: number;
43
+ }>;
44
+ }
45
+ /**
46
+ * Build a compact summary of network request data.
47
+ *
48
+ * @param network - Raw network data from NetworkCollector
49
+ * @returns A compact NetworkSummary (~1-3 KB)
50
+ */
51
+ export declare function buildNetworkSummary(network: NetworkRawData): NetworkSummary;
52
+ /**
53
+ * Build a compact summary of Lighthouse audit results.
54
+ *
55
+ * @param lighthouse - Raw Lighthouse data from LighthouseCollector
56
+ * @returns A compact LighthouseSummary (~1-2 KB)
57
+ */
58
+ export declare function buildLighthouseSummary(lighthouse: LighthouseRawData): LighthouseSummary;
59
+ /**
60
+ * Build a compact summary of JS/CSS code coverage data.
61
+ *
62
+ * Coverage data from CDP does not include the full script source, so
63
+ * `totalBytes` is approximated as the maximum `endOffset` across all
64
+ * coverage ranges. This gives a lower-bound estimate of the script size;
65
+ * truly uncovered code that falls outside any range is not counted.
66
+ *
67
+ * @param coverage - Raw coverage data from CoverageCollector
68
+ * @returns A compact CoverageSummary (~1-3 KB)
69
+ */
70
+ export declare function buildCoverageSummary(coverage: CoverageRawData): CoverageSummary;
71
+ //# sourceMappingURL=summaries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summaries.d.ts","sourceRoot":"","sources":["../../src/distill/summaries.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,eAAe,EAEhB,MAAM,qBAAqB,CAAC;AAM7B,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB,EAAE,KAAK,CAAC;QAC3B,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;IACH,iBAAiB,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,eAAe,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,mBAAmB,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,eAAe;IAC9B,gBAAgB,EAAE,KAAK,CAAC;QACtB,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC,CAAC;CACJ;AAyCD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAgC3E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,iBAAiB,GAC5B,iBAAiB,CA8BnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,GACxB,eAAe,CA6DjB"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Compact summary builders for large raw data files.
3
+ *
4
+ * Each function takes a raw data structure (network.json, lighthouse.json,
5
+ * coverage.json) and returns a small summary object that can be written
6
+ * as a companion file (~1-5 KB) for agent consumption.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ // ---------------------------------------------------------------------------
11
+ // Helpers
12
+ // ---------------------------------------------------------------------------
13
+ function isRecord(value) {
14
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
15
+ }
16
+ /**
17
+ * Merge overlapping CoverageRange[] so that intersecting spans are
18
+ * counted once. Returns a new sorted, non-overlapping array.
19
+ */
20
+ function mergeRanges(ranges) {
21
+ if (ranges.length === 0)
22
+ return [];
23
+ const sorted = [...ranges].sort((a, b) => a.startOffset - b.startOffset);
24
+ const merged = [{ ...sorted[0] }];
25
+ for (let i = 1; i < sorted.length; i++) {
26
+ const last = merged[merged.length - 1];
27
+ const current = sorted[i];
28
+ if (current.startOffset <= last.endOffset) {
29
+ // Extend last range if current ends further
30
+ if (current.endOffset > last.endOffset) {
31
+ last.endOffset = current.endOffset;
32
+ }
33
+ }
34
+ else {
35
+ merged.push({ ...current });
36
+ }
37
+ }
38
+ return merged;
39
+ }
40
+ // ---------------------------------------------------------------------------
41
+ // Summary builders
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * Build a compact summary of network request data.
45
+ *
46
+ * @param network - Raw network data from NetworkCollector
47
+ * @returns A compact NetworkSummary (~1-3 KB)
48
+ */
49
+ export function buildNetworkSummary(network) {
50
+ const requests = network.requests ?? [];
51
+ // Sort by response receive time descending (longest first)
52
+ const sorted = [...requests].sort((a, b) => {
53
+ const durA = a.response?.timing?.receiveHeadersEnd ?? 0;
54
+ const durB = b.response?.timing?.receiveHeadersEnd ?? 0;
55
+ return durB - durA;
56
+ });
57
+ return {
58
+ totalRequests: requests.length,
59
+ totalBytes: requests.reduce((s, r) => s + (r.response?.encodedDataLength ?? 0), 0),
60
+ topRequestsByDuration: sorted.slice(0, 20).map((r) => ({
61
+ url: r.url,
62
+ duration: r.response?.timing?.receiveHeadersEnd ?? 0,
63
+ resourceType: r.type ?? 'unknown',
64
+ bytes: r.response?.encodedDataLength ?? 0,
65
+ })),
66
+ blockingResources: requests
67
+ .filter((r) => r.type === 'Stylesheet' || r.type === 'Script')
68
+ .map((r) => ({
69
+ url: r.url,
70
+ resourceType: r.type ?? 'unknown',
71
+ })),
72
+ initiatorChains: [], // Placeholder — real initiator chain data from IR
73
+ };
74
+ }
75
+ /**
76
+ * Build a compact summary of Lighthouse audit results.
77
+ *
78
+ * @param lighthouse - Raw Lighthouse data from LighthouseCollector
79
+ * @returns A compact LighthouseSummary (~1-2 KB)
80
+ */
81
+ export function buildLighthouseSummary(lighthouse) {
82
+ const lhr = isRecord(lighthouse.lhr) ? lighthouse.lhr : {};
83
+ // Extract category scores
84
+ const categories = {};
85
+ const catObj = isRecord(lhr.categories) ? lhr.categories : {};
86
+ for (const [id, cat] of Object.entries(catObj)) {
87
+ if (isRecord(cat) && typeof cat.score === 'number') {
88
+ categories[id] = cat.score;
89
+ }
90
+ }
91
+ // Extract failed insight audits (score < 0.5)
92
+ const failedInsightAudits = [];
93
+ const auditsObj = isRecord(lhr.audits) ? lhr.audits : {};
94
+ for (const [id, audit] of Object.entries(auditsObj)) {
95
+ if (isRecord(audit) &&
96
+ typeof audit.score === 'number' &&
97
+ audit.score < 0.5) {
98
+ failedInsightAudits.push({
99
+ id,
100
+ title: typeof audit.title === 'string' ? audit.title : id,
101
+ score: audit.score,
102
+ });
103
+ }
104
+ }
105
+ return { categories, failedInsightAudits };
106
+ }
107
+ /**
108
+ * Build a compact summary of JS/CSS code coverage data.
109
+ *
110
+ * Coverage data from CDP does not include the full script source, so
111
+ * `totalBytes` is approximated as the maximum `endOffset` across all
112
+ * coverage ranges. This gives a lower-bound estimate of the script size;
113
+ * truly uncovered code that falls outside any range is not counted.
114
+ *
115
+ * @param coverage - Raw coverage data from CoverageCollector
116
+ * @returns A compact CoverageSummary (~1-3 KB)
117
+ */
118
+ export function buildCoverageSummary(coverage) {
119
+ const entries = [];
120
+ // ---- JS scripts ----
121
+ for (const script of coverage.js ?? []) {
122
+ const allRanges = [];
123
+ for (const fn of script.functions ?? []) {
124
+ for (const range of fn.ranges ?? []) {
125
+ allRanges.push(range);
126
+ }
127
+ }
128
+ if (allRanges.length === 0)
129
+ continue;
130
+ const merged = mergeRanges(allRanges);
131
+ const totalBytes = merged[merged.length - 1].endOffset;
132
+ const usedBytes = merged.reduce((sum, r) => sum + (r.endOffset - r.startOffset), 0);
133
+ const unusedBytes = Math.max(0, totalBytes - usedBytes);
134
+ entries.push({
135
+ url: script.url || '(inline)',
136
+ totalBytes,
137
+ unusedBytes,
138
+ unusedPercentage: totalBytes > 0
139
+ ? Math.round((unusedBytes / totalBytes) * 100)
140
+ : 0,
141
+ });
142
+ }
143
+ // ---- CSS stylesheets ----
144
+ for (const sheet of coverage.css ?? []) {
145
+ const ranges = sheet.ranges ?? [];
146
+ if (ranges.length === 0)
147
+ continue;
148
+ const merged = mergeRanges(ranges);
149
+ const totalBytes = merged[merged.length - 1].endOffset;
150
+ const usedBytes = merged.reduce((sum, r) => sum + (r.endOffset - r.startOffset), 0);
151
+ const unusedBytes = Math.max(0, totalBytes - usedBytes);
152
+ entries.push({
153
+ url: sheet.url || '(inline)',
154
+ totalBytes,
155
+ unusedBytes,
156
+ unusedPercentage: totalBytes > 0
157
+ ? Math.round((unusedBytes / totalBytes) * 100)
158
+ : 0,
159
+ });
160
+ }
161
+ // Sort by unused bytes descending, take top 10
162
+ entries.sort((a, b) => b.unusedBytes - a.unusedBytes);
163
+ return { unusedBytesByUrl: entries.slice(0, 10) };
164
+ }
165
+ //# sourceMappingURL=summaries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summaries.js","sourceRoot":"","sources":["../../src/distill/summaries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Critical Path Length extractor.
3
+ *
4
+ * Computes metrics from the critical path chain derived in the Network IR:
5
+ * total chain length (duration sum), request counts, depth, and longest
6
+ * single request.
7
+ */
8
+ import type { IRBundle } from '../normalize/types.js';
9
+ import type { CriticalPath } from './types.js';
10
+ /**
11
+ * Extract critical path metrics from an IRBundle.
12
+ *
13
+ * Returns undefined when the critical path info is empty or none of its
14
+ * tree URLs can be matched to a network request.
15
+ */
16
+ export declare function extractCriticalPath(ir: IRBundle): CriticalPath | undefined;
17
+ //# sourceMappingURL=critical-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"critical-path.d.ts","sourceRoot":"","sources":["../../src/extract/critical-path.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAA2C,MAAM,uBAAuB,CAAC;AAC/F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA2E/C;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,GAAG,YAAY,GAAG,SAAS,CA2B1E"}