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.
- package/CHANGELOG.md +41 -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 +3 -2
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite snapshot for verify-fix loops: capture a memgraph + screenshot +
|
|
3
|
+
* UI tree from the current simulator state into one labeled bundle. The
|
|
4
|
+
* intended workflow is `captureScenarioState({label:"before"})` → run a fix
|
|
5
|
+
* (or further repro via replayScenario) → `captureScenarioState({label:"after"})`
|
|
6
|
+
* → diffMemgraphs across the two outputs.
|
|
7
|
+
*
|
|
8
|
+
* Each sub-capture (memgraph, screenshot, uiTree) is best-effort: if one
|
|
9
|
+
* fails, the others still proceed and the failure is surfaced via
|
|
10
|
+
* `subFailures` so the caller has partial state instead of nothing.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import { type WorkaroundNotice } from "./captureMemgraph.js";
|
|
14
|
+
export declare const captureScenarioStateShape: {
|
|
15
|
+
readonly simulatorUDID: z.ZodString;
|
|
16
|
+
readonly pid: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
readonly appName: z.ZodOptional<z.ZodString>;
|
|
18
|
+
readonly outputDir: z.ZodString;
|
|
19
|
+
readonly label: z.ZodDefault<z.ZodString>;
|
|
20
|
+
readonly include: z.ZodDefault<z.ZodArray<z.ZodEnum<["memgraph", "screenshot", "uiTree"]>, "many">>;
|
|
21
|
+
};
|
|
22
|
+
export declare const captureScenarioStateSchema: z.ZodEffects<z.ZodObject<{
|
|
23
|
+
readonly simulatorUDID: z.ZodString;
|
|
24
|
+
readonly pid: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
readonly appName: z.ZodOptional<z.ZodString>;
|
|
26
|
+
readonly outputDir: z.ZodString;
|
|
27
|
+
readonly label: z.ZodDefault<z.ZodString>;
|
|
28
|
+
readonly include: z.ZodDefault<z.ZodArray<z.ZodEnum<["memgraph", "screenshot", "uiTree"]>, "many">>;
|
|
29
|
+
}, "strip", z.ZodTypeAny, {
|
|
30
|
+
simulatorUDID: string;
|
|
31
|
+
label: string;
|
|
32
|
+
outputDir: string;
|
|
33
|
+
include: ("screenshot" | "memgraph" | "uiTree")[];
|
|
34
|
+
pid?: number | undefined;
|
|
35
|
+
appName?: string | undefined;
|
|
36
|
+
}, {
|
|
37
|
+
simulatorUDID: string;
|
|
38
|
+
outputDir: string;
|
|
39
|
+
pid?: number | undefined;
|
|
40
|
+
appName?: string | undefined;
|
|
41
|
+
label?: string | undefined;
|
|
42
|
+
include?: ("screenshot" | "memgraph" | "uiTree")[] | undefined;
|
|
43
|
+
}>, {
|
|
44
|
+
simulatorUDID: string;
|
|
45
|
+
label: string;
|
|
46
|
+
outputDir: string;
|
|
47
|
+
include: ("screenshot" | "memgraph" | "uiTree")[];
|
|
48
|
+
pid?: number | undefined;
|
|
49
|
+
appName?: string | undefined;
|
|
50
|
+
}, {
|
|
51
|
+
simulatorUDID: string;
|
|
52
|
+
outputDir: string;
|
|
53
|
+
pid?: number | undefined;
|
|
54
|
+
appName?: string | undefined;
|
|
55
|
+
label?: string | undefined;
|
|
56
|
+
include?: ("screenshot" | "memgraph" | "uiTree")[] | undefined;
|
|
57
|
+
}>;
|
|
58
|
+
export type CaptureScenarioStateInput = z.infer<typeof captureScenarioStateSchema>;
|
|
59
|
+
export interface CaptureScenarioSubFailure {
|
|
60
|
+
kind: "memgraph" | "screenshot" | "uiTree";
|
|
61
|
+
reason: string;
|
|
62
|
+
}
|
|
63
|
+
export interface CaptureScenarioStateResult {
|
|
64
|
+
ok: boolean;
|
|
65
|
+
label: string;
|
|
66
|
+
outputDir: string;
|
|
67
|
+
memgraphPath?: string;
|
|
68
|
+
screenshotPath?: string;
|
|
69
|
+
uiTreePath?: string;
|
|
70
|
+
/** Surfaced from captureMemgraph when leaks fails with a known issue. */
|
|
71
|
+
memgraphWorkaroundNotice?: WorkaroundNotice;
|
|
72
|
+
subFailures: CaptureScenarioSubFailure[];
|
|
73
|
+
warnings?: string[];
|
|
74
|
+
}
|
|
75
|
+
export declare function captureScenarioState(input: CaptureScenarioStateInput): Promise<CaptureScenarioStateResult>;
|
|
76
|
+
/** Pure: replace filesystem-unsafe characters in a label. Exposed for tests. */
|
|
77
|
+
export declare function sanitizeLabel(label: string): string;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite snapshot for verify-fix loops: capture a memgraph + screenshot +
|
|
3
|
+
* UI tree from the current simulator state into one labeled bundle. The
|
|
4
|
+
* intended workflow is `captureScenarioState({label:"before"})` → run a fix
|
|
5
|
+
* (or further repro via replayScenario) → `captureScenarioState({label:"after"})`
|
|
6
|
+
* → diffMemgraphs across the two outputs.
|
|
7
|
+
*
|
|
8
|
+
* Each sub-capture (memgraph, screenshot, uiTree) is best-effort: if one
|
|
9
|
+
* fails, the others still proceed and the failure is surfaced via
|
|
10
|
+
* `subFailures` so the caller has partial state instead of nothing.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
14
|
+
import { writeFile } from "node:fs/promises";
|
|
15
|
+
import { join as joinPath, resolve as resolvePath } from "node:path";
|
|
16
|
+
import { captureMemgraph, } from "./captureMemgraph.js";
|
|
17
|
+
import { takeScreenshot } from "../runtime/simctl.js";
|
|
18
|
+
import { checkAxeAvailable, describeUI } from "../runtime/axe.js";
|
|
19
|
+
export const captureScenarioStateShape = {
|
|
20
|
+
simulatorUDID: z
|
|
21
|
+
.string()
|
|
22
|
+
.min(1)
|
|
23
|
+
.describe("UDID of the booted simulator hosting the target app. Used for screenshot + UI tree captures."),
|
|
24
|
+
pid: z
|
|
25
|
+
.number()
|
|
26
|
+
.int()
|
|
27
|
+
.positive()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("PID of the host-side app process. Mutually exclusive with `appName`. Pass the value returned by bootAndLaunchForLeakInvestigation."),
|
|
30
|
+
appName: z
|
|
31
|
+
.string()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("App executable name as visible in pgrep. Mutually exclusive with `pid`."),
|
|
34
|
+
outputDir: z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1)
|
|
37
|
+
.describe("Absolute directory where the snapshot files are written. Created if it does not exist."),
|
|
38
|
+
label: z
|
|
39
|
+
.string()
|
|
40
|
+
.min(1)
|
|
41
|
+
.default("snapshot")
|
|
42
|
+
.describe("Filename prefix for the captured artifacts. Use \"before\" / \"after\" for verify-fix flows."),
|
|
43
|
+
include: z
|
|
44
|
+
.array(z.enum(["memgraph", "screenshot", "uiTree"]))
|
|
45
|
+
.default(["memgraph", "screenshot", "uiTree"])
|
|
46
|
+
.describe("Which artifacts to capture. Default captures all three."),
|
|
47
|
+
};
|
|
48
|
+
export const captureScenarioStateSchema = z
|
|
49
|
+
.object(captureScenarioStateShape)
|
|
50
|
+
.superRefine((val, ctx) => {
|
|
51
|
+
const targets = [val.pid, val.appName].filter((v) => v !== undefined).length;
|
|
52
|
+
if (targets !== 1) {
|
|
53
|
+
ctx.addIssue({
|
|
54
|
+
code: z.ZodIssueCode.custom,
|
|
55
|
+
message: "Provide exactly one of `pid` or `appName`.",
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
export async function captureScenarioState(input) {
|
|
60
|
+
const outputDir = resolvePath(input.outputDir);
|
|
61
|
+
if (!existsSync(outputDir)) {
|
|
62
|
+
mkdirSync(outputDir, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
const subFailures = [];
|
|
65
|
+
const warnings = [];
|
|
66
|
+
const safeLabel = sanitizeLabel(input.label);
|
|
67
|
+
let memgraphPath;
|
|
68
|
+
let memgraphWorkaroundNotice;
|
|
69
|
+
if (input.include.includes("memgraph")) {
|
|
70
|
+
const target = joinPath(outputDir, `${safeLabel}.memgraph`);
|
|
71
|
+
try {
|
|
72
|
+
const result = await captureMemgraph({
|
|
73
|
+
...(input.pid ? { pid: input.pid } : {}),
|
|
74
|
+
...(input.appName ? { appName: input.appName } : {}),
|
|
75
|
+
output: target,
|
|
76
|
+
});
|
|
77
|
+
if (result.ok && result.output) {
|
|
78
|
+
memgraphPath = result.output;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
memgraphWorkaroundNotice = result.workaroundNotice;
|
|
82
|
+
subFailures.push({
|
|
83
|
+
kind: "memgraph",
|
|
84
|
+
reason: result.workaroundNotice?.message ??
|
|
85
|
+
result.stderr ??
|
|
86
|
+
"captureMemgraph reported ok:false without a workaroundNotice.",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (result.warnings) {
|
|
90
|
+
warnings.push(...result.warnings);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
subFailures.push({
|
|
95
|
+
kind: "memgraph",
|
|
96
|
+
reason: err.message,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
let screenshotPath;
|
|
101
|
+
if (input.include.includes("screenshot")) {
|
|
102
|
+
const target = joinPath(outputDir, `${safeLabel}.png`);
|
|
103
|
+
try {
|
|
104
|
+
await takeScreenshot(input.simulatorUDID, target);
|
|
105
|
+
screenshotPath = target;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
subFailures.push({
|
|
109
|
+
kind: "screenshot",
|
|
110
|
+
reason: err.message,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
let uiTreePath;
|
|
115
|
+
if (input.include.includes("uiTree")) {
|
|
116
|
+
const target = joinPath(outputDir, `${safeLabel}.ui.json`);
|
|
117
|
+
const availability = await checkAxeAvailable();
|
|
118
|
+
if (!availability.available) {
|
|
119
|
+
subFailures.push({
|
|
120
|
+
kind: "uiTree",
|
|
121
|
+
reason: availability.installHint ??
|
|
122
|
+
"axe CLI not found. uiTree capture requires axe.",
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
try {
|
|
127
|
+
const tree = await describeUI(input.simulatorUDID);
|
|
128
|
+
await writeFile(target, JSON.stringify(tree, null, 2), "utf8");
|
|
129
|
+
uiTreePath = target;
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
subFailures.push({
|
|
133
|
+
kind: "uiTree",
|
|
134
|
+
reason: err.message,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const ok = subFailures.length === 0;
|
|
140
|
+
return {
|
|
141
|
+
ok,
|
|
142
|
+
label: input.label,
|
|
143
|
+
outputDir,
|
|
144
|
+
...(memgraphPath ? { memgraphPath } : {}),
|
|
145
|
+
...(screenshotPath ? { screenshotPath } : {}),
|
|
146
|
+
...(uiTreePath ? { uiTreePath } : {}),
|
|
147
|
+
...(memgraphWorkaroundNotice ? { memgraphWorkaroundNotice } : {}),
|
|
148
|
+
subFailures,
|
|
149
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/** Pure: replace filesystem-unsafe characters in a label. Exposed for tests. */
|
|
153
|
+
export function sanitizeLabel(label) {
|
|
154
|
+
return label
|
|
155
|
+
.replace(/[\/\\:*?"<>|\s]+/g, "-")
|
|
156
|
+
.replace(/^-+|-+$/g, "")
|
|
157
|
+
.slice(0, 64) || "snapshot";
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=captureScenarioState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captureScenarioState.js","sourceRoot":"","sources":["../../src/tools/captureScenarioState.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,EACL,eAAe,GAGhB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAElE,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,8FAA8F,CAC/F;IACH,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,QAAQ,EAAE;SACV,QAAQ,CACP,oIAAoI,CACrI;IACH,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,yEAAyE,CAC1E;IACH,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,wFAAwF,CACzF;IACH,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,OAAO,CAAC,UAAU,CAAC;SACnB,QAAQ,CACP,8FAA8F,CAC/F;IACH,OAAO,EAAE,CAAC;SACP,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;SACnD,OAAO,CAAC,CAAC,UAAU,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;SAC7C,QAAQ,CACP,yDAAyD,CAC1D;CACK,CAAC;AAEX,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC;KACxC,MAAM,CAAC,yBAAyB,CAAC;KACjC,WAAW,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACxB,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAC7E,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;QAClB,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,4CAA4C;SACtD,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAwBL,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAgC;IAEhC,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,WAAW,GAAgC,EAAE,CAAC;IACpD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7C,IAAI,YAAgC,CAAC;IACrC,IAAI,wBAAsD,CAAC;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,SAAS,WAAW,CAAC,CAAC;QAC5D,IAAI,CAAC;YACH,MAAM,MAAM,GAA0B,MAAM,eAAe,CAAC;gBAC1D,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpD,MAAM,EAAE,MAAM;aAC0B,CAAC,CAAC;YAC5C,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC/B,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,wBAAwB,GAAG,MAAM,CAAC,gBAAgB,CAAC;gBACnD,WAAW,CAAC,IAAI,CAAC;oBACf,IAAI,EAAE,UAAU;oBAChB,MAAM,EACJ,MAAM,CAAC,gBAAgB,EAAE,OAAO;wBAChC,MAAM,CAAC,MAAM;wBACb,+DAA+D;iBAClE,CAAC,CAAC;YACL,CAAC;YACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACpB,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAG,GAAa,CAAC,OAAO;aAC/B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,cAAkC,CAAC;IACvC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,SAAS,MAAM,CAAC,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,cAAc,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YAClD,cAAc,GAAG,MAAM,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAG,GAAa,CAAC,OAAO;aAC/B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,UAA8B,CAAC;IACnC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,SAAS,UAAU,CAAC,CAAC;QAC3D,MAAM,YAAY,GAAG,MAAM,iBAAiB,EAAE,CAAC;QAC/C,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC;YAC5B,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,QAAQ;gBACd,MAAM,EACJ,YAAY,CAAC,WAAW;oBACxB,iDAAiD;aACpD,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;gBACnD,MAAM,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;gBAC/D,UAAU,GAAG,MAAM,CAAC;YACtB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,WAAW,CAAC,IAAI,CAAC;oBACf,IAAI,EAAE,QAAQ;oBACd,MAAM,EAAG,GAAa,CAAC,OAAO;iBAC/B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC;IACpC,OAAO;QACL,EAAE;QACF,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,SAAS;QACT,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,wBAAwB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,WAAW;QACX,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,KAAK;SACT,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC;SACjC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC;AAChC,CAAC"}
|
|
@@ -29,9 +29,9 @@ export declare const detectLeaksInXCUITestSchema: z.ZodObject<{
|
|
|
29
29
|
appName: string;
|
|
30
30
|
workspace: string;
|
|
31
31
|
scheme: string;
|
|
32
|
+
outputDir: string;
|
|
32
33
|
testIdentifier: string;
|
|
33
34
|
destination: string;
|
|
34
|
-
outputDir: string;
|
|
35
35
|
allowlistPatterns: string[];
|
|
36
36
|
skipBuild: boolean;
|
|
37
37
|
}, {
|
|
@@ -39,8 +39,8 @@ export declare const detectLeaksInXCUITestSchema: z.ZodObject<{
|
|
|
39
39
|
workspace: string;
|
|
40
40
|
scheme: string;
|
|
41
41
|
testIdentifier: string;
|
|
42
|
-
destination?: string | undefined;
|
|
43
42
|
outputDir?: string | undefined;
|
|
43
|
+
destination?: string | undefined;
|
|
44
44
|
allowlistPatterns?: string[] | undefined;
|
|
45
45
|
skipBuild?: boolean | undefined;
|
|
46
46
|
}>;
|
|
@@ -27,12 +27,27 @@ export interface PlaybookStep {
|
|
|
27
27
|
/** Optional notes about how to interpret the result before moving to the next step. */
|
|
28
28
|
resultGuidance?: string;
|
|
29
29
|
}
|
|
30
|
+
export interface PlaybookTroubleshooting {
|
|
31
|
+
/** Tool whose failure this entry addresses. */
|
|
32
|
+
tool: string;
|
|
33
|
+
/**
|
|
34
|
+
* Stable identifier matching `workaroundNotice.issue` when the underlying
|
|
35
|
+
* tool emits one. Lets the LLM agent branch deterministically.
|
|
36
|
+
*/
|
|
37
|
+
issueId?: string;
|
|
38
|
+
/** One-line description of the symptom that triggers this entry. */
|
|
39
|
+
trigger: string;
|
|
40
|
+
/** Ordered recovery steps the agent can take. */
|
|
41
|
+
recovery: string[];
|
|
42
|
+
}
|
|
30
43
|
export interface Playbook {
|
|
31
44
|
kind: PlaybookKind;
|
|
32
45
|
summary: string;
|
|
33
46
|
steps: PlaybookStep[];
|
|
34
47
|
/** Pointers to alternative playbooks the agent might want next. */
|
|
35
48
|
seeAlso?: PlaybookKind[];
|
|
49
|
+
/** Known failure modes for tools used in this playbook + recovery paths. */
|
|
50
|
+
troubleshooting?: PlaybookTroubleshooting[];
|
|
36
51
|
}
|
|
37
52
|
declare const PLAYBOOKS: Record<PlaybookKind, Playbook>;
|
|
38
53
|
export interface GetInvestigationPlaybookResult {
|
|
@@ -69,7 +69,7 @@ const PLAYBOOKS = {
|
|
|
69
69
|
{
|
|
70
70
|
step: 6,
|
|
71
71
|
tool: "swiftFindSymbolReferences",
|
|
72
|
-
purpose: "List every callsite
|
|
72
|
+
purpose: "List every callsite, useful to compare capture-list patterns across them and detect inconsistencies.",
|
|
73
73
|
argsTemplate: {
|
|
74
74
|
symbolName: "<class from step 3>",
|
|
75
75
|
filePath: "<from step 5 result>",
|
|
@@ -77,6 +77,29 @@ const PLAYBOOKS = {
|
|
|
77
77
|
},
|
|
78
78
|
],
|
|
79
79
|
seeAlso: ["verify-fix"],
|
|
80
|
+
troubleshooting: [
|
|
81
|
+
{
|
|
82
|
+
tool: "captureMemgraph",
|
|
83
|
+
issueId: "minimal-corpse",
|
|
84
|
+
trigger: "leaks --outputGraph aborts with 'Failed to get DYLD info for task' on macOS 26.x. Known regression in Apple's leaks tooling.",
|
|
85
|
+
recovery: [
|
|
86
|
+
"Read `workaroundNotice.fallbacks` from the captureMemgraph result for ordered options.",
|
|
87
|
+
"Open Xcode > Debug > View Memory Graph Hierarchy on the running process, then File > Export Memory Graph to save a .memgraph manually. Pass that path to analyzeMemgraph.",
|
|
88
|
+
"Fall back to recordTimeProfile (template Allocations) + analyzeAllocations to identify top live classes. This is not full cycle detection but reveals leak suspects.",
|
|
89
|
+
"Once Phase 2 ships, relaunch the app via bootAndLaunchForLeakInvestigation with MallocStackLogging=1 and retry capture.",
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
tool: "captureMemgraph",
|
|
94
|
+
issueId: "permission-denied",
|
|
95
|
+
trigger: "leaks cannot attach to the target process due to insufficient privileges (task_for_pid failure).",
|
|
96
|
+
recovery: [
|
|
97
|
+
"Confirm the target was built with a debuggable entitlement (DEBUG, not Release).",
|
|
98
|
+
"Grant Developer Tools access to the parent shell in System Settings > Privacy & Security.",
|
|
99
|
+
"Use Xcode's Memory Graph button while the app is attached to the debugger.",
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
],
|
|
80
103
|
},
|
|
81
104
|
"perf-hangs": {
|
|
82
105
|
kind: "perf-hangs",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getInvestigationPlaybook.js","sourceRoot":"","sources":["../../src/tools/getInvestigationPlaybook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC;IACrC,eAAe;IACf,YAAY;IACZ,SAAS;IACT,iBAAiB;IACjB,YAAY;CACb,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC,MAAM,CAAC;IACrD,IAAI,EAAE,gBAAgB,CAAC,QAAQ,CAC7B,8JAA8J,CAC/J;CACF,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"getInvestigationPlaybook.js","sourceRoot":"","sources":["../../src/tools/getInvestigationPlaybook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drive the iOS Simulator through a sequence of UI actions to amplify a
|
|
3
|
+
* suspected leak before capturing a memgraph. Tied to the leak/perf workflow:
|
|
4
|
+
* the only reason this tool exists is to make verify-fix loops reproducible
|
|
5
|
+
* (same scenario before/after a fix) and to surface leaks that only manifest
|
|
6
|
+
* after N iterations of a flow.
|
|
7
|
+
*
|
|
8
|
+
* Soft dependency on `axe` (https://github.com/cameroncooke/AXe). When axe is
|
|
9
|
+
* not on PATH, this tool returns ok:false with a structured workaroundNotice
|
|
10
|
+
* pointing the caller at the install instructions, instead of throwing.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import { type TapTarget } from "../runtime/axe.js";
|
|
14
|
+
declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
15
|
+
type: z.ZodLiteral<"tap">;
|
|
16
|
+
label: z.ZodOptional<z.ZodString>;
|
|
17
|
+
elementId: z.ZodOptional<z.ZodString>;
|
|
18
|
+
coords: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
type: "tap";
|
|
21
|
+
label?: string | undefined;
|
|
22
|
+
elementId?: string | undefined;
|
|
23
|
+
coords?: [number, number] | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
type: "tap";
|
|
26
|
+
label?: string | undefined;
|
|
27
|
+
elementId?: string | undefined;
|
|
28
|
+
coords?: [number, number] | undefined;
|
|
29
|
+
}>, z.ZodObject<{
|
|
30
|
+
type: z.ZodLiteral<"swipe">;
|
|
31
|
+
from: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
32
|
+
to: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
33
|
+
durationMs: z.ZodDefault<z.ZodNumber>;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
type: "swipe";
|
|
36
|
+
from: [number, number];
|
|
37
|
+
to: [number, number];
|
|
38
|
+
durationMs: number;
|
|
39
|
+
}, {
|
|
40
|
+
type: "swipe";
|
|
41
|
+
from: [number, number];
|
|
42
|
+
to: [number, number];
|
|
43
|
+
durationMs?: number | undefined;
|
|
44
|
+
}>, z.ZodObject<{
|
|
45
|
+
type: z.ZodLiteral<"wait">;
|
|
46
|
+
seconds: z.ZodNumber;
|
|
47
|
+
}, "strip", z.ZodTypeAny, {
|
|
48
|
+
type: "wait";
|
|
49
|
+
seconds: number;
|
|
50
|
+
}, {
|
|
51
|
+
type: "wait";
|
|
52
|
+
seconds: number;
|
|
53
|
+
}>, z.ZodObject<{
|
|
54
|
+
type: z.ZodLiteral<"type">;
|
|
55
|
+
text: z.ZodString;
|
|
56
|
+
}, "strip", z.ZodTypeAny, {
|
|
57
|
+
type: "type";
|
|
58
|
+
text: string;
|
|
59
|
+
}, {
|
|
60
|
+
type: "type";
|
|
61
|
+
text: string;
|
|
62
|
+
}>]>;
|
|
63
|
+
export type ReplayAction = z.infer<typeof actionSchema>;
|
|
64
|
+
export declare const replayScenarioShape: {
|
|
65
|
+
readonly simulatorUDID: z.ZodString;
|
|
66
|
+
readonly actions: z.ZodArray<z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
67
|
+
type: z.ZodLiteral<"tap">;
|
|
68
|
+
label: z.ZodOptional<z.ZodString>;
|
|
69
|
+
elementId: z.ZodOptional<z.ZodString>;
|
|
70
|
+
coords: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
|
|
71
|
+
}, "strip", z.ZodTypeAny, {
|
|
72
|
+
type: "tap";
|
|
73
|
+
label?: string | undefined;
|
|
74
|
+
elementId?: string | undefined;
|
|
75
|
+
coords?: [number, number] | undefined;
|
|
76
|
+
}, {
|
|
77
|
+
type: "tap";
|
|
78
|
+
label?: string | undefined;
|
|
79
|
+
elementId?: string | undefined;
|
|
80
|
+
coords?: [number, number] | undefined;
|
|
81
|
+
}>, z.ZodObject<{
|
|
82
|
+
type: z.ZodLiteral<"swipe">;
|
|
83
|
+
from: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
84
|
+
to: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
85
|
+
durationMs: z.ZodDefault<z.ZodNumber>;
|
|
86
|
+
}, "strip", z.ZodTypeAny, {
|
|
87
|
+
type: "swipe";
|
|
88
|
+
from: [number, number];
|
|
89
|
+
to: [number, number];
|
|
90
|
+
durationMs: number;
|
|
91
|
+
}, {
|
|
92
|
+
type: "swipe";
|
|
93
|
+
from: [number, number];
|
|
94
|
+
to: [number, number];
|
|
95
|
+
durationMs?: number | undefined;
|
|
96
|
+
}>, z.ZodObject<{
|
|
97
|
+
type: z.ZodLiteral<"wait">;
|
|
98
|
+
seconds: z.ZodNumber;
|
|
99
|
+
}, "strip", z.ZodTypeAny, {
|
|
100
|
+
type: "wait";
|
|
101
|
+
seconds: number;
|
|
102
|
+
}, {
|
|
103
|
+
type: "wait";
|
|
104
|
+
seconds: number;
|
|
105
|
+
}>, z.ZodObject<{
|
|
106
|
+
type: z.ZodLiteral<"type">;
|
|
107
|
+
text: z.ZodString;
|
|
108
|
+
}, "strip", z.ZodTypeAny, {
|
|
109
|
+
type: "type";
|
|
110
|
+
text: string;
|
|
111
|
+
}, {
|
|
112
|
+
type: "type";
|
|
113
|
+
text: string;
|
|
114
|
+
}>]>, "many">;
|
|
115
|
+
readonly repeat: z.ZodDefault<z.ZodNumber>;
|
|
116
|
+
readonly settleBetweenActionsMs: z.ZodDefault<z.ZodNumber>;
|
|
117
|
+
readonly finalUITreePath: z.ZodOptional<z.ZodString>;
|
|
118
|
+
};
|
|
119
|
+
export declare const replayScenarioSchema: z.ZodObject<{
|
|
120
|
+
readonly simulatorUDID: z.ZodString;
|
|
121
|
+
readonly actions: z.ZodArray<z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
122
|
+
type: z.ZodLiteral<"tap">;
|
|
123
|
+
label: z.ZodOptional<z.ZodString>;
|
|
124
|
+
elementId: z.ZodOptional<z.ZodString>;
|
|
125
|
+
coords: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
|
|
126
|
+
}, "strip", z.ZodTypeAny, {
|
|
127
|
+
type: "tap";
|
|
128
|
+
label?: string | undefined;
|
|
129
|
+
elementId?: string | undefined;
|
|
130
|
+
coords?: [number, number] | undefined;
|
|
131
|
+
}, {
|
|
132
|
+
type: "tap";
|
|
133
|
+
label?: string | undefined;
|
|
134
|
+
elementId?: string | undefined;
|
|
135
|
+
coords?: [number, number] | undefined;
|
|
136
|
+
}>, z.ZodObject<{
|
|
137
|
+
type: z.ZodLiteral<"swipe">;
|
|
138
|
+
from: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
139
|
+
to: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
140
|
+
durationMs: z.ZodDefault<z.ZodNumber>;
|
|
141
|
+
}, "strip", z.ZodTypeAny, {
|
|
142
|
+
type: "swipe";
|
|
143
|
+
from: [number, number];
|
|
144
|
+
to: [number, number];
|
|
145
|
+
durationMs: number;
|
|
146
|
+
}, {
|
|
147
|
+
type: "swipe";
|
|
148
|
+
from: [number, number];
|
|
149
|
+
to: [number, number];
|
|
150
|
+
durationMs?: number | undefined;
|
|
151
|
+
}>, z.ZodObject<{
|
|
152
|
+
type: z.ZodLiteral<"wait">;
|
|
153
|
+
seconds: z.ZodNumber;
|
|
154
|
+
}, "strip", z.ZodTypeAny, {
|
|
155
|
+
type: "wait";
|
|
156
|
+
seconds: number;
|
|
157
|
+
}, {
|
|
158
|
+
type: "wait";
|
|
159
|
+
seconds: number;
|
|
160
|
+
}>, z.ZodObject<{
|
|
161
|
+
type: z.ZodLiteral<"type">;
|
|
162
|
+
text: z.ZodString;
|
|
163
|
+
}, "strip", z.ZodTypeAny, {
|
|
164
|
+
type: "type";
|
|
165
|
+
text: string;
|
|
166
|
+
}, {
|
|
167
|
+
type: "type";
|
|
168
|
+
text: string;
|
|
169
|
+
}>]>, "many">;
|
|
170
|
+
readonly repeat: z.ZodDefault<z.ZodNumber>;
|
|
171
|
+
readonly settleBetweenActionsMs: z.ZodDefault<z.ZodNumber>;
|
|
172
|
+
readonly finalUITreePath: z.ZodOptional<z.ZodString>;
|
|
173
|
+
}, "strip", z.ZodTypeAny, {
|
|
174
|
+
repeat: number;
|
|
175
|
+
simulatorUDID: string;
|
|
176
|
+
actions: ({
|
|
177
|
+
type: "tap";
|
|
178
|
+
label?: string | undefined;
|
|
179
|
+
elementId?: string | undefined;
|
|
180
|
+
coords?: [number, number] | undefined;
|
|
181
|
+
} | {
|
|
182
|
+
type: "swipe";
|
|
183
|
+
from: [number, number];
|
|
184
|
+
to: [number, number];
|
|
185
|
+
durationMs: number;
|
|
186
|
+
} | {
|
|
187
|
+
type: "wait";
|
|
188
|
+
seconds: number;
|
|
189
|
+
} | {
|
|
190
|
+
type: "type";
|
|
191
|
+
text: string;
|
|
192
|
+
})[];
|
|
193
|
+
settleBetweenActionsMs: number;
|
|
194
|
+
finalUITreePath?: string | undefined;
|
|
195
|
+
}, {
|
|
196
|
+
simulatorUDID: string;
|
|
197
|
+
actions: ({
|
|
198
|
+
type: "tap";
|
|
199
|
+
label?: string | undefined;
|
|
200
|
+
elementId?: string | undefined;
|
|
201
|
+
coords?: [number, number] | undefined;
|
|
202
|
+
} | {
|
|
203
|
+
type: "swipe";
|
|
204
|
+
from: [number, number];
|
|
205
|
+
to: [number, number];
|
|
206
|
+
durationMs?: number | undefined;
|
|
207
|
+
} | {
|
|
208
|
+
type: "wait";
|
|
209
|
+
seconds: number;
|
|
210
|
+
} | {
|
|
211
|
+
type: "type";
|
|
212
|
+
text: string;
|
|
213
|
+
})[];
|
|
214
|
+
repeat?: number | undefined;
|
|
215
|
+
settleBetweenActionsMs?: number | undefined;
|
|
216
|
+
finalUITreePath?: string | undefined;
|
|
217
|
+
}>;
|
|
218
|
+
export type ReplayScenarioInput = z.infer<typeof replayScenarioSchema>;
|
|
219
|
+
export interface ReplayScenarioFailure {
|
|
220
|
+
iteration: number;
|
|
221
|
+
stepIndex: number;
|
|
222
|
+
reason: string;
|
|
223
|
+
}
|
|
224
|
+
export interface ReplayScenarioWorkaroundNotice {
|
|
225
|
+
issue: "axe-not-found";
|
|
226
|
+
message: string;
|
|
227
|
+
}
|
|
228
|
+
export interface ReplayScenarioResult {
|
|
229
|
+
ok: boolean;
|
|
230
|
+
executedSteps: number;
|
|
231
|
+
failures: ReplayScenarioFailure[];
|
|
232
|
+
totalDurationMs: number;
|
|
233
|
+
finalUITreePath?: string;
|
|
234
|
+
workaroundNotice?: ReplayScenarioWorkaroundNotice;
|
|
235
|
+
}
|
|
236
|
+
export declare function replayScenario(input: ReplayScenarioInput): Promise<ReplayScenarioResult>;
|
|
237
|
+
/** Pure: convert a tap-action input shape into the runtime TapTarget union. Exposed for tests. */
|
|
238
|
+
export declare function resolveTapTarget(action: {
|
|
239
|
+
label?: string;
|
|
240
|
+
elementId?: string;
|
|
241
|
+
coords?: [number, number];
|
|
242
|
+
}): TapTarget;
|
|
243
|
+
export {};
|