fix(apple): refuse captures whose window or panel identity is unknown

TH
4h ago
+443-53

Summary

  • Native macOS capture, scroll, and click fallback share one visible, nonempty layer-0 front-window selection and one on-screen window-list query. App-modal level-8 alerts and floating palettes are skipped. Capture refuses instead of substituting another window, with typed exclusion reasons and a runnable snapshot remedy. Each refusal builds its reason, hint, and front-window id in the Swift helper, so the TypeScript client forwards the details envelope without a lookup table. Screenshot and scroll report window-list-unreadable with a retry hint when the window-list query fails.
  • Foldable capture refuses with capture-panel-unidentified when neither panel power nor primary identity selects a panel. Help warns that an ambiguous primary panel may be dark.

10 files. Part of #3744. ADR 0031 and modal-panel eligibility remain outside this PR. Helper packaging (npm files and Package.swift test targets) is owned by a separate PR.

Validation

  • Head 6d40fbc0f2: pnpm check:affected --run --head 6d40fbc0f2 passed (exactCommit=true) (receipt run-ggnrE5).
  • At 6d40fbc0f2: Swift debug build and 16 helper + 6 input tests passed, including nil-versus-empty reads and per-refusal hint pins. 12 focused helper tests and 1338 capture/platform-apple tests passed. Format, lint, typecheck, layering, fallow, and docs checks passed in the receipt above.
  • Live native runs on this Mac (Screen Recording granted, helper rebuilt from this head, isolated session and state dir): TextEdit front-window captures succeeded (1172x976 and 780x636 PNGs); a menu-bar-only app after closing its windows refused with COMMAND_FAILED, details.reason: "window-not-found", and details.hint: "Open or unminimize a window of the app on the current Space, then retry the screenshot." reaching the CLI untouched. Sessions closed, daemon stopped, state dir removed.
  • Earlier-head live evidence also covers minimized-window refusal, overlays, diff, and front-only scrolling. Capture exclusions remain fixture-tested; no iOS 27.1 Duo run.
  • New-head CI: pending; Coverage, Integration, native/device lanes remain required.