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,127 @@
1
+ /**
2
+ * Third-Party Overhead extractor.
3
+ *
4
+ * Identifies and categorises requests to third-party origins and computes
5
+ * aggregate metrics: count, bytes, duration, and ratio vs first-party.
6
+ */
7
+ /** Common third-party categories keyed by hostname substring. */
8
+ const THIRD_PARTY_PATTERNS = {
9
+ 'google-analytics': 'analytics',
10
+ 'googletagmanager': 'analytics',
11
+ 'gtag': 'analytics',
12
+ 'facebook': 'social',
13
+ 'fbcdn': 'social',
14
+ 'twitter': 'social',
15
+ 'linkedin': 'social',
16
+ 'doubleclick': 'advertising',
17
+ 'adsystem': 'advertising',
18
+ 'adservice': 'advertising',
19
+ 'cloudflare': 'cdn',
20
+ 'cloudfront': 'cdn',
21
+ 'fastly': 'cdn',
22
+ 'akamai': 'cdn',
23
+ 'cdn': 'cdn',
24
+ 'stackpath': 'cdn',
25
+ 'hotjar': 'analytics',
26
+ 'amplitude': 'analytics',
27
+ 'mixpanel': 'analytics',
28
+ 'segment': 'analytics',
29
+ 'sentry': 'monitoring',
30
+ 'datadog': 'monitoring',
31
+ 'newrelic': 'monitoring',
32
+ 'stripe': 'payment',
33
+ 'paypal': 'payment',
34
+ 'recaptcha': 'utility',
35
+ 'gstatic': 'utility',
36
+ 'googleapis': 'utility',
37
+ 'googlefonts': 'fonts',
38
+ 'fontawesome': 'fonts',
39
+ 'typekit': 'fonts',
40
+ 'youtube': 'media',
41
+ 'vimeo': 'media',
42
+ };
43
+ /**
44
+ * Extract the origin from a URL string.
45
+ */
46
+ function getOrigin(url) {
47
+ try {
48
+ const parsed = new URL(url);
49
+ return parsed.origin;
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ }
55
+ /**
56
+ * Categorise a third-party hostname into a known bucket.
57
+ */
58
+ function categoriseHostname(hostname) {
59
+ const lower = hostname.toLowerCase();
60
+ for (const [pattern, category] of Object.entries(THIRD_PARTY_PATTERNS)) {
61
+ if (lower.includes(pattern))
62
+ return category;
63
+ }
64
+ return 'other';
65
+ }
66
+ /**
67
+ * Extract third-party overhead metrics from an IRBundle.
68
+ *
69
+ * Returns undefined when there are no network requests.
70
+ */
71
+ export function extractThirdPartyOverhead(ir) {
72
+ const requests = ir.network.requests;
73
+ if (requests.length === 0)
74
+ return undefined;
75
+ const pageOrigin = getOrigin(ir.meta.url);
76
+ if (!pageOrigin)
77
+ return undefined;
78
+ const byCategory = new Map();
79
+ let thirdPartyRequests = 0;
80
+ let thirdPartyBytes = 0;
81
+ let thirdPartyDuration = 0;
82
+ let firstPartyBytes = 0;
83
+ let firstPartyRequests = 0;
84
+ for (const req of requests) {
85
+ const origin = getOrigin(req.url);
86
+ if (!origin)
87
+ continue;
88
+ if (origin === pageOrigin) {
89
+ firstPartyRequests++;
90
+ firstPartyBytes += Math.max(0, req.bytes);
91
+ continue;
92
+ }
93
+ // Third-party
94
+ thirdPartyRequests++;
95
+ const bytes = Math.max(0, req.bytes);
96
+ const duration = Math.max(0, Number.isFinite(req.duration) ? req.duration : 0);
97
+ thirdPartyBytes += bytes;
98
+ thirdPartyDuration += duration;
99
+ const hostname = new URL(req.url).hostname;
100
+ const category = categoriseHostname(hostname);
101
+ const existing = byCategory.get(category);
102
+ if (existing) {
103
+ existing.requests++;
104
+ existing.bytes += bytes;
105
+ existing.duration += duration;
106
+ }
107
+ else {
108
+ byCategory.set(category, { requests: 1, bytes, duration });
109
+ }
110
+ }
111
+ const totalRequests = thirdPartyRequests + firstPartyRequests;
112
+ const thirdPartyRatio = totalRequests > 0 ? thirdPartyRequests / totalRequests : 0;
113
+ const byCategoryObj = {};
114
+ for (const [cat, data] of byCategory) {
115
+ byCategoryObj[cat] = data;
116
+ }
117
+ return {
118
+ totalThirdPartyRequests: thirdPartyRequests,
119
+ totalThirdPartyBytes: thirdPartyBytes,
120
+ totalThirdPartyDuration: thirdPartyDuration,
121
+ firstPartyBytes,
122
+ firstPartyRequests,
123
+ thirdPartyRatio,
124
+ byCategory: byCategoryObj,
125
+ };
126
+ }
127
+ //# sourceMappingURL=third-party.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"third-party.js","sourceRoot":"","sources":["../../src/extract/third-party.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,183 @@
1
+ /**
2
+ * FeatureSet Zod schemas and inferred TypeScript types.
3
+ *
4
+ * FeatureSet — результат feature extraction из IRBundle.
5
+ * Каждая фича опциональна (undefined если данных недостаточно).
6
+ * Все функции extraction детерминированы: одинаковый IRBundle → одинаковый FeatureSet.
7
+ */
8
+ import { z } from 'zod';
9
+ export declare const LCPBreakdownSchema: z.ZodObject<{
10
+ ttfb: z.ZodNumber;
11
+ resourceLoadDelay: z.ZodNumber;
12
+ resourceLoadTime: z.ZodNumber;
13
+ elementRenderDelay: z.ZodNumber;
14
+ totalLCP: z.ZodNumber;
15
+ lcpElementUrl: z.ZodOptional<z.ZodString>;
16
+ lcpResourceType: z.ZodOptional<z.ZodString>;
17
+ lcpElement: z.ZodOptional<z.ZodObject<{
18
+ selector: z.ZodString;
19
+ snippet: z.ZodOptional<z.ZodString>;
20
+ nodeLabel: z.ZodOptional<z.ZodString>;
21
+ }, z.core.$strip>>;
22
+ source: z.ZodOptional<z.ZodEnum<{
23
+ trace: "trace";
24
+ mixed: "mixed";
25
+ lighthouse: "lighthouse";
26
+ }>>;
27
+ }, z.core.$strip>;
28
+ export declare const CriticalPathSchema: z.ZodObject<{
29
+ totalChainLength: z.ZodNumber;
30
+ requestCount: z.ZodNumber;
31
+ blockingCount: z.ZodNumber;
32
+ nonBlockingCount: z.ZodNumber;
33
+ deepestChainDepth: z.ZodNumber;
34
+ longestSingleRequest: z.ZodNumber;
35
+ urlsOnLongestPath: z.ZodOptional<z.ZodArray<z.ZodString>>;
36
+ }, z.core.$strip>;
37
+ export declare const MainThreadBlockingSchema: z.ZodObject<{
38
+ blockingScore: z.ZodNumber;
39
+ busyMs: z.ZodNumber;
40
+ idleMs: z.ZodNumber;
41
+ blockingRatio: z.ZodNumber;
42
+ categories: z.ZodRecord<z.ZodString, z.ZodNumber>;
43
+ }, z.core.$strip>;
44
+ export declare const JSHotspotsSchema: z.ZodObject<{
45
+ bootupTime: z.ZodNumber;
46
+ evaluatedScripts: z.ZodNumber;
47
+ longTaskCount: z.ZodNumber;
48
+ maxBlockingDuration: z.ZodNumber;
49
+ contextCount: z.ZodNumber;
50
+ }, z.core.$strip>;
51
+ export declare const LayoutShiftsSchema: z.ZodObject<{
52
+ cls: z.ZodOptional<z.ZodNumber>;
53
+ highComplexitySubtreeCount: z.ZodNumber;
54
+ deepNesting: z.ZodBoolean;
55
+ clusterScore: z.ZodNumber;
56
+ }, z.core.$strip>;
57
+ export declare const ThirdPartyCategorySchema: z.ZodObject<{
58
+ requests: z.ZodNumber;
59
+ bytes: z.ZodNumber;
60
+ duration: z.ZodNumber;
61
+ }, z.core.$strip>;
62
+ export declare const ThirdPartyOverheadSchema: z.ZodObject<{
63
+ totalThirdPartyRequests: z.ZodNumber;
64
+ totalThirdPartyBytes: z.ZodNumber;
65
+ totalThirdPartyDuration: z.ZodNumber;
66
+ firstPartyBytes: z.ZodNumber;
67
+ firstPartyRequests: z.ZodNumber;
68
+ thirdPartyRatio: z.ZodNumber;
69
+ byCategory: z.ZodRecord<z.ZodString, z.ZodObject<{
70
+ requests: z.ZodNumber;
71
+ bytes: z.ZodNumber;
72
+ duration: z.ZodNumber;
73
+ }, z.core.$strip>>;
74
+ }, z.core.$strip>;
75
+ export declare const RenderBlockingResourceSchema: z.ZodObject<{
76
+ url: z.ZodString;
77
+ totalBytes: z.ZodOptional<z.ZodNumber>;
78
+ wastedMs: z.ZodOptional<z.ZodNumber>;
79
+ resourceType: z.ZodOptional<z.ZodString>;
80
+ }, z.core.$strip>;
81
+ export declare const RenderBlockingScoreSchema: z.ZodObject<{
82
+ blockingRequestCount: z.ZodNumber;
83
+ blockingBytes: z.ZodNumber;
84
+ blockingDuration: z.ZodNumber;
85
+ renderBlockingScore: z.ZodNumber;
86
+ lhRenderBlockingMs: z.ZodOptional<z.ZodNumber>;
87
+ resources: z.ZodOptional<z.ZodArray<z.ZodObject<{
88
+ url: z.ZodString;
89
+ totalBytes: z.ZodOptional<z.ZodNumber>;
90
+ wastedMs: z.ZodOptional<z.ZodNumber>;
91
+ resourceType: z.ZodOptional<z.ZodString>;
92
+ }, z.core.$strip>>>;
93
+ totalWastedMs: z.ZodOptional<z.ZodNumber>;
94
+ }, z.core.$strip>;
95
+ export declare const FeatureSetSchema: z.ZodObject<{
96
+ url: z.ZodOptional<z.ZodString>;
97
+ lcpBreakdown: z.ZodOptional<z.ZodObject<{
98
+ ttfb: z.ZodNumber;
99
+ resourceLoadDelay: z.ZodNumber;
100
+ resourceLoadTime: z.ZodNumber;
101
+ elementRenderDelay: z.ZodNumber;
102
+ totalLCP: z.ZodNumber;
103
+ lcpElementUrl: z.ZodOptional<z.ZodString>;
104
+ lcpResourceType: z.ZodOptional<z.ZodString>;
105
+ lcpElement: z.ZodOptional<z.ZodObject<{
106
+ selector: z.ZodString;
107
+ snippet: z.ZodOptional<z.ZodString>;
108
+ nodeLabel: z.ZodOptional<z.ZodString>;
109
+ }, z.core.$strip>>;
110
+ source: z.ZodOptional<z.ZodEnum<{
111
+ trace: "trace";
112
+ mixed: "mixed";
113
+ lighthouse: "lighthouse";
114
+ }>>;
115
+ }, z.core.$strip>>;
116
+ criticalPath: z.ZodOptional<z.ZodObject<{
117
+ totalChainLength: z.ZodNumber;
118
+ requestCount: z.ZodNumber;
119
+ blockingCount: z.ZodNumber;
120
+ nonBlockingCount: z.ZodNumber;
121
+ deepestChainDepth: z.ZodNumber;
122
+ longestSingleRequest: z.ZodNumber;
123
+ urlsOnLongestPath: z.ZodOptional<z.ZodArray<z.ZodString>>;
124
+ }, z.core.$strip>>;
125
+ mainThreadBlocking: z.ZodOptional<z.ZodObject<{
126
+ blockingScore: z.ZodNumber;
127
+ busyMs: z.ZodNumber;
128
+ idleMs: z.ZodNumber;
129
+ blockingRatio: z.ZodNumber;
130
+ categories: z.ZodRecord<z.ZodString, z.ZodNumber>;
131
+ }, z.core.$strip>>;
132
+ jsHotspots: z.ZodOptional<z.ZodObject<{
133
+ bootupTime: z.ZodNumber;
134
+ evaluatedScripts: z.ZodNumber;
135
+ longTaskCount: z.ZodNumber;
136
+ maxBlockingDuration: z.ZodNumber;
137
+ contextCount: z.ZodNumber;
138
+ }, z.core.$strip>>;
139
+ layoutShifts: z.ZodOptional<z.ZodObject<{
140
+ cls: z.ZodOptional<z.ZodNumber>;
141
+ highComplexitySubtreeCount: z.ZodNumber;
142
+ deepNesting: z.ZodBoolean;
143
+ clusterScore: z.ZodNumber;
144
+ }, z.core.$strip>>;
145
+ thirdPartyOverhead: z.ZodOptional<z.ZodObject<{
146
+ totalThirdPartyRequests: z.ZodNumber;
147
+ totalThirdPartyBytes: z.ZodNumber;
148
+ totalThirdPartyDuration: z.ZodNumber;
149
+ firstPartyBytes: z.ZodNumber;
150
+ firstPartyRequests: z.ZodNumber;
151
+ thirdPartyRatio: z.ZodNumber;
152
+ byCategory: z.ZodRecord<z.ZodString, z.ZodObject<{
153
+ requests: z.ZodNumber;
154
+ bytes: z.ZodNumber;
155
+ duration: z.ZodNumber;
156
+ }, z.core.$strip>>;
157
+ }, z.core.$strip>>;
158
+ renderBlocking: z.ZodOptional<z.ZodObject<{
159
+ blockingRequestCount: z.ZodNumber;
160
+ blockingBytes: z.ZodNumber;
161
+ blockingDuration: z.ZodNumber;
162
+ renderBlockingScore: z.ZodNumber;
163
+ lhRenderBlockingMs: z.ZodOptional<z.ZodNumber>;
164
+ resources: z.ZodOptional<z.ZodArray<z.ZodObject<{
165
+ url: z.ZodString;
166
+ totalBytes: z.ZodOptional<z.ZodNumber>;
167
+ wastedMs: z.ZodOptional<z.ZodNumber>;
168
+ resourceType: z.ZodOptional<z.ZodString>;
169
+ }, z.core.$strip>>>;
170
+ totalWastedMs: z.ZodOptional<z.ZodNumber>;
171
+ }, z.core.$strip>>;
172
+ }, z.core.$strict>;
173
+ export type LCPBreakdown = z.infer<typeof LCPBreakdownSchema>;
174
+ export type CriticalPath = z.infer<typeof CriticalPathSchema>;
175
+ export type MainThreadBlocking = z.infer<typeof MainThreadBlockingSchema>;
176
+ export type JSHotspots = z.infer<typeof JSHotspotsSchema>;
177
+ export type LayoutShifts = z.infer<typeof LayoutShiftsSchema>;
178
+ export type ThirdPartyCategory = z.infer<typeof ThirdPartyCategorySchema>;
179
+ export type ThirdPartyOverhead = z.infer<typeof ThirdPartyOverheadSchema>;
180
+ export type RenderBlockingResource = z.infer<typeof RenderBlockingResourceSchema>;
181
+ export type RenderBlockingScore = z.infer<typeof RenderBlockingScoreSchema>;
182
+ export type FeatureSet = z.infer<typeof FeatureSetSchema>;
183
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/extract/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;iBAc7B,CAAC;AAMH,eAAO,MAAM,kBAAkB;;;;;;;;iBAS7B,CAAC;AAMH,eAAO,MAAM,wBAAwB;;;;;;iBAMnC,CAAC;AAMH,eAAO,MAAM,gBAAgB;;;;;;iBAM3B,CAAC;AAMH,eAAO,MAAM,kBAAkB;;;;;iBAK7B,CAAC;AAMH,eAAO,MAAM,wBAAwB;;;;iBAInC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;iBAQnC,CAAC;AAMH,eAAO,MAAM,4BAA4B;;;;;iBAKvC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;iBAQpC,CAAC;AAMH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAU3B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAClF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * FeatureSet Zod schemas and inferred TypeScript types.
3
+ *
4
+ * FeatureSet — результат feature extraction из IRBundle.
5
+ * Каждая фича опциональна (undefined если данных недостаточно).
6
+ * Все функции extraction детерминированы: одинаковый IRBundle → одинаковый FeatureSet.
7
+ */
8
+ import { z } from 'zod';
9
+ // ---------------------------------------------------------------------------
10
+ // LCP Breakdown (FEA-01)
11
+ // ---------------------------------------------------------------------------
12
+ export const LCPBreakdownSchema = z.object({
13
+ ttfb: z.number(),
14
+ resourceLoadDelay: z.number(),
15
+ resourceLoadTime: z.number(),
16
+ elementRenderDelay: z.number(),
17
+ totalLCP: z.number(),
18
+ lcpElementUrl: z.string().optional(),
19
+ lcpResourceType: z.string().optional(),
20
+ lcpElement: z.object({
21
+ selector: z.string(),
22
+ snippet: z.string().optional(),
23
+ nodeLabel: z.string().optional(),
24
+ }).optional(),
25
+ source: z.enum(['trace', 'lighthouse', 'mixed']).optional(),
26
+ });
27
+ // ---------------------------------------------------------------------------
28
+ // Critical Path Length (FEA-03)
29
+ // ---------------------------------------------------------------------------
30
+ export const CriticalPathSchema = z.object({
31
+ totalChainLength: z.number(),
32
+ requestCount: z.number(),
33
+ blockingCount: z.number(),
34
+ nonBlockingCount: z.number(),
35
+ deepestChainDepth: z.number(),
36
+ longestSingleRequest: z.number(),
37
+ /** URLs on the longest critical path chain */
38
+ urlsOnLongestPath: z.array(z.string()).optional(),
39
+ });
40
+ // ---------------------------------------------------------------------------
41
+ // Main Thread Blocking (FEA-05)
42
+ // ---------------------------------------------------------------------------
43
+ export const MainThreadBlockingSchema = z.object({
44
+ blockingScore: z.number().min(0).max(1),
45
+ busyMs: z.number(),
46
+ idleMs: z.number(),
47
+ blockingRatio: z.number().min(0).max(1),
48
+ categories: z.record(z.string(), z.number()),
49
+ });
50
+ // ---------------------------------------------------------------------------
51
+ // JS Hotspots (FEA-06)
52
+ // ---------------------------------------------------------------------------
53
+ export const JSHotspotsSchema = z.object({
54
+ bootupTime: z.number(),
55
+ evaluatedScripts: z.number(),
56
+ longTaskCount: z.number(),
57
+ maxBlockingDuration: z.number(),
58
+ contextCount: z.number(),
59
+ });
60
+ // ---------------------------------------------------------------------------
61
+ // Layout Shifts (FEA-07)
62
+ // ---------------------------------------------------------------------------
63
+ export const LayoutShiftsSchema = z.object({
64
+ cls: z.number().optional(),
65
+ highComplexitySubtreeCount: z.number(),
66
+ deepNesting: z.boolean(),
67
+ clusterScore: z.number().min(0).max(1),
68
+ });
69
+ // ---------------------------------------------------------------------------
70
+ // Third-Party Overhead (FEA-09)
71
+ // ---------------------------------------------------------------------------
72
+ export const ThirdPartyCategorySchema = z.object({
73
+ requests: z.number(),
74
+ bytes: z.number(),
75
+ duration: z.number(),
76
+ });
77
+ export const ThirdPartyOverheadSchema = z.object({
78
+ totalThirdPartyRequests: z.number(),
79
+ totalThirdPartyBytes: z.number(),
80
+ totalThirdPartyDuration: z.number(),
81
+ firstPartyBytes: z.number(),
82
+ firstPartyRequests: z.number(),
83
+ thirdPartyRatio: z.number().min(0).max(1),
84
+ byCategory: z.record(z.string(), ThirdPartyCategorySchema),
85
+ });
86
+ // ---------------------------------------------------------------------------
87
+ // Render-Blocking Score (FEA-08)
88
+ // ---------------------------------------------------------------------------
89
+ export const RenderBlockingResourceSchema = z.object({
90
+ url: z.string(),
91
+ totalBytes: z.number().optional(),
92
+ wastedMs: z.number().optional(),
93
+ resourceType: z.string().optional(),
94
+ });
95
+ export const RenderBlockingScoreSchema = z.object({
96
+ blockingRequestCount: z.number(),
97
+ blockingBytes: z.number(),
98
+ blockingDuration: z.number(),
99
+ renderBlockingScore: z.number().min(0).max(1),
100
+ lhRenderBlockingMs: z.number().optional(),
101
+ resources: z.array(RenderBlockingResourceSchema).optional(),
102
+ totalWastedMs: z.number().optional(),
103
+ });
104
+ // ---------------------------------------------------------------------------
105
+ // FeatureSet — полный набор вычисленных фич
106
+ // ---------------------------------------------------------------------------
107
+ export const FeatureSetSchema = z.strictObject({
108
+ /** Target URL that was analyzed */
109
+ url: z.string().optional(),
110
+ lcpBreakdown: LCPBreakdownSchema.optional(),
111
+ criticalPath: CriticalPathSchema.optional(),
112
+ mainThreadBlocking: MainThreadBlockingSchema.optional(),
113
+ jsHotspots: JSHotspotsSchema.optional(),
114
+ layoutShifts: LayoutShiftsSchema.optional(),
115
+ thirdPartyOverhead: ThirdPartyOverheadSchema.optional(),
116
+ renderBlocking: RenderBlockingScoreSchema.optional(),
117
+ });
118
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/extract/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PerfGraph CLI entry point.
4
+ *
5
+ * All command handlers are lazy-loaded so that `--help` stays fast —
6
+ * Playwright, Lighthouse and other heavy deps only load when a
7
+ * command is actually invoked.
8
+ *
9
+ * Usage:
10
+ * perfgraph collect --url <url> [--output <dir>] [--runs <n>]
11
+ * perfgraph normalize <input> [--output <file>] [--pretty]
12
+ * perfgraph extract <ir-file> [--output <file>] [--pretty]
13
+ * perfgraph analyze <features-file> [--output <file>] [--pretty]
14
+ * perfgraph report <features-file> [--output <file>] [--pretty]
15
+ * perfgraph run --url <url> [--output <dir>] [--runs <n>] [--pretty]
16
+ * perfgraph mcp (MCP stdio server for AI agents)
17
+ * perfgraph --help
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;GAgBG"}
package/dist/index.js ADDED
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PerfGraph CLI entry point.
4
+ *
5
+ * All command handlers are lazy-loaded so that `--help` stays fast —
6
+ * Playwright, Lighthouse and other heavy deps only load when a
7
+ * command is actually invoked.
8
+ *
9
+ * Usage:
10
+ * perfgraph collect --url <url> [--output <dir>] [--runs <n>]
11
+ * perfgraph normalize <input> [--output <file>] [--pretty]
12
+ * perfgraph extract <ir-file> [--output <file>] [--pretty]
13
+ * perfgraph analyze <features-file> [--output <file>] [--pretty]
14
+ * perfgraph report <features-file> [--output <file>] [--pretty]
15
+ * perfgraph run --url <url> [--output <dir>] [--runs <n>] [--pretty]
16
+ * perfgraph mcp (MCP stdio server for AI agents)
17
+ * perfgraph --help
18
+ */
19
+ const args = process.argv.slice(2);
20
+ function printHelp() {
21
+ console.log(`
22
+ PerfGraph — Web Performance Diagnostic Tool
23
+
24
+ USAGE
25
+ perfgraph collect --url <url> [options]
26
+ perfgraph normalize <input> [--output <file>] [--pretty]
27
+ perfgraph extract <ir-file> [--output <file>] [--pretty]
28
+ perfgraph analyze <features-file> [--output <file>] [--pretty]
29
+ perfgraph report <features-file> [--output <file>] [--pretty]
30
+ perfgraph run --url <url> [options] (full pipeline in one command)
31
+ perfgraph mcp (MCP stdio server for AI agents)
32
+
33
+ COMMANDS
34
+ collect Collect performance data from a URL
35
+ normalize Normalize raw data into Intermediate Representation (IR)
36
+ extract Extract diagnostic features from IR bundle
37
+ analyze Build causal degradation graph from features
38
+ report Generate comprehensive JSON report for AI consumption
39
+ run Full pipeline: collect -> normalize -> extract -> analyze -> report
40
+ mcp Start MCP stdio server for AI agent integration
41
+
42
+ COLLECT OPTIONS
43
+ --url <url> Target URL to analyze (required)
44
+ --output <dir> Output directory (default: ./perfgraph-output)
45
+ --runs <n> Number of collection runs (default: 1)
46
+ --device <name> Device name for mobile emulation (e.g. "iPhone 13")
47
+ --no-lighthouse Skip Lighthouse collection
48
+ --no-coverage Skip JS/CSS coverage collection
49
+ --no-console Skip console log collection
50
+ --no-dom Skip DOM snapshot collection
51
+ --help, -h Show this help message
52
+
53
+ NORMALIZE OPTIONS
54
+ <input> Path to a run directory OR parent output directory (positional, required)
55
+ --output, -o <file> Write output to a file (default: stdout)
56
+ --pretty Pretty-print JSON output
57
+ --help, -h Show this help message
58
+
59
+ EXTRACT OPTIONS
60
+ <file> Path to a normalised IR JSON file (positional, required)
61
+ --input, -i <file> Path to IR JSON file (alternative to positional)
62
+ --output, -o <file> Write output to a file (default: stdout)
63
+ --pretty Pretty-print JSON output
64
+ --help, -h Show this help message
65
+
66
+ ANALYZE OPTIONS
67
+ <file> Path to a FeatureSet JSON file (positional, required)
68
+ --input, -i <file> Path to FeatureSet JSON file (alternative to positional)
69
+ --output, -o <file> Write output to a file (default: stdout)
70
+ --pretty Pretty-print JSON output
71
+ --help, -h Show this help message
72
+
73
+ REPORT OPTIONS
74
+ <file> Path to a FeatureSet JSON file (positional, required)
75
+ --input, -i <file> Path to FeatureSet JSON file (alternative to positional)
76
+ --output, -o <file> Write output to a file (default: stdout)
77
+ --pretty Pretty-print JSON output
78
+ --help, -h Show this help message
79
+
80
+ RUN OPTIONS
81
+ --url <url> Target URL to analyze (required)
82
+ --output <dir> Output directory (default: ./perfgraph-output)
83
+ --runs <n> Number of collection runs (default: 1)
84
+ --pretty Pretty-print final report JSON
85
+ --device <name> Device name for mobile emulation (e.g. "iPhone 13")
86
+ --no-lighthouse Skip Lighthouse collection
87
+ --no-coverage Skip JS/CSS coverage collection
88
+ --no-console Skip console log collection
89
+ --no-dom Skip DOM snapshot collection
90
+ --help, -h Show this help message
91
+
92
+ MCP OPTIONS
93
+ No flags required. Starts an MCP stdio server.
94
+
95
+ EXAMPLES
96
+ perfgraph collect --url https://example.com
97
+ perfgraph collect --url https://example.com --output ./results
98
+ perfgraph collect --url https://example.com --runs 3
99
+ perfgraph collect --url https://example.com --no-lighthouse
100
+ perfgraph normalize ./runs/2025-01-15T10-30-00
101
+ perfgraph normalize ./runs/2025-01-15T10-30-00 --output ir.json
102
+ perfgraph normalize ./runs (auto-detect latest run)
103
+ perfgraph extract ./ir.json
104
+ perfgraph extract ./ir.json --output features.toon --pretty
105
+ perfgraph analyze ./features.toon --output graph.toon --pretty
106
+ perfgraph report ./features.toon --output report.toon --pretty
107
+ perfgraph run --url https://example.com --pretty (full pipeline)
108
+ perfgraph run --url https://example.com --pretty --runs 3
109
+ perfgraph mcp (MCP server)
110
+ `);
111
+ }
112
+ async function main() {
113
+ const [subcommand] = args;
114
+ if (args.length === 0) {
115
+ printHelp();
116
+ process.exit(0);
117
+ }
118
+ if ((args.includes('--help') || args.includes('-h')) && subcommand !== 'normalize' && subcommand !== 'run' && subcommand !== 'mcp') {
119
+ printHelp();
120
+ process.exit(0);
121
+ }
122
+ switch (subcommand) {
123
+ case 'collect': {
124
+ const { runCollect } = await import('./cli/collect.js');
125
+ const result = await runCollect(args.slice(1));
126
+ if (!result)
127
+ process.exit(1);
128
+ break;
129
+ }
130
+ case 'normalize': {
131
+ const { runNormalizeFromArgs } = await import('./cli/normalize.js');
132
+ const subArgs = args.slice(1);
133
+ const isHelpRequest = subArgs.includes('--help') || subArgs.includes('-h');
134
+ const result = await runNormalizeFromArgs(subArgs);
135
+ if (!result)
136
+ process.exit(isHelpRequest ? 0 : 1);
137
+ break;
138
+ }
139
+ case 'extract': {
140
+ const { runExtractFromArgs } = await import('./cli/extract.js');
141
+ const result = await runExtractFromArgs(args.slice(1));
142
+ if (!result)
143
+ process.exit(1);
144
+ break;
145
+ }
146
+ case 'analyze': {
147
+ const { runAnalyzeFromArgs } = await import('./cli/analyze.js');
148
+ const result = await runAnalyzeFromArgs(args.slice(1));
149
+ if (!result)
150
+ process.exit(1);
151
+ break;
152
+ }
153
+ case 'report': {
154
+ const { runReportFromArgs } = await import('./cli/report.js');
155
+ const result = await runReportFromArgs(args.slice(1));
156
+ if (!result)
157
+ process.exit(1);
158
+ break;
159
+ }
160
+ case 'run': {
161
+ const { runRunFromArgs } = await import('./cli/run.js');
162
+ const result = await runRunFromArgs(args.slice(1));
163
+ if (!result) {
164
+ process.exit(1);
165
+ }
166
+ break;
167
+ }
168
+ case 'mcp': {
169
+ const { runMcpFromArgs } = await import('./cli/mcp.js');
170
+ const ok = await runMcpFromArgs(args.slice(1));
171
+ if (!ok) {
172
+ process.exit(1);
173
+ }
174
+ break;
175
+ }
176
+ default: {
177
+ console.error(`Unknown command: "${subcommand}"`);
178
+ printHelp();
179
+ process.exit(1);
180
+ }
181
+ }
182
+ }
183
+ main().catch((error) => {
184
+ console.error(`Fatal error: ${error}`);
185
+ process.exit(1);
186
+ });
187
+ export {};
188
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}