import { z } from "zod"; /** * Base shape, exposed so the MCP layer can read `.shape` (ZodEffects from * `.superRefine()` doesn't expose shape). */ export declare const recordTimeProfileShape: { readonly template: z.ZodDefault; readonly deviceId: z.ZodOptional; readonly simulatorId: z.ZodOptional; readonly attachAppName: z.ZodOptional; readonly attachPid: z.ZodOptional; readonly launchBundleId: z.ZodOptional; readonly durationSec: z.ZodDefault; readonly output: z.ZodString; }; export declare const recordTimeProfileSchema: z.ZodEffects; readonly deviceId: z.ZodOptional; readonly simulatorId: z.ZodOptional; readonly attachAppName: z.ZodOptional; readonly attachPid: z.ZodOptional; readonly launchBundleId: z.ZodOptional; readonly durationSec: z.ZodDefault; readonly output: z.ZodString; }, "strip", z.ZodTypeAny, { output: string; template: string; durationSec: number; simulatorId?: string | undefined; attachAppName?: string | undefined; deviceId?: string | undefined; attachPid?: number | undefined; launchBundleId?: string | undefined; }, { output: string; template?: string | undefined; simulatorId?: string | undefined; attachAppName?: string | undefined; durationSec?: number | undefined; deviceId?: string | undefined; attachPid?: number | undefined; launchBundleId?: string | undefined; }>, { output: string; template: string; durationSec: number; simulatorId?: string | undefined; attachAppName?: string | undefined; deviceId?: string | undefined; attachPid?: number | undefined; launchBundleId?: string | undefined; }, { output: string; template?: string | undefined; simulatorId?: string | undefined; attachAppName?: string | undefined; durationSec?: number | undefined; deviceId?: string | undefined; attachPid?: number | undefined; launchBundleId?: string | undefined; }>; export type RecordTimeProfileInput = z.infer; export interface RecordingTimeoutWorkaroundNotice { issue: "xctrace-time-limit-ignored"; message: string; fallbacks: string[]; } export interface RecordTimeProfileResult { ok: boolean; command: string; output: string; durationSec: number; template: string; stderr?: string; /** * Present and `true` when xctrace ignored `--time-limit` and the external * timeout wrapper had to SIGINT it. The `.trace` bundle on disk MAY be * usable: xctrace flushes the active template on SIGINT, but if the * escalation path had to send SIGKILL (after the graceful window) the * trace may be missing template metadata and `analyzeTimeProfile` will * fail to export it. Inspect `workaroundNotice` for the recovery path. */ recordingTimedOut?: boolean; /** * v1.17 B-09. Reports whether the .trace bundle on disk is * salvageable. `unknown` when recording succeeded normally * (the caller can run inspectTrace to confirm). `salvageable` when * a timeout / SIGINT path produced a bundle with the canonical * Trace1.run/MANIFEST.plist marker (xctrace flushed cleanly). * `wedged` when the bundle is missing MANIFEST.plist (the macOS 26.x * regression signature; xctrace export will reject it). Use this to * branch without re-checking the filesystem. */ bundleStatus?: "unknown" | "salvageable" | "wedged"; /** * Present when `recordingTimedOut` is true. Documents the * `xctrace --time-limit` regression observed on macOS 26.x simulators * and the practical mitigations. */ workaroundNotice?: RecordingTimeoutWorkaroundNotice; /** * v1.14+. `true` when, after a timed-out recording, the wrapper invoked * `open -a Instruments ` so the user can inspect the partial * trace in the GUI (Instruments.app on macOS 26.x can still open and * symbolicate traces the CLI export path rejects). Opt-in via * `MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS=1`. `false` when the env flag is * unset (default) or the trace bundle is missing from disk. Absent when * the recording did not time out. */ openedInInstrumentsApp?: boolean; } /** * v1.14 item H. Pre-flight probe for the xctrace `--time-limit` ignore * regression on macOS 26.x simulators. Runs a 2-second test recording * against the same target the user requested. If the probe completes * cleanly inside its wrapper window, the user's full recording is * expected to behave; if the probe times out, we bail before spending * the user's full `durationSec` + 30s grace window on a wedge. * * Returns `{ healthy: true }` when the probe exited cleanly. Returns * `{ healthy: false, reason }` when the probe timed out OR when xctrace * exited non-zero (the wedge does not always produce timedOut=true; * sometimes xctrace exits early with a misleading error code when the * sim is in a bad state). The recordTimeProfile flow treats either as * "skip the full recording, return workaroundNotice now". * * Pre-flight is gated to ATTACH mode only. The `--launch` path would * start the user's app a second time (probe launch + full-recording * launch), losing first-launch state. For `--launch` callers we skip * the probe and fall back to the existing 70s timeout wrapper. * * Exported so the gating logic can be unit-tested without spawning * xctrace. */ export interface PreflightResult { healthy: boolean; reason?: string; durationMs: number; } /** * Returns true when a pre-flight probe should run before the user's * actual recording. v1.14 item H. * * - `MEMORYDETECTIVE_PREFLIGHT_XCTRACE=1` forces preflight on. * - `MEMORYDETECTIVE_PREFLIGHT_XCTRACE=0` forces it off. * - Default: auto-enabled when host is macOS 26.x AND target is a * simulator AND attach mode (`--attach`, not `--launch`). The set of * configurations where the regression is known to fire. * * The `osPlatform` and `osRelease` params are threaded through to * `getPlatformAdvisory` so tests can simulate non-macOS-26 hosts even * when running on a real macOS 26.x machine. */ export declare function shouldPreflightXctrace(input: RecordTimeProfileInput, env?: Readonly>, osPlatform?: () => NodeJS.Platform, osRelease?: () => string): boolean; /** * Runs the 2-second probe. Reuses runCommand's timeout wrapper with the * same SIGINT-first / SIGKILL-fallback shape that the full recording * uses, so the probe's salvage behavior matches the real path. * * The output bundle is placed at `.preflight` to keep it * recognizable in cleanup tools and not collide with the user's actual * output path. */ export declare function preflightXctraceRecord(input: RecordTimeProfileInput, resolvedOutput: string): Promise; /** * v1.17 B-09. Classify a `.trace` bundle on disk by the canonical * markers xctrace writes. The `MANIFEST.plist` file under `Trace1.run/` * is the marker of a complete export; absent means xctrace was killed * before flushing (the macOS 26.x wedge signature). * * Returns `unknown` when the path doesn't exist (caller error). * Used by recordTimeProfile to surface `bundleStatus` on the response. * * Exported so other tools (recordViaInstrumentsApp, etc.) can share * the heuristic. */ export declare function classifyBundleOnDisk(tracePath: string): "unknown" | "salvageable" | "wedged"; /** * v1.14 item J. When a `recordTimeProfile` call times out, optionally * launch the partial `.trace` in Instruments.app so the user has a GUI * escape hatch. Returns `true` when `open -a Instruments ` * was spawned, `false` otherwise. * * Gated on `MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS=1` to avoid spamming * the user's GUI on unattended runs and CI. Also requires the trace * bundle to exist on disk (xctrace's SIGINT path may have failed to * write anything). * * The `open` invocation is fire-and-forget: `detached: true` + `unref()` * so the recording tool returns immediately. Failures to launch * Instruments.app are swallowed; the user is no worse off than without * the flag enabled. * * Exported so the env-gating logic can be tested without spawning * Instruments in test runs. */ export declare function maybeOpenInInstruments(tracePath: string): boolean; /** Pure: build the xctrace argv for the given input. Exposed for testing. */ export declare function buildXctraceArgs(input: RecordTimeProfileInput): string[]; export declare function recordTimeProfile(input: RecordTimeProfileInput): Promise;