Skip to content

v4.9.0

Choose a tag to compare

@steipete steipete released this 07 Oct 14:47
· 33 commits to main since this release
7020aed

4.9.0 - 2026-10-06

Highlights: Add exact app- and PID-scoped menu-bar extra clicks, keep foreground file dialogs bound to their parent window, tailor Agent guidance to the acquired tool catalog, show visualizer overlays from a hidden companion app, restore clipboard slots faithfully across processes, and harden release archive and artifact validation.

  • Add exact app/PID-scoped menu-extra clicks with bounded AX owner preparation and revalidation, preserving displayed-CG names and indices without scanning unrelated applications. Thanks @buremba! #953.
  • Keep targeted foreground file-dialog focus, navigation, and result receipts under one parent-window owner; negotiate exact execution with Bridge hosts and scope document reads to that parent without losing file-on-disk verification when Save closes it.
  • Fix application-targeted file sheets losing their parent-window identity; preserve compatible panels and ignore unrelated alerts when selecting a unique file panel. Thanks @buremba! #951.
  • Recognize native file-panel identifiers and reuse fresh classification evidence to avoid redundant button scans; batch strict dialog AX reads without truncating hierarchy discovery.
  • Recognize equivalent saved-file paths such as /tmp and /private/tmp in dialog diagnostics, preserving reported paths and directory-only enforcement.
  • Tailor Agent and learn guidance to the available tool catalog, removing irrelevant recipes while preserving execution authority, observation requirements and session history.
  • Show eligible visualizer overlays from a hidden companion app without unhiding or activating it, accepting input, or changing background-input suppression.
  • Avoid redundant PNG encoding for unchanged live capture frames, preserving original bytes and metadata while retaining transformed-frame encoding, actual-byte caps, and artifact validation.
  • Restore clipboard slots from the current persisted contents instead of a stale per-process cache, and keep multi-item clipboards' item order and boundaries through save and restore. Thanks @rudycelekli! #990.
  • Update AXorcist to 0.2.1 to unwrap live Accessibility values and clear inherited typing and final hotkey modifier flags. Thanks @jandubois! #797.
  • Prepare the final-qualification launcher's atomic receipt publisher before spawning the suspended coordinator, so loaded release Macs no longer spend the identity-acknowledgement window compiling Swift; each use still re-verifies the exact executable, and the exit receipt keeps a fresh build.
  • Reject negative SDK automation waits before preparation or earlier input, and keep large positive waits safely cancellable without integer overflow. Thanks @rudycelekli! #973.
  • Preserve literal environment values inside configuration JSON strings and omit expanded documents from decode warnings; retain numeric substitutions and credential references. Thanks @rudycelekli! #972.
  • Reject non-ASCII tar size/checksum text and PAX record lengths/keys before decoding can disguise malformed bytes, preserving binary tar numbers and UTF-8 values. Thanks @rudycelekli! #966.
  • Retain failed browser connection attempts across ordinary provider tools and invalidate cached verification after socket loss, preventing implicit reconnects and stale success. Thanks @rudycelekli! #949.
  • Honor cancellation and connection deadlines during browser application-metadata reads; reconcile failures without repeating a blocked lookup, retaining connected or uncertain provider ownership. Thanks @rudycelekli! #950.
  • Preserve literal log-helper search and filter text without shell re-parsing, including quotes, backslashes and trailing newlines; retain output, streaming and private-mode arguments. Thanks @rudycelekli! #934.
  • Reject missing log-helper option values promptly with a targeted usage error instead of looping indefinitely, before any log access; match native log severity for historical error-only queries. Thanks @rudycelekli! #938.
  • Preserve conventional shell exit statuses when a wrapped source-build command is terminated by a signal, while retaining mapping integrity checks and lock cleanup. Thanks @rudycelekli! #932.
  • Reject malformed or overflowing release versions before computing build numbers, preserving stable versions and supported alpha/beta/rc aliases instead of allowing extra identifiers to alias a different build. Thanks @rudycelekli! #936.
  • Require explicit npm error codes when detecting unpublished versions; server/authentication failures and contradictory responses no longer become absence merely because a diagnostic contains E404. Thanks @rudycelekli! #965.
  • Reject symlinked or nonregular controller sources and catalogs when producing source receipts, while preserving regular executable files and frozen-commit receipts. Thanks @rudycelekli! #957.
  • Bound ZIP data descriptors before allocating or reading their untrusted gap, preserving valid descriptor checks while avoiding malformed-archive memory amplification. Thanks @rudycelekli! #967.
  • Resolve composed symlink targets before accepting artifact trees and archives, refusing root escapes and native-unreadable chains beyond 32 traversals while preserving contained framework and dangling links. Thanks @rudycelekli! #954.
  • Reject archive entries nested beneath regular files as well as symlinks, independent of entry order, before extraction. Thanks @rudycelekli! #955.
  • Fix the Playground log wrapper's moved script path and clarify repository-root examples, preserving arguments and exit status. Thanks @rudycelekli! #933.
  • Fix signed Bridge typing receipts after already-empty clears and already-satisfied caret moves, preserving zero-dispatch no-ops and strict key, delivery and dispatch-count validation.
  • Preserve accepted dispatch evidence and retry-unsafe status after unchanged readback instead of reporting a no-dispatch no-op or a safe retry; positively observed changes still confirm the action. Thanks @rudycelekli! #942.
  • Preserve recorded response-loss evidence when action sequences or quit batches are cancelled, retaining indeterminate outcomes and unsafe retry guidance. Thanks @rudycelekli! #943.
  • Share literal-replacement eligibility between native typing and Bridge validation without changing confirmation policy, and clarify that typing counts represent keystrokes and accepted typing units rather than raw event or Accessibility setter calls.
  • Accept equivalent PID aliases consistently in read-only window listing and target resolution, while retaining conflicting-PID errors and strict single-selector mutation gates. Thanks @rudycelekli! #945.
  • Clarify type --clear help and generated learning guidance to distinguish eligible native Accessibility clearing from keyboard routes, without changing delivery, targeting, or success rules.
  • Format complete keyboard shortcut names without rewriting substrings, distinguish forward and backward delete aliases in compatibility summaries, and reuse the immutable symbol table. Thanks @rudycelekli! #962.
  • Preserve fractional timeout durations in command and dialog diagnostics instead of truncating them to whole seconds, without changing deadlines or error codes. Thanks @rudycelekli! #946.
  • Preserve pending native-operation evidence when combining action receipts, without downgrading it to accepted delivery or weakening response-loss and retry-safety semantics. Thanks @rudycelekli! #944.
  • Escape update-feed URLs and metadata as XML while preserving decoded values and literal replacement characters, including multi-parameter URLs. Thanks @rudycelekli! #935.
  • Validate Swift compatibility-library loader paths and required library architectures per executable slice, so another architecture cannot hide a missing path. Thanks @rudycelekli! #937.
  • Reject ZIP entries with unconsumed trailing DEFLATE bytes before extraction, even when their inflated size and CRC match. Thanks @rudycelekli! #956.
  • Distinguish missing blank title-bar space from changed retained geometry in background paste preparation diagnostics, without relaxing clearance or input guards.
  • Keep CLI and MCP action summaries explicit about unverified or unreported receiver effects, and report paste clipboard cleanup separately without changing canonical outcomes, JSON, retry rules, or exit status.
  • Strip terminal control scalars from agent/task titles before both VibeTunnel and ANSI output, preserving Unicode joiners and preventing embedded title text from injecting terminal commands. Thanks @rudycelekli! #964.
  • Avoid agent-summary crashes on unrepresentable numeric metadata, preserve each consumer's rounding and lookup rules, and report unusable shell exit codes as unavailable rather than success. Thanks @rudycelekli! #961.
  • Preserve apostrophes and escaped characters in JSON documentation reading hints, retaining the legacy single-quoted fallback and malformed-input diagnostics. Thanks @rudycelekli! #941.
  • Explain evaluated Bridge host requirements when see --fresh cannot obtain authenticated producer-bound snapshots, instead of incorrectly claiming fresh AX is unsupported or a binary update is sufficient; preserve host selection, trust, and error codes.
  • Correct the visualizer log helper's receiver subsystem and include info/debug output while preserving explicit predicates, without changing logging settings or rendering behavior.
  • Preserve failed log-query exit statuses through tail-limited terminal and file output instead of reporting success from the downstream pipeline. Thanks @rudycelekli! #959.
  • Preserve complete JSON log output and forward live events without waiting for stream completion; retain line limits for completed text queries. Thanks @rudycelekli! #958.
  • Bound npm MCP wrapper shutdown: cancel pending restarts, allow five seconds for the owned server to exit after SIGTERM, then terminate that same child if necessary. Thanks @rudycelekli! #947.
  • Keep MCP wrapper imports free of server-start side effects for eval, print and stdin consumers, including arguments matching its own path or symlink; preserve real entrypoints and unrelated filesystem errors. Thanks @rudycelekli! #948.
  • Refuse companion-app deployment when source or staged directory permissions prevent moving or cleaning up the bundle, before stopping the running GUI, while preserving read-only files and leaving artifact permissions unchanged.
  • Stop inferring a captured window's main state from selection, list position, or visibility; retain the existing false/unavailable convention and preserve already-supplied main-state metadata without extra Accessibility reads.
  • Keep Playground log filters and message text literal, reject missing option values, preserve export failures and complete JSON/live output, and match native error severity. Thanks @rudycelekli! #968.
  • Validate smooth duration and step overrides for the human MCP move profile, which forces smooth movement but previously dispatched out-of-range overrides. Thanks @rudycelekli! #970.
  • Report MCP cursor movement directions in screen coordinates, where eastward movement was previously reported as west. Thanks @rudycelekli! #960.
  • Report dialog classification and truncation from cached snapshots instead of always returning a non-dialog, untruncated result. Thanks @rudycelekli! #989.
  • Publish release CLI archives and the app ZIP atomically so a failed write leaves any previous artifact intact. Thanks @rudycelekli! #979.
  • Drain ZIP entry readers before the archive closes its descriptor, so a rejected payload no longer crashes later with an uncaught EBADF (#985). Thanks @rudycelekli! #986.
  • Reject release package resolution when the pinned Sparkle checkout has tracked, staged, or untracked changes. Thanks @rudycelekli! #978.
  • Install the Swift compatibility libraries that standalone CLI builds need next to the binary, so a standalone install loads after moving; release builds keep the mandatory older-SDK runtime audit. Thanks @rudycelekli! #982.
  • Bound release-preflight CLI probes with a timeout and report spawn or timeout failures instead of hanging or misreading them as contract failures. Thanks @rudycelekli! #984.
  • Clean up Node runtime build downloads and work directories when an early transfer or temporary-directory allocation fails. Thanks @rudycelekli! #980.
  • Render capture-timeout and rate-limit retry durations that cannot be represented as integers without trapping. Thanks @rudycelekli! #981.
  • Preserve managed screenshots when a snapshot reuses its own stored image as input, copying through a staged file before replacing the artifact. Thanks @rudycelekli! #987.
  • Require canonical lowercase ASCII hex selected-leaf candidate digests, rejecting full-width digits and letters that Swift's hex check accepted. Thanks @rudycelekli! #983.
  • Report the qualification guardian's own failure when the managed launcher's identity acknowledgement reaches an exited guardian, instead of crashing on an uncaught EPIPE before cleanup; guardian deadlines and the acknowledgement protocol are unchanged.

Compatibility

  • App/PID-scoped menubar click and exact-owner file-dialog execution require a 4.9.0 GUI Bridge host that advertises those capabilities at protocol 1.43. With an older Peekaboo app as the Bridge host, these requests refuse before any input instead of falling back to a global search or unscoped dialog handling; update the app together with the CLI.

Verification

Proof

Peekaboo 4.9.0 is built from the frozen source commit recorded in release-plan.json: 7020aedd362038043e4fc1988a8634657270e476.

  • Release preparation: 4.9.0 publishes from release/4.9.0 (#997), created from main at 2a8de8d7c, with the driver's --release-branch mode. The branch adds chore(release): prepare Peekaboo 4.9.0. A first publication attempt stopped before any build or public action because the preflight's SwiftFormat check reformatted eight Apps/CLI files left by recent landings; style: apply SwiftFormat to recently landed CLI sources (formatter output only, reviewed) fixed that on main, and the branch was rebuilt on top. A second attempt stopped in the CLI tests, again before any public action: a git-backed fixture test reused the staleness probe's 5-second product deadline for git init under heavy CPU contention. test(cli): give git staleness fixture calls room under CPU contention fixed it on main, which by then also carried #995's release-preflight determinism fixes, and the release preparation was regenerated on that main. A third attempt passed the native preflight and built the CLI, but Apple's notarization upload kept aborting while the host's uplink was saturated; once the exact binary was accepted, main had gained #999 (qualification launcher ACK-window fix) and #1002 (SwiftFormat enforcement in macOS CI), so the preparation was regenerated again on that main and rebuilt. A fourth attempt stopped in the CLI tests when a config-editor timeout fixture's one-second window reaped /bin/sh before it recorded its PID; test(cli): give the config editor timeout fixture room under CPU contention fixed it, and #1003 now freezes --release-branch preflights at the pushed cut (HEAD must equal the live origin/release/<version>), so a relaunch no longer requires a new cut when main moves. An independent Codex P0–P2 review passed with no findings: all 65 root changelog entries survive verbatim with contributor credits, the release notes equal the root 4.9.0 section, the CLI section keeps its 40 entries, and the highlights, README, and Compatibility note are supported by the entries and by the Bridge capability gates (exact file-dialog execution and scoped menu-bar actions at protocol 1.43 refuse before dispatch on older hosts). The version-surface, changelog, tracked release-notes, documentation, and release-preflight contracts were run directly against the branch; the publication preflight runs the complete prepare-release, including CLI command/help/inventory contracts, against the freshly built CLI.
  • Native publication toolchain: Xcode 27.2, Swift 6.4, macOS SDK 27.2, Node 26.10.0, pnpm 11.28.4, on macOS 27.0, at normal scheduling priority, from a relocated staging clone with the pinned release helper.
  • The publication driver runs the complete native preflight on the frozen source before packaging, then builds, signs, and notarizes the universal CLI, app, and DMG.
  • main before the cut passed the full serial package suites (Supplemental release validation) after the 2026-10-06 contributor landings, including the restored AgentRun50PolicyTests expectation and the ZIP reader EBADF fix.
  • npm publication runs through the Publish npm release tarball workflow, the registered npm trusted publisher for @steipete/peekaboo, which publishes the exact tarball uploaded to this release after checking it against checksums.txt and its embedded name/version, with signed provenance; the driver's resume verifies registry integrity against the retained tarball.

Older-runtime qualification

  • The driver's Swift runtime import audit verifies every CLI slice against the macOS 26.5 SDK runtime baseline (minimum macOS 15.0) and rejects unsupported strong runtime imports, including _swift_initBorrow, before packaging.
  • Before publication is confirmed, the packaged arm64, x86_64, and universal archives are independently audited against the same SDK's Swift runtime export lists (following re-exports) and launched with all Xcode, Command Line Tools, and cryptex toolchain paths denied.

Exact-source hosted validation

Coverage limits: no physical macOS 26 or macOS 15 machine executed the 4.9.0 bytes. SwiftLint reports existing non-serious violations; the hosted SwiftLint gate passes. No task-owned isolated desktop was available for live desktop proof of scoped menu-bar clicks or exact file-dialog execution; synthetic certification and hosted tests are not claimed as live desktop proof. The human-profile MCP move validation (#970) was proven against the real MCP server without dispatching input.

Publication source: 7020aedd362038043e4fc1988a8634657270e476. Publication requires successful completion of the linked exact-source workflows.