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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,280 @@
1
+ # PerfGraph
2
+
3
+ [![npm][badge-version]][npm] [![license][badge-license]][license]
4
+ [![npm downloads][badge-downloads]][npm] [![github stars][badge-stars]][repo]
5
+
6
+ > Real browser metrics → causal degradation graph → actionable report. Built for AI agents, useful for humans.
7
+
8
+ PerfGraph launches a headless Chromium browser, captures performance data via Chrome DevTools Protocol, runs it through a 5-stage analysis pipeline, and spits out a structured JSON report with issues sorted by severity, causal chains, and prioritized fixes.
9
+
10
+ ```bash
11
+ npx perfgraph run --url https://example.com --pretty
12
+ ```
13
+
14
+ ## Why
15
+
16
+ Lighthouse gives you a score. PerfGraph tells you _why_ it's bad and what to fix first.
17
+
18
+ Instead of digging through a 10k-line trace.json or a wall of Lighthouse audits, you get a focused report with root causes linked to impact. The output is designed to be read by AI agents (or you) without a decoder ring.
19
+
20
+ ## Pipeline
21
+
22
+ ![diagram](./assets/diagram-tall.svg)
23
+
24
+ ```
25
+ collect → normalize → extract → analyze → report
26
+ ```
27
+
28
+ | Step | What it does |
29
+ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
30
+ | **Collect** | Launches headless Chromium, captures network, trace, performance API, JS coverage, console logs, DOM snapshot, and Lighthouse audit |
31
+ | **Normalize** | Validates raw data through Zod schemas into a unified Intermediate Representation (IRBundle). All timestamps normalized, data cleaned |
32
+ | **Extract** | Computes 7 diagnostic feature sets from the IR: LCP breakdown, critical network chain, main-thread blocking time, JS hotspots, layout shifts, third-party overhead, render-blocking score |
33
+ | **Analyze** | Runs 30+ causal rules against the features, builds a directed graph where edges represent known causal relationships with confidence levels (strong/medium/weak) |
34
+ | **Report** | Produces a self-contained JSON report with issues sorted by severity, causal chains from root cause to user impact, and prioritized recommendations with expected impact estimates |
35
+
36
+ ## Install
37
+
38
+ ```bash
39
+ npm install -g perfgraph
40
+ ```
41
+
42
+ Or skip the install:
43
+
44
+ ```bash
45
+ npx perfgraph --help
46
+ ```
47
+
48
+ **Requirements:** Node.js ≥ 22, Chromium (Playwright installs it automatically on first run).
49
+
50
+ ## Quick start
51
+
52
+ Full pipeline, one command:
53
+
54
+ ```bash
55
+ perfgraph run --url https://example.com --pretty
56
+ ```
57
+
58
+ Step by step:
59
+
60
+ ```bash
61
+ # 1. Collect data
62
+ perfgraph collect --url https://example.com --output ./results
63
+
64
+ # 2. Normalize → Extract → Report
65
+ perfgraph normalize ./results/perfgraph_example_20260609_120000 --output ir.json
66
+ perfgraph extract ir.json --output features.json
67
+ perfgraph report features.json --output report.json --pretty
68
+ ```
69
+
70
+ ## Commands
71
+
72
+ ### `perfgraph run`
73
+
74
+ Full pipeline in one shot.
75
+
76
+ ```
77
+ --url <url> Required. Target URL to analyze.
78
+ --output <dir> Output directory (default: ./perfgraph-output).
79
+ --runs <n> Number of collection runs (default: 1).
80
+ --pretty Pretty-print the final report JSON.
81
+ --device <name> Mobile emulation (e.g. "iPhone 13").
82
+ --no-lighthouse Skip Lighthouse collection.
83
+ --no-coverage Skip JS/CSS coverage.
84
+ --no-console Skip console log capture.
85
+ --no-dom Skip DOM snapshot.
86
+ ```
87
+
88
+ ### `perfgraph collect`
89
+
90
+ Captures performance data from a URL. See `run` options — same flags apply.
91
+
92
+ ### `perfgraph normalize <input>`
93
+
94
+ Converts raw collected data into a validated IRBundle. Accepts a run directory or a parent directory (auto-detects latest run).
95
+
96
+ ```
97
+ --output, -o <file> Write to file (default: stdout).
98
+ --pretty Pretty-print JSON.
99
+ ```
100
+
101
+ ### `perfgraph extract <ir-file>`
102
+
103
+ Computes diagnostic features from a normalized IR bundle.
104
+
105
+ ```
106
+ --input, -i <file> Path to IR JSON (alternative to positional).
107
+ --output, -o <file> Write to file (default: stdout).
108
+ --pretty Pretty-print JSON.
109
+ ```
110
+
111
+ ### `perfgraph analyze <features-file>`
112
+
113
+ Applies causal rules and builds a degradation graph.
114
+
115
+ ```
116
+ --input, -i <file> Path to FeatureSet JSON (alternative to positional).
117
+ --output, -o <file> Write to file (default: stdout).
118
+ --pretty Pretty-print JSON.
119
+ ```
120
+
121
+ ### `perfgraph report <features-file>`
122
+
123
+ Generates the final performance report. Accepts a FeatureSet JSON (from `extract`) — runs the causal engine internally, no need to call `analyze` separately.
124
+
125
+ ```
126
+ --input, -i <file> Path to FeatureSet JSON (alternative to positional).
127
+ --output, -o <file> Write to file (default: stdout).
128
+ --pretty Pretty-print JSON.
129
+ ```
130
+
131
+ ### `perfgraph mcp`
132
+
133
+ Starts an MCP stdio server for AI agent integration. No flags. See [AGENTS.md](AGENTS.md) for details.
134
+
135
+ ## Report format
136
+
137
+ The report is a single JSON file. Key sections:
138
+
139
+ ```jsonc
140
+ {
141
+ "meta": {
142
+ "url": "https://example.com",
143
+ "analyzedAt": "2026-06-09T19:15:19.000Z",
144
+ "reportVersion": "1.0.0",
145
+ "featureCount": 7,
146
+ "graphNodeCount": 24,
147
+ "graphEdgeCount": 31,
148
+ "ruleCount": 32,
149
+ },
150
+ "summary": {
151
+ "score": "moderate", // "good" | "moderate" | "poor"
152
+ "criticalIssues": 2,
153
+ "warnings": 5,
154
+ "infos": 3,
155
+ "topIssues": [
156
+ {
157
+ "id": "js-long-task",
158
+ "label": "Long task",
159
+ "severity": "critical",
160
+ "confidence": "strong",
161
+ },
162
+ ],
163
+ },
164
+ "issues": [
165
+ {
166
+ "id": "lcp-slow",
167
+ "label": "LCP exceeds 2.5s threshold",
168
+ "severity": "critical",
169
+ "value": 4320,
170
+ "unit": "ms",
171
+ "threshold": 2500,
172
+ "confidence": "strong",
173
+ "remediation": "Optimize largest contentful paint element...",
174
+ "chainId": "lcp:3",
175
+ },
176
+ ],
177
+ "chains": [
178
+ {
179
+ "id": "lcp:3",
180
+ "rootCause": "LCP > 2.5s",
181
+ "impact": "Poor user experience",
182
+ "path": [
183
+ "TTFB delayed by server response",
184
+ "Render-blocking stylesheets",
185
+ "LCP element render delay",
186
+ ],
187
+ "length": 3,
188
+ },
189
+ ],
190
+ "recommendations": [
191
+ {
192
+ "priority": "critical",
193
+ "category": "LCP",
194
+ "title": "Optimize Largest Contentful Paint",
195
+ "action": "Inline critical styles, defer non-critical CSS",
196
+ "expectedImpact": "Reduces LCP by ~40%",
197
+ "relatedIssues": ["lcp-slow"],
198
+ },
199
+ ],
200
+ "features": {
201
+ /* raw extracted features for cross-referencing */
202
+ },
203
+ }
204
+ ```
205
+
206
+ ## What it detects
207
+
208
+ | Category | Issues |
209
+ | --------------- | ----------------------------------------------------------------------------------- |
210
+ | **LCP** | Slow LCP, high TTFB, render-blocking resources, LCP resource delay chains |
211
+ | **JavaScript** | Long tasks, high TBT, heavy execution, unused code, main-thread bottlenecks |
212
+ | **Network** | Deep request chains, bandwidth bottlenecks, waterfall depth, critical path analysis |
213
+ | **Layout** | Layout shifts (CLS), large DOM size, forced reflows |
214
+ | **Third-party** | Third-party script overhead, tracking pixels, embedded widget impact |
215
+
216
+ ## Architecture
217
+
218
+ ```
219
+ src/
220
+ ├── index.ts CLI entry — lazy-loads commands
221
+ ├── collect/ CDP data collection via Playwright
222
+ │ ├── browser.ts Browser launcher
223
+ │ ├── collector.ts Orchestrator
224
+ │ ├── coverage.ts JS/CSS coverage
225
+ │ ├── network.ts Network request capture
226
+ │ ├── performance.ts Performance API metrics
227
+ │ ├── runtime.ts Runtime metadata
228
+ │ ├── dom.ts DOM snapshot
229
+ │ └── lighthouse.ts Lighthouse audit
230
+ ├── normalize/ Data normalization & IR validation
231
+ ├── extract/ 7 diagnostic feature extractors
232
+ ├── causal/ Causal rule engine (30+ rules)
233
+ │ ├── builder.ts Graph construction
234
+ │ ├── rules/ Individual causal rules by category
235
+ │ └── types.ts Graph data types
236
+ ├── report/ Report generation & scoring
237
+ │ ├── analyzer.ts Report builder
238
+ │ ├── scorer.ts Score computation
239
+ │ ├── remediations.ts Remediation templates
240
+ │ └── types.ts Report schema
241
+ ├── distill/ Agent-optimized summary layer (insights.json)
242
+ ├── mcp/ MCP stdio server
243
+ ├── cli/ CLI command handlers
244
+ └── shared/ Shared utilities & types
245
+ ```
246
+
247
+ ## Development
248
+
249
+ ```bash
250
+ npm install
251
+ npm run build # compile TypeScript
252
+ npm run typecheck # check types only
253
+ npm test # run tests
254
+ npm run test:watch # tests in watch mode
255
+ npm run dev # tsx watch — no build step
256
+ ```
257
+
258
+ ## Tech
259
+
260
+ | Thing | What |
261
+ | ------------------ | --------------------------------------------- |
262
+ | Runtime | Node.js ≥ 22 |
263
+ | Language | TypeScript (strict, noUncheckedIndexedAccess) |
264
+ | Browser | Playwright (Chromium) |
265
+ | Validation | Zod at every data boundary |
266
+ | Graph engine | @dagrejs/graphlib |
267
+ | Performance audits | Lighthouse |
268
+ | Testing | Vitest |
269
+
270
+ ## License
271
+
272
+ MIT
273
+
274
+ [badge-version]: https://img.shields.io/npm/v/perfgraph.svg
275
+ [badge-license]: https://img.shields.io/npm/l/perfgraph.svg
276
+ [badge-downloads]: https://img.shields.io/npm/dm/perfgraph.svg
277
+ [badge-stars]: https://img.shields.io/github/stars/Be1zebub/PerfGraph.svg?style=flat&logo=github
278
+ [npm]: https://www.npmjs.com/package/perfgraph
279
+ [license]: https://github.com/Be1zebub/PerfGraph/blob/master/LICENSE
280
+ [repo]: https://github.com/Be1zebub/PerfGraph
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Causal Graph Builder — deterministic rules engine.
3
+ *
4
+ * Takes a FeatureSet, evaluates all known causal rules, builds a DAG,
5
+ * validates acyclicity, and returns a typed CausalGraph.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import type { FeatureSet } from '../extract/types.js';
10
+ import type { CausalGraph, CausalNode, CausalEdge } from './types.js';
11
+ export interface CausalRule {
12
+ /** Unique rule identifier (e.g. "lcp-ttfb-chain") */
13
+ id: string;
14
+ /** Human-readable rule label */
15
+ label: string;
16
+ /** Check whether this rule applies to the given FeatureSet */
17
+ applies: (features: FeatureSet) => boolean;
18
+ /** Build nodes and edges for this causal chain */
19
+ build: (features: FeatureSet) => {
20
+ nodes: CausalNode[];
21
+ edges: CausalEdge[];
22
+ };
23
+ }
24
+ /**
25
+ * Build a deterministic CausalGraph from a FeatureSet.
26
+ *
27
+ * This is a pure function: same FeatureSet → same CausalGraph (given the same rules).
28
+ *
29
+ * @param features - The FeatureSet from Phase 3 extraction
30
+ * @returns A typed CausalGraph with nodes, edges, and metadata
31
+ * @throws If the graph contains cycles after all rules are applied
32
+ */
33
+ export declare function buildCausalGraph(features: FeatureSet): CausalGraph;
34
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/causal/builder.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACX,MAAM,YAAY,CAAC;AAWpB,MAAM,WAAW,UAAU;IACzB,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,OAAO,EAAE,CAAC,QAAQ,EAAE,UAAU,KAAK,OAAO,CAAC;IAC3C,kDAAkD;IAClD,KAAK,EAAE,CAAC,QAAQ,EAAE,UAAU,KAAK;QAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,KAAK,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;CAC/E;AAkCD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,UAAU,GAAG,WAAW,CA8FlE"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Causal Graph Builder — deterministic rules engine.
3
+ *
4
+ * Takes a FeatureSet, evaluates all known causal rules, builds a DAG,
5
+ * validates acyclicity, and returns a typed CausalGraph.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import { Graph, alg } from '@dagrejs/graphlib';
10
+ import { CausalGraphSchema } from './types.js';
11
+ import { lcpRules } from './rules/lcp.js';
12
+ import { networkRules } from './rules/network.js';
13
+ import { jsRules } from './rules/js.js';
14
+ import { layoutRules } from './rules/layout.js';
15
+ // ---------------------------------------------------------------------------
16
+ // All registered rules
17
+ // ---------------------------------------------------------------------------
18
+ // IMPORTANT: order matters — rules evaluated first get priority for
19
+ // node/edge IDs if there are overlaps (unlikely, but possible).
20
+ const ALL_RULES = [
21
+ ...lcpRules,
22
+ ...networkRules,
23
+ ...jsRules,
24
+ ...layoutRules,
25
+ ];
26
+ // ---------------------------------------------------------------------------
27
+ // Node deduplication: merge nodes with the same id
28
+ // ---------------------------------------------------------------------------
29
+ function mergeNodes(existing, incoming) {
30
+ return {
31
+ ...existing,
32
+ // Prefer the non-undefined value
33
+ severity: incoming.severity ?? existing.severity,
34
+ value: incoming.value ?? existing.value,
35
+ unit: incoming.unit ?? existing.unit,
36
+ threshold: incoming.threshold ?? existing.threshold,
37
+ };
38
+ }
39
+ // ---------------------------------------------------------------------------
40
+ // Build the causal graph from a FeatureSet
41
+ // ---------------------------------------------------------------------------
42
+ /**
43
+ * Build a deterministic CausalGraph from a FeatureSet.
44
+ *
45
+ * This is a pure function: same FeatureSet → same CausalGraph (given the same rules).
46
+ *
47
+ * @param features - The FeatureSet from Phase 3 extraction
48
+ * @returns A typed CausalGraph with nodes, edges, and metadata
49
+ * @throws If the graph contains cycles after all rules are applied
50
+ */
51
+ export function buildCausalGraph(features) {
52
+ const g = new Graph({ directed: true });
53
+ const nodeMap = new Map();
54
+ // Track which rules were applicable
55
+ let applicableCount = 0;
56
+ for (const rule of ALL_RULES) {
57
+ if (!rule.applies(features))
58
+ continue;
59
+ applicableCount++;
60
+ const { nodes, edges } = rule.build(features);
61
+ // Add nodes (deduplicate by id)
62
+ for (const node of nodes) {
63
+ const existing = nodeMap.get(node.id);
64
+ if (existing) {
65
+ nodeMap.set(node.id, mergeNodes(existing, node));
66
+ }
67
+ else {
68
+ nodeMap.set(node.id, node);
69
+ }
70
+ g.setNode(node.id, nodeMap.get(node.id));
71
+ }
72
+ // Add edges
73
+ for (const edge of edges) {
74
+ // Ensure both endpoints exist in the graph
75
+ if (!nodeMap.has(edge.source)) {
76
+ const fallback = {
77
+ id: edge.source,
78
+ label: edge.source,
79
+ type: 'bottleneck',
80
+ };
81
+ nodeMap.set(edge.source, fallback);
82
+ g.setNode(edge.source, fallback);
83
+ }
84
+ if (!nodeMap.has(edge.target)) {
85
+ const fallback = {
86
+ id: edge.target,
87
+ label: edge.target,
88
+ type: 'impact',
89
+ };
90
+ nodeMap.set(edge.target, fallback);
91
+ g.setNode(edge.target, fallback);
92
+ }
93
+ g.setEdge(edge.source, edge.target, edge);
94
+ }
95
+ }
96
+ // -----------------------------------------------------------------------
97
+ // Validation: check for cycles
98
+ // -----------------------------------------------------------------------
99
+ const cycles = alg.findCycles(g);
100
+ const hasCycle = cycles.length > 0;
101
+ if (hasCycle) {
102
+ const cycleDescriptions = cycles
103
+ .map((cycle) => cycle.join(' → '))
104
+ .join('; ');
105
+ throw new Error(`Causal graph contains cycle(s): ${cycleDescriptions}. ` +
106
+ `Cycle-free DAG is required for deterministic analysis.`);
107
+ }
108
+ // Topological sort (will throw if cycles remain)
109
+ const sortedIds = alg.topsort(g);
110
+ // -----------------------------------------------------------------------
111
+ // Build output — sorted by topological order
112
+ // -----------------------------------------------------------------------
113
+ const sortedNodes = sortedIds
114
+ .map((id) => g.node(id))
115
+ .filter((n) => n != null);
116
+ const allEdges = g.edges().map((e) => g.edge(e.v, e.w));
117
+ const output = {
118
+ nodes: sortedNodes,
119
+ edges: allEdges,
120
+ metadata: {
121
+ featureCount: applicableCount,
122
+ ruleCount: ALL_RULES.length,
123
+ totalNodes: sortedNodes.length,
124
+ totalEdges: allEdges.length,
125
+ hasCycle: false,
126
+ targetUrl: features.url ?? undefined,
127
+ },
128
+ };
129
+ // Final schema validation
130
+ return CausalGraphSchema.parse(output);
131
+ }
132
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/causal/builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Causal Graph Builder — public API.
3
+ *
4
+ * Entry point for Phase 4: takes FeatureSet → returns CausalGraph.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export { buildCausalGraph } from './builder.js';
9
+ export type { CausalRule } from './builder.js';
10
+ export { CausalNodeSchema, CausalEdgeSchema, CausalGraphSchema, type CausalNode, type CausalEdge, type CausalGraph, type CausalGraphMetadata, type Confidence, type Severity, } from './types.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/causal/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,QAAQ,GACd,MAAM,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Causal Graph Builder — public API.
3
+ *
4
+ * Entry point for Phase 4: takes FeatureSet → returns CausalGraph.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export { buildCausalGraph } from './builder.js';
9
+ export { CausalNodeSchema, CausalEdgeSchema, CausalGraphSchema, } from './types.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/causal/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,GAOlB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * JavaScript / Main Thread causal rules.
3
+ *
4
+ * Chains covered:
5
+ * 1. Long main thread blocking → high TBT → delayed INP
6
+ * 2. Excessive JS → long parse time → main thread contention
7
+ * 3. JS execution hotspots → long tasks → blocking
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ import type { FeatureSet } from '../../extract/types.js';
12
+ import type { CausalNode, CausalEdge } from '../types.js';
13
+ export declare const tbtInpChain: {
14
+ id: string;
15
+ label: string;
16
+ applies(features: FeatureSet): boolean;
17
+ build(features: FeatureSet): {
18
+ nodes: CausalNode[];
19
+ edges: CausalEdge[];
20
+ };
21
+ };
22
+ export declare const jsHotspotsChain: {
23
+ id: string;
24
+ label: string;
25
+ applies(features: FeatureSet): boolean;
26
+ build(features: FeatureSet): {
27
+ nodes: CausalNode[];
28
+ edges: CausalEdge[];
29
+ };
30
+ };
31
+ export declare const excessiveScriptsChain: {
32
+ id: string;
33
+ label: string;
34
+ applies(features: FeatureSet): boolean;
35
+ build(features: FeatureSet): {
36
+ nodes: CausalNode[];
37
+ edges: CausalEdge[];
38
+ };
39
+ };
40
+ export declare const jsRules: {
41
+ id: string;
42
+ label: string;
43
+ applies(features: FeatureSet): boolean;
44
+ build(features: FeatureSet): {
45
+ nodes: CausalNode[];
46
+ edges: CausalEdge[];
47
+ };
48
+ }[];
49
+ //# sourceMappingURL=js.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"js.d.ts","sourceRoot":"","sources":["../../../src/causal/rules/js.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAc,UAAU,EAAE,UAAU,EAAY,MAAM,aAAa,CAAC;AAiChF,eAAO,MAAM,WAAW;;;sBAIJ,UAAU,GAAG,OAAO;oBAKtB,UAAU,GAAG;QAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,KAAK,EAAE,UAAU,EAAE,CAAA;KAAE;CAwD1E,CAAC;AAMF,eAAO,MAAM,eAAe;;;sBAIR,UAAU,GAAG,OAAO;oBAKtB,UAAU,GAAG;QAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,KAAK,EAAE,UAAU,EAAE,CAAA;KAAE;CAuD1E,CAAC;AAMF,eAAO,MAAM,qBAAqB;;;sBAId,UAAU,GAAG,OAAO;oBAKtB,UAAU,GAAG;QAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,KAAK,EAAE,UAAU,EAAE,CAAA;KAAE;CAqC1E,CAAC;AAMF,eAAO,MAAM,OAAO;;;sBA7LA,UAAU,GAAG,OAAO;oBAKtB,UAAU,GAAG;QAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,KAAK,EAAE,UAAU,EAAE,CAAA;KAAE;GA4L1E,CAAC"}