Open
Conversation
- Fix Pods.xcworkspace not being skipped in ios_resolve_app_via_xcodebuild - Remove unsafe eval in android and ios build scripts; use proper positional parameter passthrough instead - Fix IOS_DOWNLOAD_RUNTIME default documented as 0 (actual: 1) - Remove phantom IOS_APP_BUNDLE_PATH from wiki/reference/ios.md - Fix start-emu/start-sim hyphen naming to start:emu/start:sim colons in REFERENCE.md files, CONVENTIONS.md, and troubleshooting.md - Add missing env vars (IOS_BUILD_CONFIG, IOS_DERIVED_DATA_PATH, etc.) to wiki/reference/ios.md and wiki/reference/android.md - Add Build and Run command sections to wiki/reference/android.md - Update ios_config_show to display all new config variables - Fix Xcode discovery order in CLAUDE.md to match actual code Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The react-native plugin.json init_hook used `source` (bash-ism) which fails on Linux CI runners where devbox generates .hooks.sh executed by /bin/sh (dash). The init-hook.sh also used `[[ ]]` bash syntax. - Change `source` to `.` (dot) in plugin.json init_hook - Change shebang to #!/usr/bin/env sh in init-hook.sh - Replace `[[ ]]` PATH check with POSIX `case` statement - Remove `set -e` (not appropriate for sourced files) This matches the pattern used by the android and ios plugins, which already use POSIX-compatible constructs in their init hooks. Fixes React Native E2E failures on Linux (android-min, android-max, web-none) caused by "source: not found" error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Init script consistency:
- Android setup.sh: change shebang to #!/usr/bin/env sh (POSIX) since
it's sourced, not executed; add sourcing note comment
- iOS setup.sh: add sourcing note comment, fix stale error message
referencing "env.sh", fix stale debug log script name
- iOS init-hook.sh: align header comment format with Android
("{Platform} Plugin - Initialization Hook", "before setup.sh")
All init scripts now follow consistent conventions:
- init-hook.sh: #!/usr/bin/env bash, set -e (executed as subprocess)
- setup.sh: #!/usr/bin/env sh (sourced, POSIX-compatible)
- react-native init-hook.sh: #!/usr/bin/env sh (sourced, POSIX)
CI changes:
- pr-checks.yml: reduce E2E matrix from min+max to max-only (5 E2E
jobs instead of 9), keeping fast tests unchanged
- e2e-full.yml: unchanged, still runs min+max weekly and on-demand
- Update CLAUDE.md CI section to reflect the new structure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The devbox.d/android/ directory is created when the example uses local path includes (path:../../plugins/android/plugin.json). Contains the same min/max device definitions as the GitHub-include variant (segment-integrations.devbox-plugins.android/). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ox-mcp/v0.1.4 ## What changed Standardized initialization scripts, fixed React Native POSIX compatibility, and migrated to GitHub plugin references for improved stability. ### Plugins bumped | Plugin | Version | |--------|---------| | android | 0.0.2 -> 0.0.3 | | ios | 0.0.2 -> 0.0.3 | | react-native | 0.0.3 -> 0.0.4 | | devbox-mcp | 0.1.3 -> 0.1.4 | ### Changes #### Fixes - **react-native**: Fixed POSIX-compatible sourcing in init hook for better shell compatibility - **react-native**: Use GitHub includes instead of relative paths for plugin dependencies #### Other - **all plugins**: Standardized init scripts across Android, iOS, and React Native plugins - **ios**: Refactored environment setup for improved maintainability - **ci**: Reduced PR checks to max-only devices for faster CI runs - **ci**: Added support for multiple scoped tags in release workflow - **docs**: Improved documentation across plugins and examples
- Replace all `devbox run` commands inside process-compose processes with direct commands (ios.sh, android.sh, npm) for --pure compatibility. `devbox` is not in PATH inside --pure mode since it's not a Nix package. - Add `is_strict: true` to all test suites so process-compose returns non-zero exit code when any process fails - Make summary processes depend on verification steps via `process_completed_successfully` so they only run on test success - Remove hardcoded `exit 0` from summary processes and test-summary.sh - Create run-web-tests.sh wrapper script for React Native web tests matching the android/ios pattern - Update CI workflows to call web wrapper script directly Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
process-compose exits 0 even when processes fail if the summary process (the last to run) succeeds or is blocked. This caused CI jobs to pass despite actual test failures. Changes: - All test suites now use marker-file (.e2e-passed) to track success - Verification steps create marker only on actual success - test-summary.sh checks for marker and exits 1 if missing - Removed pkill usage (unavailable in --pure mode) - Removed metro-bundler process_healthy deps from cleanup (blocked cleanup when metro never started, preventing summary from running) - Fixed iOS build.sh scheme detection to use POSIX parameter expansion instead of BSD-incompatible sed alternation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All test logs should use reports/ directory per project conventions. Remove tracked test-results log files and update .gitignore to prevent future accidental tracking. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add exit_on_end: true to all process-compose test suites (is_strict is silently ignored, causing tests to always exit 0) - Use ios_xcodebuild() wrapper in build.sh to strip Nix stdenv vars that conflict with Apple toolchain (fixes ld linker errors) - Enhance ios_xcodebuild() safety-net with comprehensive Nix var stripping; keep devbox_omit_nix_env() minimal (relies on devbox shellenv --omit-nix-env=true for PATH, then re-adds Xcode tools via DEVELOPER_DIR) - Switch react-native plugin includes from github:...&ref=main to local path:../ so PR tests use current branch code - Add Nix env var stripping before pod install in RN iOS test suites - Add EMU_HEADLESS passthrough to Android test suite environments (empty default for dev GUI, CI sets 1 for headless) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… YAML exit_on_end is only valid inside a process's availability block, not at the top level. The top-level usage caused process-compose --dry-run to fail, breaking the lint check. The per-process exit_on_end on summary processes (added in previous commit) is the correct mechanism. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace internal script sourcing and direct xcrun/adb calls in test suites with user-layer commands (ios.sh, android.sh). This ensures tests exercise the same commands users run. New commands added: - ios.sh deploy, ios.sh app status/stop, ios.sh simulator ready - android.sh deploy, android.sh app status/stop, android.sh emulator ready Suite namespacing via SUITE_NAME env var enables concurrent test execution with isolated runtime state files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Processes that run tail -f /dev/null in pure mode or foreground emulators never reach process_completed_successfully. Downstream processes must depend on process_healthy (via readiness probe) instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Process-compose readiness probes only fire while a process is running. In non-pure mode, simulator/emulator processes exited immediately after starting, so the probe never fired and downstream processes waiting on process_healthy blocked forever. Fix: always keep simulator/emulator processes alive with tail -f /dev/null (process-compose services pattern). Also pass --pure flag explicitly to ios.sh/android.sh when IN_NIX_SHELL=pure, and make android.sh self- initializing by auto-sourcing setup.sh when ANDROID_SDK_ROOT is missing. Verified: iOS E2E (non-pure) and Android E2E (non-pure) both pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Device definition files (min.json, max.json, devices.lock) for iOS and React Native examples created during devbox sync. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The workflow name was `tname:` instead of `name:`, causing the GitHub Actions workflow file to fail YAML validation in the lint step. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document new user-layer commands added as part of the test suite standardization effort: - ios.sh: simulator ready, deploy, app status/stop - android.sh: emulator ready, deploy, app status/stop - SUITE_NAME env var for test isolation - IOS_RUNTIME_DIR / ANDROID_RUNTIME_DIR state files Updated across all reference docs: - plugins/android/REFERENCE.md - plugins/ios/REFERENCE.md - wiki/reference/android.md - wiki/reference/ios.md - wiki/reference/cli-commands.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
devbox run --pure strips environment variables from the parent shell. EMU_HEADLESS and SIM_HEADLESS must be passed explicitly via the -e flag so emulators/simulators run headless on CI runners. Also removes Nix compiler env var stripping from RN iOS pod install steps, which was causing glog build failures in CocoaPods. The old working version did not strip these vars. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace npx react-native run-android/run-ios with android.sh deploy and ios.sh build/deploy in all RN test suites. The npx commands don't write state files (app-id.txt, emulator-serial.txt) needed by android.sh app status and ios.sh app status for verification. Cap React Native max device at API 35 since RN 0.83 doesn't support API 36. Add ANDROID_COMPILE_SDK support to flake.nix so projects can compile against a different API than their device targets. Fix -e flag format in CI workflows and wrapper scripts to use key=value format required by devbox. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CI always runs headless - pass EMU_HEADLESS=1 and SIM_HEADLESS=1 directly via -e flag instead of indirectly referencing an env var that --pure would strip anyway. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e mode detection IN_NIX_SHELL is a Nix-native variable that devbox never sets. Replace all references with DEVBOX_PURE_SHELL, which devbox sets to "1" when running with --pure. Also add REUSE_EMU and REUSE_SIM env var overrides to allow simulator/emulator reuse while still running in pure mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…x.json The run-android-tests.sh, run-ios-tests.sh, and run-web-tests.sh wrapper scripts are no longer needed. The devbox.json test scripts now invoke process-compose directly, and platform skipping is handled via -e flags at the call site (e.g., devbox run --pure -e IOS_SKIP_SETUP=1 test:e2e:android). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace wrapper script invocations with direct devbox run --pure -e calls in both pr-checks and e2e-full workflows. Remove redundant env blocks since env vars are now passed inline via -e flags. Update iOS max device runners from macos-15 to macos-26. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set DEVBOX_COREPACK_ENABLED="" in root devbox.json and react-native plugin.json to prevent corepack from interfering with npm. Regenerate device lock files with updated timestamps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixed verify-emulator-ready and verify-simulator-ready to work correctly in pure mode where launch processes stay running in foreground. Problem: In pure mode, launch-emulator/launch-simulator processes stay running (with tail -f /dev/null) and never complete. The verify-*-ready processes depended on launch-*: process_completed, which blocked them from ever starting in pure mode. Solution: Changed verify-*-ready to depend on sync-avds/sync-simulators instead of launch processes. This allows verify to run in parallel with launch, working in both modes: - Pure mode: launch stays running, verify polls until ready - Dev mode: launch exits after --wait-ready, verify polls until ready - Already running: launch exits early, verify succeeds immediately Added 5-second delay in verify for Android and 3-second delay for iOS to give launch process time to start before polling begins. Changes: - test-suite-android-e2e.yaml: verify depends on sync-avds - test-suite-ios-e2e.yaml: verify depends on sync-simulators - test-suite-all-e2e.yaml: verify steps depend on sync, not launch - Updated device lock files from test runs Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove "process-compose-" prefix from test suite YAML files for cleaner naming: - tests/process-compose-unit-tests.yaml → tests/unit-tests.yaml - tests/process-compose-e2e.yaml → tests/e2e.yaml Updated all references in: - devbox.json (test:unit, test:e2e scripts) - CLAUDE.md (naming standards) - tests/README.md (configuration references) - wiki/project/CONTRIBUTING.md (naming standards) - wiki/guides/testing.md (example code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhanced app verification to properly detect Metro connection failures: - Remove log tag filter (-s ReactNativeJS/ReactNative) - check ALL logs - Increase from 100 to 500 log lines to catch errors earlier in boot - Add 5 second wait after app process starts to let errors surface - Add "packaged.*correctly.*for.*release" to error patterns (full red box text) - Show 30 lines of matched patterns + 50 lines of full logs for debugging - Increase max_attempts from 15 to 20 This should properly fail the test when the "unable to load script" Metro error occurs, allowing us to debug the root cause. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The Metro connection issue was caused by stale port forwarding rules from previous test runs. When an emulator persists between runs (dev mode), old adb reverse rules stay active and conflict with new Metro ports. Solution: - Remove existing tcp:8081 reverse before setting new one - Verify the reverse is active with `adb reverse --list` - This ensures clean state for each test run Fixes the "Unable to load script" error that occurred when: 1. Metro allocated port 8091 (or any non-8081 port) 2. Old reverse rule forwarded 8081 -> old Metro port (or didn't exist) 3. App tried to connect to localhost:8081 and failed Note: adb reverse is NOT a long-lived process - it sets up forwarding in the adb daemon and exits. The forwarding persists until removed or the emulator is stopped. Changes: - test-suite-android-e2e.yaml: Remove old reverse, verify new one - test-suite-all-e2e.yaml: Remove old reverse, verify new one - Updated device lock files from test runs Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
React Native Android apps need to know the Metro bundler port at build time. Pass the port to Gradle using the existing passthrough mechanism (android.sh build -- <gradle-flags>). Changes: - Source Metro environment to get $METRO_PORT - Pass port to Gradle: android.sh build ... -- -PreactNativeDevServerPort="$METRO_PORT" - Make build-android depend on metro-bundler: process_healthy This ensures the Android app connects to the correct Metro port instead of trying to load from assets. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ectly Removed android.sh build and ios.sh build commands. Users should call gradle/xcodebuild directly with their project-specific requirements. The plugins focus on what they're good at: device/emulator management and deployment. Build configuration is app-specific and better handled by users directly. Changes: - Removed build command handlers from android.sh and ios.sh - Deleted plugins/android/virtenv/scripts/domain/build.sh - Deleted plugins/ios/virtenv/scripts/domain/build.sh - Removed build.sh from plugin.json includes - Updated all test suites to call gradle/xcodebuild directly - Updated usage/help text with note about direct build commands Test suite changes: - Android: ./gradlew assembleDebug -PreactNativeDevServerPort=$METRO_PORT - iOS: xcodebuild -workspace ... -scheme ... -configuration ... build Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The Android example doesn't have a gradle wrapper, so use the system gradle command. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The emulator start --wait-ready command was calling android_emulator_ready which didn't exist, causing "command not found" errors in dev mode. Added the function to emulator.sh with logic that matches the "ready" command handler: checks emulator serial and waits for sys.boot_completed. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
When we removed android.sh build, we lost the automatic SDK setup that was at the top of android.sh. Now gradle is called directly without the environment being initialized, causing 'SDK location not found' errors. Added explicit SDK setup check before gradle build in test suite: - Source ANDROID_SCRIPTS_DIR/init/setup.sh if ANDROID_SDK_ROOT not set - Matches the auto-setup logic that was in android.sh Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
React Native test suites also need the SDK setup before calling gradle directly. Added the same SDK initialization check to both Android E2E and All E2E test suites. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Process-compose processes inherit the devbox environment, including ANDROID_SDK_ROOT which is set by the init_hook. The manual SDK setup in build commands was unnecessary duplication. Test confirmed that process-compose inherits environment: ANDROID_SDK_ROOT=/nix/store/.../androidsdk/libexec/android-sdk The init_hook in plugin.json already handles SDK setup via: plugins/android/virtenv/scripts/init/setup.sh Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Defines clear hierarchy and responsibility for environment setup across all plugins (Android, iOS, React Native). Key decisions: 1. Static config → plugin.json (templated paths, defaults, flags) 2. Computed setup → platform/core.sh (SDK resolution, PATH setup) 3. Orchestration → init/setup.sh (calls setup functions) 4. Runtime state → domain/*.sh (process-specific variables) 5. Utilities → lib/lib.sh (pure functions, no exports) Includes justifications for why each variable belongs in its location, with concrete examples from actual plugins. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
When we removed ios.sh build, we lost the -derivedDataPath configuration. This caused builds to output to Xcode's default location instead of the project-local .devbox/virtenv/ios/DerivedData, breaking app deployment. Fixed by adding -derivedDataPath to all iOS xcodebuild commands in test suites. Also clarified in strategy doc that runtime state variables (like ANDROID_EMULATOR_SERIAL) are implementation details. Concurrent test suites work via suite-namespaced state files, not env vars. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The simulator start --wait-ready command was calling ios_simulator_ready which didn't exist, causing "command not found" errors in dev mode. Added the function to simulator.sh with logic that: - Checks simulator UDID from suite-namespaced state files - Falls back to IOS_SIM_UDID env var - Verifies simulator state is "Booted" via simctl Mirrors the android_emulator_ready implementation. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Update device lock file timestamps across all example projects. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…n on Linux On Linux CI, Nix outputs warnings to stderr (e.g., "warning: Git tree is dirty"). Using 2>&1 mixed these warnings into the captured path, causing the directory check to fail and ANDROID_SDK_ROOT to stay empty. Changed to 2>/dev/null so only the stdout store path is captured. Also replaced android.sh build references in examples/android/devbox.json with native gradle commands since android.sh build was removed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
android.sh build and ios.sh build were intentionally removed. Replace all references with native tool commands (gradle assembleDebug, xcodebuild, ios.sh xcodebuild wrapper). Update deploy.sh fallbacks to error instead of calling non-existent commands. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The function is iOS-specific (sets CC/CXX to system clang, unsets Nix build flags). The devbox_ prefix was misleading since it no longer calls devbox shellenv. Also renamed the guard variable to match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace heuristic positional parsing (sniffing for '/' or '.apk'/'.app' in args) with explicit --apk/--app and --device flags. Bare positional args are still accepted as device names for convenience and backward compatibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…clear errors Replace the monkey command fallback with a clear error when am start fails. Make process verification return non-zero on failure instead of printing a warning. Users get actionable error messages with logcat debugging hints. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix set -e documentation to describe actual pattern per script type - Add wiki/ to project structure tree - Add ARCHITECTURE.md and ENVIRONMENT-SETUP-STRATEGY.md to references - Remove temporal "now" from configuration section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove "What's New" heading and emoji from workflow README - Remove "now" from several documentation files - Remove "NEW:" labels from workflow README - Remove "robust" from testing docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove Implementation Checklist from ENVIRONMENT-SETUP-STRATEGY.md. Delete review.md and pr-message.md (temporary PR artifacts, untracked). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add tests that verify sourced scripts (lib.sh, core.sh, device_config.sh, setup.sh) work correctly under dash. Uses shellcheck --shell=sh for static analysis and dash runtime sourcing when available. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update example devbox.json files and process-compose YAML files to use native build tools instead of removed android.sh build and ios.sh build commands. Also remove Build section from wiki/reference/android.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add e2e_step_pass, e2e_step_fail, and e2e_report_steps functions that enable per-step pass/fail reporting in E2E test suites. This replaces the binary .e2e-passed marker file pattern with granular status files under reports/steps/, so CI failures show exactly which step failed and why. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… deploy Three fixes for E2E reliability: 1. Add allocate-metro-port step to RN Android/iOS/All suites so builds depend on port allocation instead of metro running. This lets the gradle/xcodebuild run concurrently with the emulator/simulator boot instead of waiting for metro to be healthy first. 2. Increase readiness probe and verify timeouts: - Android emulator: 120s -> 300s (survives long gradle builds) - iOS simulator: 60s -> 180s (survives long xcodebuild) 3. Uninstall existing app before install in both deploy scripts to avoid INSTALL_FAILED_UPDATE_INCOMPATIBLE (Android) and ensure clean state (iOS). 4. Add per-step status tracking to all E2E processes and replace assert_file_exists .e2e-passed with e2e_report_steps in summaries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The timestamp caused unnecessary commit churn since running devices eval always produced a diff even when device definitions hadn't changed. The checksum field already captures whether content changed, making the timestamp redundant. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The root e2e.yaml orchestrator references this script but it was never defined, causing the RN all-platforms E2E to fail with "command not found". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The deploy command in android.sh and ios.sh called install directly without uninstalling first, causing INSTALL_FAILED_UPDATE_INCOMPATIBLE errors. The uninstall logic was only in the run command path. Step tracking in YAML processes that cd into subdirectories (cd android, cd ios) used relative paths for reports/steps/, which broke after the directory change. Use $PWD/reports/steps to capture absolute path before cd. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.
Changes
New features
ios.sh build/android.sh build— auto-detect Xcode/Gradle projects, derive schemes/tasks, passthrough argsios.sh run/android.sh run— auto-detect .app/.apk, fallback chain:build:{platform}→build→{platform}.sh buildtest-apk-resolution.shandtest-app-resolution.sh— unit tests for artifact auto-detectionBug fixes
source→.(POSIX compat, fixes Linux CI)ios_resolve_app_via_xcodebuild(): skipPods.xcworkspaceeval+$*with positional parameter passthroughIOS_DOWNLOAD_RUNTIMEdefault: documented as 0, actual is 1start-emu/start-sim→start:emu/start:simsetup.sh: stale "env.sh" referenceswiki/reference/ios.md: remove phantomIOS_APP_BUNDLE_PATHRefactors
IOS_APP_PROJECT,IOS_APP_BUNDLE_ID,IOS_APP_DERIVED_DATA; add optionalIOS_APP_SCHEME,IOS_BUILD_CONFIG,IOS_DERIVED_DATA_PATHsetup.sh→#!/usr/bin/env sh(POSIX),init-hook.sh→#!/usr/bin/env bash+set -e, aligned headersCI
pr-checks.yml: max-only E2E (9 → 5 jobs)e2e-full.yml: min+max, weekly + manual (unchanged)release.yml: support multiple scoped tags per commitDocs
wiki/reference/ios.mdandandroid.mdios.sh config show: display new build/app variablesTest plan
🤖 Generated with Claude Code