chore(release): bump plugin manifest to ship cdp-bridge work to installs#361
Merged
Conversation
Add a rn-dev-agent-plugin changeset so the next Version Packages PR bumps plugin.json + marketplace.json (0.55.5 → 0.56.0). Past changesets only versioned rn-dev-agent-cdp, so the plugin manifest stayed pinned and the merged #351/#353/#359 never reached installed users via /plugin update. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lykhoyda
added a commit
that referenced
this pull request
Jun 19, 2026
…hanges (#364) * fix(ci): require a rn-dev-agent-plugin changeset for cdp-bridge/src changes Close the #361/#363 delivery gap at the source. cdp-bridge ships to users only via the plugin manifest (plugin.json/marketplace.json), versioned by the synthetic rn-dev-agent-plugin package. A rn-dev-agent-cdp-only changeset bumps the internal package but leaves the manifest pinned — so the change reaches main but never reaches installs via /plugin update (cdp-bridge advanced 0.48→0.49 while the plugin sat at 0.55.5, stranding #351/#353/#359). require-changeset.sh now requires a rn-dev-agent-plugin changeset entry whenever scripts/cdp-bridge/src/ changes, with an actionable error. Regression test updated: cdp-only changeset must now fail; plugin-only and cdp+plugin pass. Keeps the two packages on independent version lines (no changesets linked/fixed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ci): parse changeset frontmatter, not whole file, for plugin bump Codex PR #364 P1: grepping the whole changeset file for "rn-dev-agent-plugin" let a cdp-only changeset falsely pass if its release-note body merely mentioned the plugin (e.g. a quoted format example), recreating the delivery gap. Now extract the frontmatter (lines between the first/second ---, same awk as validate-changeset-names.sh) and match only a rn-dev-agent-plugin package key. Added regression test: cdp-only frontmatter + body mentioning the quoted plugin name must still fail. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ci): accept single-quoted rn-dev-agent-plugin changeset keys Codex PR #364 P2: the frontmatter key regex matched bare and double-quoted keys but not valid-YAML single-quoted ones ('rn-dev-agent-plugin': patch), so a correctly-authored changeset would falsely fail the guard. Widen the quote class to ["'] (both quote styles). Added a single-quoted regression test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Lykhoyda
added a commit
that referenced
this pull request
Jun 19, 2026
…t/byPlaceholder + selector bundle) (#362) * docs(spec): RNTL-style selector resolver + durable Maestro projector (design) Two-phase design: an RNTL-style discovery ladder (byRole/byText/byPlaceholder) on the live fiber tree emitting a selector bundle, projected to Maestro YAML via a fail-closed, CONTAINS-aware, TS-owned-gated fallback ladder, with bundle-aware self-heal. Grounded by a Codex adversarial debate (approach selection) + a 6-agent hardening pass across rn-dev-agent / RNTL / maestro-runner. Captures the verified CONTAINS-not-EXACT native-match verdict and two Section-1 corrections: the maestro-runner selector gate is advisory-only (so the hard gate is re-homed into the TS projector), and the RNTL helpers must be ported against a fiber->host adapter rather than copied verbatim. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(plan): RNTL selector resolver Phase 1 (discovery ladder) — TDD plan 9 bite-sized TDD tasks: Task 0 vm test harness, then __match / __hostKind / __role / __accessibleName / __hidden ports, fail-closed truncation, resolveLadder + interact() routing, and anchor capture — implementing the precision half of the selector-resolver design spec. Each task is failing-test (vm + buildFiber) -> ES5 port inside the INJECTED_HELPERS IIFE -> passing test -> commit, with source-drift guards. Drafted via an 8-agent grounding + drafting workflow against real RNTL v14 and injected-helpers source; task-number cross-refs and the bounds-null caveat reconciled in self-review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(selector): shared injected-helpers vm test harness (Phase 1 Task 0) * feat(resolver): port RNTL matches() + normalizer to __RN_AGENT.__match Single-matcher form ({value,exact?} | {regexSource,regexFlags?}); trim+collapse normalizer that does NOT lowercase (case-insensitivity lives in the non-exact compare). Bumps HELPERS_VERSION 26->27. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(cdp): add __RN_AGENT.__hostKind live-fiber host classifier Port RNTL host-component-names (isHostText/TextInput/Image/Switch/ ScrollView/Modal) into a single hostKind(fiber) that maps a host name (string fiber.type or fiber.type.displayName/name) to one of text|textinput|image|switch|scrollview|modal|null. Name lists widened to native view names (RCTSinglelineTextInputView, RCTImageView, RCTModalHostView, ...) since live fibers expose the platform view name. Placed at IIFE top level (not inside getTree); returns null for Views, user components, text nodes, and null types. HELPERS_VERSION already at 27 from Task 1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(selector): make #321 HELPERS_VERSION guards value-agnostic (>=26) Phase 1 bumps HELPERS_VERSION past 26; the two #321 guards pinned it to exactly 26 and broke on the first bump. Assert the >=26 baseline instead so feature branches bump freely without false regressions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(injected-helpers): port RNTL getRole to __RN_AGENT.__role Add normalizeRole + __role (explicit role → accessibilityRole image→img → host Text → none), reusing __hostKind from Task 2. Does not reuse the digest inferRole (which defaults Pressable to button); divergence pinned by test. Bump HELPERS_VERSION 26→27. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(cdp-bridge): port computeAccessibleName to __accessibleName Port RNTL computeAccessibleName + computeAriaLabel + getAriaLabelledByIds + joinAccessibleNameParts to ES5 on __RN_AGENT. labelledBy nativeID refs are resolved to the referenced node's plain TEXT CONTENT (port of RNTL getTextContent via __refTextContent), NOT by recursively computing its accessible name — this matches RNTL's computeAriaLabel and makes a malformed labelledBy cycle (A->B->A) safe (no stack overflow). The normal child-name recursion in computeAccessibleName is retained. Inline host-text parts join with '' (so 'Sign'+'In' -> 'SignIn'), otherwise ' '. TextInput placeholder is the name only at root. HELPERS_VERSION unchanged (27). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(a11y): port isHiddenFromAccessibility to __RN_AGENT.__hidden Climbs fiber.return, flattens memoizedProps.style arrays manually (no StyleSheet.flatten in-page), and treats aria-hidden / accessibilityElementsHidden / importantForAccessibility=no-hide-descendants / display:none / aria-modal host siblings as hidden. opacity:0 is not hidden. HELPERS_VERSION stays at 27 (already bumped on this branch). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(injected): fail-closed truncation in interact() findFiber Replace the silent `if (findCount > 8000) return;` cap with a rootsSeeded-scaled node budget (Math.min(40000, 8000*roots)) plus a 3s wall-clock guard, mirroring the salient-digest budget. On trip, set a findTruncated flag and short-circuit interact() to return {error:"Resolution truncated", truncated:true, scanned:<n>, hint:...} BEFORE any tier[0] pick, "Component not found" branch, or onPress fire — so a partial scan can never trigger a false action. HELPERS_VERSION stays at 27 (single branch bump). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(resolver): resolveLadder + interact() ladder routing (Task 7) Add __RN_AGENT.resolveLadder(specJson) composing __match/__role/ __accessibleName/__hidden/hostKind into byRole/byText/byPlaceholder predicates. Collect-all across renderers: 0 -> Component not found, >1 -> Ambiguous component match (count + descriptors), 1 -> bundle. Hidden excluded unless includeHidden; bundle.bounds is null in Phase 1. interact() routes role/name/text/placeholder specs (no testID/ accessibilityLabel) through the resolver and presses the found fiber or its nearest onPress ancestor, via the fiber-returning twin __resolveLadderFiber. Legacy testID/accessibilityLabel paths and Task 6 fail-closed truncation untouched. HELPERS_VERSION stays 27 (no bump). Also widen the find-active-renderer-migration B145 guard window (3000 -> 8000 chars): a pre-existing brittle source-position assertion that Task 6 already pushed out of range; the guarded findFiber-in- forEachRootFiber behavior is intact, only its byte offset moved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(plan): execution-time refinements (bounds-null note; cross-ref fixes; HELPERS_VERSION single-branch-bump policy) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(cdp-bridge): capture ancestor anchors into resolveLadder bundle Add __collectAnchors — a bounded (depth 8) fiber.return ancestor walk mirroring the setFieldValue ancestor walk — recording nearest-first {testID, text, relation: childOf, depth, provenance} entries for any ancestor with a testID/nativeID or explicit accessibility label (__ariaLabel only, no recursive child traversal so bare host Text nodes are skipped). provenance is authored-testID for testID/nativeID ancestors, else text. Populate bundle.anchors in resolveLadder. Expose __collectAnchors on the __RN_AGENT public surface. Full suite: 2437/2437 pass, 0 fail. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(build): rebuild committed dist with Task 8 anchors (stale-mirror fix) Task 8 changed src/injected-helpers.ts but did not rebuild the tracked dist/injected-helpers.js. dist is the shipped artifact (imported by cdp/setup.ts; no build hook), so the committed resolver silently omitted bundle.anchors; CI masked it by rebuilding before tests. Regenerated dist so the committed artifact matches src. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style(test): apply oxfmt to Phase 1 selector-resolver test files Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(resolver): matchDeepestOnly — collapse composite+host fiber pairs (live-device bug) Live-simulator testing revealed every RN text/input element matched TWICE in resolveLadder — once as the composite fiber (Text/TextInput) and once as its host child (RCTText/RCTSinglelineTextInputView), both passing hostKind — so byText/byPlaceholder always fail-closed as Ambiguous on a real device. The vm tests missed it because buildFiber made one node per element. Add __deepestOnly (RNTL matchDeepestOnly parity): drop any match that is an ancestor of another match, keeping the deepest; distinct siblings stay ambiguous. Applied in both resolveLadder and __resolveLadderFiber. Bump HELPERS_VERSION 27->28. Verified live on the running test app: byText "Go to Dashboard" and byPlaceholder "Add a task..." now resolve uniquely with correct anchors. Full suite 2495/2495. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(changeset): rn-dev-agent-cdp minor — Phase 1 discovery resolver Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(changeset): also bump rn-dev-agent-plugin (marketplace propagation) The 'Require changeset' gate (per the #361/#363 post-mortem) requires shippable src changes to bump the plugin manifest too, else the change reaches main but not marketplace installs via /plugin update. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(resolver): address Codex review — tool surface, fail-closed truncation, byText content, non-press guard PR #362 review (chatgpt-codex-connector) — 4 P2 findings, all verified + fixed: - #1 cdp_interact now accepts the ladder selectors (role / text / placeholder / exact / includeHidden): relax the host guard, forward the fields, add them to the zod schema. The resolver is reachable via the supported tool, not only via raw eval. - #2 resolveLadder / __resolveLadderFiber had their own silent 8000-fiber cap; a duplicate past the cap could leave matched.length===1 and press the wrong element. Now fail-closed (truncated:true) with a rootsSeeded-scaled budget + wall-clock guard, matching the legacy findFiber path. - #3 byText matched __accessibleName (accessibilityLabel precedence) instead of the visible text content — now uses __refTextContent (getTextContent port); accessible names stay for byRole/name; bundle.text is text content too. - #4 the ladder interact() branch pressed regardless of the requested action — now fails closed for any action other than press. Verified live on the running test app; full suite 2502/2502. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(resolver): Codex review round 2 — Android TextInput host + ladder testID matcher PR #362 (chatgpt-codex-connector) — 2 P2 findings: - #5 __hostKind now recognizes Android's `AndroidTextInput` host name; without it byPlaceholder/byText returned null for every TextInput in Android sessions. - #6 resolveLadder / __resolveLadderFiber now match a `testID` spec — the spec already accepted testID but had no matcher, so resolveLadder({testID:'x'}) returned Component not found for mounted ids. Bump HELPERS_VERSION 28->29 (the injected surface changed across the review fixes; a same-version re-inject is skipped by the __v freshness guard). Verified live (testID + byText resolve on the running app) + full suite 2507/2507. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(resolver): Codex review round 3 — limit matchDeepestOnly to same-element duplicates #7: __deepestOnly blanket-dropped every ancestor match, so two DISTINCT nested components both matching a selector (e.g. an outer card button + an inner button both named "Settings") collapsed to the inner one and got silently pressed instead of failing closed as Ambiguous. Now drop a match's nearest matching ancestor only when they are the SAME element: (1) composite+host pair (the composite wrapper of a host match), or (2) the same testID/nativeID (one element whose id propagates across nested fibers, e.g. a tab button). Distinct nested matches stay Ambiguous. The same-testID arm also keeps resolveLadder({testID}) at found:1 (a tab's id spans ~7 fibers on-device). Bump HELPERS_VERSION 29->30. Verified live (testID / byText / byPlaceholder resolve; nested stays ambiguous); full suite 2509/2509. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(resolver): Codex review round 4 — byRole RNTL parity (accessible opt-out + role normalization) #8: byRole now respects the explicit accessible={false} opt-out (RNTL isAccessibilityElement) — an opted-out duplicate (e.g. an offscreen Pressable kept mounted) no longer causes false ambiguity or gets pressed. #9: the REQUESTED role is now normalized (normalizeRole(spec.role)) like the element side, so byRole({role:'image'}) matches an element whose accessibilityRole 'image' normalizes to 'img' — callers pass the RN prop value, not 'img'. Bump HELPERS_VERSION 30->31. Full suite 2513/2513; byRole verified live (buttons still resolve, no accessible-exclusion regression). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(resolver): Codex review round 5 — gate byRole on the full RNTL accessibility-element predicate The earlier accessible={false} exclusion still let a plain <View accessibilityRole="button"> with accessible undefined match byRole, even though RNTL / screen readers would not expose it. byRole now requires the full isAccessibilityElement predicate (__isA11yElement): Text / TextInput / Switch and Image+alt are accessibility elements by default; everything else must opt in with accessible={true}. Applied in both isCandidate and __resolveLadderFiber. Verified live: real RN buttons expose accessible:true in their fiber memoizedProps (40/48 role=button fibers — host RCTView + inner Pressable layers), so byRole({role:'button'}) still resolves them (count unchanged) — only plain-View role props are now excluded. Updated synthetic byRole tests to model real a11y elements (accessible:true). Bump HELPERS_VERSION 31->32. Full suite 2518/2518. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jul 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
/plugin updatekeys on the plugin manifest version (.claude-plugin/plugin.json+marketplace.json), but the changesets flow has only ever versioned the internalrn-dev-agent-cdppackage (scripts/cdp-bridge/package.json, now 0.49.0). The plugin manifest has stayed pinned at 0.55.5 since before #351 — so the cache key never moved and installed users never refetched, even though the bundleddist/advanced. (This is exactly why a live debug session found the installed 0.55.5 plugin running pre-#351 cdp-bridge code.)What
Adds a
rn-dev-agent-plugin(minor) changeset so the next Version Packages PR bumps the plugin manifest 0.55.5 → 0.56.0, making the currentdist/installable. Delivers to installed users:NO_PROJECT_ROOT; the run reaches the device).cdp_status.actionStore).changeset statusconfirms:rn-dev-agent-plugin→ minor (0.56.0);rn-dev-agent-cdpunchanged (already at 0.49.0).Follow-up (process gap — not in this PR)
cdp-bridge changes ship to users only via the plugin manifest, so a
rn-dev-agent-cdpchangeset should be paired with arn-dev-agent-pluginchangeset. Recommend hardeningscripts/require-changeset.shto require arn-dev-agent-pluginentry wheneverscripts/cdp-bridge/src/changes — otherwise this recurs.After merge: the changesets bot opens the canonical
chore(release): version packagesPR bumping the manifest; merging that publishes 0.56.0.🤖 Generated with Claude Code