memorydetective 1.16.0 → 1.17.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 +44 -0
- package/README.md +18 -15
- package/USAGE.md +3 -2
- package/dist/parsers/schemaDiscovery.d.ts +26 -0
- package/dist/parsers/schemaDiscovery.js +40 -11
- package/dist/parsers/schemaDiscovery.js.map +1 -1
- package/dist/runtime/parseBooleanEnv.d.ts +22 -0
- package/dist/runtime/parseBooleanEnv.js +47 -0
- package/dist/runtime/parseBooleanEnv.js.map +1 -0
- package/dist/runtime/platformCheck.js +4 -1
- package/dist/runtime/platformCheck.js.map +1 -1
- package/dist/runtime/securityFlags.js +3 -1
- package/dist/runtime/securityFlags.js.map +1 -1
- package/dist/tools/analyzeEnergyImpact.d.ts +7 -1
- package/dist/tools/analyzeEnergyImpact.js +9 -3
- package/dist/tools/analyzeEnergyImpact.js.map +1 -1
- package/dist/tools/analyzeHangs.js +21 -12
- package/dist/tools/analyzeHangs.js.map +1 -1
- package/dist/tools/analyzeLeakTimeline.js +27 -10
- package/dist/tools/analyzeLeakTimeline.js.map +1 -1
- package/dist/tools/analyzeMemoryFootprint.js +1 -2
- package/dist/tools/analyzeMemoryFootprint.js.map +1 -1
- package/dist/tools/analyzeNetworkActivity.d.ts +6 -1
- package/dist/tools/analyzeNetworkActivity.js +13 -1
- package/dist/tools/analyzeNetworkActivity.js.map +1 -1
- package/dist/tools/cleanupTraces.js +2 -1
- package/dist/tools/cleanupTraces.js.map +1 -1
- package/dist/tools/countAlive.d.ts +51 -5
- package/dist/tools/countAlive.js +140 -11
- package/dist/tools/countAlive.js.map +1 -1
- package/dist/tools/inspectTrace.js +22 -1
- package/dist/tools/inspectTrace.js.map +1 -1
- package/dist/tools/recordTimeProfile.d.ts +24 -0
- package/dist/tools/recordTimeProfile.js +38 -5
- package/dist/tools/recordTimeProfile.js.map +1 -1
- package/dist/tools/recordViaInstrumentsApp.d.ts +25 -0
- package/dist/tools/recordViaInstrumentsApp.js +97 -23
- package/dist/tools/recordViaInstrumentsApp.js.map +1 -1
- package/dist/tools/verifyFix.d.ts +18 -3
- package/dist/tools/verifyFix.js +51 -31
- package/dist/tools/verifyFix.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,50 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.17.1] - 2026-05-16
|
|
10
|
+
|
|
11
|
+
Docs-only patch. Syncs the npm README + USAGE with the v1.17 surface notes shipped to GitHub right after v1.17.0 was published. No code changes.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- README leads with the v1.17 reliability headlines; env-var table prefaced with the strtobool truthy parsing rule; macOS 26.x callout cites the new `bundleStatus` field on `recordTimeProfile`, the `savedOutsideWatchDir` field on `recordViaInstrumentsApp`, and the fault-tolerant `inspectTrace` fallback. Capture / record section renumbered from (3) to (4) with the previously-missing `recordViaInstrumentsApp` row. `verifyFix` + `countAlive` + `inspectTrace` + `recordTimeProfile` rows annotated with their v1.17 surface additions.
|
|
16
|
+
- USAGE.md follow-up prompts table gained a `verifyFix` example using `{ pattern, mode: "exact" }`. Troubleshooting recovery list for the macOS 26.x recording wedge documents the `savedOutsideWatchDir` AppleScript fallback.
|
|
17
|
+
|
|
18
|
+
## [1.17.0] - 2026-05-16
|
|
19
|
+
|
|
20
|
+
Reliability pass. v1.16 closed the macOS 26.x recording gap with `recordViaInstrumentsApp`. v1.17 sweeps the audit punch list that surfaced after dogfooding: 14 bugs across three tiers, 3 known limitations documented, 3 tech-debt items deferred. The headlines are env-var truthy parsing (every `MEMORYDETECTIVE_*` boolean now accepts `1 / true / yes / on`, was `1`-only), a `verifyFix` whitelist that supports exact / substring / regex modes (was substring-only), the `recordViaInstrumentsApp` watcher catching saves outside the watch dir, and the `inspectTrace` fault-tolerant fallback so a wedged 52K bundle no longer throws. 41 MCP tools, 701 tests (+24 vs v1.16).
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
#### Tier 1 (user-visible)
|
|
25
|
+
|
|
26
|
+
- **`recordViaInstrumentsApp` watcher misses saves outside `watchDir` (B-01).** Pre-v1.17 the tool only watched the filesystem path; users who hit Save in Instruments.app and accepted the default Desktop location would time out even though the trace was on disk. Now queries the running Instruments.app via AppleScript every poll for any `document` whose file path was set after the tool started; on first match outside `watchDir` returns the path with `savedOutsideWatchDir: true`. Uses the documented `Instruments.sdef` `file of document` accessor only (no unsupported verbs).
|
|
27
|
+
- **`verifyFix.expectedAliveClasses` supports per-entry mode (B-02).** Pre-v1.17 every whitelist entry was matched as a case-insensitive substring. Caller wanting "match exactly `UIRemoteKeyboardWindow`, do not match `MyUIRemoteKeyboardWindowWrapper`" had no way to express it. Schema now accepts `string` (defaults to substring for backwards compat) or `{ pattern: string, mode: "exact" | "substring" | "regex" }`. ESLint and Jest both use single-mode matching, but their users have asked for the inverse in tracked issues; we picked the opposite trade-off.
|
|
28
|
+
- **`MEMORYDETECTIVE_*` env booleans accept the strtobool truthy set (B-03).** Pre-v1.17 only the literal string `1` turned a gate on. Users exporting `MEMORYDETECTIVE_ALLOW_LAUNCH=true` or `=yes` saw silent no-op behavior. v1.17 normalizes the five booleans through `parseBooleanEnv`, which accepts `1 / true / t / yes / y / on` (truthy) and `0 / false / f / no / n / off` (falsy), case-insensitive. Unrecognized values emit a one-time stderr warning per var so the operator knows the setting was ignored. Mirrors `envalid`'s `bool()` semantics without taking the dependency.
|
|
29
|
+
- **`maybeOpenInInstruments` checks bundle viability before opening (B-04).** Pre-v1.17 the auto-open path would launch a wedged 52K macOS 26.x stub bundle in Instruments.app, where it presents a Document Missing Template Error dialog the operator has to dismiss. Now probes `Trace1.run/MANIFEST.plist` before calling `open`; on missing manifest, skips the open and surfaces the bundle status to the caller. The exported `classifyBundleOnDisk(tracePath)` helper returns `"unknown" | "salvageable" | "wedged"` for reuse.
|
|
30
|
+
|
|
31
|
+
#### Tier 2 (silently sub-optimal)
|
|
32
|
+
|
|
33
|
+
- **`inspectTrace` fault-tolerant fallback when `xctrace export --toc` fails (B-05).** Pre-v1.17 a failed TOC export threw, which broke the entire MCP call. Now returns `ok: true` with `schemas: []`, `rowCounts: {}`, `suggestedNextCalls: []`, and a diagnosis string naming the 52K macOS 26.x stub pattern so callers can self-diagnose. Throwing is reserved for missing trace paths.
|
|
34
|
+
- **`schemaDiscovery.fetchDiscoveredSchemasWithStatus` surfaces failures (B-06).** New sibling of `fetchDiscoveredSchemas` returns `{ schemas, status: "ok" | "failed", reason? }` so trace analyzers can include a discovery-failure entry in `supportStatus[]` instead of silently using canonical schema names against a renamed-schema trace. Emits a one-time stderr warning per `tracePath:reason`, gated on `MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY`. Legacy `fetchDiscoveredSchemas` keeps its silent-fallback contract.
|
|
35
|
+
- **`countByClassWithBytes` reports min/max/median for variable-size classes (B-07).** Pre-v1.17 we returned the first observed `instanceSize` as canonical for every class. Misled callers inspecting `NSData`, `NSString`, `CFData` whose per-instance size is payload-dependent. Now: fixed-size classes return a single `instanceSizeBytes` value as before; variable-size classes return `{ instanceSizeBytes: median, instanceSizeBytesMin, instanceSizeBytesMax, instanceSizeBytesMedian }`. `totalBytes` unchanged. `CountAliveEntry` propagates the spread through per-class and topN paths.
|
|
36
|
+
- **`analyzeHangs.supportStatus[]` always includes both schema entries (B-08).** Pre-v1.17 a caller without `hangRisksXml` saw a single entry, a caller with it saw two. Agent code branching on `supportStatus.find(s => s.kind === "hang-risks")` could not distinguish "I did not ask" from "schema absent". Both entries are now always present; the missing-XML path returns `status: "not_present"` with reason `"caller did not provide hangRisksXml"`.
|
|
37
|
+
- **`recordTimeProfile.bundleStatus` reflects on-disk reality (B-09).** New `bundleStatus: "unknown" | "salvageable" | "wedged"` field on the response. The timeout path now probes `MANIFEST.plist` via `classifyBundleOnDisk` so callers branching on `tracePath ? "have trace" : "no trace"` get an honest signal.
|
|
38
|
+
- **`countAlive` framework-noise filter is configurable (B-10).** New inputs: `excludeFrameworkNoise: boolean` (default true), `additionalNoisePatterns?: string[]`, `unsuppressClassPatterns?: string[]`, `noiseAuditMode: boolean`. The curated noise list (calibrated for the v1.5 notelet investigation) remains the default. Audit mode returns a `noiseAudit[]` array listing every filtered class with reason `'default-list'`, `'additional-pattern'`, or `'kept-by-unsuppress'`. User-supplied regex strings compile with a literal-escape fallback on syntax errors.
|
|
39
|
+
|
|
40
|
+
#### Tier 3 (edge case / cosmetic)
|
|
41
|
+
|
|
42
|
+
- **`extractHost` parses IPv6 bracket form (B-11).** `analyzeNetworkActivity` was misreporting hosts like `[::1]:443` as the empty string. Now strips brackets and splits the port correctly.
|
|
43
|
+
- **`normalizeBucket` priority fix (B-12).** `analyzeEnergyImpact` was matching `"high"` before `"foreground"` in xctrace's varying-case bucket strings. Reordered to check the named buckets first.
|
|
44
|
+
- **Redundant `t.schema === "memory-footprint"` equality removed (B-13).** `analyzeMemoryFootprint` was double-checking after `discoverSchemas` already resolved the family name.
|
|
45
|
+
- **`analyzeLeakTimeline` handles column-drift gracefully (B-14).** When every row is skipped due to missing `className`, returns `status: "partial"` with a reason naming the column drift instead of silently emitting an empty timeline.
|
|
46
|
+
|
|
47
|
+
### Behavior changes (informational)
|
|
48
|
+
|
|
49
|
+
- The `MEMORYDETECTIVE_*` boolean env vars are now case-insensitively recognized for the strtobool set. Setting `=yes` or `=true` now turns gates on; pre-v1.17 it did not. Operators who deliberately set unrecognized values will see a stderr warning but no behavioral change (unrecognized falls back to default).
|
|
50
|
+
- `verifyFix.expectedAliveClasses` string entries continue to behave as case-insensitive substring matches for backwards compat. The new object form `{ pattern, mode }` is opt-in.
|
|
51
|
+
- The deprecated `notice` and `status` aliases on trace analyzers stay (will be removed in a future major bump).
|
|
52
|
+
|
|
9
53
|
## [1.16.0] - 2026-05-15
|
|
10
54
|
|
|
11
55
|
macOS 26.x recording-unblock release. The single feature that v1.14 punted on. `xcrun xctrace record --time-limit Ns` is broken on macOS 26.x simulator targets (documented in v1.14). Instruments.app GUI still produces valid `.trace` bundles. v1.16 ships the wrapper that automates the surrounding choreography: open the app, prompt the user with step-by-step instructions, poll for the saved trace, chain into `inspectTrace` on success. 41 MCP tools, 677 tests.
|
package/README.md
CHANGED
|
@@ -17,17 +17,17 @@
|
|
|
17
17
|
- **MCP-native.** Plugs into Claude Code, Claude Desktop, Cursor, Cline, and any other MCP client. The agent drives the full investigate → classify → suggest-fix loop without you opening Instruments.
|
|
18
18
|
- **Honest about its limits.** No mocked outputs, no over-promises. Hangs analysis works clean from `xctrace`; sample-level Time Profile is parsed when `xctrace` symbolicates the trace and returns a structured workaround notice when it can't (the underlying `xctrace` SIGSEGV on heavy unsymbolicated traces is an Apple-side limitation we surface explicitly). Memory Graph capture works on Mac apps and iOS simulator; physical iOS devices still need Xcode.
|
|
19
19
|
|
|
20
|
-
> **What's new in v1.
|
|
20
|
+
> **What's new in v1.17** (2026-05-16): reliability pass. 14 bug fixes across three tiers swept after dogfooding. Headlines: every `MEMORYDETECTIVE_*` boolean env var now accepts the strtobool truthy set (`1 / true / yes / on`, was `1`-only, with a one-time stderr warning on unrecognized values); `verifyFix.expectedAliveClasses` supports per-entry exact / substring / regex match modes (was substring-only); `recordViaInstrumentsApp` catches traces saved outside `watchDir` via an Instruments.app AppleScript document query; `inspectTrace` fault-tolerant fallback returns `ok: true` with diagnosis text on wedged 52K bundles instead of throwing; `countAlive` framework-noise filter is now configurable with audit mode; `countByClassWithBytes` reports min / max / median for variable-size classes like `NSData`. 677 → 701 tests. Still 41 MCP tools (reliability tightening, no surface changes).
|
|
21
21
|
>
|
|
22
|
-
> **Also recent (v1.
|
|
22
|
+
> **Also recent (v1.16)**: macOS 26.x recording-unblock release. New `recordViaInstrumentsApp` MCP tool (41st) wraps the Instruments.app GUI flow: opens the app, surfaces step-by-step instructions, watches a directory for the saved `.trace`, and chains into `inspectTrace` on success. Until Apple fixes the `xcrun xctrace record` regression on macOS 26.x sims, this is the automated path. Times out after `timeoutSec` (default 10 min).
|
|
23
23
|
>
|
|
24
|
-
> **And v1.
|
|
24
|
+
> **And v1.15**: schema coverage + verify-fix UX. Three new MCP trace tools filled the remaining schema gap: `analyzeMemoryFootprint` (38th, VM resident / dirty / virtual + jetsam diagnosis), `analyzeEnergyImpact` (39th, battery drain investigation), `analyzeLeakTimeline` (40th, xctrace's leaks instrument as a time series). `summarizeTrace` now chains `analyzeNetworkActivity`. `replayScenario` captures simulator screenshots per step.
|
|
25
25
|
>
|
|
26
|
-
> **Earlier**: v1.13 shipped `summarizeTrace` + `/summarize-trace` MCP prompt. v1.12 completed reference-tree propagation
|
|
26
|
+
> **Earlier**: v1.14 trace-side reliability, `analyzeNetworkActivity`, unified `supportStatus[]`, FLEX-inspired `countAlive` size view, MLeaksFinder + DebugSwift-inspired `verifyFix` whitelist. v1.13 shipped `summarizeTrace` + `/summarize-trace` MCP prompt. v1.12 completed reference-tree propagation. v1.11 added inspectTrace, diffMemgraphs reference-tree. v1.9 shipped analyzeAbandonedMemory, detectLeaksInXCTest, cleanupTraces, mainThreadViolations. Full notes in [CHANGELOG](./CHANGELOG.md).
|
|
27
27
|
|
|
28
28
|
> **Heads up for macOS 26.x users:** Apple shipped a `task_for_pid` kernel regression on macOS 26.x that blocks `leaks --outputGraph`, `heap`, AND `xctrace --template Allocations` against iOS simulator processes regardless of `MallocStackLogging`. Even Xcode's "View Memory Graph Hierarchy" hits it unless `Malloc Stack Logging` is enabled in the scheme's Diagnostics tab. memorydetective surfaces this as a proactive `platformAdvisory` on the first capture-class tool call, plus a `workaroundNotice` with `issue: "macos-26-task-for-pid-broken"` if `leaks` is invoked. **The most reliable workaround today is to target an iOS 18 simulator runtime** (install via Xcode > Settings > Platforms > +iOS 18.x). Empirically validated in the [notelet investigation](https://github.com/carloshpdoc/memorydetective/blob/main/CHANGELOG.md#unreleased) 2026-05-12 where three independent CLI memory-introspection paths all failed before iOS 18 was identified as the working escape hatch. Set `MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY=1` to silence the notice once you have settled on a workaround.
|
|
29
29
|
|
|
30
|
-
> **Also on macOS 26.x: `xctrace record` is broken for simulator targets.** Independent from the `task_for_pid` regression above, `xcrun xctrace record --time-limit Ns` against iOS simulator processes wedges past the time limit, eventually exits when killed, and the resulting `.trace` bundle is missing template metadata. `xctrace export --toc` then fails with `Document Missing Template Error`. Re-validated against Xcode 26.5 (build 17F42, xctrace 16.0) 2026-05-15: regression survives the update. This hits the entire `xctrace`-based ecosystem the same way (`memorydetective.recordTimeProfile`, XcodeTraceMCP, and naked `xcrun xctrace record` calls all fail identically). **Workarounds:** (1) **v1.16
|
|
30
|
+
> **Also on macOS 26.x: `xctrace record` is broken for simulator targets.** Independent from the `task_for_pid` regression above, `xcrun xctrace record --time-limit Ns` against iOS simulator processes wedges past the time limit, eventually exits when killed, and the resulting `.trace` bundle is missing template metadata. `xctrace export --toc` then fails with `Document Missing Template Error`. Re-validated against Xcode 26.5 (build 17F42, xctrace 16.0) 2026-05-15: regression survives the update. This hits the entire `xctrace`-based ecosystem the same way (`memorydetective.recordTimeProfile`, XcodeTraceMCP, and naked `xcrun xctrace record` calls all fail identically). **Workarounds:** (1) **use `recordViaInstrumentsApp`** (v1.16, hardened in v1.17), which opens Instruments.app for you, prompts you to record + save the `.trace`, then chains into `inspectTrace` automatically once the bundle appears. v1.17 also catches saves outside the watch directory via an Instruments.app AppleScript document query, returning `savedOutsideWatchDir: true` plus the actual path; (2) record from an older macOS host with Xcode 26.0 if you have one; (3) record against a physical device (the regression appears to be simulator-specific). v1.17 added a viability probe on `recordTimeProfile` (`bundleStatus: "wedged"` when the on-disk bundle is the 52K stub) and on `inspectTrace` (returns `ok: true` with diagnosis text instead of throwing). USAGE.md > Troubleshooting has a step-by-step.
|
|
31
31
|
|
|
32
32
|
## Quickstart
|
|
33
33
|
|
|
@@ -288,16 +288,18 @@ Copilot's MCP integration moves fast. If this snippet is stale, see the [VS Code
|
|
|
288
288
|
|
|
289
289
|
### Environment variables
|
|
290
290
|
|
|
291
|
+
Every boolean `MEMORYDETECTIVE_*` flag below accepts the **strtobool** truthy set (case-insensitive): `1 / true / t / yes / y / on` (truthy) and `0 / false / f / no / n / off` (falsy). Unrecognized values emit a one-time stderr warning per variable and fall back to the documented default. Pre-v1.17 the parser was `1`-only, which caused silent no-ops when operators exported `=true` or `=yes`. The advisory warning is gated on `MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY`.
|
|
292
|
+
|
|
291
293
|
| Variable | Default | Effect |
|
|
292
294
|
|---|---|---|
|
|
293
295
|
| `MEMORYDETECTIVE_REDACTION` | `balanced` | Output scrubbing applied to every tool response. `balanced` collapses home-directory paths to `~/...` and masks token-shaped secrets (AWS keys, GitHub PATs, Stripe, Slack, Bearer auth). `strict` adds hostname, IPv4, and bundle-identifier masking. `off` disables redaction (useful for local-only debugging). Mode is logged once at server startup. |
|
|
294
|
-
| `MEMORYDETECTIVE_ALLOW_LAUNCH` | unset |
|
|
296
|
+
| `MEMORYDETECTIVE_ALLOW_LAUNCH` | unset | Boolean (strtobool). Allows `bootAndLaunchForLeakInvestigation`. The tool executes `xcodebuild` and `xcrun simctl launch` against caller-supplied paths and bundle ids, so opt-in is required. Without the gate, the tool returns `ok: false` with `state: launchNotAllowed` and a clear explanation. Set this only when you trust the inputs the agent is producing. |
|
|
295
297
|
| `MEMORYDETECTIVE_MAX_RECORDING_SECONDS` | `300` | Cap on `recordTimeProfile.durationSec`. Requests above the cap are rejected with a clear error. Bounded internally to a 3600s (1h) hard ceiling so a misconfigured env var cannot disable the gate. |
|
|
296
298
|
| `MEMORYDETECTIVE_TRACE_ROOT` | `~/Library/Application Support/memorydetective/traces` | Directory used when `recordTimeProfile.output` is a relative path. Absolute paths bypass this default for v1.8 backwards-compat. Also the default scan path for `cleanupTraces`. The directory is auto-created on first write. |
|
|
297
|
-
| `MEMORYDETECTIVE_ALLOW_EXTERNAL_CLEANUP` | unset |
|
|
298
|
-
| `MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY` | unset |
|
|
299
|
-
| `MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS` | unset |
|
|
300
|
-
| `MEMORYDETECTIVE_PREFLIGHT_XCTRACE` | unset (auto) | Controls the pre-flight probe in `recordTimeProfile` that detects the macOS 26.x xctrace wedge in ~3-5 seconds instead of paying the user's full `durationSec` plus 30s grace.
|
|
299
|
+
| `MEMORYDETECTIVE_ALLOW_EXTERNAL_CLEANUP` | unset | Boolean (strtobool). Allows `cleanupTraces` to scan and delete `.trace` bundles OUTSIDE `MEMORYDETECTIVE_TRACE_ROOT`. Without it, requests that resolve outside the configured root return `ok: false` with the failure reason and delete nothing. Default-deny on destructive disk operations outside the configured boundary. |
|
|
300
|
+
| `MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY` | unset | Boolean (strtobool). Silences the macOS 26.x platform advisory that captureMemgraph, captureScenarioState, and bootAndLaunchForLeakInvestigation emit on first use. Also silences the v1.17 stderr warnings emitted on unrecognized boolean values (any `MEMORYDETECTIVE_*` flag) and on `schemaDiscovery` TOC fetch failures. Useful once you have an iOS 18 sim runtime installed and do not need the reminders. |
|
|
301
|
+
| `MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS` | unset | Boolean (strtobool). Makes `recordTimeProfile` invoke `open -a Instruments <tracePath>` as a fire-and-forget escape hatch when xctrace times out (the macOS 26.x regression). v1.17 adds a `MANIFEST.plist` viability check before opening so the auto-open path skips wedged 52K stub bundles (which would otherwise present a "Document Missing Template Error" dialog in Instruments.app). The response's `openedInInstrumentsApp` field reports whether the open was invoked; `bundleStatus` (v1.17) reports whether the bundle on disk is `unknown` / `salvageable` / `wedged`. |
|
|
302
|
+
| `MEMORYDETECTIVE_PREFLIGHT_XCTRACE` | unset (auto) | Boolean (strtobool) + `auto`. Controls the pre-flight probe in `recordTimeProfile` that detects the macOS 26.x xctrace wedge in ~3-5 seconds instead of paying the user's full `durationSec` plus 30s grace. Truthy forces on regardless of platform / target. Falsy forces off. When unset, the probe auto-enables on macOS 26.x simulator attach (the known-broken combo) and stays off elsewhere. Pre-flight is skipped for `--launch` mode to avoid double-launching the app. Side-effect of auto-enable: 2-second probe runs before the full recording starts. |
|
|
301
303
|
|
|
302
304
|
---
|
|
303
305
|
|
|
@@ -321,11 +323,11 @@ The cycle classifier ships **36 named antipatterns** spanning SwiftUI (including
|
|
|
321
323
|
| `analyzeMemgraph` | Run `leaks` against a `.memgraph` and return summary (totals, ROOT CYCLE blocks, plain-English diagnosis). |
|
|
322
324
|
| `findCycles` | Extract just the ROOT CYCLE blocks as flattened chains, with optional `className` substring filter. |
|
|
323
325
|
| `findRetainers` | "Who is keeping `<class>` alive?". Returns retain chain paths from a top-level node down to the match. |
|
|
324
|
-
| `countAlive` | Count instances by class. Provide `className` for one number, or omit for top-N most-leaked classes. |
|
|
326
|
+
| `countAlive` | Count instances by class. Provide `className` for one number, or omit for top-N most-leaked classes. v1.17: configurable noise filter (`excludeFrameworkNoise`, `additionalNoisePatterns`, `unsuppressClassPatterns`, `noiseAuditMode`) so the actionable view is tunable per app. Variable-size classes report `instanceSizeBytesMin / Max / Median` (was first-observed value pre-v1.17). |
|
|
325
327
|
| `reachableFromCycle` | Cycle-scoped reachability. "How many `<X>` instances are reachable from the cycle rooted at `<Y>`?". Distinguishes the actual culprit from its retained dependencies. |
|
|
326
328
|
| `diffMemgraphs` | Compare two `.memgraph` snapshots: total deltas + class-count changes + cycles new/gone/persisted. |
|
|
327
329
|
| `analyzeAbandonedMemory` | Diff two `.memgraph` snapshots on heap reference-tree class counts (not cycle list) and classify each grown class as `kvo-observer-orphaned`, `notificationcenter-observer-leaked`, `cache-too-aggressive`, `singleton-retains-payload`, or `unknown-growth`. Surfaces the family of bugs `leaks(1)` reports as `leakCount: 0` because no strict cycle exists. v1.10 adds `actionableGrowth[]` + `actionableShrinkage[]` (framework-noise-filtered views) and supports `outputFormat: "verify-fix-table"` which emits a focused Class \| Before \| After \| Delta markdown table directly. |
|
|
328
|
-
| `verifyFix` | Cycle-semantic diff: per-pattern PASS/PARTIAL/FAIL verdict + bytes freed. CI-gateable. |
|
|
330
|
+
| `verifyFix` | Cycle-semantic diff: per-pattern PASS/PARTIAL/FAIL verdict + bytes freed. CI-gateable. `expectedAliveClasses` whitelist (v1.14) carves out singletons / caches / OS-retained windows so they do not vote FAIL; v1.17 extends each entry to per-mode matching (`{ pattern, mode: "exact" \| "substring" \| "regex" }`), with bare strings keeping the substring default. |
|
|
329
331
|
| `classifyCycle` | Match each ROOT CYCLE against a built-in catalog of **36 named antipatterns** (SwiftUI / Combine / Concurrency / UIKit / Core Animation / Core Data / Coordinator / RxSwift / Realm) with confidence + textual `fixHint` + `staticAnalysisHint` (which SwiftLint rule complements this, or explicit gap) + `fixTemplate` (Swift before/after snippet). |
|
|
330
332
|
| `analyzeHangs` | Parse `xctrace` `potential-hangs` schema; return Hang vs Microhang counts + top N longest. Pass `topFramesByHangStartNs` (typically from a chained `analyzeTimeProfile` correlation) to enrich each top hang with `mainThreadViolations[]` classifying the blocker as `sync-io`, `db-lock`, `network`, or `lock-contention`. |
|
|
331
333
|
| `analyzeAnimationHitches` | Parse `xctrace` `animation-hitches` schema; report by-type counts and how many hitches crossed Apple's user-perceptible 100ms threshold. |
|
|
@@ -334,11 +336,12 @@ The cycle classifier ships **36 named antipatterns** spanning SwiftUI (including
|
|
|
334
336
|
| `analyzeAppLaunch` | Parse `xctrace` `app-launch` schema; return cold/warm launch type + per-phase breakdown (process-creation, dyld-init, ObjC-init, AppDelegate, first-frame). |
|
|
335
337
|
| `logShow` | One-shot query of macOS unified logging via `log show --style compact` with predicate / process / subsystem filters. Returns parsed entries (timestamp, type, process, subsystem, category, message). |
|
|
336
338
|
|
|
337
|
-
### Capture / record (
|
|
339
|
+
### Capture / record (4)
|
|
338
340
|
|
|
339
341
|
| Tool | What | Sim | Device |
|
|
340
342
|
|---|---|---|---|
|
|
341
|
-
| `recordTimeProfile` | Wrap `xcrun xctrace record --template "Time Profiler" --attach ... --time-limit Ns --output ...`. | ✅ | ✅ |
|
|
343
|
+
| `recordTimeProfile` | Wrap `xcrun xctrace record --template "Time Profiler" --attach ... --time-limit Ns --output ...`. Returns `bundleStatus: "unknown" \| "salvageable" \| "wedged"` (v1.17) so callers can branch on on-disk reality after a timeout instead of trusting the `tracePath` blindly. Auto-open path (`MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS`) probes `MANIFEST.plist` before launching Instruments.app to skip wedged 52K stubs. | ✅ | ✅ |
|
|
344
|
+
| `recordViaInstrumentsApp` | macOS 26.x escape hatch (v1.16). Opens Instruments.app via `open -a Instruments`, returns an `instructions[]` array telling the user which template to pick + when to hit Record / Stop / Save, then polls `watchDir` every 5s for new `.trace` bundles (mtime-stable for 10s). v1.17: also queries running Instruments.app via AppleScript every poll for any saved document outside `watchDir`. On match, returns the path with `savedOutsideWatchDir: true` so users who hit Save and accepted the Desktop default no longer time out. Chains into `inspectTrace` on success. | ✅ | ✅ |
|
|
342
345
|
| `captureMemgraph` | Wrap `leaks --outputGraph <path> <pid>`. Resolves `appName → pid` via `pgrep -x`. Returns a structured `workaroundNotice` on the macOS 26.x `Failed to get DYLD info for task` regression with stable issue ids (`minimal-corpse`, `permission-denied`, `leaks-not-found`, `transient`) and a fallback path to `recordTimeProfile` (Allocations) + `analyzeAllocations`. | ✅ | ❌. Use Xcode |
|
|
343
346
|
| `logStream` | Wrap `log stream --style compact` for a bounded duration (≤ 60 s). Returns parsed entries collected during the window. | n/a | n/a |
|
|
344
347
|
|
|
@@ -358,7 +361,7 @@ These three tools combine into a single deterministic verify-fix loop: launch th
|
|
|
358
361
|
|---|---|
|
|
359
362
|
| `listTraceDevices` | Parse `xcrun xctrace list devices` (devices + simulators + UDIDs). |
|
|
360
363
|
| `listTraceTemplates` | Parse `xcrun xctrace list templates` (standard + custom). |
|
|
361
|
-
| `inspectTrace` | Orientation tool for `.trace` bundles. Returns schemas present + row counts + device/OS/template metadata + `suggestedNextCalls[]` mapping each populated known schema to its analyzer. Use this as the FIRST call on any `.trace`. New in v1.11. |
|
|
364
|
+
| `inspectTrace` | Orientation tool for `.trace` bundles. Returns schemas present + row counts + device/OS/template metadata + `suggestedNextCalls[]` mapping each populated known schema to its analyzer. Use this as the FIRST call on any `.trace`. New in v1.11. v1.17: fault-tolerant — returns `ok: true` with `schemas: []` and a diagnosis string when `xctrace export --toc` fails on wedged 52K bundles, instead of throwing. |
|
|
362
365
|
|
|
363
366
|
### Synthesize (1)
|
|
364
367
|
|
package/USAGE.md
CHANGED
|
@@ -302,6 +302,7 @@ Once you have the diagnosis, here are useful follow-up prompts you can paste int
|
|
|
302
302
|
| "Show the retain chain that keeps `DetailViewModel` alive." | `findRetainers(path, className: "DetailViewModel")` |
|
|
303
303
|
| "Compare `~/Desktop/before.memgraph` to `~/Desktop/after.memgraph`. Did the leak go away?" | `diffMemgraphs(before, after)` |
|
|
304
304
|
| "Did my fix actually resolve the `swiftui.tag-index-projection` cycle?" | `verifyFix(before, after, expectedPatternId: "swiftui.tag-index-projection")`. Returns PASS/PARTIAL/FAIL |
|
|
305
|
+
| "Whitelist `MySingletonCache` (exact match) so it does not vote FAIL on the verify." | `verifyFix(before, after, expectedAliveClasses: [{ pattern: "MySingletonCache", mode: "exact" }])`. v1.17 introduces per-entry modes (`"exact" \| "substring" \| "regex"`); bare strings still default to substring for backwards compat. |
|
|
305
306
|
| "Render the cycle as a Mermaid graph for the PR description." | `renderCycleGraph(path, format: "mermaid")` |
|
|
306
307
|
| "Profile this app on my iPhone for 90 seconds and tell me about hangs." | `listTraceDevices` → `recordTimeProfile` → `analyzeHangs` |
|
|
307
308
|
| "Pull the last 5 minutes of `error`-level logs from `MyApp`." | `logShow(last: "5m", process: "MyApp", level: "default")` |
|
|
@@ -420,13 +421,13 @@ It hits every `xctrace`-based tool the same way (this MCP, XcodeTraceMCP, raw `x
|
|
|
420
421
|
|
|
421
422
|
Recovery options, ranked by automation cost:
|
|
422
423
|
|
|
423
|
-
1. **`recordViaInstrumentsApp` MCP tool (v1.16+).** Opens Instruments.app for you, surfaces step-by-step instructions in the response, then watches a directory for the saved `.trace`. Once it appears, the tool returns the path plus a chained `inspectTrace` summary. The user-in-loop step is the recording itself (pick template, hit Record, hit Stop, hit Save). Why is it user-in-loop? Instruments.app's AppleScript surface is minimal: queries on the `document` class only, no verbs for start/stop/select-template (see `Xcode.app/Contents/Applications/Instruments.app/Contents/Resources/Instruments.sdef`). The watcher polls every 5 seconds and considers a bundle "saved" after its mtime is stable for 10 seconds.
|
|
424
|
+
1. **`recordViaInstrumentsApp` MCP tool (v1.16+).** Opens Instruments.app for you, surfaces step-by-step instructions in the response, then watches a directory for the saved `.trace`. Once it appears, the tool returns the path plus a chained `inspectTrace` summary. The user-in-loop step is the recording itself (pick template, hit Record, hit Stop, hit Save). Why is it user-in-loop? Instruments.app's AppleScript surface is minimal: queries on the `document` class only, no verbs for start/stop/select-template (see `Xcode.app/Contents/Applications/Instruments.app/Contents/Resources/Instruments.sdef`). The watcher polls every 5 seconds and considers a bundle "saved" after its mtime is stable for 10 seconds. **v1.17 fixed the common "I hit Save and accepted the Desktop default" miss**: the watcher now also queries running Instruments.app via AppleScript each poll for any document whose file path was set after the tool started. On match, returns the path with `savedOutsideWatchDir: true` so you do not have to re-record into `watchDir`.
|
|
424
425
|
2. **Record on an older macOS host with Xcode 26.0 if you have one available.** Pre-regression `xctrace record` produces clean traces. The 2026-05-15 validation used `~/Desktop/wishlist-tti-device.trace`, a Time Profiler trace captured this way: 91s recording, 35 hangs detected, 44 418 time-profile samples, fully analyzable by memorydetective's trace-side tools.
|
|
425
426
|
3. **Record manually via Instruments.app GUI without the wrapper.** Instruments.app on macOS 26.x still produces valid `.trace` bundles. Open Instruments, pick a template, choose the simulator + app, hit Record, drive the scenario, Stop, Save. Then point `inspectTrace` / `summarizeTrace` / `analyzeHangs` / `analyzeTimeProfile` / `compareTracesByPattern` at the saved bundle. All trace-side analyzers work normally on Instruments-recorded `.trace` bundles.
|
|
426
427
|
4. **Record against a physical device (USB or wireless).** The regression appears to be simulator-specific. `xctrace record --device <UUID> --launch <app>` against a real iPhone / iPad does NOT exhibit the same wedge. Use this when you have a physical target available.
|
|
427
428
|
5. **Wait for Apple.** The Feedback assistant is the right escalation path. The regression has shipped through Xcode 26.4 + 26.5; expect a fix in 26.6 or later.
|
|
428
429
|
|
|
429
|
-
memorydetective's `recordViaInstrumentsApp` (v1.16) + pre-flight probe (v1.14) cover the automated paths around the regression until Apple ships a fix.
|
|
430
|
+
memorydetective's `recordViaInstrumentsApp` (v1.16, hardened in v1.17) + pre-flight probe (v1.14) cover the automated paths around the regression until Apple ships a fix. v1.17 also added a `bundleStatus: "unknown" \| "salvageable" \| "wedged"` field on `recordTimeProfile` responses and a fault-tolerant fallback on `inspectTrace` so the entire MCP call no longer throws when xctrace refuses a wedged bundle.
|
|
430
431
|
|
|
431
432
|
### `replayScenario` returns `workaroundNotice: { issue: "axe-not-found" }`
|
|
432
433
|
|
|
@@ -86,3 +86,29 @@ export interface SchemaDiscoveryRunner {
|
|
|
86
86
|
}>;
|
|
87
87
|
}
|
|
88
88
|
export declare function fetchDiscoveredSchemas<F extends SchemaFamily>(runCommand: SchemaDiscoveryRunner, tracePath: string, families: readonly F[]): Promise<Record<F, string>>;
|
|
89
|
+
/**
|
|
90
|
+
* v1.17 B-06. Same as {@link fetchDiscoveredSchemas} but also returns a
|
|
91
|
+
* discovery status so callers can surface "we fell back" via the unified
|
|
92
|
+
* `supportStatus[]` instead of silently using canonical names.
|
|
93
|
+
*
|
|
94
|
+
* Status values:
|
|
95
|
+
*
|
|
96
|
+
* - `ok`: TOC fetched, pattern match succeeded for at least one family.
|
|
97
|
+
* (When a specific family does not match, the canonical name is still
|
|
98
|
+
* returned for it, but the overall status is still `ok` because the TOC
|
|
99
|
+
* itself was readable.)
|
|
100
|
+
* - `failed`: `xctrace --toc` returned non-zero, or threw, or returned
|
|
101
|
+
* empty stdout. `schemas` are all canonical fallbacks.
|
|
102
|
+
*
|
|
103
|
+
* The legacy `fetchDiscoveredSchemas` keeps its existing silent-fallback
|
|
104
|
+
* contract for callers that do not care.
|
|
105
|
+
*/
|
|
106
|
+
export interface SchemaDiscoveryStatus<F extends SchemaFamily> {
|
|
107
|
+
schemas: Record<F, string>;
|
|
108
|
+
status: "ok" | "failed";
|
|
109
|
+
/** When status is `failed`, a short reason suitable for `supportStatus.reason`. */
|
|
110
|
+
reason?: string;
|
|
111
|
+
}
|
|
112
|
+
export declare function fetchDiscoveredSchemasWithStatus<F extends SchemaFamily>(runCommand: SchemaDiscoveryRunner, tracePath: string, families: readonly F[]): Promise<SchemaDiscoveryStatus<F>>;
|
|
113
|
+
/** Test hook — clears the one-time warning dedupe. */
|
|
114
|
+
export declare function _resetSchemaDiscoveryWarningsForTests(): void;
|
|
@@ -123,22 +123,51 @@ export function discoverSchemas(tocXml, families) {
|
|
|
123
123
|
return out;
|
|
124
124
|
}
|
|
125
125
|
export async function fetchDiscoveredSchemas(runCommand, tracePath, families) {
|
|
126
|
+
const { schemas } = await fetchDiscoveredSchemasWithStatus(runCommand, tracePath, families);
|
|
127
|
+
return schemas;
|
|
128
|
+
}
|
|
129
|
+
export async function fetchDiscoveredSchemasWithStatus(runCommand, tracePath, families) {
|
|
130
|
+
const fallback = () => {
|
|
131
|
+
const out = {};
|
|
132
|
+
for (const f of families)
|
|
133
|
+
out[f] = CANONICAL_SCHEMA_NAME[f];
|
|
134
|
+
return out;
|
|
135
|
+
};
|
|
126
136
|
try {
|
|
127
137
|
const result = await runCommand("xcrun", ["xctrace", "export", "--input", tracePath, "--toc"], { timeoutMs: 60_000 });
|
|
128
138
|
if (result.code !== 0) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
139
|
+
const reason = `xctrace --toc failed (code ${result.code}): ` +
|
|
140
|
+
(result.stderr.trim() || result.stdout.trim() || "<no output>");
|
|
141
|
+
warnSchemaDiscoveryOnce(tracePath, reason);
|
|
142
|
+
return { schemas: fallback(), status: "failed", reason };
|
|
143
|
+
}
|
|
144
|
+
if (!result.stdout.trim()) {
|
|
145
|
+
const reason = "xctrace --toc returned empty stdout";
|
|
146
|
+
warnSchemaDiscoveryOnce(tracePath, reason);
|
|
147
|
+
return { schemas: fallback(), status: "failed", reason };
|
|
134
148
|
}
|
|
135
|
-
return discoverSchemas(result.stdout, families);
|
|
149
|
+
return { schemas: discoverSchemas(result.stdout, families), status: "ok" };
|
|
136
150
|
}
|
|
137
|
-
catch {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return out;
|
|
151
|
+
catch (err) {
|
|
152
|
+
const reason = `xctrace --toc threw: ${err?.message ?? String(err)}`;
|
|
153
|
+
warnSchemaDiscoveryOnce(tracePath, reason);
|
|
154
|
+
return { schemas: fallback(), status: "failed", reason };
|
|
142
155
|
}
|
|
143
156
|
}
|
|
157
|
+
const schemaDiscoveryWarnings = new Set();
|
|
158
|
+
function warnSchemaDiscoveryOnce(tracePath, reason) {
|
|
159
|
+
const key = `${tracePath}:${reason}`;
|
|
160
|
+
if (schemaDiscoveryWarnings.has(key))
|
|
161
|
+
return;
|
|
162
|
+
schemaDiscoveryWarnings.add(key);
|
|
163
|
+
// Respect the global stderr-mute used elsewhere in the codebase.
|
|
164
|
+
if (process.env.MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY)
|
|
165
|
+
return;
|
|
166
|
+
process.stderr.write(`[memorydetective] schemaDiscovery: ${reason} (path: ${tracePath}). ` +
|
|
167
|
+
`Analyzers will use canonical schema names; results may be stale on traces that renamed schemas.\n`);
|
|
168
|
+
}
|
|
169
|
+
/** Test hook — clears the one-time warning dedupe. */
|
|
170
|
+
export function _resetSchemaDiscoveryWarningsForTests() {
|
|
171
|
+
schemaDiscoveryWarnings.clear();
|
|
172
|
+
}
|
|
144
173
|
//# sourceMappingURL=schemaDiscovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemaDiscovery.js","sourceRoot":"","sources":["../../src/parsers/schemaDiscovery.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"schemaDiscovery.js","sourceRoot":"","sources":["../../src/parsers/schemaDiscovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a string env var value into a boolean using the strtobool set:
|
|
3
|
+
*
|
|
4
|
+
* truthy: 1 / true / t / yes / y / on
|
|
5
|
+
* falsy: 0 / false / f / no / n / off
|
|
6
|
+
*
|
|
7
|
+
* Case-insensitive. Leading / trailing whitespace tolerated. The set
|
|
8
|
+
* is the same one Python's `distutils.util.strtobool` uses and that
|
|
9
|
+
* envalid's `bool()` accepts. v1.17 B-03.
|
|
10
|
+
*
|
|
11
|
+
* On unrecognized non-empty input, emits a one-time stderr warning
|
|
12
|
+
* naming the env var and falls back to `defaultValue`. The warning is
|
|
13
|
+
* suppressed when `MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY=1` is set
|
|
14
|
+
* (consistent with the rest of our advisory plumbing).
|
|
15
|
+
*
|
|
16
|
+
* `varName` is required so the warning surfaces a useful message; pass
|
|
17
|
+
* the literal env var name (e.g. "MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS")
|
|
18
|
+
* even if you read it from another source.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseBooleanEnv(raw: string | undefined, defaultValue: boolean, varName: string): boolean;
|
|
21
|
+
/** Test-only: reset the once-per-var warning flag set. */
|
|
22
|
+
export declare function resetParseBooleanEnvWarningsForTests(): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a string env var value into a boolean using the strtobool set:
|
|
3
|
+
*
|
|
4
|
+
* truthy: 1 / true / t / yes / y / on
|
|
5
|
+
* falsy: 0 / false / f / no / n / off
|
|
6
|
+
*
|
|
7
|
+
* Case-insensitive. Leading / trailing whitespace tolerated. The set
|
|
8
|
+
* is the same one Python's `distutils.util.strtobool` uses and that
|
|
9
|
+
* envalid's `bool()` accepts. v1.17 B-03.
|
|
10
|
+
*
|
|
11
|
+
* On unrecognized non-empty input, emits a one-time stderr warning
|
|
12
|
+
* naming the env var and falls back to `defaultValue`. The warning is
|
|
13
|
+
* suppressed when `MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY=1` is set
|
|
14
|
+
* (consistent with the rest of our advisory plumbing).
|
|
15
|
+
*
|
|
16
|
+
* `varName` is required so the warning surfaces a useful message; pass
|
|
17
|
+
* the literal env var name (e.g. "MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS")
|
|
18
|
+
* even if you read it from another source.
|
|
19
|
+
*/
|
|
20
|
+
const TRUTHY = new Set(["1", "true", "t", "yes", "y", "on"]);
|
|
21
|
+
const FALSY = new Set(["0", "false", "f", "no", "n", "off"]);
|
|
22
|
+
const warnedVars = new Set();
|
|
23
|
+
export function parseBooleanEnv(raw, defaultValue, varName) {
|
|
24
|
+
if (raw == null)
|
|
25
|
+
return defaultValue;
|
|
26
|
+
const trimmed = raw.trim();
|
|
27
|
+
if (trimmed === "")
|
|
28
|
+
return defaultValue;
|
|
29
|
+
const lc = trimmed.toLowerCase();
|
|
30
|
+
if (TRUTHY.has(lc))
|
|
31
|
+
return true;
|
|
32
|
+
if (FALSY.has(lc))
|
|
33
|
+
return false;
|
|
34
|
+
// Unrecognized non-empty value: warn once per var.
|
|
35
|
+
if (!warnedVars.has(varName) &&
|
|
36
|
+
process.env.MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY !== "1") {
|
|
37
|
+
warnedVars.add(varName);
|
|
38
|
+
const accepted = "1 / true / t / yes / y / on | 0 / false / f / no / n / off";
|
|
39
|
+
process.stderr.write(`[memorydetective] ${varName}="${raw}" is not a recognized boolean. Accepted (case-insensitive): ${accepted}. Falling back to default (${defaultValue}).\n`);
|
|
40
|
+
}
|
|
41
|
+
return defaultValue;
|
|
42
|
+
}
|
|
43
|
+
/** Test-only: reset the once-per-var warning flag set. */
|
|
44
|
+
export function resetParseBooleanEnvWarningsForTests() {
|
|
45
|
+
warnedVars.clear();
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=parseBooleanEnv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseBooleanEnv.js","sourceRoot":"","sources":["../../src/runtime/parseBooleanEnv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAC7D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;AAE7D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;AAErC,MAAM,UAAU,eAAe,CAC7B,GAAuB,EACvB,YAAqB,EACrB,OAAe;IAEf,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,YAAY,CAAC;IACrC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,YAAY,CAAC;IACxC,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACjC,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAChC,mDAAmD;IACnD,IACE,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,0CAA0C,KAAK,GAAG,EAC9D,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACxB,MAAM,QAAQ,GAAG,4DAA4D,CAAC;QAC9E,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qBAAqB,OAAO,KAAK,GAAG,+DAA+D,QAAQ,8BAA8B,YAAY,MAAM,CAC5J,CAAC;IACJ,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,oCAAoC;IAClD,UAAU,CAAC,KAAK,EAAE,CAAC;AACrB,CAAC"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* before any tool work.
|
|
17
17
|
*/
|
|
18
18
|
import os from "node:os";
|
|
19
|
+
import { parseBooleanEnv } from "./parseBooleanEnv.js";
|
|
19
20
|
const ADVISORY_MESSAGE = "macOS 26.x has an Apple-side kernel regression in `task_for_pid` against simulator processes. " +
|
|
20
21
|
"`leaks --outputGraph`, `heap`, and `xctrace --template Allocations` all abort with " +
|
|
21
22
|
"`Failed to get DYLD info for task` / minimal-corpse, even with `MallocStackLogging=1` " +
|
|
@@ -49,8 +50,10 @@ const ADVISORY_ACTIONS = [
|
|
|
49
50
|
* @param osRelease - `os.release()` value (defaults to live).
|
|
50
51
|
*/
|
|
51
52
|
export function getPlatformAdvisory(env = process.env, osPlatform = os.platform, osRelease = os.release) {
|
|
52
|
-
|
|
53
|
+
// v1.17 B-03: accept the strtobool truthy set (1 / true / yes / on / etc.).
|
|
54
|
+
if (parseBooleanEnv(env.MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY, false, "MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY")) {
|
|
53
55
|
return null;
|
|
56
|
+
}
|
|
54
57
|
if (osPlatform() !== "darwin")
|
|
55
58
|
return null;
|
|
56
59
|
const release = osRelease();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platformCheck.js","sourceRoot":"","sources":["../../src/runtime/platformCheck.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"platformCheck.js","sourceRoot":"","sources":["../../src/runtime/platformCheck.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAQvD,MAAM,gBAAgB,GACpB,gGAAgG;IAChG,qFAAqF;IACrF,wFAAwF;IACxF,uFAAuF;IACvF,0FAA0F;IAC1F,yFAAyF;IACzF,cAAc,CAAC;AAEjB,MAAM,gBAAgB,GAAG;IACvB,mFAAmF;IACnF,yFAAyF;IACzF,+JAA+J;IAC/J,+FAA+F;CAChG,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAoD,OAAO,CAAC,GAAG,EAC/D,aAAoC,EAAE,CAAC,QAAQ,EAC/C,YAA0B,EAAE,CAAC,OAAO;IAEpC,4EAA4E;IAC5E,IACE,eAAe,CACb,GAAG,CAAC,0CAA0C,EAC9C,KAAK,EACL,4CAA4C,CAC7C,EACD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,UAAU,EAAE,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,6EAA6E;IAC7E,6EAA6E;IAC7E,oBAAoB;IACpB,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO;QACL,KAAK,EAAE,8BAA8B;QACrC,OAAO,EAAE,gBAAgB;QACzB,kBAAkB,EAAE,gBAAgB;KACrC,CAAC;AACJ,CAAC;AAED,IAAI,0BAA0B,GAAG,KAAK,CAAC;AAEvC;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B,CAC1C,QAAiC,EACjC,SAAiC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;IAErE,IAAI,0BAA0B;QAAE,OAAO;IACvC,IAAI,QAAQ,IAAI,IAAI;QAAE,OAAO;IAC7B,MAAM,CAAC,wCAAwC,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;IACrE,0BAA0B,GAAG,IAAI,CAAC;AACpC,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,iCAAiC;IAC/C,0BAA0B,GAAG,KAAK,CAAC;AACrC,CAAC"}
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
*/
|
|
35
35
|
import os from "node:os";
|
|
36
36
|
import { join as joinPath } from "node:path";
|
|
37
|
+
import { parseBooleanEnv } from "./parseBooleanEnv.js";
|
|
37
38
|
export const DEFAULT_MAX_RECORDING_SECONDS = 300;
|
|
38
39
|
export function defaultTraceRoot(homeDir = os.homedir()) {
|
|
39
40
|
return joinPath(homeDir, "Library", "Application Support", "memorydetective", "traces");
|
|
@@ -59,7 +60,8 @@ export function defaultTraceRoot(homeDir = os.homedir()) {
|
|
|
59
60
|
* or missing values fall back to the default location.
|
|
60
61
|
*/
|
|
61
62
|
export function getSecurityFlags(env = process.env, homeDir = os.homedir()) {
|
|
62
|
-
|
|
63
|
+
// v1.17 B-03: accept the strtobool truthy set.
|
|
64
|
+
const allowLaunch = parseBooleanEnv(env.MEMORYDETECTIVE_ALLOW_LAUNCH, false, "MEMORYDETECTIVE_ALLOW_LAUNCH");
|
|
63
65
|
const rawMax = env.MEMORYDETECTIVE_MAX_RECORDING_SECONDS;
|
|
64
66
|
let maxRecordingSeconds = DEFAULT_MAX_RECORDING_SECONDS;
|
|
65
67
|
if (rawMax != null && rawMax !== "") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"securityFlags.js","sourceRoot":"","sources":["../../src/runtime/securityFlags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"securityFlags.js","sourceRoot":"","sources":["../../src/runtime/securityFlags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAQvD,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,CAAC;AAEjD,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,CAAC,OAAO,EAAE;IAC7D,OAAO,QAAQ,CACb,OAAO,EACP,SAAS,EACT,qBAAqB,EACrB,iBAAiB,EACjB,QAAQ,CACT,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAoD,OAAO,CAAC,GAAG,EAC/D,UAAkB,EAAE,CAAC,OAAO,EAAE;IAE9B,+CAA+C;IAC/C,MAAM,WAAW,GAAG,eAAe,CACjC,GAAG,CAAC,4BAA4B,EAChC,KAAK,EACL,8BAA8B,CAC/B,CAAC;IAEF,MAAM,MAAM,GAAG,GAAG,CAAC,qCAAqC,CAAC;IACzD,IAAI,mBAAmB,GAAG,6BAA6B,CAAC;IACxD,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3C,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,0BAA0B,CAAC;IAC/C,MAAM,SAAS,GACb,OAAO,IAAI,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE9E,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,SAAS,EAAE,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GACxC,0RAA0R,CAAC;AAE7R;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CACzC,SAAiB,EACjB,GAAW;IAEX,OAAO,CACL,iCAAiC,SAAS,kCAAkC,GAAG,IAAI;QACnF,gGAAgG,CACjG,CAAC;AACJ,CAAC"}
|
|
@@ -62,7 +62,13 @@ export interface AnalyzeEnergyImpactResult {
|
|
|
62
62
|
supportStatus: SupportStatus[];
|
|
63
63
|
}
|
|
64
64
|
/** Normalize whatever string xctrace puts in the bucket column to our
|
|
65
|
-
* canonical enum. v1.15. Exported for testing.
|
|
65
|
+
* canonical enum. v1.15. Exported for testing.
|
|
66
|
+
*
|
|
67
|
+
* v1.17: priority order fixed. "active" / "foreground" / "passive" /
|
|
68
|
+
* "background" are checked BEFORE "high" so strings like "highly active"
|
|
69
|
+
* classify as `active` (per the dominant lexical signal) instead of
|
|
70
|
+
* `high`. Long-tail edge case from real xctrace output, but observed
|
|
71
|
+
* enough to warrant the reorder. */
|
|
66
72
|
export declare function normalizeBucket(raw: string | undefined): EnergyBucket;
|
|
67
73
|
/** Pure: turn the energy-impact XML into the analyzed result. */
|
|
68
74
|
export declare function analyzeEnergyImpactFromXml(xml: string, tracePath: string, topN?: number): AnalyzeEnergyImpactResult;
|
|
@@ -49,19 +49,25 @@ function pickString(row, keys) {
|
|
|
49
49
|
return undefined;
|
|
50
50
|
}
|
|
51
51
|
/** Normalize whatever string xctrace puts in the bucket column to our
|
|
52
|
-
* canonical enum. v1.15. Exported for testing.
|
|
52
|
+
* canonical enum. v1.15. Exported for testing.
|
|
53
|
+
*
|
|
54
|
+
* v1.17: priority order fixed. "active" / "foreground" / "passive" /
|
|
55
|
+
* "background" are checked BEFORE "high" so strings like "highly active"
|
|
56
|
+
* classify as `active` (per the dominant lexical signal) instead of
|
|
57
|
+
* `high`. Long-tail edge case from real xctrace output, but observed
|
|
58
|
+
* enough to warrant the reorder. */
|
|
53
59
|
export function normalizeBucket(raw) {
|
|
54
60
|
if (!raw)
|
|
55
61
|
return "unknown";
|
|
56
62
|
const lc = raw.toLowerCase();
|
|
57
63
|
if (lc.includes("idle"))
|
|
58
64
|
return "idle";
|
|
59
|
-
if (lc.includes("high"))
|
|
60
|
-
return "high";
|
|
61
65
|
if (lc.includes("active") || lc.includes("foreground"))
|
|
62
66
|
return "active";
|
|
63
67
|
if (lc.includes("passive") || lc.includes("background"))
|
|
64
68
|
return "passive";
|
|
69
|
+
if (lc.includes("high"))
|
|
70
|
+
return "high";
|
|
65
71
|
return "unknown";
|
|
66
72
|
}
|
|
67
73
|
/** Pure: turn the energy-impact XML into the analyzed result. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzeEnergyImpact.js","sourceRoot":"","sources":["../../src/tools/analyzeEnergyImpact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EACL,eAAe,EACf,QAAQ,EACR,WAAW,GAEZ,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEpE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,qHAAqH,CACtH;IACH,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CACP,yEAAyE,CAC1E;IACH,YAAY,EAAE,iBAAiB;CAChC,CAAC,CAAC;AA0CH,SAAS,UAAU,CACjB,GAAiC,EACjC,IAAc;IAEd,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,UAAU,CACjB,GAAiC,EACjC,IAAc;IAEd,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;
|
|
1
|
+
{"version":3,"file":"analyzeEnergyImpact.js","sourceRoot":"","sources":["../../src/tools/analyzeEnergyImpact.ts"],"names":[],"mappings":"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"}
|
|
@@ -220,24 +220,33 @@ export function analyzeHangsFromXml(xml, tracePath, topN = 10, minDurationMs = 0
|
|
|
220
220
|
: {}),
|
|
221
221
|
diagnosis,
|
|
222
222
|
status: "available",
|
|
223
|
+
// v1.17 B-08: supportStatus[] ALWAYS includes both potential-hangs
|
|
224
|
+
// and hang-risks entries so consumers can disambiguate the four
|
|
225
|
+
// distinct states by inspecting the array:
|
|
226
|
+
// 1. potential-hangs available + hang-risks available -> both schemas had rows
|
|
227
|
+
// 2. potential-hangs available + hang-risks not_present (reason: schema empty) -> exported, no rows
|
|
228
|
+
// 3. potential-hangs available + hang-risks not_present (reason: caller did not provide hangRisksXml) -> caller skipped
|
|
229
|
+
// 4. potential-hangs not_present (handled in the early-return branch above)
|
|
223
230
|
supportStatus: [
|
|
224
231
|
{
|
|
225
232
|
kind: "potential-hangs",
|
|
226
233
|
status: "available",
|
|
227
234
|
sourceSchemas: ["potential-hangs"],
|
|
228
235
|
},
|
|
229
|
-
|
|
230
|
-
?
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
236
|
+
risksAnalysis
|
|
237
|
+
? {
|
|
238
|
+
kind: "hang-risks",
|
|
239
|
+
status: risksAnalysis.total > 0 ? "available" : "not_present",
|
|
240
|
+
sourceSchemas: ["hang-risks"],
|
|
241
|
+
...(risksAnalysis.total === 0
|
|
242
|
+
? { reason: "Schema exported but no rows present." }
|
|
243
|
+
: {}),
|
|
244
|
+
}
|
|
245
|
+
: {
|
|
246
|
+
kind: "hang-risks",
|
|
247
|
+
status: "not_present",
|
|
248
|
+
reason: "Caller did not provide hangRisksXml; pass the hang-risks export to opt in.",
|
|
249
|
+
},
|
|
241
250
|
],
|
|
242
251
|
};
|
|
243
252
|
}
|