memorydetective 1.2.0 → 1.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.
@@ -0,0 +1,220 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Meta-tool: returns the canonical investigation sequence for a known
4
+ * problem class. Lets a fresh LLM agent jump straight to the right pipeline
5
+ * without rediscovering the order from tool descriptions.
6
+ *
7
+ * Each playbook is a versioned, declarative sequence of tool calls with a
8
+ * stable `step` number, a `purpose` line, and `argsTemplate` showing which
9
+ * args matter most. The agent fills in concrete values from the user's
10
+ * context (file paths, class names, etc.).
11
+ */
12
+ export const PlaybookKindEnum = z.enum([
13
+ "memgraph-leak",
14
+ "perf-hangs",
15
+ "ui-jank",
16
+ "app-launch-slow",
17
+ "verify-fix",
18
+ ]);
19
+ export const getInvestigationPlaybookSchema = z.object({
20
+ kind: PlaybookKindEnum.describe("Which investigation flow to return. `memgraph-leak` is the most common — diagnose a SwiftUI/Combine retain cycle from a `.memgraph` and locate it in source."),
21
+ });
22
+ const PLAYBOOKS = {
23
+ "memgraph-leak": {
24
+ kind: "memgraph-leak",
25
+ summary: "Diagnose a SwiftUI / Combine retain cycle from a `.memgraph` snapshot, locate the offending code, and propose a fix.",
26
+ steps: [
27
+ {
28
+ step: 1,
29
+ tool: "analyzeMemgraph",
30
+ purpose: "Run leaks(1) and get totals + top-level ROOT CYCLE summaries with class chains in compact form.",
31
+ argsTemplate: { path: "<absolute path to the .memgraph>" },
32
+ resultGuidance: "Note the count of ROOT CYCLEs and the dominant class chain. The response includes `suggestedNextCalls` — follow them.",
33
+ },
34
+ {
35
+ step: 2,
36
+ tool: "classifyCycle",
37
+ purpose: "Match each ROOT CYCLE against the built-in catalog of known antipatterns. Returns a fix hint and pre-populated `suggestedNextCalls` for source-code lookup.",
38
+ argsTemplate: { path: "<same path as step 1>" },
39
+ resultGuidance: "If `primaryMatch` is `null`, the cycle is novel — use `findRetainers` to walk the chain manually instead.",
40
+ },
41
+ {
42
+ step: 3,
43
+ tool: "reachableFromCycle",
44
+ purpose: "Confirm which app-level class is the actual culprit (cycle root) versus collateral retained instances.",
45
+ argsTemplate: {
46
+ path: "<same path>",
47
+ rootClassName: "<class from step 2's primaryMatch>",
48
+ },
49
+ resultGuidance: "If a single app-level class dominates `counts`, that's the leak. If many compete, the cycle may be deeper than a single owner.",
50
+ },
51
+ {
52
+ step: 4,
53
+ tool: "swiftSearchPattern",
54
+ purpose: "Locate the code construct the classifier flagged (e.g. `.tag(`, `.sink {`, `Task {`).",
55
+ argsTemplate: {
56
+ filePath: "<a candidate Swift file in the project>",
57
+ pattern: "<from step 2's suggestedNextCalls>",
58
+ },
59
+ },
60
+ {
61
+ step: 5,
62
+ tool: "swiftGetSymbolDefinition",
63
+ purpose: "Jump to the declaration of the cycle's app-level class.",
64
+ argsTemplate: {
65
+ symbolName: "<class from step 3>",
66
+ candidatePaths: ["<Sources/, app target dirs>"],
67
+ },
68
+ },
69
+ {
70
+ step: 6,
71
+ tool: "swiftFindSymbolReferences",
72
+ purpose: "List every callsite — useful to compare capture-list patterns across them and detect inconsistencies.",
73
+ argsTemplate: {
74
+ symbolName: "<class from step 3>",
75
+ filePath: "<from step 5 result>",
76
+ },
77
+ },
78
+ ],
79
+ seeAlso: ["verify-fix"],
80
+ },
81
+ "perf-hangs": {
82
+ kind: "perf-hangs",
83
+ summary: "Diagnose user-visible main-thread hangs from a `.trace` recorded with the Time Profiler or Hangs template.",
84
+ steps: [
85
+ {
86
+ step: 1,
87
+ tool: "listTraceDevices",
88
+ purpose: "Find the simulator or device UDID to attach to.",
89
+ argsTemplate: {},
90
+ },
91
+ {
92
+ step: 2,
93
+ tool: "recordTimeProfile",
94
+ purpose: "Capture a fresh `.trace` while reproducing the slow path.",
95
+ argsTemplate: {
96
+ template: "Time Profiler",
97
+ deviceId: "<from step 1>",
98
+ attachAppName: "<your app name>",
99
+ durationSec: 90,
100
+ output: "<absolute path ending in .trace>",
101
+ },
102
+ },
103
+ {
104
+ step: 3,
105
+ tool: "analyzeHangs",
106
+ purpose: "Parse the `potential-hangs` schema; report Hang vs Microhang counts plus the top N longest.",
107
+ argsTemplate: {
108
+ tracePath: "<from step 2>",
109
+ minDurationMs: 250,
110
+ },
111
+ },
112
+ {
113
+ step: 4,
114
+ tool: "swiftSearchPattern",
115
+ purpose: "If hangs are dominated by a specific call site (visible in `top` entries), grep for likely main-thread offenders: `Task { ... }` blocks without `[weak self]`, synchronous I/O on the main queue, etc.",
116
+ argsTemplate: {
117
+ filePath: "<candidate file>",
118
+ pattern: "DispatchQueue\\.main\\.sync|Task\\s*\\{",
119
+ },
120
+ },
121
+ ],
122
+ seeAlso: ["ui-jank", "app-launch-slow"],
123
+ },
124
+ "ui-jank": {
125
+ kind: "ui-jank",
126
+ summary: "Diagnose dropped frames / animation hitches from a `.trace` recorded with the Animation Hitches template.",
127
+ steps: [
128
+ {
129
+ step: 1,
130
+ tool: "recordTimeProfile",
131
+ purpose: "Capture a `.trace` with the Animation Hitches template active.",
132
+ argsTemplate: {
133
+ template: "Animation Hitches",
134
+ deviceId: "<UDID>",
135
+ attachAppName: "<app>",
136
+ durationSec: 60,
137
+ output: "<.trace path>",
138
+ },
139
+ },
140
+ {
141
+ step: 2,
142
+ tool: "analyzeAnimationHitches",
143
+ purpose: "Parse the `animation-hitches` schema; report by-type counts and the count of user-perceptible hitches (>100ms).",
144
+ argsTemplate: { tracePath: "<from step 1>", minDurationMs: 100 },
145
+ },
146
+ {
147
+ step: 3,
148
+ tool: "swiftFindSymbolReferences",
149
+ purpose: "Once a suspected `View` is identified, find callsites to scope which screens render with this view.",
150
+ argsTemplate: { symbolName: "<View name>", filePath: "<source>" },
151
+ },
152
+ ],
153
+ },
154
+ "app-launch-slow": {
155
+ kind: "app-launch-slow",
156
+ summary: "Diagnose cold/warm launch slowness from a `.trace` recorded with the App Launch template.",
157
+ steps: [
158
+ {
159
+ step: 1,
160
+ tool: "recordTimeProfile",
161
+ purpose: "Capture a launch trace.",
162
+ argsTemplate: {
163
+ template: "App Launch",
164
+ deviceId: "<UDID>",
165
+ launchBundleId: "<com.example.app>",
166
+ durationSec: 30,
167
+ output: "<.trace path>",
168
+ },
169
+ },
170
+ {
171
+ step: 2,
172
+ tool: "analyzeAppLaunch",
173
+ purpose: "Get cold/warm classification + per-phase breakdown (process-creation, dyld, ObjC init, AppDelegate, first-frame).",
174
+ argsTemplate: { tracePath: "<from step 1>" },
175
+ },
176
+ {
177
+ step: 3,
178
+ tool: "swiftSearchPattern",
179
+ purpose: "If `appdelegate-init` dominates, grep for synchronous work in `application(_:didFinishLaunchingWithOptions:)`.",
180
+ argsTemplate: {
181
+ filePath: "<AppDelegate.swift>",
182
+ pattern: "didFinishLaunchingWithOptions",
183
+ },
184
+ },
185
+ ],
186
+ },
187
+ "verify-fix": {
188
+ kind: "verify-fix",
189
+ summary: "Confirm a fix actually closed a known cycle by diffing a before/after pair of `.memgraph` snapshots.",
190
+ steps: [
191
+ {
192
+ step: 1,
193
+ tool: "diffMemgraphs",
194
+ purpose: "Compare totals + class-count deltas + cycle signatures across before/after snapshots.",
195
+ argsTemplate: {
196
+ before: "<path to before.memgraph>",
197
+ after: "<path to after.memgraph>",
198
+ },
199
+ resultGuidance: "Look for the originally-classified cycle in `cycles.goneFromBefore`. If still in `cycles.persisted`, the fix didn't address the right capture.",
200
+ },
201
+ {
202
+ step: 2,
203
+ tool: "classifyCycle",
204
+ purpose: "Re-classify the after snapshot to confirm no new patterns appeared.",
205
+ argsTemplate: { path: "<path to after.memgraph>" },
206
+ },
207
+ ],
208
+ seeAlso: ["memgraph-leak"],
209
+ },
210
+ };
211
+ export async function getInvestigationPlaybook(input) {
212
+ const playbook = PLAYBOOKS[input.kind];
213
+ if (!playbook) {
214
+ throw new Error(`Unknown playbook kind: ${input.kind}. Known: ${Object.keys(PLAYBOOKS).join(", ")}`);
215
+ }
216
+ return { ok: true, playbook };
217
+ }
218
+ /** Exposed for tests. */
219
+ export const PLAYBOOK_KINDS = Object.keys(PLAYBOOKS);
220
+ //# sourceMappingURL=getInvestigationPlaybook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getInvestigationPlaybook.js","sourceRoot":"","sources":["../../src/tools/getInvestigationPlaybook.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import type { LeaksReport } from "../types.js";
2
+ import type { LeaksReport, NextCallSuggestion } from "../types.js";
3
3
  /**
4
4
  * Cycle-scoped reachability + class counting.
5
5
  *
@@ -30,9 +30,9 @@ export declare const reachableFromCycleSchema: z.ZodObject<{
30
30
  }, {
31
31
  path: string;
32
32
  className?: string | undefined;
33
+ cycleIndex?: number | undefined;
33
34
  verbosity?: "compact" | "normal" | "full" | undefined;
34
35
  topN?: number | undefined;
35
- cycleIndex?: number | undefined;
36
36
  rootClassName?: string | undefined;
37
37
  }>;
38
38
  export type ReachableFromCycleInput = z.infer<typeof reachableFromCycleSchema>;
@@ -55,6 +55,8 @@ export interface ReachableFromCycleResult {
55
55
  counts: ClassCount[];
56
56
  /** Total unique classes in the cycle's reachable set. */
57
57
  uniqueClasses: number;
58
+ /** Pipeline hint — locate the cycle root in source code. */
59
+ suggestedNextCalls?: NextCallSuggestion[];
58
60
  }
59
61
  /** Pure: compute the result from a parsed report. Exposed for testing. */
60
62
  export declare function reachableFromReport(report: LeaksReport, path: string, input: ReachableFromCycleInput): ReachableFromCycleResult;
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import { runLeaksAndParse } from "../runtime/leaks.js";
3
3
  import { rootCyclesOnly } from "../parsers/leaksOutput.js";
4
4
  import { shortenForVerbosity, } from "../parsers/shortenClassName.js";
5
+ import { pickPrimaryAppClass, suggestionFindReferences, suggestionGetDefinition, } from "../runtime/suggestions.js";
5
6
  /**
6
7
  * Cycle-scoped reachability + class counting.
7
8
  *
@@ -93,17 +94,29 @@ export function reachableFromReport(report, path, input) {
93
94
  }
94
95
  entries.sort((a, b) => b.count - a.count);
95
96
  entries = entries.slice(0, input.topN ?? 20);
97
+ // Find a class that looks "app-level" (not stdlib / SwiftUI internal) to
98
+ // suggest as the followup target. The cycle root is the canonical answer
99
+ // when it itself is app-level; otherwise we walk the counts.
100
+ const suggestedNextCalls = [];
101
+ const rootShort = shortenForVerbosity(picked.node.className, verbosity);
102
+ const candidate = pickPrimaryAppClass([rootShort]) ??
103
+ pickPrimaryAppClass(entries.map((e) => e.className));
104
+ if (candidate) {
105
+ suggestedNextCalls.push(suggestionGetDefinition({ symbolName: candidate }));
106
+ suggestedNextCalls.push(suggestionFindReferences({ symbolName: candidate }));
107
+ }
96
108
  return {
97
109
  ok: true,
98
110
  path,
99
111
  cycle: {
100
112
  index: picked.index,
101
- rootClass: shortenForVerbosity(picked.node.className, verbosity),
113
+ rootClass: rootShort,
102
114
  rootAddress: picked.node.address,
103
115
  totalReachable: total,
104
116
  },
105
117
  counts: entries,
106
118
  uniqueClasses: byClass.size,
119
+ ...(suggestedNextCalls.length > 0 ? { suggestedNextCalls } : {}),
107
120
  };
108
121
  }
109
122
  export async function reachableFromCycle(input) {
@@ -1 +1 @@
1
- {"version":3,"file":"reachableFromCycle.js","sourceRoot":"","sources":["../../src/tools/reachableFromCycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reachableFromCycle.js","sourceRoot":"","sources":["../../src/tools/reachableFromCycle.ts"],"names":[],"mappings":"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"}
@@ -6,13 +6,13 @@ export declare const swiftFindSymbolReferencesSchema: z.ZodObject<{
6
6
  projectRoot: z.ZodOptional<z.ZodString>;
7
7
  includeDeclaration: z.ZodDefault<z.ZodBoolean>;
8
8
  }, "strip", z.ZodTypeAny, {
9
- symbolName: string;
10
9
  filePath: string;
10
+ symbolName: string;
11
11
  includeDeclaration: boolean;
12
12
  projectRoot?: string | undefined;
13
13
  }, {
14
- symbolName: string;
15
14
  filePath: string;
15
+ symbolName: string;
16
16
  projectRoot?: string | undefined;
17
17
  includeDeclaration?: boolean | undefined;
18
18
  }>;
@@ -5,14 +5,14 @@ export declare const swiftGetHoverInfoSchema: z.ZodObject<{
5
5
  character: z.ZodNumber;
6
6
  projectRoot: z.ZodOptional<z.ZodString>;
7
7
  }, "strip", z.ZodTypeAny, {
8
+ filePath: string;
8
9
  line: number;
9
10
  character: number;
10
- filePath: string;
11
11
  projectRoot?: string | undefined;
12
12
  }, {
13
+ filePath: string;
13
14
  line: number;
14
15
  character: number;
15
- filePath: string;
16
16
  projectRoot?: string | undefined;
17
17
  }>;
18
18
  export type SwiftGetHoverInfoInput = z.infer<typeof swiftGetHoverInfoSchema>;
@@ -6,30 +6,30 @@ export declare const swiftGetSymbolDefinitionSchema: z.ZodObject<{
6
6
  filePath: z.ZodOptional<z.ZodString>;
7
7
  module: z.ZodOptional<z.ZodString>;
8
8
  }, "strip", z.ZodTypeAny, {
9
- module?: string | undefined;
10
9
  filePath?: string | undefined;
11
- }, {
12
10
  module?: string | undefined;
11
+ }, {
13
12
  filePath?: string | undefined;
13
+ module?: string | undefined;
14
14
  }>>;
15
15
  projectRoot: z.ZodOptional<z.ZodString>;
16
16
  candidatePaths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
17
17
  }, "strip", z.ZodTypeAny, {
18
18
  symbolName: string;
19
+ candidatePaths?: string[] | undefined;
19
20
  hint?: {
20
- module?: string | undefined;
21
21
  filePath?: string | undefined;
22
+ module?: string | undefined;
22
23
  } | undefined;
23
24
  projectRoot?: string | undefined;
24
- candidatePaths?: string[] | undefined;
25
25
  }, {
26
26
  symbolName: string;
27
+ candidatePaths?: string[] | undefined;
27
28
  hint?: {
28
- module?: string | undefined;
29
29
  filePath?: string | undefined;
30
+ module?: string | undefined;
30
31
  } | undefined;
31
32
  projectRoot?: string | undefined;
32
- candidatePaths?: string[] | undefined;
33
33
  }>;
34
34
  export type SwiftGetSymbolDefinitionInput = z.infer<typeof swiftGetSymbolDefinitionSchema>;
35
35
  export interface SwiftGetSymbolDefinitionResult {
@@ -11,13 +11,13 @@ export declare const swiftSearchPatternSchema: z.ZodObject<{
11
11
  flags: z.ZodOptional<z.ZodString>;
12
12
  maxMatches: z.ZodDefault<z.ZodNumber>;
13
13
  }, "strip", z.ZodTypeAny, {
14
- filePath: string;
15
14
  pattern: string;
15
+ filePath: string;
16
16
  maxMatches: number;
17
17
  flags?: string | undefined;
18
18
  }, {
19
- filePath: string;
20
19
  pattern: string;
20
+ filePath: string;
21
21
  flags?: string | undefined;
22
22
  maxMatches?: number | undefined;
23
23
  }>;
package/dist/types.d.ts CHANGED
@@ -52,3 +52,17 @@ export interface LeaksReport {
52
52
  /** True if the report contains zero ROOT CYCLE entries (independent of leakCount, since plain leaks may exist). */
53
53
  hasNoCycles: boolean;
54
54
  }
55
+ /**
56
+ * HATEOAS-style hint that an LLM agent can chain after the current tool's
57
+ * result. We pre-populate `args` from the current response so the agent can
58
+ * call the next tool with one fewer inference step. The agent is free to
59
+ * adapt or ignore — these are suggestions, not commands.
60
+ */
61
+ export interface NextCallSuggestion {
62
+ /** Name of the tool to call next. */
63
+ tool: string;
64
+ /** Pre-populated arguments based on the current result. */
65
+ args: Record<string, unknown>;
66
+ /** One-sentence rationale: why this next call advances the investigation. */
67
+ why: string;
68
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorydetective",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "MCP server for iOS leak hunting and performance investigation. Reads .memgraph + .trace files, captures new ones via xctrace and leaks(1), classifies retain cycles.",
5
5
  "type": "module",
6
6
  "bin": {