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,51 @@
1
+ /**
2
+ * Output writer — creates timestamped directories and writes JSON data.
3
+ */
4
+ import { mkdir, writeFile } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ /**
7
+ * Create a timestamped output directory under the given base path.
8
+ *
9
+ * Directory format: `perfgraph_<hostname>_<YYYYMMDD_HHmmss>`
10
+ *
11
+ * @param basePath - Base directory for output
12
+ * @param url - Source URL (used to extract hostname for directory naming)
13
+ * @returns Absolute path to the created directory
14
+ */
15
+ export async function createOutputDir(basePath, url) {
16
+ const hostname = new URL(url).hostname.replace(/[^a-zA-Z0-9.-]/g, '_');
17
+ const now = new Date();
18
+ const pad = (n) => String(n).padStart(2, '0');
19
+ const timestamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
20
+ const dirName = `perfgraph_${hostname}_${timestamp}`;
21
+ const dirPath = join(basePath, dirName);
22
+ await mkdir(dirPath, { recursive: true });
23
+ return dirPath;
24
+ }
25
+ /**
26
+ * Write a JSON-serializable value to a file inside the given directory.
27
+ *
28
+ * @param dir - Target directory
29
+ * @param filename - File name (e.g. "trace.json")
30
+ * @param data - Data to serialize as JSON
31
+ * @returns Full path to the written file
32
+ */
33
+ export async function writeJsonFile(dir, filename, data) {
34
+ const filePath = join(dir, filename);
35
+ await writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');
36
+ return filePath;
37
+ }
38
+ /**
39
+ * Write a warnings file to the given directory.
40
+ *
41
+ * @param dir - Target directory
42
+ * @param warnings - Array of warning strings
43
+ * @returns Full path to the written file
44
+ */
45
+ export async function writeWarnings(dir, warnings) {
46
+ return writeJsonFile(dir, 'warnings.json', {
47
+ warnings,
48
+ timestamp: new Date().toISOString(),
49
+ });
50
+ }
51
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/output/writer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,GAAW;IACjE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;IAC/J,MAAM,OAAO,GAAG,aAAa,QAAQ,IAAI,SAAS,EAAE,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,QAAgB,EAAE,IAAa;IAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAClE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,QAAkB;IACjE,OAAO,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE;QACzC,QAAQ;QACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Report Analyzer — core logic for Phase 5.
3
+ *
4
+ * Takes CausalGraph + FeatureSet and produces a comprehensive Report:
5
+ * - Extracts causal chains (root cause → intermediate → impact)
6
+ * - Builds flat issue list with remediation texts
7
+ * - Computes overall score
8
+ * - Generates prioritized recommendations
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import type { CausalGraph } from '../causal/types.js';
13
+ import type { FeatureSet } from '../extract/types.js';
14
+ import type { Report } from './types.js';
15
+ /**
16
+ * Build a comprehensive Report from a CausalGraph and FeatureSet.
17
+ *
18
+ * Pure function: same inputs → same Report.
19
+ *
20
+ * @param graph - The CausalGraph from Phase 4
21
+ * @param features - The FeatureSet from Phase 3 (optional — included in report as-is)
22
+ * @returns A fully populated Report
23
+ */
24
+ export declare function buildReport(graph: CausalGraph, features?: FeatureSet, lighthousePerformance?: number): Report;
25
+ /**
26
+ * Check whether a report has actionable issues.
27
+ */
28
+ export declare function hasActionableIssues(report: Report): boolean;
29
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/report/analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,WAAW,EAA0B,MAAM,oBAAoB,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EACV,MAAM,EAOP,MAAM,YAAY,CAAC;AAsHpB;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,QAAQ,CAAC,EAAE,UAAU,EACrB,qBAAqB,CAAC,EAAE,MAAM,GAC7B,MAAM,CAyOR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE3D"}
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Report Analyzer — core logic for Phase 5.
3
+ *
4
+ * Takes CausalGraph + FeatureSet and produces a comprehensive Report:
5
+ * - Extracts causal chains (root cause → intermediate → impact)
6
+ * - Builds flat issue list with remediation texts
7
+ * - Computes overall score
8
+ * - Generates prioritized recommendations
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import { Graph, alg } from '@dagrejs/graphlib';
13
+ import { ReportSchema } from './types.js';
14
+ import { computeScore } from './scorer.js';
15
+ import { getRemediation } from './remediations.js';
16
+ // ---------------------------------------------------------------------------
17
+ // Constants
18
+ // ---------------------------------------------------------------------------
19
+ const REPORT_VERSION = '1.0.0';
20
+ // ---------------------------------------------------------------------------
21
+ // Helpers
22
+ // ---------------------------------------------------------------------------
23
+ /**
24
+ * Reconstruct a graphlib Graph from a CausalGraph for traversal.
25
+ */
26
+ function rebuildGraph(graph) {
27
+ const g = new Graph({ directed: true });
28
+ for (const node of graph.nodes) {
29
+ g.setNode(node.id, node);
30
+ }
31
+ for (const edge of graph.edges) {
32
+ if (!g.hasNode(edge.source)) {
33
+ g.setNode(edge.source, { id: edge.source, label: edge.source, type: 'bottleneck' });
34
+ }
35
+ if (!g.hasNode(edge.target)) {
36
+ g.setNode(edge.target, { id: edge.target, label: edge.target, type: 'impact' });
37
+ }
38
+ g.setEdge(edge.source, edge.target, edge);
39
+ }
40
+ return g;
41
+ }
42
+ /**
43
+ * DFS from a node to find all paths to sink nodes.
44
+ * Uses simple recursion with visited set to avoid infinite loops.
45
+ */
46
+ function findPathsToSinks(g, nodeId, visited = new Set()) {
47
+ if (visited.has(nodeId))
48
+ return [];
49
+ visited.add(nodeId);
50
+ const outEdges = g.outEdges(nodeId) ?? [];
51
+ // If no outgoing edges, this is a sink — return path with just this node
52
+ if (outEdges.length === 0) {
53
+ return [[nodeId]];
54
+ }
55
+ const paths = [];
56
+ for (const edge of outEdges) {
57
+ const subPaths = findPathsToSinks(g, edge.w, new Set(visited));
58
+ for (const sub of subPaths) {
59
+ paths.push([nodeId, ...sub]);
60
+ }
61
+ }
62
+ return paths;
63
+ }
64
+ /**
65
+ * Find the overall confidence for a chain (lowest in the path).
66
+ */
67
+ function chainConfidence(path, edges) {
68
+ const confOrder = { strong: 3, medium: 2, weak: 1 };
69
+ let minConf = 3;
70
+ for (let i = 0; i < path.length - 1; i++) {
71
+ const edge = edges.find((e) => e.source === path[i] && e.target === path[i + 1]);
72
+ if (edge) {
73
+ minConf = Math.min(minConf, confOrder[edge.confidence] ?? 1);
74
+ }
75
+ }
76
+ const reverse = { 3: 'strong', 2: 'medium', 1: 'weak' };
77
+ return reverse[minConf] ?? 'weak';
78
+ }
79
+ // ---------------------------------------------------------------------------
80
+ // Category mapping for recommendations
81
+ // ---------------------------------------------------------------------------
82
+ function categorizeNode(nodeId, ruleId) {
83
+ if (!ruleId) {
84
+ if (nodeId.includes('lcp') || nodeId.includes('ttfb') || nodeId.includes('rb-'))
85
+ return 'LCP';
86
+ if (nodeId.includes('js-') || nodeId.includes('tbt') || nodeId.includes('inp'))
87
+ return 'JavaScript';
88
+ if (nodeId.includes('net-') || nodeId.includes('chain') || nodeId.includes('request') || nodeId.includes('bandwidth'))
89
+ return 'Network';
90
+ if (nodeId.includes('layout') || nodeId.includes('cls') || nodeId.includes('dom'))
91
+ return 'Layout';
92
+ return 'Performance';
93
+ }
94
+ if (ruleId.startsWith('lcp'))
95
+ return 'LCP';
96
+ if (ruleId.startsWith('net'))
97
+ return 'Network';
98
+ if (ruleId.startsWith('js'))
99
+ return 'JavaScript';
100
+ if (ruleId.startsWith('layout'))
101
+ return 'Layout';
102
+ return 'Performance';
103
+ }
104
+ /**
105
+ * Build a deterministic chain ID from a rule ID and path length.
106
+ */
107
+ function buildChainId(ruleId, path) {
108
+ return `${ruleId}:${path.length}`;
109
+ }
110
+ // ---------------------------------------------------------------------------
111
+ // Main analyzer
112
+ // ---------------------------------------------------------------------------
113
+ /**
114
+ * Build a comprehensive Report from a CausalGraph and FeatureSet.
115
+ *
116
+ * Pure function: same inputs → same Report.
117
+ *
118
+ * @param graph - The CausalGraph from Phase 4
119
+ * @param features - The FeatureSet from Phase 3 (optional — included in report as-is)
120
+ * @returns A fully populated Report
121
+ */
122
+ export function buildReport(graph, features, lighthousePerformance) {
123
+ const g = rebuildGraph(graph);
124
+ // -----------------------------------------------------------------------
125
+ // 1. Build causal chains
126
+ // -----------------------------------------------------------------------
127
+ const sources = g.sources();
128
+ const nodeMap = new Map(graph.nodes.map((n) => [n.id, n]));
129
+ const allPaths = [];
130
+ const seenPaths = new Set();
131
+ for (const source of sources) {
132
+ const paths = findPathsToSinks(g, source);
133
+ for (const path of paths) {
134
+ if (path.length < 2)
135
+ continue; // skip single-node "chains"
136
+ // Determine ruleId from the first edge
137
+ const firstEdge = graph.edges.find((e) => e.source === path[0] && e.target === path[1]);
138
+ const ruleId = firstEdge?.ruleId ?? 'unknown';
139
+ // Deduplicate identical paths
140
+ const pathKey = `${ruleId}:${path.join('→')}`;
141
+ if (seenPaths.has(pathKey))
142
+ continue;
143
+ seenPaths.add(pathKey);
144
+ allPaths.push({ ruleId, path });
145
+ }
146
+ }
147
+ const chains = allPaths.map(({ ruleId, path }) => {
148
+ const chainId = buildChainId(ruleId, path);
149
+ const headId = path[0];
150
+ const tailId = path[path.length - 1];
151
+ const firstNode = nodeMap.get(headId) ?? { label: headId };
152
+ const lastNode = nodeMap.get(tailId) ?? { label: tailId };
153
+ const conf = chainConfidence(path, graph.edges);
154
+ // Highest severity in the chain
155
+ let maxSev = 'info';
156
+ for (const p of path) {
157
+ const n = nodeMap.get(p);
158
+ if (n?.severity === 'critical') {
159
+ maxSev = 'critical';
160
+ break;
161
+ }
162
+ if (n?.severity === 'warning')
163
+ maxSev = 'warning';
164
+ }
165
+ return {
166
+ id: chainId,
167
+ rootCause: firstNode.label,
168
+ impact: lastNode.label,
169
+ confidence: conf,
170
+ severity: maxSev,
171
+ path: path.map((nodeId) => {
172
+ const n = nodeMap.get(nodeId);
173
+ return {
174
+ nodeId,
175
+ label: n?.label ?? nodeId,
176
+ type: n?.type ?? 'bottleneck',
177
+ severity: n?.severity,
178
+ };
179
+ }),
180
+ length: path.length,
181
+ };
182
+ });
183
+ // -----------------------------------------------------------------------
184
+ // 2. Build issues (flat list, sorted by severity)
185
+ // -----------------------------------------------------------------------
186
+ // Map each node to a chain ID
187
+ const nodeToChain = new Map();
188
+ for (const chain of chains) {
189
+ for (const step of chain.path) {
190
+ // Prefer shorter chain (more direct causal link)
191
+ const existing = nodeToChain.get(step.nodeId);
192
+ if (!existing || chain.length < 3) {
193
+ nodeToChain.set(step.nodeId, chain.id);
194
+ }
195
+ }
196
+ }
197
+ // Find edge confidence for each node (confidence of the edge leading INTO it)
198
+ const nodeInConfidence = new Map();
199
+ for (const edge of graph.edges) {
200
+ nodeInConfidence.set(edge.target, edge.confidence);
201
+ }
202
+ const issues = graph.nodes.map((node) => {
203
+ // Determine the rule ID for remediation lookup
204
+ const incomingEdge = graph.edges.find((e) => e.target === node.id);
205
+ const ruleId = incomingEdge?.ruleId;
206
+ const confidence = nodeInConfidence.get(node.id) ?? 'weak';
207
+ return {
208
+ id: node.id,
209
+ label: node.label,
210
+ type: node.type,
211
+ severity: node.severity ?? 'info',
212
+ value: node.value,
213
+ unit: node.unit,
214
+ threshold: node.threshold,
215
+ confidence,
216
+ remediation: getRemediation(node.id, {
217
+ evidence: node.evidence,
218
+ value: node.value,
219
+ unit: node.unit,
220
+ nodeType: node.type,
221
+ ruleId,
222
+ }),
223
+ chainId: nodeToChain.get(node.id) ?? 'standalone',
224
+ evidence: node.evidence,
225
+ };
226
+ });
227
+ // Sort: critical first, then warning, then info
228
+ const sevOrder = { critical: 0, warning: 1, info: 2 };
229
+ issues.sort((a, b) => (sevOrder[a.severity] ?? 3) - (sevOrder[b.severity] ?? 3));
230
+ // -----------------------------------------------------------------------
231
+ // 3. Build summary
232
+ // -----------------------------------------------------------------------
233
+ const criticalCount = issues.filter((i) => i.severity === 'critical').length;
234
+ const warningCount = issues.filter((i) => i.severity === 'warning').length;
235
+ const infoCount = issues.filter((i) => i.severity === 'info').length;
236
+ const scoreResult = computeScore(graph, lighthousePerformance);
237
+ const score = typeof scoreResult === 'string' ? scoreResult : scoreResult.score;
238
+ const scoreExplanation = typeof scoreResult === 'object' ? scoreResult.explanation : undefined;
239
+ // Top 5 issues (sorted by severity, then by confidence: strong > medium > weak)
240
+ const confOrder = { strong: 0, medium: 1, weak: 2 };
241
+ const sortedTop = [...issues].sort((a, b) => {
242
+ const sevCmp = (sevOrder[a.severity] ?? 3) - (sevOrder[b.severity] ?? 3);
243
+ if (sevCmp !== 0)
244
+ return sevCmp;
245
+ return (confOrder[a.confidence] ?? 3) - (confOrder[b.confidence] ?? 3);
246
+ });
247
+ const topIssues = sortedTop.slice(0, 5).map((i) => ({
248
+ id: i.id,
249
+ label: i.label,
250
+ severity: i.severity,
251
+ confidence: i.confidence,
252
+ }));
253
+ const summary = {
254
+ score,
255
+ criticalIssues: criticalCount,
256
+ warnings: warningCount,
257
+ infos: infoCount,
258
+ topIssues,
259
+ lighthousePerformance,
260
+ scoreExplanation,
261
+ };
262
+ // -----------------------------------------------------------------------
263
+ // 4. Build recommendations
264
+ // -----------------------------------------------------------------------
265
+ const recommendations = [];
266
+ const recSeen = new Set();
267
+ // Build recommendations from critical and warning issues
268
+ const actionableIssues = issues.filter((i) => i.severity === 'critical' || i.severity === 'warning');
269
+ for (const issue of actionableIssues) {
270
+ const cat = categorizeNode(issue.id);
271
+ // Deduplicate by category + action prefix
272
+ const dedupKey = `${cat}:${issue.remediation.slice(0, 80)}`;
273
+ if (recSeen.has(dedupKey))
274
+ continue;
275
+ recSeen.add(dedupKey);
276
+ const priority = issue.severity === 'critical' ? 'critical' : 'high';
277
+ // Extract action from remediation (first sentence)
278
+ const actionEnd = issue.remediation.indexOf('. ');
279
+ const action = actionEnd > 0
280
+ ? issue.remediation.slice(0, actionEnd + 1)
281
+ : issue.remediation;
282
+ recommendations.push({
283
+ priority,
284
+ category: cat,
285
+ title: issue.label,
286
+ description: issue.remediation,
287
+ action,
288
+ expectedImpact: issue.type === 'impact'
289
+ ? 'Target metric improvement'
290
+ : 'Eliminates bottleneck in the degradation chain',
291
+ relatedIssues: issues
292
+ .filter((other) => other.chainId === issue.chainId && other.id !== issue.id)
293
+ .map((other) => other.id),
294
+ });
295
+ }
296
+ // Sort recommendations: critical first, then high, then medium, then low
297
+ const recPriority = { critical: 0, high: 1, medium: 2, low: 3 };
298
+ recommendations.sort((a, b) => (recPriority[a.priority] ?? 4) - (recPriority[b.priority] ?? 4));
299
+ // -----------------------------------------------------------------------
300
+ // 5. Build metadata
301
+ // -----------------------------------------------------------------------
302
+ const meta = {
303
+ url: graph.metadata.targetUrl ?? features?.url ?? '',
304
+ analyzedAt: new Date().toISOString(),
305
+ reportVersion: REPORT_VERSION,
306
+ featureCount: graph.metadata.featureCount,
307
+ graphNodeCount: graph.metadata.totalNodes,
308
+ graphEdgeCount: graph.metadata.totalEdges,
309
+ ruleCount: graph.metadata.ruleCount,
310
+ };
311
+ // -----------------------------------------------------------------------
312
+ // 6. Assemble + validate
313
+ // -----------------------------------------------------------------------
314
+ const report = {
315
+ meta,
316
+ summary,
317
+ issues,
318
+ chains,
319
+ recommendations,
320
+ features: features ?? null,
321
+ };
322
+ return ReportSchema.parse(report);
323
+ }
324
+ /**
325
+ * Check whether a report has actionable issues.
326
+ */
327
+ export function hasActionableIssues(report) {
328
+ return report.summary.criticalIssues > 0 || report.summary.warnings > 0;
329
+ }
330
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../src/report/analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Report Generator — Phase 5 public API.
3
+ *
4
+ * Usage:
5
+ * import { buildReport } from '../report/index.js';
6
+ * const report = buildReport(causalGraph, featureSet);
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ export { buildReport, hasActionableIssues } from './analyzer.js';
11
+ export type { Report, ReportMeta, ReportSummary, ReportIssue, CausalChain, Recommendation, TopIssue, ReportScore, RecommendationPriority, } from './types.js';
12
+ export { getRemediation } from './remediations.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EACV,MAAM,EACN,UAAU,EACV,aAAa,EACb,WAAW,EACX,WAAW,EACX,cAAc,EACd,QAAQ,EACR,WAAW,EACX,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Report Generator — Phase 5 public API.
3
+ *
4
+ * Usage:
5
+ * import { buildReport } from '../report/index.js';
6
+ * const report = buildReport(causalGraph, featureSet);
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ export { buildReport, hasActionableIssues } from './analyzer.js';
11
+ export { getRemediation } from './remediations.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAYjE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Markdown report generator — produces a human-readable performance report
3
+ * from a PerfGraph {@link Report} and optional {@link Insights}.
4
+ *
5
+ * The output is designed for direct consumption by developers and includes
6
+ * score summary, all issues with severities, causal chains, recommendations,
7
+ * and Lighthouse insights when available.
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ import type { Report } from './types.js';
12
+ import type { Insights } from '../distill/insights.js';
13
+ /**
14
+ * Generate a human-readable markdown report from a PerfGraph Report + Insights.
15
+ *
16
+ * @param report - The structured report from `buildReport()`
17
+ * @param insights - Optional Lighthouse-derived insights from `buildInsights()`
18
+ * @returns A formatted Markdown string
19
+ */
20
+ export declare function buildReportMarkdown(report: Report, insights?: Insights): string;
21
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/report/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAyBvD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,QAAQ,GAClB,MAAM,CA4KR"}