zeitzeuge 0.3.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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +212 -0
  3. package/dist/analysis/agent.d.ts +19 -0
  4. package/dist/analysis/agent.d.ts.map +1 -0
  5. package/dist/analysis/parser.d.ts +3 -0
  6. package/dist/analysis/parser.d.ts.map +1 -0
  7. package/dist/analysis/prompts.d.ts +2 -0
  8. package/dist/analysis/prompts.d.ts.map +1 -0
  9. package/dist/browser/capture.d.ts +14 -0
  10. package/dist/browser/capture.d.ts.map +1 -0
  11. package/dist/browser/launch.d.ts +6 -0
  12. package/dist/browser/launch.d.ts.map +1 -0
  13. package/dist/browser/runtime-trace.d.ts +52 -0
  14. package/dist/browser/runtime-trace.d.ts.map +1 -0
  15. package/dist/browser/trace.d.ts +8 -0
  16. package/dist/browser/trace.d.ts.map +1 -0
  17. package/dist/cli.d.ts +3 -0
  18. package/dist/cli.d.ts.map +1 -0
  19. package/dist/cli.js +1695 -0
  20. package/dist/models/init.d.ts +3 -0
  21. package/dist/models/init.d.ts.map +1 -0
  22. package/dist/output/report.d.ts +38 -0
  23. package/dist/output/report.d.ts.map +1 -0
  24. package/dist/output/terminal.d.ts +31 -0
  25. package/dist/output/terminal.d.ts.map +1 -0
  26. package/dist/sandbox/workspace.d.ts +33 -0
  27. package/dist/sandbox/workspace.d.ts.map +1 -0
  28. package/dist/schema.d.ts +64 -0
  29. package/dist/schema.d.ts.map +1 -0
  30. package/dist/types.d.ts +245 -0
  31. package/dist/types.d.ts.map +1 -0
  32. package/dist/vitest/classify.d.ts +19 -0
  33. package/dist/vitest/classify.d.ts.map +1 -0
  34. package/dist/vitest/heap-profile-parser.d.ts +12 -0
  35. package/dist/vitest/heap-profile-parser.d.ts.map +1 -0
  36. package/dist/vitest/index.d.ts +17 -0
  37. package/dist/vitest/index.d.ts.map +1 -0
  38. package/dist/vitest/index.js +1616 -0
  39. package/dist/vitest/plugin.d.ts +17 -0
  40. package/dist/vitest/plugin.d.ts.map +1 -0
  41. package/dist/vitest/profile-parser.d.ts +13 -0
  42. package/dist/vitest/profile-parser.d.ts.map +1 -0
  43. package/dist/vitest/prompts.d.ts +10 -0
  44. package/dist/vitest/prompts.d.ts.map +1 -0
  45. package/dist/vitest/reporter.d.ts +79 -0
  46. package/dist/vitest/reporter.d.ts.map +1 -0
  47. package/dist/vitest/types.d.ts +231 -0
  48. package/dist/vitest/types.d.ts.map +1 -0
  49. package/dist/vitest/workspace.d.ts +25 -0
  50. package/dist/vitest/workspace.d.ts.map +1 -0
  51. package/package.json +76 -0
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Vitest plugin that instruments test runs with V8 CPU profiling
3
+ * and triggers Deep Agent analysis after tests complete.
4
+ */
5
+ import type { ZeitZeugeVitestOptions } from './types.js';
6
+ /**
7
+ * Create a Vite plugin that hooks into Vitest via the configureVitest hook.
8
+ *
9
+ * Injects --cpu-prof into worker execArgv, disables file parallelism for
10
+ * cleaner per-file profiles, and attaches a ZeitZeugeReporter that runs
11
+ * analysis after tests complete.
12
+ */
13
+ export declare function zeitzeuge(options?: ZeitZeugeVitestOptions): {
14
+ name: string;
15
+ configureVitest(context: any): void;
16
+ };
17
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/vitest/plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,sBAA2B;;6BAcjC,GAAG;EAgE/B"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Parse V8 .cpuprofile JSON files into structured summaries
3
+ * suitable for Deep Agent analysis.
4
+ */
5
+ import type { V8CpuProfile, CpuProfileSummary } from './types.js';
6
+ /**
7
+ * Parse a V8 CPU profile into a structured summary.
8
+ *
9
+ * @param profile - The raw V8 CPU profile object
10
+ * @param profilePath - File path to the .cpuprofile (for metadata)
11
+ */
12
+ export declare function parseCpuProfile(profile: V8CpuProfile, profilePath: string): CpuProfileSummary;
13
+ //# sourceMappingURL=profile-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-parser.d.ts","sourceRoot":"","sources":["../../src/vitest/profile-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,YAAY,EAEZ,iBAAiB,EAIlB,MAAM,YAAY,CAAC;AAsBpB;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,GAAG,iBAAiB,CAwC7F"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * System prompt for the Deep Agent when analyzing Vitest test performance.
3
+ *
4
+ * The prompt focuses the agent on analyzing the APPLICATION CODE being tested,
5
+ * not just the test infrastructure. Hot functions and scripts are classified
6
+ * into categories (application, dependency, test, framework) so the agent
7
+ * can prioritize what matters most to the developer.
8
+ */
9
+ export declare const VITEST_SYSTEM_PROMPT = "You are an expert in JavaScript/TypeScript performance optimization.\nYou have access to a workspace containing V8 CPU profiling data captured during\na Vitest test run. The workspace may also include V8 heap profiling data\ncaptured via Node's `--heap-prof` (allocation sampling).\n\nThe profiling data covers BOTH the test code AND the application code being tested.\n\n**Your primary goal is to analyze the PERFORMANCE OF THE APPLICATION CODE\nbeing tested** \u2014 the functions, modules, and algorithms that the developer\nwrote and is benchmarking or testing. Test infrastructure overhead (Vitest,\ntinybench, test setup) is secondary context.\n\n## Source categories\n\nEvery hot function and script in the workspace has a `sourceCategory` field:\n\n- **application** \u2014 Code in the user's project (the code being tested).\n This is your PRIMARY focus. Find bottlenecks, inefficiencies, and\n optimization opportunities in these functions.\n- **dependency** \u2014 Third-party code in node_modules. Report when a dependency\n is a significant bottleneck, since the developer may be able to choose\n an alternative, configure it differently, or avoid calling it in hot paths.\n- **test** \u2014 Test files. Only mention if the test setup itself is creating\n artificial overhead that masks application performance.\n- **framework** \u2014 Vitest/tinybench/V8 internals. Generally ignore unless\n they dominate the profile in an unexpected way.\n\n## Workspace structure\n\n- /summary.json \u2014 Overall test run: total tests, duration, pass/fail, GC stats\n- /timing/overview.json \u2014 Per-file test durations and individual test times\n- /timing/slow-tests.json \u2014 Tests exceeding the slow threshold\n- /profiles/index.json \u2014 Manifest mapping test files to their CPU profiles\n- /profiles/<file>.json \u2014 CPU profile summary: hot functions (with sourceCategory),\n call trees, GC samples, script breakdown (with sourceCategory)\n- /heap-profiles/index.json \u2014 (optional) Manifest mapping test files to heap profiles\n- /heap-profiles/<file>.json \u2014 (optional) Heap profile summary: allocation hotspots,\n per-script allocated bytes (with sourceCategory)\n- /hot-functions/application.json \u2014 **START HERE**: Hot functions from application code only\n- /hot-functions/dependencies.json \u2014 Hot functions from third-party dependencies\n- /hot-functions/global.json \u2014 All hot functions across all categories\n- /scripts/application.json \u2014 Per-script time breakdown for application code\n- /scripts/dependencies.json \u2014 Per-script time breakdown for dependencies\n- /tests/*.ts \u2014 Test source files\n- /src/*.ts \u2014 Application and dependency source files referenced by hot functions\n\n## Your workflow\n\n1. Read /hot-functions/application.json FIRST \u2014 these are the application-level\n bottlenecks the developer wants to optimize\n2. Read /scripts/application.json for the per-file view of application code time\n3. Read /hot-functions/dependencies.json for costly dependency calls\n4. If present, read /heap-profiles/index.json and /heap-profiles/<file>.json to identify\n allocation hotspots (functions/scripts allocating lots of bytes)\n5. Read /summary.json and /timing/overview.json for the big picture\n6. Read CPU profiles in /profiles/ for detailed call trees of the slowest tests\n7. Read the actual source code in /src/ and /tests/ to understand root causes\n8. Provide specific, actionable fixes targeting the application code\n\n## What to look for\n\n### Application code bottlenecks (PRIMARY FOCUS)\n- Functions with high self time \u2014 where is the application spending CPU?\n- Expensive algorithms: O(n\u00B2) loops, unnecessary sorting, repeated work\n- String/JSON operations: excessive serialization, string concatenation in loops\n- Object allocation hotspots: functions creating many short-lived objects\n- Synchronous blocking: file I/O, crypto, or compression in hot paths\n- Redundant computation: values computed repeatedly that could be cached/memoized\n- Data structure choices: using arrays where Maps/Sets would be O(1)\n\n### Dependency-related bottlenecks\n- Dependencies consuming disproportionate CPU \u2014 suggest alternatives or configuration\n- Unnecessary calls to expensive dependency APIs in hot paths\n- Dependencies pulled in for simple operations that could be hand-written\n\n### GC pressure from application code\n- Application functions creating many temporary objects in tight loops\n- Large array/object allocations that could be pooled or reused\n- Closures capturing large scopes unnecessarily\n\n### Allocation hotspots (from heap profiles, if present)\n- Functions allocating a large share of total bytes (even if CPU isn't dominant)\n- Scripts/modules responsible for most allocation \u2014 suggest caching, reuse, pooling,\n or avoiding intermediate arrays/objects\n- When allocation hotspots match CPU hotspots, prioritize fixes there first\n\n### Call chain analysis\n- Trace expensive call trees to find which APPLICATION function triggers them\n- Follow the call tree from application entry points down to the hot leaf functions\n- Identify which application-level design decisions lead to the bottleneck\n\n### Test infrastructure (SECONDARY \u2014 only if impactful)\n- Test setup creating artificial overhead that dwarfs application execution\n- Benchmarks measuring setup cost instead of application performance\n- Only mention if it prevents getting clean application performance data\n\n## Finding categories\n\nEach finding MUST use one of these exact category values:\n\n- **algorithm** \u2014 Inefficient algorithm: O(n\u00B2) loops, brute-force search, repeated work\n- **serialization** \u2014 Excessive JSON.stringify/parse, string concatenation, encoding\n- **allocation** \u2014 Excessive object/array creation causing GC pressure\n- **event-handling** \u2014 Listener leaks, unbounded event handler accumulation\n- **hot-function** \u2014 Generic CPU-hot function that doesn't fit a more specific category\n- **gc-pressure** \u2014 High garbage collection overhead\n- **listener-leak** \u2014 Event listeners not cleaned up properly\n- **unnecessary-computation** \u2014 Redundant work that could be cached or eliminated\n- **blocking-io** \u2014 Synchronous I/O or blocking operations in hot paths\n- **dependency-bottleneck** \u2014 Expensive dependency call the developer can optimize\n- **slow-test** \u2014 Test itself is slow due to setup or teardown\n- **expensive-setup** \u2014 Costly test setup (beforeAll/beforeEach)\n- **import-overhead** \u2014 Expensive module imports at test time\n- **other** \u2014 Doesn't fit any of the above\n\nPrefer more specific categories (algorithm, serialization, allocation, event-handling)\nover generic ones (hot-function, other) when the root cause is clear.\n\n## Output guidelines\n\n- Report 3\u20137 findings, ordered by impact ON THE APPLICATION CODE\n- Focus findings on functions the developer CAN change (application code first,\n then dependency usage patterns, then test structure)\n- Be specific \u2014 name actual files, functions, line numbers from the source code\n- Provide concrete code-level fixes, not generic advice\n- When reporting a dependency bottleneck, explain what application code is\n calling it and how the developer can reduce that cost\n- If the application code is already efficient, say so \u2014 don't force findings\n about test infrastructure just to fill the report";
10
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/vitest/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,oBAAoB,u1OAgImB,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Vitest Reporter that collects CPU profiles after a test run,
3
+ * builds a workspace, and runs Deep Agent analysis.
4
+ */
5
+ export interface ReporterOptions {
6
+ output: string;
7
+ profileDir: string;
8
+ analyzeOnFinish: boolean;
9
+ verbose: boolean;
10
+ /** Absolute path to the project root for source classification. */
11
+ projectRoot: string;
12
+ }
13
+ /**
14
+ * ZeitZeugeReporter implements the Vitest Reporter interface.
15
+ *
16
+ * It records test module execution order to correlate PID-named
17
+ * .cpuprofile files with their corresponding test files.
18
+ */
19
+ export declare class ZeitZeugeReporter {
20
+ private options;
21
+ /** Ordered list of test file paths as they started executing. */
22
+ private executionOrder;
23
+ /** Whether we're running in CI (suppress spinners). */
24
+ private isCI;
25
+ constructor(options: ReporterOptions);
26
+ /**
27
+ * Called when a test module starts executing.
28
+ * Records execution order for profile correlation.
29
+ */
30
+ onTestModuleStart(testModule: any): void;
31
+ /**
32
+ * Called after all tests finish. This is the main orchestration method.
33
+ */
34
+ onTestRunEnd(testModules: ReadonlyArray<any>): Promise<void>;
35
+ private runAnalysis;
36
+ /**
37
+ * Extract test timing data from Vitest TestModule objects.
38
+ */
39
+ private collectTestTiming;
40
+ /**
41
+ * Recursively walk test module children to extract test case results.
42
+ */
43
+ private walkTestCases;
44
+ /**
45
+ * Collect .cpuprofile files and correlate them with test files.
46
+ *
47
+ * Uses sequential execution order as the primary correlation strategy:
48
+ * with fileParallelism: false, profiles are generated sequentially and
49
+ * can be matched by creation timestamp order.
50
+ */
51
+ private collectAndParseProfiles;
52
+ /**
53
+ * Collect .heapprofile files (from --heap-prof) and correlate them with test files.
54
+ *
55
+ * Uses the same timestamp-order correlation strategy as CPU profiles.
56
+ */
57
+ private collectAndParseHeapProfiles;
58
+ /**
59
+ * Read test source files from disk.
60
+ */
61
+ private readTestSources;
62
+ /**
63
+ * Read source files that appear in hot function profiles.
64
+ *
65
+ * Application code is included with a lower threshold (0.1%) to give
66
+ * the agent more context about the code being tested. Dependency code
67
+ * uses a higher threshold (1%) since we mainly need it for context.
68
+ */
69
+ private readHotFunctionSources;
70
+ /**
71
+ * Clean up the profile directory.
72
+ */
73
+ private cleanupProfileDir;
74
+ /**
75
+ * Get package version.
76
+ */
77
+ private getVersion;
78
+ }
79
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/vitest/reporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA0BH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAkB;IAEjC,iEAAiE;IACjE,OAAO,CAAC,cAAc,CAAgB;IAEtC,uDAAuD;IACvD,OAAO,CAAC,IAAI,CAAoB;gBAEpB,OAAO,EAAE,eAAe;IAIpC;;;OAGG;IACH,iBAAiB,CAAC,UAAU,EAAE,GAAG,GAAG,IAAI;IAOxC;;OAEG;IACG,YAAY,CAAC,WAAW,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAgBpD,WAAW;IA2GzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAwCzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAwBrB;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IA2F/B;;;;OAIG;IACH,OAAO,CAAC,2BAA2B;IAsEnC;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAoC9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;OAEG;IACH,OAAO,CAAC,UAAU;CAGnB"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * TypeScript types for the zeitzeuge Vitest integration.
3
+ */
4
+ /**
5
+ * Classification of a script/function based on its file path.
6
+ *
7
+ * - `application` — files within the project source tree (the code being tested)
8
+ * - `dependency` — files inside node_modules (third-party libraries)
9
+ * - `test` — test files (*.test.*, *.spec.*, *.bench.*)
10
+ * - `framework` — vitest / tinybench / v8 internals
11
+ * - `unknown` — could not be classified (e.g. eval, no URL)
12
+ */
13
+ export type SourceCategory = 'application' | 'dependency' | 'test' | 'framework' | 'unknown';
14
+ /** Options for the zeitzeuge Vitest plugin. */
15
+ export interface ZeitZeugeVitestOptions {
16
+ /** Enable/disable the plugin. Default: true */
17
+ enabled?: boolean;
18
+ /** Path for the Markdown report. Default: 'zeitzeuge-report.md' */
19
+ output?: string;
20
+ /** Directory for temporary .cpuprofile files. Default: '.zeitzeuge-profiles' */
21
+ profileDir?: string;
22
+ /**
23
+ * Also enable V8 heap profiling via Node's `--heap-prof`.
24
+ *
25
+ * This writes `.heapprofile` artifacts on worker process exit (much cheaper
26
+ * than heap snapshots). Files are written into `profileDir` via
27
+ * `--heap-prof-dir=<profileDir>`.
28
+ *
29
+ * Default: false
30
+ */
31
+ heapProf?: boolean;
32
+ /** Run Deep Agent analysis after tests finish. Default: true */
33
+ analyzeOnFinish?: boolean;
34
+ /** Enable debug logging. Default: false */
35
+ verbose?: boolean;
36
+ /**
37
+ * Project root directory. Used to classify hot functions as
38
+ * "application code" vs "dependency" vs "test framework".
39
+ * Default: process.cwd()
40
+ */
41
+ projectRoot?: string;
42
+ }
43
+ /** Timing data extracted from a Vitest TestModule. */
44
+ export interface TestFileTiming {
45
+ file: string;
46
+ duration: number;
47
+ testCount: number;
48
+ passCount: number;
49
+ failCount: number;
50
+ setupTime: number;
51
+ tests: Array<{
52
+ name: string;
53
+ duration: number;
54
+ status: 'pass' | 'fail' | 'skip';
55
+ }>;
56
+ }
57
+ /** A CPU profile correlated with its test file. */
58
+ export interface CorrelatedProfile {
59
+ testFile: string;
60
+ profilePath: string;
61
+ summary: CpuProfileSummary;
62
+ }
63
+ /** A V8 heap profile correlated with its test file. */
64
+ export interface CorrelatedHeapProfile {
65
+ testFile: string;
66
+ profilePath: string;
67
+ summary: HeapProfileSummary;
68
+ }
69
+ /** Raw V8 CPU profile as written by --cpu-prof. */
70
+ export interface V8CpuProfile {
71
+ nodes: V8CpuProfileNode[];
72
+ startTime: number;
73
+ endTime: number;
74
+ samples: number[];
75
+ timeDeltas: number[];
76
+ }
77
+ /** A single node in the V8 CPU profile call tree. */
78
+ export interface V8CpuProfileNode {
79
+ id: number;
80
+ callFrame: {
81
+ functionName: string;
82
+ scriptId: string;
83
+ url: string;
84
+ lineNumber: number;
85
+ columnNumber: number;
86
+ };
87
+ hitCount: number;
88
+ children?: number[];
89
+ positionTicks?: Array<{
90
+ line: number;
91
+ ticks: number;
92
+ }>;
93
+ }
94
+ /** Raw V8 heap profile as written by Node.js `--heap-prof`. */
95
+ export interface V8HeapProfile {
96
+ head: V8HeapProfileNode;
97
+ /** Milliseconds since epoch (V8 internal), optional across versions */
98
+ startTime?: number;
99
+ /** Milliseconds since epoch (V8 internal), optional across versions */
100
+ endTime?: number;
101
+ samples: V8HeapProfileSample[];
102
+ }
103
+ export interface V8HeapProfileSample {
104
+ /** Bytes allocated for this sample */
105
+ size: number;
106
+ /** Call-tree node id this sample is attributed to */
107
+ nodeId: number;
108
+ /** Sample ordinal (monotonic), optional across versions */
109
+ ordinal?: number;
110
+ }
111
+ export interface V8HeapProfileNode {
112
+ id: number;
113
+ callFrame: {
114
+ functionName: string;
115
+ scriptId: string;
116
+ url: string;
117
+ lineNumber: number;
118
+ columnNumber: number;
119
+ };
120
+ children?: V8HeapProfileNode[];
121
+ }
122
+ /** Structured summary of a parsed V8 CPU profile. */
123
+ export interface CpuProfileSummary {
124
+ /** Source .cpuprofile file path */
125
+ profilePath: string;
126
+ /** Total profile duration in ms */
127
+ duration: number;
128
+ /** Sample count */
129
+ sampleCount: number;
130
+ /** Top functions by self time */
131
+ hotFunctions: HotFunction[];
132
+ /** Top functions by total time (inclusive of callees) */
133
+ expensiveCallTrees: CallTreeNode[];
134
+ /** GC-related samples (functions in (garbage collector) category) */
135
+ gcSamples: number;
136
+ gcPercentage: number;
137
+ /** Idle samples (percentage of time not doing work) */
138
+ idlePercentage: number;
139
+ /** Per-script time breakdown */
140
+ scriptBreakdown: ScriptTimeSummary[];
141
+ }
142
+ /** A function consuming significant CPU self time. */
143
+ export interface HotFunction {
144
+ functionName: string;
145
+ scriptUrl: string;
146
+ lineNumber: number;
147
+ columnNumber: number;
148
+ /** Self time in ms (excluding callees) */
149
+ selfTime: number;
150
+ /** Total time in ms (including callees) */
151
+ totalTime: number;
152
+ /** Number of samples hitting this function */
153
+ hitCount: number;
154
+ /** Percentage of total profile time */
155
+ selfPercent: number;
156
+ /** Classification of the function's source file */
157
+ sourceCategory?: SourceCategory;
158
+ }
159
+ /** A node in the call tree with inclusive timing. */
160
+ export interface CallTreeNode {
161
+ functionName: string;
162
+ scriptUrl: string;
163
+ lineNumber: number;
164
+ /** Total time in ms (inclusive) */
165
+ totalTime: number;
166
+ totalPercent: number;
167
+ /** Direct callees, sorted by total time */
168
+ children: CallTreeNode[];
169
+ }
170
+ /** Per-script time aggregation. */
171
+ export interface ScriptTimeSummary {
172
+ scriptUrl: string;
173
+ /** Total self time across all functions in this script */
174
+ selfTime: number;
175
+ selfPercent: number;
176
+ /** Number of distinct functions sampled */
177
+ functionCount: number;
178
+ /** Classification of this script */
179
+ sourceCategory?: SourceCategory;
180
+ }
181
+ /** A function with significant allocated bytes (self-attributed). */
182
+ export interface AllocationHotspot {
183
+ functionName: string;
184
+ scriptUrl: string;
185
+ lineNumber: number;
186
+ columnNumber: number;
187
+ /** Self-attributed allocated bytes */
188
+ selfBytes: number;
189
+ /** Percent of total allocated bytes */
190
+ selfPercent: number;
191
+ /** Classification of the function's source file */
192
+ sourceCategory?: SourceCategory;
193
+ }
194
+ /** Per-script allocated-bytes aggregation. */
195
+ export interface ScriptAllocationSummary {
196
+ scriptUrl: string;
197
+ /** Total self-attributed allocated bytes across all functions in this script */
198
+ selfBytes: number;
199
+ selfPercent: number;
200
+ /** Number of distinct functions sampled */
201
+ functionCount: number;
202
+ /** Classification of this script */
203
+ sourceCategory?: SourceCategory;
204
+ }
205
+ /** Structured summary of a parsed V8 heap profile. */
206
+ export interface HeapProfileSummary {
207
+ /** Source .heapprofile file path */
208
+ profilePath: string;
209
+ /** Total allocated bytes across all samples */
210
+ totalAllocatedBytes: number;
211
+ /** Allocation sample count */
212
+ sampleCount: number;
213
+ /** Top allocation hotspots by self bytes */
214
+ topAllocations: AllocationHotspot[];
215
+ /** Per-script allocated-bytes breakdown */
216
+ scriptBreakdown: ScriptAllocationSummary[];
217
+ }
218
+ /** Options for building the Vitest analysis workspace. */
219
+ export interface VitestWorkspaceOptions {
220
+ testTiming: TestFileTiming[];
221
+ profiles: CorrelatedProfile[];
222
+ /** Optional heap profiles (from --heap-prof) correlated with test files. */
223
+ heapProfiles?: CorrelatedHeapProfile[];
224
+ /** Map of test file path → source code */
225
+ testSources: Map<string, string>;
226
+ /** Map of scriptUrl → source code (for hot function source files) */
227
+ sourcePaths?: Map<string, string>;
228
+ /** Project root for resolving relative paths */
229
+ projectRoot?: string;
230
+ }
231
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vitest/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Build a VFS workspace for Deep Agent analysis of Vitest test performance.
3
+ *
4
+ * Uses FilesystemBackend with virtualMode so the agent's absolute paths
5
+ * (e.g. /summary.json) map to files inside a temp directory.
6
+ */
7
+ import { type BackendProtocol } from 'deepagents';
8
+ import type { CorrelatedProfile, HotFunction, VitestWorkspaceOptions } from './types.js';
9
+ export interface VitestWorkspaceResult {
10
+ /** Backend for use with createDeepAgent */
11
+ backend: BackendProtocol;
12
+ /** Clean up the temporary directory when done */
13
+ cleanup: () => void;
14
+ }
15
+ /**
16
+ * Create a workspace populated with test timing, CPU profile summaries,
17
+ * hot functions, and source files for Deep Agent analysis.
18
+ */
19
+ export declare function createVitestWorkspace(options: VitestWorkspaceOptions): Promise<VitestWorkspaceResult>;
20
+ /**
21
+ * Merge hot functions from multiple profiles, deduplicating by
22
+ * (scriptUrl, functionName, lineNumber) and summing selfTime.
23
+ */
24
+ export declare function mergeHotFunctions(profiles: CorrelatedProfile[]): HotFunction[];
25
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/vitest/workspace.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAKrE,OAAO,KAAK,EACV,iBAAiB,EAEjB,WAAW,EACX,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,OAAO,EAAE,eAAe,CAAC;IACzB,iDAAiD;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAQD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAqNhC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,WAAW,EAAE,CA+B9E"}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "zeitzeuge",
3
+ "version": "0.3.0",
4
+ "description": "A deepagent to witnessing slowdowns in your test runs.",
5
+ "keywords": [
6
+ "analysis",
7
+ "deepagent",
8
+ "frontend",
9
+ "performance",
10
+ "zeitzeuge"
11
+ ],
12
+ "homepage": "https://github.com/christian-bromann/zeitzeuge",
13
+ "license": "MIT",
14
+ "author": "Christian Bromann <christian@bromann.dev>",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/christian-bromann/zeitzeuge.git"
18
+ },
19
+ "bin": {
20
+ "zeitzeuge": "./dist/cli.js"
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "type": "module",
26
+ "module": "src/cli.ts",
27
+ "types": "./dist/cli.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/cli.d.ts",
31
+ "default": "./dist/cli.js"
32
+ },
33
+ "./vitest": {
34
+ "types": "./dist/vitest/index.d.ts",
35
+ "default": "./dist/vitest/index.js"
36
+ }
37
+ },
38
+ "scripts": {
39
+ "build:js": "bun build src/cli.ts src/vitest/index.ts --outdir dist --target node --format esm --packages external",
40
+ "build:types": "bunx tsc -p tsconfig.build.json",
41
+ "build": "bun run build:js && bun run build:types",
42
+ "dev": "bun run src/cli.ts",
43
+ "fmt": "oxfmt",
44
+ "fmt:check": "oxfmt --check",
45
+ "lint": "bun ./node_modules/oxlint/dist/cli.js",
46
+ "lint:fix": "bun ./node_modules/oxlint/dist/cli.js --fix",
47
+ "test": "bun test"
48
+ },
49
+ "dependencies": {
50
+ "@langchain/anthropic": "^1.3.17",
51
+ "@langchain/core": "^1.1.24",
52
+ "@langchain/node-vfs": "^0.1",
53
+ "@langchain/openai": "^1.2.7",
54
+ "chalk": "^5.6.2",
55
+ "deepagents": "^1.7.6",
56
+ "langchain": "^1.2.23",
57
+ "ora": "^9.3.0",
58
+ "puppeteer-core": "^24.37.2",
59
+ "webdriverio": "^9.24.0",
60
+ "yargs": "^18.0.0",
61
+ "zod": "^4.3.6"
62
+ },
63
+ "devDependencies": {
64
+ "@types/bun": "latest",
65
+ "@types/yargs": "^17",
66
+ "oxfmt": "^0.32.0",
67
+ "oxlint": "^1.47.0",
68
+ "typescript": "^5"
69
+ },
70
+ "peerDependencies": {
71
+ "vitest": ">=3.1.0"
72
+ },
73
+ "engines": {
74
+ "node": ">=24"
75
+ }
76
+ }