memorydetective 1.7.0 → 1.8.1

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 (34) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +61 -29
  3. package/USAGE.md +87 -41
  4. package/dist/index.js +34 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/runtime/axe.d.ts +86 -0
  7. package/dist/runtime/axe.js +249 -0
  8. package/dist/runtime/axe.js.map +1 -0
  9. package/dist/runtime/buildSettings.d.ts +27 -0
  10. package/dist/runtime/buildSettings.js +88 -0
  11. package/dist/runtime/buildSettings.js.map +1 -0
  12. package/dist/runtime/exec.d.ts +8 -1
  13. package/dist/runtime/exec.js +8 -2
  14. package/dist/runtime/exec.js.map +1 -1
  15. package/dist/runtime/simctl.d.ts +68 -0
  16. package/dist/runtime/simctl.js +194 -0
  17. package/dist/runtime/simctl.js.map +1 -0
  18. package/dist/tools/bootAndLaunchForLeakInvestigation.d.ts +166 -0
  19. package/dist/tools/bootAndLaunchForLeakInvestigation.js +367 -0
  20. package/dist/tools/bootAndLaunchForLeakInvestigation.js.map +1 -0
  21. package/dist/tools/captureMemgraph.d.ts +29 -1
  22. package/dist/tools/captureMemgraph.js +148 -6
  23. package/dist/tools/captureMemgraph.js.map +1 -1
  24. package/dist/tools/captureScenarioState.d.ts +77 -0
  25. package/dist/tools/captureScenarioState.js +159 -0
  26. package/dist/tools/captureScenarioState.js.map +1 -0
  27. package/dist/tools/detectLeaksInXCUITest.d.ts +2 -2
  28. package/dist/tools/getInvestigationPlaybook.d.ts +15 -0
  29. package/dist/tools/getInvestigationPlaybook.js +24 -1
  30. package/dist/tools/getInvestigationPlaybook.js.map +1 -1
  31. package/dist/tools/replayScenario.d.ts +243 -0
  32. package/dist/tools/replayScenario.js +187 -0
  33. package/dist/tools/replayScenario.js.map +1 -0
  34. package/package.json +3 -2
@@ -0,0 +1,367 @@
1
+ /**
2
+ * Build, boot, install, and launch an iOS app on the iOS Simulator with
3
+ * `MallocStackLogging=1` (and any caller-supplied env vars) applied. Returns
4
+ * the host PID + simulator UDID + bundle id ready to chain into
5
+ * `captureMemgraph`.
6
+ *
7
+ * Why this exists: `leaks --outputGraph` regressed on macOS 26.x and aborts
8
+ * with `Failed to get DYLD info for task` when the target was not launched
9
+ * with malloc-stack-logging in its environment. Capturing a memgraph after
10
+ * the fact does not work; the env vars must be set at launch. This tool
11
+ * gives users a single MCP call that produces a leak-investigable process
12
+ * without requiring them to wire up xcodebuild + simctl manually.
13
+ *
14
+ * Out of scope: UI driving (Phase 3), composite snapshots (Phase 3), physical
15
+ * iOS devices (`leaks --outputGraph` does not support them).
16
+ */
17
+ import { z } from "zod";
18
+ import { join as joinPath } from "node:path";
19
+ import { runCommand } from "../runtime/exec.js";
20
+ import { parseBuildSettingsJson, } from "../runtime/buildSettings.js";
21
+ import { bootSimulator, findBootedSimulator, findSimulatorByName, installApp, launchApp, } from "../runtime/simctl.js";
22
+ const simulatorSelectorSchema = z.object({
23
+ udid: z.string().optional(),
24
+ name: z.string().optional(),
25
+ os: z.string().optional(),
26
+ });
27
+ export const bootAndLaunchForLeakInvestigationShape = {
28
+ workspace: z
29
+ .string()
30
+ .optional()
31
+ .describe("Absolute path to a .xcworkspace. Mutually exclusive with `project`."),
32
+ project: z
33
+ .string()
34
+ .optional()
35
+ .describe("Absolute path to a .xcodeproj. Mutually exclusive with `workspace`."),
36
+ scheme: z
37
+ .string()
38
+ .min(1)
39
+ .describe("Xcode scheme that builds the iOS application bundle."),
40
+ configuration: z
41
+ .string()
42
+ .default("Debug")
43
+ .describe("xcodebuild configuration. Default \"Debug\"."),
44
+ bundleId: z
45
+ .string()
46
+ .optional()
47
+ .describe("Override the bundle identifier. By default it is discovered from `xcodebuild -showBuildSettings`."),
48
+ derivedDataPath: z
49
+ .string()
50
+ .optional()
51
+ .describe("Custom -derivedDataPath. Useful to avoid collisions when multiple investigations run in parallel."),
52
+ simulator: simulatorSelectorSchema
53
+ .optional()
54
+ .describe("Pick a simulator by `udid`, by `name` (with optional `os`), or omit to use whichever simulator is currently booted."),
55
+ envVars: z
56
+ .record(z.string())
57
+ .optional()
58
+ .describe("Extra env vars to apply to the launched app (propagated via SIMCTL_CHILD_*). Default already includes MallocStackLogging=1."),
59
+ launchArgs: z
60
+ .array(z.string())
61
+ .default([])
62
+ .describe("Extra arguments passed to the app on launch."),
63
+ buildBeforeLaunch: z
64
+ .boolean()
65
+ .default(true)
66
+ .describe("Run `xcodebuild build` before installing. Set false when you've already built and want to skip straight to install/launch."),
67
+ warmupSeconds: z
68
+ .number()
69
+ .nonnegative()
70
+ .max(60)
71
+ .default(3)
72
+ .describe("How long to wait after launch before resolving the host PID. Default 3 seconds."),
73
+ };
74
+ export const bootAndLaunchForLeakInvestigationSchema = z
75
+ .object(bootAndLaunchForLeakInvestigationShape)
76
+ .superRefine((val, ctx) => {
77
+ const projectsCount = [val.workspace, val.project].filter(Boolean).length;
78
+ if (projectsCount !== 1) {
79
+ ctx.addIssue({
80
+ code: z.ZodIssueCode.custom,
81
+ message: "Provide exactly one of `workspace` or `project`.",
82
+ });
83
+ }
84
+ });
85
+ const DEFAULT_ENV_VARS = {
86
+ MallocStackLogging: "1",
87
+ };
88
+ export async function bootAndLaunchForLeakInvestigation(input) {
89
+ const steps = [];
90
+ const warnings = [];
91
+ const mergedEnv = {
92
+ ...DEFAULT_ENV_VARS,
93
+ ...(input.envVars ?? {}),
94
+ };
95
+ let udid;
96
+ try {
97
+ udid = await resolveSimulator(input, steps);
98
+ }
99
+ catch (err) {
100
+ return {
101
+ ok: false,
102
+ state: "noSimulatorAvailable",
103
+ appliedEnvVars: mergedEnv,
104
+ steps,
105
+ failureReason: err.message,
106
+ };
107
+ }
108
+ let buildSettings;
109
+ try {
110
+ buildSettings = await fetchBuildSettings(input, udid, steps);
111
+ }
112
+ catch (err) {
113
+ return {
114
+ ok: false,
115
+ state: "buildFailed",
116
+ simulatorUDID: udid,
117
+ appliedEnvVars: mergedEnv,
118
+ steps,
119
+ failureReason: `xcodebuild -showBuildSettings: ${err.message}`,
120
+ };
121
+ }
122
+ const bundleId = input.bundleId ?? buildSettings.productBundleIdentifier;
123
+ const appPath = joinPath(buildSettings.builtProductsDir, buildSettings.wrapperName);
124
+ const appName = buildSettings.executableName;
125
+ if (input.buildBeforeLaunch !== false) {
126
+ try {
127
+ await runBuild(input, udid, steps);
128
+ }
129
+ catch (err) {
130
+ return {
131
+ ok: false,
132
+ state: "buildFailed",
133
+ simulatorUDID: udid,
134
+ bundleId,
135
+ appName,
136
+ appPath,
137
+ appliedEnvVars: mergedEnv,
138
+ steps,
139
+ failureReason: err.message,
140
+ };
141
+ }
142
+ }
143
+ try {
144
+ steps.push(`$ xcrun simctl boot ${udid} (idempotent) && bootstatus -b`);
145
+ await bootSimulator(udid);
146
+ }
147
+ catch (err) {
148
+ return {
149
+ ok: false,
150
+ state: "noSimulatorAvailable",
151
+ simulatorUDID: udid,
152
+ bundleId,
153
+ appName,
154
+ appPath,
155
+ appliedEnvVars: mergedEnv,
156
+ steps,
157
+ failureReason: err.message,
158
+ };
159
+ }
160
+ try {
161
+ steps.push(`$ xcrun simctl install ${udid} ${appPath}`);
162
+ await installApp(udid, appPath);
163
+ }
164
+ catch (err) {
165
+ return {
166
+ ok: false,
167
+ state: "installFailed",
168
+ simulatorUDID: udid,
169
+ bundleId,
170
+ appName,
171
+ appPath,
172
+ appliedEnvVars: mergedEnv,
173
+ steps,
174
+ failureReason: err.message,
175
+ };
176
+ }
177
+ try {
178
+ steps.push(`$ xcrun simctl launch --terminate-running-process ${udid} ${bundleId}`);
179
+ await launchApp(udid, bundleId, mergedEnv, input.launchArgs);
180
+ }
181
+ catch (err) {
182
+ return {
183
+ ok: false,
184
+ state: "launchFailed",
185
+ simulatorUDID: udid,
186
+ bundleId,
187
+ appName,
188
+ appPath,
189
+ appliedEnvVars: mergedEnv,
190
+ steps,
191
+ failureReason: err.message,
192
+ };
193
+ }
194
+ if (input.warmupSeconds > 0) {
195
+ steps.push(`(warmup ${input.warmupSeconds}s)`);
196
+ await sleep(input.warmupSeconds * 1000);
197
+ }
198
+ let hostPid = null;
199
+ try {
200
+ hostPid = await resolveHostPid(udid, appName);
201
+ }
202
+ catch (err) {
203
+ warnings.push(`Host PID resolution failed: ${err.message}. The app may still be launching, or `
204
+ + `another simulator is running the same app. Retry the call with a longer warmupSeconds, `
205
+ + `or pass the PID explicitly to captureMemgraph.`);
206
+ }
207
+ if (hostPid === null) {
208
+ return {
209
+ ok: false,
210
+ state: "pidNotFound",
211
+ simulatorUDID: udid,
212
+ bundleId,
213
+ appName,
214
+ appPath,
215
+ appliedEnvVars: mergedEnv,
216
+ steps,
217
+ warnings: warnings.length > 0 ? warnings : undefined,
218
+ failureReason: "App was launched but the host process ID could not be resolved. captureMemgraph will not be able to attach by appName alone reliably.",
219
+ };
220
+ }
221
+ const suggestedNextCalls = [
222
+ {
223
+ tool: "captureMemgraph",
224
+ args: {
225
+ pid: hostPid,
226
+ output: "<absolute path ending in .memgraph>",
227
+ },
228
+ why: "The app was just launched with MallocStackLogging=1, which is the env var leaks --outputGraph needs on macOS 26.x. Capture the .memgraph now while the target process is still alive.",
229
+ },
230
+ ];
231
+ return {
232
+ ok: true,
233
+ state: "launched",
234
+ simulatorUDID: udid,
235
+ pid: hostPid,
236
+ bundleId,
237
+ appName,
238
+ appPath,
239
+ appliedEnvVars: mergedEnv,
240
+ steps,
241
+ warnings: warnings.length > 0 ? warnings : undefined,
242
+ suggestedNextCalls,
243
+ };
244
+ }
245
+ async function resolveSimulator(input, steps) {
246
+ const sel = input.simulator;
247
+ if (sel?.udid) {
248
+ steps.push(`(simulator selected by udid: ${sel.udid})`);
249
+ return sel.udid;
250
+ }
251
+ if (sel?.name) {
252
+ steps.push(`$ xcrun simctl list devices --json (filter name=${sel.name})`);
253
+ const dev = await findSimulatorByName(sel.name, sel.os);
254
+ if (!dev) {
255
+ throw new Error(`No simulator named "${sel.name}"${sel.os ? ` with os ${sel.os}` : ""}. Use \`xcrun simctl list devices\` to inspect available simulators.`);
256
+ }
257
+ return dev.udid;
258
+ }
259
+ steps.push(`$ xcrun simctl list devices booted --json`);
260
+ const booted = await findBootedSimulator();
261
+ if (!booted) {
262
+ throw new Error("No booted simulator and no `simulator` selector provided. Either boot a simulator manually or pass `simulator: { name: \"iPhone 15\" }`.");
263
+ }
264
+ return booted.udid;
265
+ }
266
+ async function fetchBuildSettings(input, udid, steps) {
267
+ const args = ["-scheme", input.scheme, "-configuration", input.configuration];
268
+ if (input.workspace)
269
+ args.unshift("-workspace", input.workspace);
270
+ else if (input.project)
271
+ args.unshift("-project", input.project);
272
+ args.push("-destination", `platform=iOS Simulator,id=${udid}`);
273
+ if (input.derivedDataPath)
274
+ args.push("-derivedDataPath", input.derivedDataPath);
275
+ args.push("-showBuildSettings", "-json");
276
+ steps.push(`$ xcodebuild ${args.join(" ")}`);
277
+ const result = await runCommand("xcodebuild", args, {
278
+ timeoutMs: 5 * 60_000,
279
+ });
280
+ if (result.code !== 0) {
281
+ throw new Error(`xcodebuild -showBuildSettings exited ${result.code}: ${result.stderr || result.stdout}`);
282
+ }
283
+ return parseBuildSettingsJson(result.stdout);
284
+ }
285
+ async function runBuild(input, udid, steps) {
286
+ const args = [];
287
+ if (input.workspace)
288
+ args.push("-workspace", input.workspace);
289
+ else if (input.project)
290
+ args.push("-project", input.project);
291
+ args.push("-scheme", input.scheme);
292
+ args.push("-configuration", input.configuration);
293
+ args.push("-destination", `platform=iOS Simulator,id=${udid}`);
294
+ if (input.derivedDataPath)
295
+ args.push("-derivedDataPath", input.derivedDataPath);
296
+ args.push("-quiet", "build");
297
+ steps.push(`$ xcodebuild ${args.join(" ")}`);
298
+ const result = await runCommand("xcodebuild", args, {
299
+ timeoutMs: 30 * 60_000,
300
+ });
301
+ if (result.code !== 0) {
302
+ throw new Error(`xcodebuild build exited ${result.code}: ${result.stderr || result.stdout}`);
303
+ }
304
+ }
305
+ /**
306
+ * Resolve the host-side PID for an app running inside the target simulator.
307
+ *
308
+ * Strategy: list every host process with `ps -Ao pid,command`, then pick lines
309
+ * whose command path includes the simulator UDID (i.e. lives under
310
+ * `~/Library/Developer/CoreSimulator/Devices/<UDID>/...`) AND whose path ends
311
+ * with `/<EXECUTABLE_NAME>`. This handles two cases natively:
312
+ * 1. Multi-simulator: filtering by UDID disambiguates from same-named apps in other simulators.
313
+ * 2. Long executable names: we match on full path, so the 15-char `comm` truncation that breaks `pgrep -x` is irrelevant.
314
+ *
315
+ * Returns the PID, or null when nothing matched (the typical reasons: app
316
+ * still launching, or executable name does not appear in the path because
317
+ * the user passed a custom override).
318
+ */
319
+ export async function resolveHostPid(udid, executableName) {
320
+ const result = await runCommand("ps", ["-Ao", "pid=,command="], {
321
+ timeoutMs: 10_000,
322
+ });
323
+ if (result.code !== 0) {
324
+ throw new Error(`ps -Ao failed (code ${result.code}): ${result.stderr || result.stdout}`);
325
+ }
326
+ return pickHostPidFromPs(result.stdout, udid, executableName);
327
+ }
328
+ /** Pure: filter `ps` output for the simulator's app process. Exposed for tests. */
329
+ export function pickHostPidFromPs(psOutput, udid, executableName) {
330
+ const exeSuffix = `/${executableName}`;
331
+ const matches = [];
332
+ for (const line of psOutput.split(/\r?\n/)) {
333
+ const trimmed = line.trim();
334
+ if (!trimmed)
335
+ continue;
336
+ if (!trimmed.includes(udid))
337
+ continue;
338
+ const spaceIdx = trimmed.indexOf(" ");
339
+ if (spaceIdx === -1)
340
+ continue;
341
+ const pidStr = trimmed.slice(0, spaceIdx);
342
+ const command = trimmed.slice(spaceIdx + 1).trim();
343
+ // The actual binary path is the first token of the command (handles cases
344
+ // where the OS appends launch arguments).
345
+ const firstToken = command.split(/\s+/)[0];
346
+ if (!firstToken.endsWith(exeSuffix))
347
+ continue;
348
+ const pid = parseInt(pidStr, 10);
349
+ if (Number.isInteger(pid) && pid > 0) {
350
+ matches.push(pid);
351
+ }
352
+ }
353
+ if (matches.length === 0)
354
+ return null;
355
+ if (matches.length > 1) {
356
+ // Multiple host processes for the same UDID + executable shouldn't happen
357
+ // in practice (only one app instance per simulator), but if it does, the
358
+ // safest move is to return null and surface the ambiguity rather than
359
+ // attach to a stale PID.
360
+ return null;
361
+ }
362
+ return matches[0];
363
+ }
364
+ function sleep(ms) {
365
+ return new Promise((r) => setTimeout(r, ms));
366
+ }
367
+ //# sourceMappingURL=bootAndLaunchForLeakInvestigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootAndLaunchForLeakInvestigation.js","sourceRoot":"","sources":["../../src/tools/bootAndLaunchForLeakInvestigation.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import { z } from "zod";
2
+ import { type CommandResult } from "../runtime/exec.js";
3
+ import type { NextCallSuggestion } from "../types.js";
2
4
  /** Base shape — exposed so the MCP layer can read `.shape`. */
3
5
  export declare const captureMemgraphShape: {
4
6
  readonly pid: z.ZodOptional<z.ZodNumber>;
@@ -27,15 +29,41 @@ export declare const captureMemgraphSchema: z.ZodEffects<z.ZodObject<{
27
29
  appName?: string | undefined;
28
30
  }>;
29
31
  export type CaptureMemgraphInput = z.infer<typeof captureMemgraphSchema>;
32
+ export type WorkaroundIssue = "minimal-corpse" | "permission-denied" | "leaks-not-found" | "transient";
33
+ export interface WorkaroundNotice {
34
+ /** Stable identifier the LLM agent can branch on. */
35
+ issue: WorkaroundIssue;
36
+ /** Human-readable explanation of what went wrong. */
37
+ message: string;
38
+ /** Concrete next steps the agent can take to recover. */
39
+ fallbacks: string[];
40
+ }
30
41
  export interface CaptureMemgraphResult {
31
42
  ok: boolean;
32
43
  pid: number;
33
- output: string;
44
+ /** Present when `ok:true`. Absent on failure paths. */
45
+ output?: string;
34
46
  /**
35
47
  * Limitation reminder. Surfaced so callers stay aware of the device-physical caveat.
36
48
  */
37
49
  notice: string;
50
+ /** Non-fatal observations (e.g. MallocStackLogging not active → backtraces will be incomplete). */
51
+ warnings?: string[];
52
+ /** Structured failure info when `ok:false`. */
53
+ workaroundNotice?: WorkaroundNotice;
54
+ /** HATEOAS-style hints to recover via other tools. Populated on failure paths. */
55
+ suggestedNextCalls?: NextCallSuggestion[];
56
+ /** Raw stderr from `leaks` when capture failed. */
57
+ stderr?: string;
38
58
  }
39
59
  /** Resolve an app name to a PID via `pgrep -x`. Errors when zero or multiple matches. */
40
60
  export declare function resolveAppNameToPid(appName: string): Promise<number>;
61
+ /**
62
+ * Inspect a running process's environment block via `ps eww <pid>`.
63
+ * Returns true when MallocStackLogging is set, false otherwise. Returns null
64
+ * when the env cannot be read (e.g. process exited or restricted).
65
+ */
66
+ export declare function detectMallocStackLogging(pid: number): Promise<boolean | null>;
67
+ /** Pure: classify a leaks failure into a stable issue id, given exit + stderr. */
68
+ export declare function classifyLeaksFailure(result: CommandResult): WorkaroundIssue | null;
41
69
  export declare function captureMemgraph(input: CaptureMemgraphInput): Promise<CaptureMemgraphResult>;
@@ -37,7 +37,54 @@ export const captureMemgraphSchema = z
37
37
  });
38
38
  }
39
39
  });
40
- const PHYSICAL_DEVICE_NOTICE = "Note: `leaks --outputGraph` only works for processes running on the local Mac (which includes iOS simulators). It does not work for physical iOS devices use Xcode's Memory Graph button + File > Export Memory Graph for those.";
40
+ const PHYSICAL_DEVICE_NOTICE = "Note: `leaks --outputGraph` only works for processes running on the local Mac (which includes iOS simulators). It does not work for physical iOS devices, use Xcode's Memory Graph button + File > Export Memory Graph for those.";
41
+ const MINIMAL_CORPSE_RE = /Failed to get DYLD info for task|minimal corpse|task_create_corpse/i;
42
+ const PERMISSION_DENIED_RE = /Operation not permitted|task_for_pid.*failed|insufficient privileges/i;
43
+ const LEAKS_NOT_FOUND_CODE = 127;
44
+ const MINIMAL_CORPSE_MESSAGE = "leaks --outputGraph could not introspect the target process (known regression on macOS 26.x). The target's task port did not yield DYLD info, so leaks aborted before writing the graph.";
45
+ const MINIMAL_CORPSE_FALLBACKS = [
46
+ "Relaunch the app with MallocStackLogging=1 in its environment, then retry capture (Phase 2 tool: bootAndLaunchForLeakInvestigation).",
47
+ "Open Xcode > Debug > View Memory Graph Hierarchy on the running process, then File > Export Memory Graph to save a .memgraph manually.",
48
+ "Record an Allocations trace via recordTimeProfile (template Allocations) and inspect with analyzeAllocations. Not full cycle detection, but reveals top live classes.",
49
+ ];
50
+ const PERMISSION_DENIED_MESSAGE = "leaks could not attach to the target process (insufficient privileges or SIP). The capture cannot proceed without elevated access.";
51
+ const PERMISSION_DENIED_FALLBACKS = [
52
+ "Run the calling shell with sudo, or grant Developer Tools access to the parent process in System Settings > Privacy & Security.",
53
+ "Confirm the target process is signed with a debuggable entitlement (DEBUG build, not Release).",
54
+ "Use Xcode's Memory Graph button while the app is attached to the debugger.",
55
+ ];
56
+ const LEAKS_NOT_FOUND_MESSAGE = "The `leaks` binary was not found in PATH. It ships with the macOS Command Line Tools.";
57
+ const LEAKS_NOT_FOUND_FALLBACKS = [
58
+ "Install Xcode Command Line Tools: xcode-select --install",
59
+ "Verify with: which leaks",
60
+ ];
61
+ const TRANSIENT_MESSAGE = "leaks --outputGraph failed twice in a row with no recognized error pattern. This may be a transient timing issue or a process that exited mid-capture.";
62
+ const TRANSIENT_FALLBACKS = [
63
+ "Confirm the target process is still running (ps -p <pid>) and retry.",
64
+ "Capture a few seconds later, after the app finishes any heavy work.",
65
+ "Fall back to an Allocations trace via recordTimeProfile if leaks keeps failing.",
66
+ ];
67
+ /** Suggested calls that recover from a captureMemgraph failure via xctrace Allocations. */
68
+ function buildAllocationsFallbackSuggestions() {
69
+ return [
70
+ {
71
+ tool: "recordTimeProfile",
72
+ args: {
73
+ template: "Allocations",
74
+ simulatorId: "<UDID from listTraceDevices>",
75
+ attachAppName: "<app name>",
76
+ durationSec: 30,
77
+ output: "<absolute path ending in .trace>",
78
+ },
79
+ why: "Record an Allocations trace to identify top live classes when leaks --outputGraph cannot capture a memgraph. Use listTraceDevices first to find the simulator UDID.",
80
+ },
81
+ {
82
+ tool: "analyzeAllocations",
83
+ args: { tracePath: "<output from recordTimeProfile>" },
84
+ why: "Parse the Allocations trace for top allocators by bytes and persistent live counts. Not full cycle detection, but reveals leak suspects.",
85
+ },
86
+ ];
87
+ }
41
88
  /** Resolve an app name to a PID via `pgrep -x`. Errors when zero or multiple matches. */
42
89
  export async function resolveAppNameToPid(appName) {
43
90
  const result = await runCommand("pgrep", ["-x", appName], {
@@ -60,6 +107,70 @@ export async function resolveAppNameToPid(appName) {
60
107
  }
61
108
  return pids[0];
62
109
  }
110
+ /**
111
+ * Inspect a running process's environment block via `ps eww <pid>`.
112
+ * Returns true when MallocStackLogging is set, false otherwise. Returns null
113
+ * when the env cannot be read (e.g. process exited or restricted).
114
+ */
115
+ export async function detectMallocStackLogging(pid) {
116
+ try {
117
+ const result = await runCommand("ps", ["eww", String(pid)], {
118
+ timeoutMs: 5_000,
119
+ });
120
+ if (result.code !== 0)
121
+ return null;
122
+ return /\bMallocStackLogging=/.test(result.stdout);
123
+ }
124
+ catch {
125
+ return null;
126
+ }
127
+ }
128
+ /** Pure: classify a leaks failure into a stable issue id, given exit + stderr. */
129
+ export function classifyLeaksFailure(result) {
130
+ if (result.code === 0 || result.code === 1)
131
+ return null;
132
+ if (result.code === LEAKS_NOT_FOUND_CODE)
133
+ return "leaks-not-found";
134
+ const stderr = result.stderr || "";
135
+ if (MINIMAL_CORPSE_RE.test(stderr))
136
+ return "minimal-corpse";
137
+ if (PERMISSION_DENIED_RE.test(stderr))
138
+ return "permission-denied";
139
+ return "transient";
140
+ }
141
+ function buildWorkaround(issue) {
142
+ switch (issue) {
143
+ case "minimal-corpse":
144
+ return {
145
+ issue,
146
+ message: MINIMAL_CORPSE_MESSAGE,
147
+ fallbacks: MINIMAL_CORPSE_FALLBACKS,
148
+ };
149
+ case "permission-denied":
150
+ return {
151
+ issue,
152
+ message: PERMISSION_DENIED_MESSAGE,
153
+ fallbacks: PERMISSION_DENIED_FALLBACKS,
154
+ };
155
+ case "leaks-not-found":
156
+ return {
157
+ issue,
158
+ message: LEAKS_NOT_FOUND_MESSAGE,
159
+ fallbacks: LEAKS_NOT_FOUND_FALLBACKS,
160
+ };
161
+ case "transient":
162
+ return {
163
+ issue,
164
+ message: TRANSIENT_MESSAGE,
165
+ fallbacks: TRANSIENT_FALLBACKS,
166
+ };
167
+ }
168
+ }
169
+ async function runLeaksOnce(pid, output) {
170
+ return runCommand("leaks", ["--outputGraph", output, String(pid)], {
171
+ timeoutMs: 2 * 60_000,
172
+ });
173
+ }
63
174
  export async function captureMemgraph(input) {
64
175
  const output = resolvePath(input.output);
65
176
  const outDir = dirname(output);
@@ -70,14 +181,45 @@ export async function captureMemgraph(input) {
70
181
  (input.appName ? await resolveAppNameToPid(input.appName) : 0);
71
182
  if (!pid)
72
183
  throw new Error("Could not determine a PID to capture.");
73
- const result = await runCommand("leaks", ["--outputGraph", output, String(pid)], { timeoutMs: 2 * 60_000 });
74
- // `leaks --outputGraph` writes the file even when leaks are present (exit 1).
75
- if (result.code !== 0 && result.code !== 1) {
76
- throw new Error(`leaks --outputGraph failed (code ${result.code}): ${result.stderr || result.stdout}`);
184
+ const warnings = [];
185
+ const hasMallocLogging = await detectMallocStackLogging(pid);
186
+ if (hasMallocLogging === false) {
187
+ warnings.push("MallocStackLogging is not active on the target process. The .memgraph will lack allocation backtraces, which limits findRetainers/reachableFromCycle precision. Relaunch the app with MallocStackLogging=1 (Phase 2: bootAndLaunchForLeakInvestigation) for full fidelity.");
77
188
  }
189
+ let result = await runLeaksOnce(pid, output);
190
+ let issue = classifyLeaksFailure(result);
191
+ // Single retry on transient failures only. Deterministic issues (minimal-corpse,
192
+ // permission-denied, leaks-not-found) won't change between attempts.
193
+ if (issue === "transient") {
194
+ await new Promise((r) => setTimeout(r, 1000));
195
+ result = await runLeaksOnce(pid, output);
196
+ issue = classifyLeaksFailure(result);
197
+ }
198
+ if (issue) {
199
+ const workaroundNotice = buildWorkaround(issue);
200
+ const suggestedNextCalls = issue === "minimal-corpse" || issue === "transient"
201
+ ? buildAllocationsFallbackSuggestions()
202
+ : undefined;
203
+ return {
204
+ ok: false,
205
+ pid,
206
+ notice: PHYSICAL_DEVICE_NOTICE,
207
+ ...(warnings.length > 0 ? { warnings } : {}),
208
+ workaroundNotice,
209
+ ...(suggestedNextCalls ? { suggestedNextCalls } : {}),
210
+ stderr: result.stderr || result.stdout,
211
+ };
212
+ }
213
+ // `leaks --outputGraph` writes the file even when leaks are present (exit 1).
78
214
  if (!existsSync(output)) {
79
215
  throw new Error(`leaks reported success but output file is missing: ${output}`);
80
216
  }
81
- return { ok: true, pid, output, notice: PHYSICAL_DEVICE_NOTICE };
217
+ return {
218
+ ok: true,
219
+ pid,
220
+ output,
221
+ notice: PHYSICAL_DEVICE_NOTICE,
222
+ ...(warnings.length > 0 ? { warnings } : {}),
223
+ };
82
224
  }
83
225
  //# sourceMappingURL=captureMemgraph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"captureMemgraph.js","sourceRoot":"","sources":["../../src/tools/captureMemgraph.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"captureMemgraph.js","sourceRoot":"","sources":["../../src/tools/captureMemgraph.ts"],"names":[],"mappings":"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"}