Skip to content

chore(release): bump plugin manifest to ship cdp-bridge work to installs#361

Merged
Lykhoyda merged 1 commit into
mainfrom
chore/ship-plugin-0.56.0
Jun 19, 2026
Merged

chore(release): bump plugin manifest to ship cdp-bridge work to installs#361
Lykhoyda merged 1 commit into
mainfrom
chore/ship-plugin-0.56.0

Conversation

@Lykhoyda

Copy link
Copy Markdown
Owner

Why

/plugin update keys on the plugin manifest version (.claude-plugin/plugin.json + marketplace.json), but the changesets flow has only ever versioned the internal rn-dev-agent-cdp package (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 bundled dist/ 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 current dist/ installable. Delivers to installed users:

changeset status confirms: rn-dev-agent-plugin → minor (0.56.0); rn-dev-agent-cdp unchanged (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-cdp changeset should be paired with a rn-dev-agent-plugin changeset. Recommend hardening scripts/require-changeset.sh to require a rn-dev-agent-plugin entry whenever scripts/cdp-bridge/src/ changes — otherwise this recurs.

After merge: the changesets bot opens the canonical chore(release): version packages PR bumping the manifest; merging that publishes 0.56.0.

🤖 Generated with Claude Code

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 Lykhoyda merged commit dd95747 into main Jun 19, 2026
11 checks passed
@Lykhoyda Lykhoyda deleted the chore/ship-plugin-0.56.0 branch June 19, 2026 20:26
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
…ion)

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>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant