Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/plugins/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"name": "rn-dev-agent",
"source": {
"source": "local",
"path": "./packages/codex-plugin"
"path": "./packages/claude-plugin"
},
"policy": {
"installation": "AVAILABLE",
Expand Down
6 changes: 6 additions & 0 deletions .changeset/single-committed-host-dist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'rn-dev-agent-plugin': patch
'rn-dev-agent-core': patch
---

Ship one committed bundled runtime with host-neutral `rn-dev-agent-core` metadata from `packages/claude-plugin`, which both the Claude and Codex marketplaces now install (Codex selects its generated `.codex-plugin/plugin.json`, `codex.mcp.json`, `bin/` launchers and `codex-*` adapters from the same directory), so a Codex local registration must point at `packages/claude-plugin` instead of the removed `packages/codex-plugin` runtime (GH #892).
2 changes: 1 addition & 1 deletion .cursor-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"name": "rn-dev-agent",
"source": "./packages/claude-plugin",
"description": "AI agent that fully tests React Native features on simulator/emulator — navigates the app, verifies UI, walks user flows, and confirms internal state.",
"version": "1.0.8",
"version": "1.0.9",
"homepage": "https://github.com/Lykhoyda/rn-dev-agent"
}
]
Expand Down
16 changes: 10 additions & 6 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# Generated trees — single writer: scripts/build-host-runtimes.ts (host
# packages) and tsc/vite (core dist). linguist-generated collapses them in
# Generated trees — single writer: scripts/build-host-runtimes.ts (distributed
# plugin package) and tsc/vite (core dist). linguist-generated collapses them in
# GitHub PR diffs and excludes them from language stats; -diff suppresses
# textual diffs for the large bundles.
packages/rn-dev-agent-core/dist/** linguist-generated
packages/rn-dev-agent-core/native/darwin-process-birth binary
packages/codex-plugin/rn-dev-agent-core/** linguist-generated -diff
packages/claude-plugin/rn-dev-agent-core/** linguist-generated -diff
packages/codex-plugin/scripts/** linguist-generated
packages/claude-plugin/scripts/** linguist-generated
packages/codex-plugin/runner-manifest.json linguist-generated
packages/claude-plugin/bin/** linguist-generated
packages/claude-plugin/.codex-plugin/** linguist-generated
packages/claude-plugin/codex.mcp.json linguist-generated
packages/claude-plugin/codex-skills/** linguist-generated
packages/claude-plugin/codex-commands/** linguist-generated
packages/claude-plugin/codex-agents/** linguist-generated
packages/claude-plugin/codex-templates/** linguist-generated
packages/claude-plugin/runner-manifest.json linguist-generated
packages/codex-plugin/CLAUDE-MD-TEMPLATE.md linguist-generated
packages/claude-plugin/CLAUDE-MD-TEMPLATE.md linguist-generated
packages/claude-plugin/AGENTS-MD-TEMPLATE.md linguist-generated
.yarn/releases/** linguist-generated -diff
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ jobs:
- name: Agent package split guard unit test
run: bash scripts/test/check-agent-package-sync.test.sh

# GH#1037: --fix must survive GNU sed so Ubuntu Version Packages can
# rewrite the generated Codex copies before build:host-runtimes.
- name: Version-sync fixer portable-sed guard
run: bash scripts/test/sync-versions.test.sh

# Postpublication readiness of the release trust root: a checkout that
# advertises a plugin version must already have that version's exact
# runner bytes public (release.yml publishes them before the Version
Expand Down
28 changes: 13 additions & 15 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ name: Release
# pin the generated candidate P (one commit on top of main B)
# prepare -> build both runner zips at P (runner-artifacts.yml, read-only,
# no persisted credential) and retain them with producer digests
# finalize -> generate runner-manifest.json + both host copies from the
# retained bytes, commit onto the version branch: candidate H
# finalize -> generate runner-manifest.json + its packages/claude-plugin
# copy from the retained bytes, commit onto the version branch:
# candidate H
# validate -> offline source/package validation of H (dist freshness, unit,
# integration, version sync, trust root == producer handoff)
# publish -> draft release vV targeting H, attach the retained bytes and
Expand Down Expand Up @@ -174,7 +175,7 @@ jobs:
# manifests and the plugin/marketplace manifests. Anything else on the
# branch did not come from the generator.
FOREIGN=$(git diff --name-only "$BASE" "$P" \
| grep -Ev '^(\.changeset/|yarn\.lock$|packages/codex-plugin/\.mcp\.json$|(.*/)?(CHANGELOG\.md|package\.json|package-lock\.json|plugin\.json|marketplace\.json)$)' || true)
| grep -Ev '^(\.changeset/|yarn\.lock$|packages/codex-plugin/\.mcp\.json$|packages/claude-plugin/codex\.mcp\.json$|(.*/)?(CHANGELOG\.md|package\.json|package-lock\.json|plugin\.json|marketplace\.json)$)' || true)
if [ -n "$FOREIGN" ]; then
echo "::error::candidate $P changes paths a version bump never generates: $FOREIGN" >&2
exit 1
Expand Down Expand Up @@ -250,20 +251,20 @@ jobs:
check "rn-fast-runner-$VERSION-sim.zip" "$IOS_SHA256" "$IOS_BYTES"
check "rn-android-runner-$VERSION.zip" "$ANDROID_SHA256" "$ANDROID_BYTES"

- name: Generate the trust root and its host copies from the retained bytes
- name: Generate the trust root and its distributed copy from the retained bytes
run: |
node scripts/build-runner-manifest.mts \
--version "$VERSION" \
--ios "handoff/rn-fast-runner-$VERSION-sim.zip" \
--android "handoff/rn-android-runner-$VERSION.zip" \
--out runner-manifest.json
# packages/claude-plugin is the one directory both marketplaces install (GH #892).
cp runner-manifest.json packages/claude-plugin/runner-manifest.json
cp runner-manifest.json packages/codex-plugin/runner-manifest.json
cat runner-manifest.json
CHANGED=$(git status --porcelain --untracked-files=no | awk '{print $2}' | sort | tr '\n' ' ')
EXPECTED="packages/claude-plugin/runner-manifest.json packages/codex-plugin/runner-manifest.json runner-manifest.json "
EXPECTED="packages/claude-plugin/runner-manifest.json runner-manifest.json "
if [ "$CHANGED" != "$EXPECTED" ]; then
echo "::error::generating the trust root changed '$CHANGED', expected exactly the three manifests" >&2
echo "::error::generating the trust root changed '$CHANGED', expected exactly the two manifests" >&2
exit 1
fi

Expand All @@ -272,7 +273,7 @@ jobs:
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add runner-manifest.json packages/claude-plugin/runner-manifest.json packages/codex-plugin/runner-manifest.json
git add runner-manifest.json packages/claude-plugin/runner-manifest.json
git commit --quiet -m "chore(release): runner trust root for v$VERSION"
H=$(git rev-parse HEAD)
# Lands only if the branch is still the candidate this run built from.
Expand Down Expand Up @@ -328,8 +329,7 @@ jobs:
--plugin-version "$(jq -r '.version' packages/claude-plugin/plugin.json)" \
--advertised-version "$ADVERTISED" \
--repo-manifest runner-manifest.json \
--claude-manifest packages/claude-plugin/runner-manifest.json \
--codex-manifest packages/codex-plugin/runner-manifest.json \
--plugin-manifest packages/claude-plugin/runner-manifest.json \
--ios-sha256 "$IOS_SHA256" --ios-bytes "$IOS_BYTES" \
--android-sha256 "$ANDROID_SHA256" --android-bytes "$ANDROID_BYTES"

Expand Down Expand Up @@ -380,10 +380,9 @@ jobs:
- name: Read the candidate's files by SHA
run: |
git fetch --quiet --depth=1 origin "$HEAD"
mkdir -p candidate/claude candidate/codex
mkdir -p candidate/plugin
git show "$HEAD:runner-manifest.json" > candidate/runner-manifest.json
git show "$HEAD:packages/claude-plugin/runner-manifest.json" > candidate/claude/runner-manifest.json
git show "$HEAD:packages/codex-plugin/runner-manifest.json" > candidate/codex/runner-manifest.json
git show "$HEAD:packages/claude-plugin/runner-manifest.json" > candidate/plugin/runner-manifest.json
git show "$HEAD:packages/claude-plugin/plugin.json" > candidate/plugin.json
git show "$HEAD:packages/claude-plugin/CHANGELOG.md" > candidate/CHANGELOG.md
[ "$(jq -r '.version' candidate/plugin.json)" = "$VERSION" ] || { echo "::error::candidate $HEAD advertises $(jq -r '.version' candidate/plugin.json), not v$VERSION" >&2; exit 1; }
Expand Down Expand Up @@ -460,8 +459,7 @@ jobs:
--plugin-version "$VERSION" \
--advertised-version "$ADVERTISED" \
--repo-manifest candidate/runner-manifest.json \
--claude-manifest candidate/claude/runner-manifest.json \
--codex-manifest candidate/codex/runner-manifest.json \
--plugin-manifest candidate/plugin/runner-manifest.json \
--ios-sha256 "$IOS_SHA256" --ios-bytes "$IOS_BYTES" \
--android-sha256 "$ANDROID_SHA256" --android-bytes "$ANDROID_BYTES" \
--release release.json \
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ node_modules/
.yarn/cache/
.yarn/install-state.gz

# Core tsc/Vite output. Marketplace runtimes live under
# packages/{claude,codex}-plugin/rn-dev-agent-core/dist/ and stay committed.
# Core tsc/Vite output. The one marketplace runtime lives under
# packages/claude-plugin/rn-dev-agent-core/dist/ and stays committed.
packages/rn-dev-agent-core/dist/

.claude/*
Expand Down
2 changes: 1 addition & 1 deletion .oxfmtrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"ignorePatterns": [
"node_modules/",
"dist/",
"packages/codex-plugin/bin/plugin-health.js",
"packages/claude-plugin/bin/plugin-health.js",
"WebDriverAgent/",
".claude/worktrees/",
".astro/",
Expand Down
87 changes: 54 additions & 33 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,23 @@ notes here.
- `packages/rn-dev-agent-core/`: TypeScript MCP server, CDP bridge, device
tools, learned actions, observability server. `dist/` is generated by
`yarn build` / `yarn build:web` and is not committed.
- `packages/claude-plugin/`: Claude Code host package and Cursor Plugin
payload. Owns Claude manifests, Cursor Plugin manifests
- `packages/claude-plugin/`: the ONE directory Claude, Cursor, and Codex
install (GH #892). Owns Claude manifests, Cursor Plugin manifests
(`.cursor-plugin/plugin.json`, `mcp.json`), hooks, commands, agents, skills,
templates, helper scripts, packaged native runners, runner manifest, and
bundled core runtime. Root `.cursor-plugin/marketplace.json` points here.
- `packages/codex-plugin/`: Codex host package. Owns `.codex-plugin/`,
`.mcp.json`, `bin/cdp-supervisor.js`, commands, agents, skills, templates,
packaged native runners, runner manifest, and bundled core runtime. Codex
does not consume Claude hooks; "No plugin hooks" is expected.
templates, helper scripts, packaged native runners, runner manifest, the
single bundled core runtime (`rn-dev-agent-core/`, host-neutral metadata),
and the generated Codex adapters: `.codex-plugin/plugin.json`,
`codex.mcp.json`, `bin/`, `codex-skills/`, `codex-commands/`,
`codex-agents/`, `codex-templates/`, `AGENTS-MD-TEMPLATE.md`. Root
`.cursor-plugin/marketplace.json` points here. Never hand-edit a generated
`codex-*`/`bin/` path.
- `packages/codex-plugin/`: Codex AUTHORING source, not an install directory.
Owns `.codex-plugin/plugin.json`, `.mcp.json`, `bin/cdp-supervisor.js`,
`src/plugin-health.ts`, `src/AGENTS-MD-TEMPLATE.md`, adapted commands,
agents, the 11 adapted domain skills, and templates;
`scripts/build-host-runtimes.ts` copies them into `packages/claude-plugin`
and generates the 17 workflow skills there. Codex does not consume Claude
hooks; "No plugin hooks" is expected.
- `packages/shared-agent-knowledge/`: canonical host-neutral workflow knowledge
for skills, commands, agents, and `templates/rn-agent/`.
- `packages/rn-fast-runner/`: source iOS XCTest native runner.
Expand Down Expand Up @@ -305,7 +313,10 @@ alive for such callers.
Claude or Cursor host manifest or the conflict message
(`scripts/check-agent-package-sync.sh` pins the Cursor spawn). The Codex
launcher's `--no-lock` stays as-is.
- Codex-only host behavior: edit `packages/codex-plugin/`.
- Codex-only host behavior: edit `packages/codex-plugin/`, then rerun
`corepack yarn build:host-runtimes` so the `codex-*` copies in
`packages/claude-plugin/` regenerate (package-relative links inside the
authoring tree target the `codex-*` names they ship under).
- Host-neutral workflow knowledge: edit `packages/shared-agent-knowledge/`,
mirror/adapt the affected files into both host packages, and run
`bash scripts/check-agent-package-sync.sh`. That gate compares Claude copies
Expand All @@ -317,25 +328,27 @@ alive for such callers.
`skills/using-rn-dev-agent/SKILL.md` § "Session ownership recovery".
- Native runner behavior: edit `packages/rn-fast-runner/` or
`packages/rn-android-runner/`, then run `corepack yarn build:host-runtimes`
so both host packages carry fresh runner sources.
so the distributed plugin package carries fresh runner sources.
- Docs site content/build: edit `apps/docs-site/` or generated docs sources,
then run `corepack yarn build:docs` for site changes.

`scripts/build-host-runtimes.ts` is the single writer for host package runtime
artifacts: bundled core runtime entries, observe web assets, runner manifests,
`CLAUDE-MD-TEMPLATE.md`, native runner copies, `record_proof.sh`, the shared
host helper scripts listed in `SHARED_HOST_HELPER_SCRIPTS` (copied into both
host packages), and Claude helper scripts. If those outputs drift, edit the
`scripts/build-host-runtimes.ts` is the single writer for the distributed
plugin package's generated artifacts: the one bundled core runtime entry set,
observe web assets, the runner manifest, `CLAUDE-MD-TEMPLATE.md`,
`AGENTS-MD-TEMPLATE.md`, native runner copies, the Codex adapters
(`.codex-plugin/`, `codex.mcp.json`, `bin/`, `codex-*`), `record_proof.sh`, the
helper scripts listed in `SHARED_HOST_HELPER_SCRIPTS`, and Claude helper
scripts — all under `packages/claude-plugin/`. If those outputs drift, edit the
source and rerun:

```bash
corepack yarn build:host-runtimes
```

A new core CLI entry point ships to host packages only if its compiled name is
listed in `RUNTIME_ENTRIES` in `scripts/build-host-runtimes.ts`; otherwise it
exists in a local `packages/rn-dev-agent-core/dist/` build and is silently
absent from every marketplace install.
A new core CLI entry point ships to the plugin package only if its compiled
name is listed in `RUNTIME_ENTRIES` in `scripts/build-host-runtimes.ts`;
otherwise it exists in a local `packages/rn-dev-agent-core/dist/` build and is
silently absent from every marketplace install.

## Validation Commands

Expand Down Expand Up @@ -404,16 +417,18 @@ corepack yarn build:docs

Core `packages/rn-dev-agent-core/dist/` is a build product, not a git source.
`scripts/check-core-dist-contract.sh` is the inventory gate: it fails if that
tree is tracked and if either host plugin runtime is missing from git.
tree is tracked, if the single committed runtime under
`packages/claude-plugin/rn-dev-agent-core/dist/` is missing from git, or if a
second `packages/*/rn-dev-agent-core/dist/` is tracked.

| Consumer | Artifact it runs | When the artifact is produced |
| --- | --- | --- |
| Workspace tests (`yarn test`, coverage, integration) | local core `dist/` after `yarn build:test` (tsc + SPA) | CI and developers; not committed |
| `scripts/build-host-runtimes.ts` | reads core `dist/` then writes host bundles | `yarn build:host-runtimes` |
| Marketplace Claude / Codex installs | `packages/{claude,codex}-plugin/rn-dev-agent-core/dist/` | committed host bundles; no user compile |
| `scripts/build-host-runtimes.ts` | reads core `dist/` then writes the one plugin-package bundle | `yarn build:host-runtimes` |
| Marketplace Claude / Codex installs | `packages/claude-plugin/rn-dev-agent-core/dist/` (one copy, both hosts) | committed host bundle; no user compile |
| `npm pack` / `yarn npm publish` of `rn-dev-agent-core` | tarball `dist/` via `.npmignore` + `prepack` | pack/publish time |
| `scripts/verify.sh`, `scripts/collect-feedback.sh` | host bundle first, then local core `dist/` | committed host copies on a clean checkout |
| Observe SPA (`check-web-bundle.sh`) | host `dist/observability/web-dist/` (and `web-dist/`) compared to a local Vite rebuild | committed host copies |
| `scripts/verify.sh`, `scripts/collect-feedback.sh` | host bundle first, then local core `dist/` | committed host copy on a clean checkout |
| Observe SPA (`check-web-bundle.sh`) | host `dist/observability/web-dist/` (and `web-dist/`) compared to a local Vite rebuild | committed host copy |
| LLM evals | local core `dist/supervisor.js` | `yarn build` before `yarn evals` |

The removed `packages/rn-dev-agent-core/run.sh` source-tree launcher was not
Expand Down Expand Up @@ -444,23 +459,28 @@ package `bin`, and marketplace consumers use the committed host supervisor.

- Claude slash commands are not native Codex commands. For a workflow named
`/rn-dev-agent:<command>`, read `packages/codex-plugin/commands/<command>.md`
and execute the protocol with available tools.
(shipped as `codex-commands/<command>.md`) and execute the protocol with
available tools.
- Claude subagents do not map 1:1 to Codex. Treat Codex agent markdown files as
playbooks to execute in the current session.
- Before app/device interaction, check `rn_session(action="status")` and
`cdp_status`, inspect reusable actions with the learned-actions flow, and
replay a covering saved action through `cdp_run_action` — not raw
`maestro_run`.
- If working on installed-plugin behavior, remember that marketplace installs
copy only the host package directory. Runtime dependencies, scripts, native
runner sources, and templates must exist inside the relevant host package.
copy only `packages/claude-plugin/` for both hosts. Runtime dependencies,
scripts, native runner sources, and templates must exist inside it.

## Release Boundaries

- Claude Code surface: `packages/claude-plugin/`.
- Distributed plugin package for Claude, Cursor, and Codex:
`packages/claude-plugin/`.
- Claude Code surface: `packages/claude-plugin/` (manifests, `commands/`,
`agents/`, `skills/`, `hooks/`).
- Cursor Plugin surface: the same `packages/claude-plugin/` (Cursor
manifests live beside the Claude ones; there is no third host package).
- Codex surface: `packages/codex-plugin/`.
- Codex surface: authored in `packages/codex-plugin/`, shipped from
`packages/claude-plugin/{.codex-plugin,codex.mcp.json,bin,codex-*}`.
- Shared doctrine and reusable workflow guidance:
`packages/shared-agent-knowledge/`.
- Core MCP/device implementation: `packages/rn-dev-agent-core/`.
Expand All @@ -478,10 +498,11 @@ package `bin`, and marketplace consumers use the committed host supervisor.
- The runner trust root ships inside the Version Packages transaction
(`.github/workflows/release.yml`, header comment is the contract):
`runner-artifacts.yml` is a read-only `workflow_call` producer at the pinned
candidate; `finalize` generates `runner-manifest.json` and both host copies
from the retained bytes onto the version branch; `publish` stages a draft
release targeting that head, reads every byte back, then publishes; `merge`
lands after the PR's own `Build & Test` run, whose `core-tests` step
candidate; `finalize` generates `runner-manifest.json` and the single
`packages/claude-plugin/` copy from the retained bytes onto the version
branch; `publish` stages a draft release targeting that head, reads every
byte back, then publishes; `merge` lands after the PR's own `Build & Test`
run, whose `core-tests` step
`scripts/check-public-runner-assets.sh` asserts the public bytes. After
publication approve the PR's queued CI run, then re-run the Release
workflow's failed jobs. A published release is never rebuilt, clobbered or
Expand Down
Loading
Loading