Skip to content

0.0.7

Choose a tag to compare

@github-actions github-actions released this 16 Jun 21:27
· 21 commits to master since this release
cfb9cbb

Added

  • dusk:console now surfaces debugPrint output even without fluttersdk_telescope. DuskPlugin.install() now chains a debugPrint override that records every call into a bounded in-package ring buffer (cap 50, newest-first). ext.dusk.console merges this buffer with the existing telescope recentLogsReader output using the same merge+dedup pattern as ext.dusk.exceptions, so debugPrint(...) / print(...) calls appear in dusk:console results regardless of whether telescope is installed. The telescope reader indirection is preserved: when telescope is wired it augments with Logger.root.onRecord entries and any other watchers it ships. Direct dart:developer log() calls that bypass debugPrint are not captured by the in-package path; they require telescope's LogWatcher. Capture scope is documented in doc/commands/index.md under "Console and exceptions".

  • Opt-in verify flag on dusk:tap / dusk_tap / ext.dusk.tap. When verify: true, the tap handler captures a cheap TARGET-scoped signal before and after the pointer (the nearest enclosing route name plus a hash of the target element's own semantics subtree: label, value, enabled/checked flags) and adds a changed: true|false field to the response reporting whether the tap produced an observable effect on the target. The signal is deliberately target-scoped, not a global route/whole-tree hash, so a counter button whose own label increments reports changed: true while unrelated background churn elsewhere in the tree does not. Default off (verify: false) keeps the response shape byte-identical to before: no changed key. The dusk:tap CLI gains a --verify flag and the dusk_tap MCP descriptor gains a verify boolean property (a parameter addition to the existing dusk:tap / dusk_tap, not a new command or tool).

  • Optional since filter on dusk:exceptions / dusk_exceptions / ext.dusk.exceptions. Pass since: "<iso8601>" (e.g. 2024-01-01T10:00:00.000Z) to receive only exceptions whose time is strictly after that timestamp. Agents can record the current time before an action, then call dusk:exceptions --since=<time> afterwards to see only new exceptions raised by that action, eliminating false positives from cumulative history. Default behavior (no since) is unchanged: the full cumulative list is returned. Unparseable since values are silently treated as absent. The dusk:exceptions CLI gains a --since flag and the dusk_exceptions MCP descriptor gains a since string property (a parameter addition to the existing dusk:exceptions / dusk_exceptions, not a new command or tool).

  • dusk:fill / dusk_fill / ext.dusk.fill — one-call text-field fill. Resolves a text-field ref (e<N> / q<N>), then focuses, clears, types, and settles in a single round-trip, replacing the manual focus + clear + type + settle dance every agent re-discovers. Composes the existing GATED ext.dusk.focus, ext.dusk.clear, and ext.dusk.type handlers verbatim (so the 6-check actionability gate, IME focus, onChanged/validator firing, and post-action snapshot semantics are reused, never re-implemented). Retries the whole resolve + focus + clear + type sequence ONCE when the ref goes stale mid-fill (a transiently-missing q<N> re-walks the now-settled tree on the second pass); a second stale outcome surfaces a typed stale envelope so the agent re-snaps or re-finds. Returns {ref, text, filled: true} plus an optional post-fill snapshot. This is a NEW command (CLI 32 -> 34) and a NEW MCP tool (31 -> 33) backed by a NEW ext.dusk.fill extension (28 -> 30).

  • dusk:reset_overlays / dusk_reset_overlays / ext.dusk.reset_overlays — one-call overlay reset. Returns the app to a known clean screen via three escalating, idempotent layers: (1) pop every PopupRoute (reusing dismissAllModals, never touching the page stack); (2) an Escape key press for overlays driven by the dismiss shortcut that are not PopupRoutes; (3) a Cancel/Dismiss/Close/OK/Done labelled tap for modal barriers that need an explicit affordance. Each layer is a no-op when the prior already cleared the overlays, so the command is safe to call speculatively between flows. Returns {popped: N, escaped: bool, dismissTapped: bool}. This is a NEW command (CLI 32 -> 34) and a NEW MCP tool (31 -> 33) backed by a NEW ext.dusk.reset_overlays extension (28 -> 30).

  • until confirmation on dusk:tap / dusk_tap / ext.dusk.tap. When until: "<text>" is set, after the tap settles the handler polls the live element tree (reusing the dusk:wait_for poll loop) for a Text whose data equals the expected string, up to untilTimeoutMs (default 3000), and adds an untilMatched: true|false field reporting whether it appeared. Confirms a navigation / state change produced the expected text in one call, replacing a separate dusk_wait_for round-trip. Default off (no until) keeps the response shape unchanged. The dusk:tap CLI gains a --until flag and the dusk_tap MCP descriptor gains until / untilTimeoutMs properties (a param addition, not a new tool).

  • "Driving real apps: gotchas for agents" doc page (doc/getting-started/driving-real-apps-gotchas.md). Captures the hard-won lessons from a long real-app E2E session, each now partly or fully addressed by D1-D7: refs go stale on rebuild (re-snap, or prefer a q<N> from dusk:find); text fields may snapshot nested (use dusk:fill, or note the typeable: true marker on the collapsed outer node); dusk:console captures debugPrint in-package now and is enriched by telescope; dusk:exceptions is cumulative (use --since); restart preserves the CDP port; overlays may need dusk:reset_overlays. Linked from llms.txt.

Fixed

  • dusk:dismiss_modals now dismisses modals on ALL NavigatorState instances, not just the first. The previous implementation walked the element tree with a first-match guard and popped PopupRoute entries one-at-a-time with an endOfFrame await between each pop. showDialog defaults to useRootNavigator: true (root navigator) and showModalBottomSheet defaults to useRootNavigator: false (nearest navigator); when these are different navigators, the first-match walk left one modal open. The fix collects every NavigatorState in a full DFS walk, then calls popUntil((r) => r is! PopupRoute) on each navigator innermost-first, counting every PopupRoute dismissed. The popped return value is the additive sum across all navigators. The per-pop endOfFrame await is removed, which also unblocks unit tests that previously hung the flutter_test fake-clock harness when real modal routes were open.

Changed

  • Pointer verbs now dispatch at the element's LIVE rect, not the cached snapshot rect. Every pointer verb (tap, hover, drag start + end endpoints, dblclick, right_click, triple_click) re-resolves the target's current bounding rect via the new dispatchRectOf(entry) helper immediately after the actionability gate passes and dispatches at that live center, falling back to the cached entry.rect.center only when the live rect is null (sliver / detached / synthetic). A host that rebuilt the target into a shifted slot between snapshot and action retains the same Element / RenderObject identity, so the live rect is valid. This fixes the false-success class where dusk:tap reported success while onTap never fired because the pointer landed on the target's stale gate-time position. The helper is purely additive to the FROZEN actionability gate: it runs after the gate passes and before dispatch, touching neither the gate order nor any failure-reason substring.
  • dusk:snap collapses nested textbox nodes and marks the survivor typeable: true. A wind WInput wraps as Semantics(textField:true) > MergeSemantics > TextField; because RenderEditable unconditionally owns its own textField Semantics node (flutter#26336) and MergeSemantics cannot absorb it (flutter#160281), the tree carried TWO nested textbox nodes and minted two eN refs. Agents naturally targeted the inner leaf, where dusk:type threw -32000. The snapshot walk now suppresses any textbox node whose render object is a render-tree DESCENDANT of an enclosing textbox node's render object, emitting a single ref for the outer typeable node so existing scripts keep resolving. The surviving textbox line gains an additive typeable: true sub-line. Collapse is by render-object CONTAINMENT only, never label/value equality, so two sibling fields sharing a label stay two distinct refs. The textbox role string is unchanged; eN minting stays snapshot-only. The source-side fix lives in wind (W1); this is the defensive dusk-side collapse.
  • Bumped fluttersdk_artisan to ^0.0.8. Picks up the substrate restart fix that preserves --cdp-port across the stop/start cycle (so dusk:resize / dusk:device keep working after fsa restart) and the published-config import-path fix in the plugin installer.