memorydetective 1.7.0 → 1.8.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.
- package/CHANGELOG.md +27 -0
- package/README.md +61 -29
- package/USAGE.md +87 -41
- package/dist/index.js +34 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/axe.d.ts +86 -0
- package/dist/runtime/axe.js +249 -0
- package/dist/runtime/axe.js.map +1 -0
- package/dist/runtime/buildSettings.d.ts +27 -0
- package/dist/runtime/buildSettings.js +88 -0
- package/dist/runtime/buildSettings.js.map +1 -0
- package/dist/runtime/exec.d.ts +8 -1
- package/dist/runtime/exec.js +8 -2
- package/dist/runtime/exec.js.map +1 -1
- package/dist/runtime/simctl.d.ts +68 -0
- package/dist/runtime/simctl.js +194 -0
- package/dist/runtime/simctl.js.map +1 -0
- package/dist/tools/bootAndLaunchForLeakInvestigation.d.ts +166 -0
- package/dist/tools/bootAndLaunchForLeakInvestigation.js +367 -0
- package/dist/tools/bootAndLaunchForLeakInvestigation.js.map +1 -0
- package/dist/tools/captureMemgraph.d.ts +29 -1
- package/dist/tools/captureMemgraph.js +148 -6
- package/dist/tools/captureMemgraph.js.map +1 -1
- package/dist/tools/captureScenarioState.d.ts +77 -0
- package/dist/tools/captureScenarioState.js +159 -0
- package/dist/tools/captureScenarioState.js.map +1 -0
- package/dist/tools/detectLeaksInXCUITest.d.ts +2 -2
- package/dist/tools/getInvestigationPlaybook.d.ts +15 -0
- package/dist/tools/getInvestigationPlaybook.js +24 -1
- package/dist/tools/getInvestigationPlaybook.js.map +1 -1
- package/dist/tools/replayScenario.d.ts +243 -0
- package/dist/tools/replayScenario.js +187 -0
- package/dist/tools/replayScenario.js.map +1 -0
- package/package.json +2 -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
|
-
|
|
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
|
|
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
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
|
|
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 {
|
|
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":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"captureMemgraph.js","sourceRoot":"","sources":["../../src/tools/captureMemgraph.ts"],"names":[],"mappings":"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"}
|