memorydetective 1.8.0 → 1.9.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 (89) hide show
  1. package/CHANGELOG.md +64 -1
  2. package/README.md +75 -9
  3. package/USAGE.md +27 -4
  4. package/dist/cli.js +106 -3
  5. package/dist/cli.js.map +1 -1
  6. package/dist/index.js +42 -22
  7. package/dist/index.js.map +1 -1
  8. package/dist/parsers/referenceTree.d.ts +73 -0
  9. package/dist/parsers/referenceTree.js +145 -0
  10. package/dist/parsers/referenceTree.js.map +1 -0
  11. package/dist/runtime/axe.js +6 -1
  12. package/dist/runtime/axe.js.map +1 -1
  13. package/dist/runtime/exec.d.ts +30 -0
  14. package/dist/runtime/exec.js +30 -3
  15. package/dist/runtime/exec.js.map +1 -1
  16. package/dist/runtime/fixTemplates.js +67 -0
  17. package/dist/runtime/fixTemplates.js.map +1 -1
  18. package/dist/runtime/leakReport.d.ts +62 -0
  19. package/dist/runtime/leakReport.js +138 -0
  20. package/dist/runtime/leakReport.js.map +1 -0
  21. package/dist/runtime/platformCheck.d.ts +54 -0
  22. package/dist/runtime/platformCheck.js +94 -0
  23. package/dist/runtime/platformCheck.js.map +1 -0
  24. package/dist/runtime/redact.d.ts +66 -0
  25. package/dist/runtime/redact.js +146 -0
  26. package/dist/runtime/redact.js.map +1 -0
  27. package/dist/runtime/responseFormatter.d.ts +55 -0
  28. package/dist/runtime/responseFormatter.js +200 -0
  29. package/dist/runtime/responseFormatter.js.map +1 -0
  30. package/dist/runtime/securityFlags.d.ts +74 -0
  31. package/dist/runtime/securityFlags.js +90 -0
  32. package/dist/runtime/securityFlags.js.map +1 -0
  33. package/dist/runtime/staticAnalysisHints.js +14 -1
  34. package/dist/runtime/staticAnalysisHints.js.map +1 -1
  35. package/dist/templates/leak-report.html +39 -0
  36. package/dist/templates/templates/leak-report.html +39 -0
  37. package/dist/tools/analyzeAbandonedMemory.d.ts +140 -0
  38. package/dist/tools/analyzeAbandonedMemory.js +287 -0
  39. package/dist/tools/analyzeAbandonedMemory.js.map +1 -0
  40. package/dist/tools/analyzeAllocations.d.ts +11 -2
  41. package/dist/tools/analyzeAllocations.js +4 -0
  42. package/dist/tools/analyzeAllocations.js.map +1 -1
  43. package/dist/tools/analyzeAnimationHitches.d.ts +32 -2
  44. package/dist/tools/analyzeAnimationHitches.js +25 -4
  45. package/dist/tools/analyzeAnimationHitches.js.map +1 -1
  46. package/dist/tools/analyzeAppLaunch.d.ts +3 -0
  47. package/dist/tools/analyzeAppLaunch.js +2 -0
  48. package/dist/tools/analyzeAppLaunch.js.map +1 -1
  49. package/dist/tools/analyzeHangs.d.ts +78 -2
  50. package/dist/tools/analyzeHangs.js +117 -4
  51. package/dist/tools/analyzeHangs.js.map +1 -1
  52. package/dist/tools/analyzeMemgraph.d.ts +21 -1
  53. package/dist/tools/analyzeMemgraph.js +52 -2
  54. package/dist/tools/analyzeMemgraph.js.map +1 -1
  55. package/dist/tools/analyzeTimeProfile.d.ts +11 -1
  56. package/dist/tools/analyzeTimeProfile.js +5 -0
  57. package/dist/tools/analyzeTimeProfile.js.map +1 -1
  58. package/dist/tools/bootAndLaunchForLeakInvestigation.d.ts +18 -9
  59. package/dist/tools/bootAndLaunchForLeakInvestigation.js +27 -0
  60. package/dist/tools/bootAndLaunchForLeakInvestigation.js.map +1 -1
  61. package/dist/tools/captureMemgraph.d.ts +22 -4
  62. package/dist/tools/captureMemgraph.js +42 -9
  63. package/dist/tools/captureMemgraph.js.map +1 -1
  64. package/dist/tools/captureScenarioState.d.ts +12 -4
  65. package/dist/tools/captureScenarioState.js +4 -0
  66. package/dist/tools/captureScenarioState.js.map +1 -1
  67. package/dist/tools/classifyCycle.js +77 -0
  68. package/dist/tools/classifyCycle.js.map +1 -1
  69. package/dist/tools/cleanupTraces.d.ts +87 -0
  70. package/dist/tools/cleanupTraces.js +232 -0
  71. package/dist/tools/cleanupTraces.js.map +1 -0
  72. package/dist/tools/compareTracesByPattern.d.ts +2 -2
  73. package/dist/tools/detectLeaksInXCTest.d.ts +116 -0
  74. package/dist/tools/detectLeaksInXCTest.js +311 -0
  75. package/dist/tools/detectLeaksInXCTest.js.map +1 -0
  76. package/dist/tools/detectLeaksInXCUITest.d.ts +8 -3
  77. package/dist/tools/detectLeaksInXCUITest.js +30 -4
  78. package/dist/tools/detectLeaksInXCUITest.js.map +1 -1
  79. package/dist/tools/diffMemgraphs.d.ts +5 -2
  80. package/dist/tools/diffMemgraphs.js +2 -0
  81. package/dist/tools/diffMemgraphs.js.map +1 -1
  82. package/dist/tools/findCycles.d.ts +1 -1
  83. package/dist/tools/recordTimeProfile.d.ts +29 -9
  84. package/dist/tools/recordTimeProfile.js +70 -7
  85. package/dist/tools/recordTimeProfile.js.map +1 -1
  86. package/dist/tools/renderCycleGraph.d.ts +1 -1
  87. package/dist/tools/verifyFix.d.ts +2 -2
  88. package/dist/types.d.ts +24 -1
  89. package/package.json +4 -3
@@ -0,0 +1,39 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="generator" content="memorydetective">
6
+ <title>{{TITLE}}</title>
7
+ <style>
8
+ :root { color-scheme: light dark; }
9
+ body { font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; margin: 0; padding: 2rem; max-width: 960px; background: #fafafa; color: #1c1c1e; }
10
+ @media (prefers-color-scheme: dark) { body { background: #1c1c1e; color: #f2f2f7; } .card { background: #2c2c2e; } th { background: #3a3a3c; } code { background: #3a3a3c; } }
11
+ h1 { font-size: 1.6rem; margin: 0 0 .5rem; }
12
+ h2 { font-size: 1.1rem; margin: 2rem 0 .5rem; }
13
+ .meta { font-size: .8rem; opacity: .65; margin-bottom: 1.5rem; }
14
+ .card { background: #fff; border: 1px solid rgba(127,127,127,.2); border-radius: 8px; padding: 1rem 1.25rem; margin-bottom: 1rem; }
15
+ .verdict { display: inline-block; padding: .25rem .75rem; border-radius: 999px; font-weight: 600; font-size: .8rem; letter-spacing: .02em; }
16
+ .verdict.pass { background: #34c759; color: #fff; }
17
+ .verdict.fail { background: #ff3b30; color: #fff; }
18
+ .verdict.skip { background: #8e8e93; color: #fff; }
19
+ table { border-collapse: collapse; width: 100%; margin: .5rem 0; font-size: .85rem; }
20
+ th, td { text-align: left; padding: .4rem .6rem; border-bottom: 1px solid rgba(127,127,127,.2); }
21
+ th { background: #f2f2f7; font-weight: 600; }
22
+ code { font: .85rem/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; background: #f2f2f7; padding: .15rem .35rem; border-radius: 4px; }
23
+ .badge { font-size: .7rem; padding: .1rem .4rem; border-radius: 4px; }
24
+ .badge.allow { background: rgba(142,142,147,.2); }
25
+ .badge.fail { background: rgba(255,59,48,.15); color: #ff3b30; }
26
+ .stat { display: inline-block; margin-right: 1.5rem; }
27
+ .stat .n { font-size: 1.4rem; font-weight: 600; }
28
+ .stat .label { font-size: .75rem; opacity: .65; text-transform: uppercase; letter-spacing: .05em; }
29
+ .steps { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .75rem; opacity: .7; white-space: pre-wrap; word-break: break-all; }
30
+ details { margin-top: .5rem; }
31
+ summary { cursor: pointer; font-size: .8rem; opacity: .7; }
32
+ </style>
33
+ </head>
34
+ <body>
35
+ <h1>{{TITLE}}</h1>
36
+ <div class="meta">Generated by memorydetective {{VERSION}} at {{TIMESTAMP}}</div>
37
+ {{BODY}}
38
+ </body>
39
+ </html>
@@ -0,0 +1,39 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="generator" content="memorydetective">
6
+ <title>{{TITLE}}</title>
7
+ <style>
8
+ :root { color-scheme: light dark; }
9
+ body { font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; margin: 0; padding: 2rem; max-width: 960px; background: #fafafa; color: #1c1c1e; }
10
+ @media (prefers-color-scheme: dark) { body { background: #1c1c1e; color: #f2f2f7; } .card { background: #2c2c2e; } th { background: #3a3a3c; } code { background: #3a3a3c; } }
11
+ h1 { font-size: 1.6rem; margin: 0 0 .5rem; }
12
+ h2 { font-size: 1.1rem; margin: 2rem 0 .5rem; }
13
+ .meta { font-size: .8rem; opacity: .65; margin-bottom: 1.5rem; }
14
+ .card { background: #fff; border: 1px solid rgba(127,127,127,.2); border-radius: 8px; padding: 1rem 1.25rem; margin-bottom: 1rem; }
15
+ .verdict { display: inline-block; padding: .25rem .75rem; border-radius: 999px; font-weight: 600; font-size: .8rem; letter-spacing: .02em; }
16
+ .verdict.pass { background: #34c759; color: #fff; }
17
+ .verdict.fail { background: #ff3b30; color: #fff; }
18
+ .verdict.skip { background: #8e8e93; color: #fff; }
19
+ table { border-collapse: collapse; width: 100%; margin: .5rem 0; font-size: .85rem; }
20
+ th, td { text-align: left; padding: .4rem .6rem; border-bottom: 1px solid rgba(127,127,127,.2); }
21
+ th { background: #f2f2f7; font-weight: 600; }
22
+ code { font: .85rem/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; background: #f2f2f7; padding: .15rem .35rem; border-radius: 4px; }
23
+ .badge { font-size: .7rem; padding: .1rem .4rem; border-radius: 4px; }
24
+ .badge.allow { background: rgba(142,142,147,.2); }
25
+ .badge.fail { background: rgba(255,59,48,.15); color: #ff3b30; }
26
+ .stat { display: inline-block; margin-right: 1.5rem; }
27
+ .stat .n { font-size: 1.4rem; font-weight: 600; }
28
+ .stat .label { font-size: .75rem; opacity: .65; text-transform: uppercase; letter-spacing: .05em; }
29
+ .steps { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .75rem; opacity: .7; white-space: pre-wrap; word-break: break-all; }
30
+ details { margin-top: .5rem; }
31
+ summary { cursor: pointer; font-size: .8rem; opacity: .7; }
32
+ </style>
33
+ </head>
34
+ <body>
35
+ <h1>{{TITLE}}</h1>
36
+ <div class="meta">Generated by memorydetective {{VERSION}} at {{TIMESTAMP}}</div>
37
+ {{BODY}}
38
+ </body>
39
+ </html>
@@ -0,0 +1,140 @@
1
+ /**
2
+ * `analyzeAbandonedMemory(beforePath, afterPath)`
3
+ *
4
+ * Diff two `.memgraph` snapshots on the reference-tree class counts (not the
5
+ * cycle list) and classify the GROWTH shape per class. Surfaces the family
6
+ * of bugs that the standard `diffMemgraphs` (cycle-focused) misses:
7
+ * orphaned KVO observers, never-removed NotificationCenter handlers, caches
8
+ * that never evict, singletons that retain payloads, and the long tail of
9
+ * "unknown growth" that warrants further inspection.
10
+ *
11
+ * The tool is the natural pair for the v1.8 verify-fix loop: capture a
12
+ * `before.memgraph`, ship the fix, capture an `after.memgraph`, then run
13
+ * this to confirm the suspect class went from N to <= 1. Validated end
14
+ * to end on the notelet investigation 2026-05-12 where AVPlayerItem went
15
+ * 342 to 0 across a fix that was invisible in `leaks` output but obvious
16
+ * in the reference tree.
17
+ *
18
+ * The classifier is pattern-catalog driven, same shape as `classifyCycle`:
19
+ * each grown class is matched against a small set of heuristics and tagged
20
+ * with a stable `classification` id + confidence tier. The agent can chain
21
+ * the result into `swiftSearchPattern` with the class name to locate the
22
+ * source.
23
+ */
24
+ import { z } from "zod";
25
+ import { type ReferenceTreeEntry } from "../parsers/referenceTree.js";
26
+ import type { NextCallSuggestion } from "../types.js";
27
+ export declare const analyzeAbandonedMemoryShape: {
28
+ readonly beforePath: z.ZodString;
29
+ readonly afterPath: z.ZodString;
30
+ readonly topN: z.ZodDefault<z.ZodNumber>;
31
+ readonly classFilter: z.ZodOptional<z.ZodString>;
32
+ readonly outputFormat: z.ZodOptional<z.ZodEnum<["markdown", "json", "both"]>>;
33
+ };
34
+ export declare const analyzeAbandonedMemorySchema: z.ZodObject<{
35
+ readonly beforePath: z.ZodString;
36
+ readonly afterPath: z.ZodString;
37
+ readonly topN: z.ZodDefault<z.ZodNumber>;
38
+ readonly classFilter: z.ZodOptional<z.ZodString>;
39
+ readonly outputFormat: z.ZodOptional<z.ZodEnum<["markdown", "json", "both"]>>;
40
+ }, "strip", z.ZodTypeAny, {
41
+ topN: number;
42
+ beforePath: string;
43
+ afterPath: string;
44
+ outputFormat?: "markdown" | "json" | "both" | undefined;
45
+ classFilter?: string | undefined;
46
+ }, {
47
+ beforePath: string;
48
+ afterPath: string;
49
+ outputFormat?: "markdown" | "json" | "both" | undefined;
50
+ topN?: number | undefined;
51
+ classFilter?: string | undefined;
52
+ }>;
53
+ export type AnalyzeAbandonedMemoryInput = z.infer<typeof analyzeAbandonedMemorySchema>;
54
+ export type AbandonedMemoryClassification = "kvo-observer-orphaned" | "notificationcenter-observer-leaked" | "cache-too-aggressive" | "singleton-retains-payload" | "unknown-growth";
55
+ export interface AbandonedMemoryEntry {
56
+ className: string;
57
+ beforeCount: number;
58
+ afterCount: number;
59
+ delta: number;
60
+ beforeBytes: number;
61
+ afterBytes: number;
62
+ bytesDelta: number;
63
+ classification: AbandonedMemoryClassification;
64
+ confidence: "high" | "medium" | "low";
65
+ hint?: string;
66
+ }
67
+ export interface AnalyzeAbandonedMemoryResult {
68
+ ok: boolean;
69
+ beforePath: string;
70
+ afterPath: string;
71
+ totals: {
72
+ classesGrown: number;
73
+ classesShrunk: number;
74
+ classesUnchanged: number;
75
+ netInstancesDelta: number;
76
+ netBytesDelta: number;
77
+ };
78
+ /**
79
+ * Classes that grew between before and after, ranked by absolute delta
80
+ * descending. Each entry carries a `classification` from the catalog plus
81
+ * a `confidence` tier. The agent can branch on `classification` to choose
82
+ * the right `swiftSearchPattern` / fix template.
83
+ */
84
+ growthByClass: AbandonedMemoryEntry[];
85
+ /**
86
+ * Classes that shrunk between before and after. Surfaced so the caller
87
+ * can confirm the fix freed the suspect class (e.g. AVPlayerItem in the
88
+ * notelet case went from 342 to 0). Sorted by absolute delta desc.
89
+ */
90
+ shrinkageByClass: AbandonedMemoryEntry[];
91
+ /** Plain-English diagnosis tying the highest-confidence growth to a fix hint. */
92
+ diagnosis: string;
93
+ /** Pipeline hints: chain into `swiftSearchPattern` against the top growth class. */
94
+ suggestedNextCalls?: NextCallSuggestion[];
95
+ }
96
+ /**
97
+ * Pure: diff two reference-tree entry lists by class name, classify each
98
+ * class with a delta != 0, and return the structured result minus the
99
+ * filesystem header fields.
100
+ *
101
+ * Exposed so tests can drive it without subprocess spawning. The async
102
+ * wrapper around it handles the leaks invocations.
103
+ */
104
+ export declare function buildAbandonedMemoryDiff(before: ReferenceTreeEntry[], after: ReferenceTreeEntry[], options: {
105
+ topN: number;
106
+ classFilter?: string;
107
+ }): Omit<AnalyzeAbandonedMemoryResult, "ok" | "beforePath" | "afterPath">;
108
+ /**
109
+ * Pure: classify a single class's growth shape based on its name + the
110
+ * presence of co-occurring NSKeyValueObservance growth.
111
+ *
112
+ * Heuristics (highest specificity first):
113
+ *
114
+ * - NSKeyValueObservance / NSKeyValueObservationInfo growth: high-confidence
115
+ * `kvo-observer-orphaned`. The KVO subsystem only allocates these tokens
116
+ * when `obj.observe(\.x) { ... }` is called; growth here means tokens
117
+ * never invalidated.
118
+ *
119
+ * - When KVO observation infrastructure grew, escalate any other class
120
+ * with delta >= 5 to `kvo-observer-orphaned` (medium confidence). These
121
+ * are typically the observed types being retained by orphaned observers
122
+ * (AVPlayerItem in the notelet case).
123
+ *
124
+ * - NSCache / NSCountedSet / NSMapTable / NSMutable{Array,Dictionary,Set}
125
+ * growth: medium-confidence `cache-too-aggressive`. Collection classes
126
+ * that grow across a workflow typically indicate missing eviction.
127
+ *
128
+ * - NotificationCenter observer block growth (NSConcreteNotification,
129
+ * __NSObserver, and similar): medium-confidence
130
+ * `notificationcenter-observer-leaked`.
131
+ *
132
+ * - Everything else: low-confidence `unknown-growth`. The agent should
133
+ * chain into `swiftSearchPattern` with the class name to confirm.
134
+ */
135
+ export declare function classifyGrowth(className: string, delta: number, hasKvoCoOccurrence: boolean, kvoObservanceDelta: number): {
136
+ classification: AbandonedMemoryClassification;
137
+ confidence: "high" | "medium" | "low";
138
+ hint?: string;
139
+ };
140
+ export declare function analyzeAbandonedMemory(input: AnalyzeAbandonedMemoryInput): Promise<AnalyzeAbandonedMemoryResult>;
@@ -0,0 +1,287 @@
1
+ /**
2
+ * `analyzeAbandonedMemory(beforePath, afterPath)`
3
+ *
4
+ * Diff two `.memgraph` snapshots on the reference-tree class counts (not the
5
+ * cycle list) and classify the GROWTH shape per class. Surfaces the family
6
+ * of bugs that the standard `diffMemgraphs` (cycle-focused) misses:
7
+ * orphaned KVO observers, never-removed NotificationCenter handlers, caches
8
+ * that never evict, singletons that retain payloads, and the long tail of
9
+ * "unknown growth" that warrants further inspection.
10
+ *
11
+ * The tool is the natural pair for the v1.8 verify-fix loop: capture a
12
+ * `before.memgraph`, ship the fix, capture an `after.memgraph`, then run
13
+ * this to confirm the suspect class went from N to <= 1. Validated end
14
+ * to end on the notelet investigation 2026-05-12 where AVPlayerItem went
15
+ * 342 to 0 across a fix that was invisible in `leaks` output but obvious
16
+ * in the reference tree.
17
+ *
18
+ * The classifier is pattern-catalog driven, same shape as `classifyCycle`:
19
+ * each grown class is matched against a small set of heuristics and tagged
20
+ * with a stable `classification` id + confidence tier. The agent can chain
21
+ * the result into `swiftSearchPattern` with the class name to locate the
22
+ * source.
23
+ */
24
+ import { z } from "zod";
25
+ import { existsSync } from "node:fs";
26
+ import { resolve as resolvePath } from "node:path";
27
+ import { runCommand } from "../runtime/exec.js";
28
+ import { parseReferenceTreeText, } from "../parsers/referenceTree.js";
29
+ import { outputFormatField } from "../runtime/responseFormatter.js";
30
+ export const analyzeAbandonedMemoryShape = {
31
+ beforePath: z
32
+ .string()
33
+ .min(1)
34
+ .describe("Absolute path to the baseline `.memgraph` (the BEFORE snapshot). Use `captureScenarioState({ label: 'before' })` to produce one in the standard verify-fix flow."),
35
+ afterPath: z
36
+ .string()
37
+ .min(1)
38
+ .describe("Absolute path to the post-fix `.memgraph` (the AFTER snapshot). Same workflow as `beforePath`, after applying the candidate fix."),
39
+ topN: z
40
+ .number()
41
+ .int()
42
+ .positive()
43
+ .max(200)
44
+ .default(25)
45
+ .describe("Cap on `growthByClass[]` length. Default 25, max 200. Classes are ranked by absolute instance-count delta descending."),
46
+ classFilter: z
47
+ .string()
48
+ .optional()
49
+ .describe("Optional substring filter. When set, only classes whose name contains this substring are included in the response. Useful for verifying a specific class went to baseline without seeing the surrounding noise."),
50
+ outputFormat: outputFormatField,
51
+ };
52
+ export const analyzeAbandonedMemorySchema = z.object(analyzeAbandonedMemoryShape);
53
+ /**
54
+ * Pure: diff two reference-tree entry lists by class name, classify each
55
+ * class with a delta != 0, and return the structured result minus the
56
+ * filesystem header fields.
57
+ *
58
+ * Exposed so tests can drive it without subprocess spawning. The async
59
+ * wrapper around it handles the leaks invocations.
60
+ */
61
+ export function buildAbandonedMemoryDiff(before, after, options) {
62
+ const beforeByName = new Map(before.map((e) => [e.className, e]));
63
+ const afterByName = new Map(after.map((e) => [e.className, e]));
64
+ const allNames = new Set([...beforeByName.keys(), ...afterByName.keys()]);
65
+ const raw = [];
66
+ for (const name of allNames) {
67
+ if (options.classFilter && !name.includes(options.classFilter))
68
+ continue;
69
+ const b = beforeByName.get(name);
70
+ const a = afterByName.get(name);
71
+ const beforeCount = b?.instanceCount ?? 0;
72
+ const afterCount = a?.instanceCount ?? 0;
73
+ const beforeBytes = b?.totalBytes ?? 0;
74
+ const afterBytes = a?.totalBytes ?? 0;
75
+ raw.push({
76
+ className: name,
77
+ beforeCount,
78
+ afterCount,
79
+ delta: afterCount - beforeCount,
80
+ beforeBytes,
81
+ afterBytes,
82
+ bytesDelta: afterBytes - beforeBytes,
83
+ });
84
+ }
85
+ // Co-occurrence signal: did the KVO observation infrastructure grow?
86
+ // If yes, the same-direction growth of other large classes is best
87
+ // explained as "those classes are the observed types being retained
88
+ // by orphaned observers", and the classifier should escalate them to
89
+ // `kvo-observer-orphaned` instead of leaving them as `unknown-growth`.
90
+ const kvoObservanceGrowth = raw.find((r) => r.className === "NSKeyValueObservance")?.delta ?? 0;
91
+ const kvoObservationInfoGrowth = raw.find((r) => r.className === "NSKeyValueObservationInfo")?.delta ?? 0;
92
+ const hasKvoCoOccurrence = kvoObservanceGrowth >= 3 || kvoObservationInfoGrowth >= 3;
93
+ const grown = raw.filter((r) => r.delta > 0);
94
+ const shrunk = raw.filter((r) => r.delta < 0);
95
+ const unchanged = raw.filter((r) => r.delta === 0).length;
96
+ const growthByClass = grown
97
+ .map((r) => {
98
+ const { classification, confidence, hint } = classifyGrowth(r.className, r.delta, hasKvoCoOccurrence, kvoObservanceGrowth);
99
+ return {
100
+ className: r.className,
101
+ beforeCount: r.beforeCount,
102
+ afterCount: r.afterCount,
103
+ delta: r.delta,
104
+ beforeBytes: r.beforeBytes,
105
+ afterBytes: r.afterBytes,
106
+ bytesDelta: r.bytesDelta,
107
+ classification,
108
+ confidence,
109
+ ...(hint ? { hint } : {}),
110
+ };
111
+ })
112
+ .sort((a, b) => b.delta - a.delta || b.bytesDelta - a.bytesDelta);
113
+ const shrinkageByClass = shrunk
114
+ .map((r) => ({
115
+ className: r.className,
116
+ beforeCount: r.beforeCount,
117
+ afterCount: r.afterCount,
118
+ delta: r.delta,
119
+ beforeBytes: r.beforeBytes,
120
+ afterBytes: r.afterBytes,
121
+ bytesDelta: r.bytesDelta,
122
+ // Shrinkage entries are still classified for symmetry, but the
123
+ // classification reflects what the suspect-shaped class WAS doing
124
+ // before; the fix freed it, which is what we want to confirm.
125
+ classification: classifyGrowth(r.className, Math.abs(r.delta), false, 0).classification,
126
+ confidence: "high",
127
+ }))
128
+ .sort((a, b) => a.delta - b.delta || a.bytesDelta - b.bytesDelta);
129
+ const netInstancesDelta = raw.reduce((acc, r) => acc + r.delta, 0);
130
+ const netBytesDelta = raw.reduce((acc, r) => acc + r.bytesDelta, 0);
131
+ const totals = {
132
+ classesGrown: grown.length,
133
+ classesShrunk: shrunk.length,
134
+ classesUnchanged: unchanged,
135
+ netInstancesDelta,
136
+ netBytesDelta,
137
+ };
138
+ const diagnosis = buildDiagnosis(growthByClass, shrinkageByClass);
139
+ const suggestedNextCalls = buildSuggestedNextCalls(growthByClass);
140
+ return {
141
+ totals,
142
+ growthByClass: growthByClass.slice(0, options.topN),
143
+ shrinkageByClass: shrinkageByClass.slice(0, options.topN),
144
+ diagnosis,
145
+ ...(suggestedNextCalls.length > 0 ? { suggestedNextCalls } : {}),
146
+ };
147
+ }
148
+ /**
149
+ * Pure: classify a single class's growth shape based on its name + the
150
+ * presence of co-occurring NSKeyValueObservance growth.
151
+ *
152
+ * Heuristics (highest specificity first):
153
+ *
154
+ * - NSKeyValueObservance / NSKeyValueObservationInfo growth: high-confidence
155
+ * `kvo-observer-orphaned`. The KVO subsystem only allocates these tokens
156
+ * when `obj.observe(\.x) { ... }` is called; growth here means tokens
157
+ * never invalidated.
158
+ *
159
+ * - When KVO observation infrastructure grew, escalate any other class
160
+ * with delta >= 5 to `kvo-observer-orphaned` (medium confidence). These
161
+ * are typically the observed types being retained by orphaned observers
162
+ * (AVPlayerItem in the notelet case).
163
+ *
164
+ * - NSCache / NSCountedSet / NSMapTable / NSMutable{Array,Dictionary,Set}
165
+ * growth: medium-confidence `cache-too-aggressive`. Collection classes
166
+ * that grow across a workflow typically indicate missing eviction.
167
+ *
168
+ * - NotificationCenter observer block growth (NSConcreteNotification,
169
+ * __NSObserver, and similar): medium-confidence
170
+ * `notificationcenter-observer-leaked`.
171
+ *
172
+ * - Everything else: low-confidence `unknown-growth`. The agent should
173
+ * chain into `swiftSearchPattern` with the class name to confirm.
174
+ */
175
+ export function classifyGrowth(className, delta, hasKvoCoOccurrence, kvoObservanceDelta) {
176
+ if (className.includes("NSKeyValueObservance") ||
177
+ className.includes("NSKeyValueObservationInfo")) {
178
+ return {
179
+ classification: "kvo-observer-orphaned",
180
+ confidence: "high",
181
+ hint: "NSKeyValueObservance growth indicates `observe(\\.x) { ... }` tokens that were never invalidated. The token strongly retains the change closure (which usually captures self), and the closure is anchored in the KVO global observer registry. Use `[weak self]` inside the observe closure and call `token?.invalidate()` in `deinit`, or invalidate-then-nil before reassigning the token. See `classifyCycle` pattern `kvo.observation-not-invalidated`.",
182
+ };
183
+ }
184
+ if (hasKvoCoOccurrence && delta >= 5) {
185
+ const confidence = delta >= 50 ? "high" : "medium";
186
+ return {
187
+ classification: "kvo-observer-orphaned",
188
+ confidence,
189
+ hint: `Co-occurring NSKeyValueObservance growth (+${kvoObservanceDelta}) suggests this type is the value being observed via \`observe(\\.x) { ... }\`. The orphaned observer holds the value alive. Fixing the observer (\`token.invalidate()\` on teardown) will free this class too. See \`classifyCycle\` pattern \`kvo.observation-not-invalidated\`.`,
190
+ };
191
+ }
192
+ if (/^NS(Cache|CountedSet|MapTable|MutableArray|MutableDictionary|MutableSet|HashTable)/.test(className)) {
193
+ return {
194
+ classification: "cache-too-aggressive",
195
+ confidence: "medium",
196
+ hint: "Bulk-storage class is growing across the workflow. Likely a cache or collection without eviction. For `NSCache`, set `countLimit` or `totalCostLimit`. For `NSMutable*`, audit the producer to confirm it is not appending without bounds. For domain caches, prefer `NSCache` over `NSMutableDictionary` when you want OS-driven eviction under memory pressure.",
197
+ };
198
+ }
199
+ if (/NotificationToken|NotificationObserver|__NSObserver|NSConcreteNotification|NSNotificationCenterObserver/.test(className)) {
200
+ return {
201
+ classification: "notificationcenter-observer-leaked",
202
+ confidence: "medium",
203
+ hint: "NotificationCenter observer block (added via `addObserver(forName:object:queue:using:)`) growth indicates the returned token was never passed to `removeObserver(_:)`. Store the token on `self` and remove it in `deinit`, or use the selector-based variant which auto-deregisters on dealloc.",
204
+ };
205
+ }
206
+ return {
207
+ classification: "unknown-growth",
208
+ confidence: "low",
209
+ hint: "Class grew between before and after but the catalog did not recognize a known abandoned-memory shape. Chain into `swiftSearchPattern` with this class name to locate the allocation sites, then inspect for missing teardown (observers, timers, dispatch sources, weak ownership invariants).",
210
+ };
211
+ }
212
+ function buildDiagnosis(grown, shrunk) {
213
+ if (grown.length === 0 && shrunk.length === 0) {
214
+ return "No class-count changes between before and after. Either the fix had no effect on the heap composition, or the workflow did not exercise the code path.";
215
+ }
216
+ if (grown.length === 0) {
217
+ const top = shrunk[0];
218
+ return `No growth detected. ${shrunk.length} class${shrunk.length === 1 ? "" : "es"} shrunk. Largest: ${top.className} (${top.beforeCount} to ${top.afterCount}, delta ${top.delta}). The fix appears to have closed an abandoned-memory chain.`;
219
+ }
220
+ const highConfidence = grown.filter((e) => e.confidence === "high");
221
+ const top = grown[0];
222
+ if (highConfidence.length > 0) {
223
+ const hc = highConfidence[0];
224
+ return `${grown.length} class${grown.length === 1 ? "" : "es"} grew. Top suspect: ${hc.className} (${hc.beforeCount} to ${hc.afterCount}, delta +${hc.delta}). Classification: ${hc.classification} (high confidence). ${hc.hint ?? ""}`;
225
+ }
226
+ return `${grown.length} class${grown.length === 1 ? "" : "es"} grew. Largest: ${top.className} (${top.beforeCount} to ${top.afterCount}, delta +${top.delta}). Classification: ${top.classification} (${top.confidence} confidence). Chain into swiftSearchPattern with the class name to locate the allocation site.`;
227
+ }
228
+ function buildSuggestedNextCalls(grown) {
229
+ if (grown.length === 0)
230
+ return [];
231
+ // Prefer the highest-confidence + largest-delta entry for the suggestion.
232
+ const ranked = [...grown].sort((a, b) => {
233
+ const confRank = (c) => c === "high" ? 2 : c === "medium" ? 1 : 0;
234
+ const diff = confRank(b.confidence) - confRank(a.confidence);
235
+ if (diff !== 0)
236
+ return diff;
237
+ return b.delta - a.delta;
238
+ });
239
+ const target = ranked[0];
240
+ return [
241
+ {
242
+ tool: "swiftSearchPattern",
243
+ args: {
244
+ pattern: target.className,
245
+ scope: "<your project root>",
246
+ },
247
+ why: `Locate the allocation site for ${target.className} (grew by +${target.delta} between snapshots; classified as ${target.classification}, ${target.confidence} confidence). The class name + a project-wide pattern search usually narrows to one or two files.`,
248
+ },
249
+ ];
250
+ }
251
+ /**
252
+ * Spawn `leaks --referenceTree --groupByType --noContent` against a .memgraph
253
+ * and return parsed entries. Wide topN here (1000) so the diff has the full
254
+ * picture; the user-facing `topN` only applies to the FINAL response slice.
255
+ */
256
+ async function loadReferenceTree(path) {
257
+ const result = await runCommand("leaks", [path, "--referenceTree", "--groupByType", "--noContent"], { timeoutMs: 5 * 60_000 });
258
+ if (result.code !== 0 && result.code !== 1) {
259
+ throw new Error(`leaks --referenceTree failed (code ${result.code}) on ${path}: ${result.stderr || result.stdout}`);
260
+ }
261
+ return parseReferenceTreeText(result.stdout, 1000);
262
+ }
263
+ export async function analyzeAbandonedMemory(input) {
264
+ const beforePath = resolvePath(input.beforePath);
265
+ const afterPath = resolvePath(input.afterPath);
266
+ if (!existsSync(beforePath)) {
267
+ throw new Error(`Before memgraph not found: ${beforePath}`);
268
+ }
269
+ if (!existsSync(afterPath)) {
270
+ throw new Error(`After memgraph not found: ${afterPath}`);
271
+ }
272
+ const [before, after] = await Promise.all([
273
+ loadReferenceTree(beforePath),
274
+ loadReferenceTree(afterPath),
275
+ ]);
276
+ const diff = buildAbandonedMemoryDiff(before, after, {
277
+ topN: input.topN ?? 25,
278
+ ...(input.classFilter ? { classFilter: input.classFilter } : {}),
279
+ });
280
+ return {
281
+ ok: true,
282
+ beforePath,
283
+ afterPath,
284
+ ...diff,
285
+ };
286
+ }
287
+ //# sourceMappingURL=analyzeAbandonedMemory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzeAbandonedMemory.js","sourceRoot":"","sources":["../../src/tools/analyzeAbandonedMemory.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,18 @@
1
1
  import { z } from "zod";
2
+ import type { DataStatus } from "../types.js";
2
3
  export declare const analyzeAllocationsSchema: z.ZodObject<{
3
4
  tracePath: z.ZodString;
4
5
  topN: z.ZodDefault<z.ZodNumber>;
5
6
  minBytes: z.ZodDefault<z.ZodNumber>;
7
+ outputFormat: z.ZodOptional<z.ZodEnum<["markdown", "json", "both"]>>;
6
8
  }, "strip", z.ZodTypeAny, {
7
- topN: number;
8
9
  tracePath: string;
10
+ topN: number;
9
11
  minBytes: number;
12
+ outputFormat?: "markdown" | "json" | "both" | undefined;
10
13
  }, {
11
14
  tracePath: string;
15
+ outputFormat?: "markdown" | "json" | "both" | undefined;
12
16
  topN?: number | undefined;
13
17
  minBytes?: number | undefined;
14
18
  }>;
@@ -38,9 +42,14 @@ export interface AnalyzeAllocationsResult {
38
42
  };
39
43
  /** Top categories by cumulative bytes. */
40
44
  topByBytes: AllocationEntry[];
41
- /** Top categories by allocation count (different signal small frequent allocations). */
45
+ /** Top categories by allocation count (different signal, small frequent allocations). */
42
46
  topByCount: AllocationEntry[];
43
47
  diagnosis: string;
48
+ /**
49
+ * Disambiguates empty arrays into "no data in the trace" vs "trace could
50
+ * not be exported" vs "data was exported partially". See {@link DataStatus}.
51
+ */
52
+ status: DataStatus;
44
53
  }
45
54
  /** Pure: turn parsed XML into the analyzed result. */
46
55
  export declare function analyzeAllocationsFromXml(xml: string, tracePath: string, topN?: number, minBytes?: number): AnalyzeAllocationsResult;
@@ -3,6 +3,7 @@ import { existsSync } from "node:fs";
3
3
  import { resolve as resolvePath } from "node:path";
4
4
  import { runCommand } from "../runtime/exec.js";
5
5
  import { parseXctraceXml, asNumber, asFormatted, } from "../parsers/xctraceXml.js";
6
+ import { outputFormatField } from "../runtime/responseFormatter.js";
6
7
  export const analyzeAllocationsSchema = z.object({
7
8
  tracePath: z
8
9
  .string()
@@ -19,6 +20,7 @@ export const analyzeAllocationsSchema = z.object({
19
20
  .nonnegative()
20
21
  .default(0)
21
22
  .describe("Filter out individual allocations smaller than this size in bytes (default 0). Use 1024 to focus on >1KB allocations."),
23
+ outputFormat: outputFormatField,
22
24
  });
23
25
  /** Pure: turn parsed XML into the analyzed result. */
24
26
  export function analyzeAllocationsFromXml(xml, tracePath, topN = 15, minBytes = 0) {
@@ -38,6 +40,7 @@ export function analyzeAllocationsFromXml(xml, tracePath, topN = 15, minBytes =
38
40
  topByBytes: [],
39
41
  topByCount: [],
40
42
  diagnosis: "No allocations table found in the trace.",
43
+ status: "not_present",
41
44
  };
42
45
  }
43
46
  // The xctrace `allocations` schema has columns roughly like:
@@ -126,6 +129,7 @@ export function analyzeAllocationsFromXml(xml, tracePath, topN = 15, minBytes =
126
129
  topByBytes,
127
130
  topByCount,
128
131
  diagnosis,
132
+ status: "available",
129
133
  };
130
134
  }
131
135
  function buildDiagnosis(rows, cumulativeBytes, topByBytes) {
@@ -1 +1 @@
1
- {"version":3,"file":"analyzeAllocations.js","sourceRoot":"","sources":["../../src/tools/analyzeAllocations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analyzeAllocations.js","sourceRoot":"","sources":["../../src/tools/analyzeAllocations.ts"],"names":[],"mappings":"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"}