Skip to content
This repository was archived by the owner on May 1, 2026. It is now read-only.

fix(init): refresh iOS run device selection#594

Merged
riderx merged 16 commits into
mainfrom
codex/fix-ios-run-device-refresh
Apr 28, 2026
Merged

fix(init): refresh iOS run device selection#594
riderx merged 16 commits into
mainfrom
codex/fix-ios-run-device-refresh

Conversation

@riderx
Copy link
Copy Markdown
Member

@riderx riderx commented Apr 28, 2026

Fixes #593

Summary

  • ask iOS onboarding users whether they want a physical device or simulator before running the baseline app
  • for physical devices, ask them to connect/unlock/trust first and provide a check-again loop before launching
  • launch detected physical devices with cap run ios --target <id> to avoid stale Capacitor target prompts
  • document the run-on-device behavior and add parser/filter coverage

Local verification

  • bun run lint
  • bun run build
  • bun run test:mcp
  • bun run test:bundle
  • ./test/fixtures/setup-test-projects.sh
  • bun run test

Summary by CodeRabbit

  • New Features

    • Added a new run-device command that reuses the device picker, lets you choose physical vs simulator, supports refresh/skip, and a --no-launch option to print the resolved run command.
  • Documentation

    • Expanded init/run-device docs and examples; clarified connecting/unlocking physical iOS devices and the CLI re-check behavior.
  • Tests

    • Added onboarding run-target tests and integrated them into the main test suite.
  • Bug Fixes

    • Improved error reporting when launches or IDE opens fail.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new CLI command run-device and enhances the iOS run-on-device onboarding: parses cap run ... --list --json, separates physical vs simulator targets, provides interactive refresh/selection/skip flows, resolves concrete cap run invocations (with --no-launch support), runs commands with guarded spawn/exit handling, and adds tests/docs.

Changes

Cohort / File(s) Summary
CLI command wiring
src/index.ts, src/init/index.ts
Register new run-device [platform] command, import/export testRunDeviceCommand, and update init help text with iOS device connect/unlock/re-check guidance.
Onboarding / Core logic
src/init/command.ts
Add CapacitorRunTarget parsing, parseCapacitorRunTargetList, getPhysicalIosRunTargets, getSimulatorIosRunTargets, interactive device picker (Refresh / Simulator / Skip), resolveRunDeviceCommand, guarded runPackageRunnerSync execution, enhanced spawn/exit/error handling, and exported testRunDeviceCommand.
Tests
test/test-onboarding-run-targets.mjs
New standalone test script validating parsing behavior, ID fallback, omission of invalid entries, non-list inputs, and iOS physical/simulator filtering; exits non-zero on failures.
Documentation
README.md, skills/usage/SKILL.md, webdocs/run-device.mdx, webdocs/init.mdx
Document new run-device command, --no-launch option, and expanded iOS onboarding instructions about choosing device vs simulator and re-checking after connect/unlock; add TOC entry and examples.
Docs metadata
webdocs/*.mdx (multiple files)
Adjusted many MDX sidebar.order frontmatter values to re-order docs in the sidebar.
Doc utilities
src/docs.ts
Map run-device command names to 📱 emoji in generated docs.
Package scripts
package.json
Add test:onboarding-run-targets script and include it in the composite test command.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as "Init / run-device CLI"
    participant CapRun as "Capacitor CLI"
    participant Parser as "Parser/Filter"
    participant Prompt as "Interactive Prompt"
    participant Runner as "Guarded Runner"

    User->>CLI: start init or run-device
    CLI->>CapRun: run 'cap run ios --list --json'
    CapRun-->>CLI: JSON target list
    CLI->>Parser: parseCapacitorRunTargetList(...)
    Parser-->>CLI: physical / simulator lists

    CLI->>Prompt: show options (devices, simulators, Refresh, Skip)
    alt User chooses Refresh
        User->>CLI: Refresh
        CLI->>CapRun: re-run 'cap run ios --list --json'
        CapRun-->>CLI: updated targets
        CLI->>Prompt: update choices
    else User chooses Device
        User->>Prompt: select device
        Prompt-->>CLI: selected target id
        CLI->>CLI: resolveRunDeviceCommand(selected)
        CLI->>Runner: run resolved cap run (unless --no-launch)
        Runner-->>CLI: exit status / errors
        CLI-->>User: success or show manual command + errors
    else User chooses Skip / --no-launch
        CLI-->>User: print resolved cap run command, do not launch
    end
Loading

Estimated Code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I sniff the cable, tap the light,
I wait till little screens wake bright.
Refresh, unlock — then we begin,
A hop, a run, the app jumps in. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(init): refresh iOS run device selection' directly addresses the core issue #593 about providing a refresh mechanism for iOS device detection during onboarding.
Linked Issues check ✅ Passed All coding requirements from issue #593 are met: iOS device vs simulator selection added, physical-device connection/unlock/check-again flow implemented, explicit target resolution in cap run command added, and test coverage provided.
Out of Scope Changes check ✅ Passed All changes are scoped to the stated objectives: iOS device selection flow, documentation updates, test script, and sidebar ordering adjustments to accommodate new run-device documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-ios-run-device-refresh

Comment @coderabbitai help to get the list of available commands and usage tips.

@riderx riderx marked this pull request as ready for review April 28, 2026 10:24
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/init/command.ts (1)

2517-2585: Split the physical-device selection loop into smaller helpers.

This loop is already carrying the error path plus three separate selection states (1 target, many targets, 0 targets). Extracting those branches into dedicated helpers would clear the Sonar finding and make future onboarding tweaks much safer to reason about.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/init/command.ts` around lines 2517 - 2585, The long
selectPhysicalIosRunTarget loop should be split into three helper functions to
handle the 1-target, many-targets, and zero-target branches: extract logic for
the single-target branch into a helper (e.g., handleSinglePhysicalTarget) that
logs and returns getRunDeviceCommand(pm,'ios', target); extract the many-targets
branch into handleMultiplePhysicalTargets that runs the pSelect flow (including
pIsCancel -> exitCanceledInitOnboarding, handling
iosRunTargetActions.refresh/simulator/skip, finding the selected target and
returning getRunDeviceCommand or continuing/returning skipped); and extract the
zero-target branch into handleNoPhysicalTargets that shows the pSelect options
and returns the appropriate getRunDeviceCommand or getSkippedRunDeviceCommand
(and handles pIsCancel). Keep selectPhysicalIosRunTarget as the thin
orchestrator: call getCapacitorRunTargetList and getPhysicalIosRunTargets, then
delegate to the new helpers, preserving use of pLog, formatError, pSelect,
pIsCancel, exitCanceledInitOnboarding, iosRunTargetActions, getRunDeviceCommand,
and getSkippedRunDeviceCommand so control flow/returns remain identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/init/command.ts`:
- Around line 2517-2585: The long selectPhysicalIosRunTarget loop should be
split into three helper functions to handle the 1-target, many-targets, and
zero-target branches: extract logic for the single-target branch into a helper
(e.g., handleSinglePhysicalTarget) that logs and returns
getRunDeviceCommand(pm,'ios', target); extract the many-targets branch into
handleMultiplePhysicalTargets that runs the pSelect flow (including pIsCancel ->
exitCanceledInitOnboarding, handling iosRunTargetActions.refresh/simulator/skip,
finding the selected target and returning getRunDeviceCommand or
continuing/returning skipped); and extract the zero-target branch into
handleNoPhysicalTargets that shows the pSelect options and returns the
appropriate getRunDeviceCommand or getSkippedRunDeviceCommand (and handles
pIsCancel). Keep selectPhysicalIosRunTarget as the thin orchestrator: call
getCapacitorRunTargetList and getPhysicalIosRunTargets, then delegate to the new
helpers, preserving use of pLog, formatError, pSelect, pIsCancel,
exitCanceledInitOnboarding, iosRunTargetActions, getRunDeviceCommand, and
getSkippedRunDeviceCommand so control flow/returns remain identical.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cab4244f-f6c1-40b7-8e1a-c5956b121a8a

📥 Commits

Reviewing files that changed from the base of the PR and between d73aa0c and 6391f2f.

📒 Files selected for processing (6)
  • README.md
  • package.json
  • skills/usage/SKILL.md
  • src/init/command.ts
  • test/test-onboarding-run-targets.mjs
  • webdocs/init.mdx

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a1523caa1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/init/command.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/init/command.ts (1)

2479-2481: Hoist the simulator regex to module scope

Line 2480 recompiles the regex on every call. Move it to a module-level constant.

Proposed fix
+const IOS_SIMULATOR_SUFFIX_RE = /\(simulator\)$/i
+
 export function getPhysicalIosRunTargets(targets: CapacitorRunTarget[]): CapacitorRunTarget[] {
-  return targets.filter(target => !/\(simulator\)$/i.test(target.name))
+  return targets.filter(target => !IOS_SIMULATOR_SUFFIX_RE.test(target.name))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/init/command.ts` around lines 2479 - 2481, The regex /\(simulator\)$/i is
being recompiled on every call in getPhysicalIosRunTargets; hoist it to a
module-level constant (e.g., const IOS_SIMULATOR_REGEX = /\(simulator\)$/i) and
replace the inline literal in getPhysicalIosRunTargets with that constant so the
pattern is compiled once and reused.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/init/command.ts`:
- Around line 2459-2461: The exported function parseCapacitorRunTargetList
currently calls JSON.parse directly and will throw on malformed or empty input;
update parseCapacitorRunTargetList to be defensive: trim the output, if it's
empty return []; wrap JSON.parse in a try/catch, and if parsing fails or the
parsed value is not an array return an empty array; keep the return type as
CapacitorRunTarget[] and ensure any caught errors are swallowed (or optionally
logged) but never propagated.

---

Nitpick comments:
In `@src/init/command.ts`:
- Around line 2479-2481: The regex /\(simulator\)$/i is being recompiled on
every call in getPhysicalIosRunTargets; hoist it to a module-level constant
(e.g., const IOS_SIMULATOR_REGEX = /\(simulator\)$/i) and replace the inline
literal in getPhysicalIosRunTargets with that constant so the pattern is
compiled once and reused.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3c1f0fe4-af2f-475b-abaa-4568a5407ce8

📥 Commits

Reviewing files that changed from the base of the PR and between 6391f2f and 9a1523c.

📒 Files selected for processing (1)
  • src/init/command.ts

Comment thread src/init/command.ts
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/init/command.ts`:
- Around line 2520-2523: The simulator branches call getRunDeviceCommand(pm,
'ios') without a target which yields "cap run ios" and lets Capacitor re-prompt;
update the simulator path to resolve a concrete simulator target from available
targets (the same logic used for physical devices) and pass it into
getRunDeviceCommand as the target so args includes '--target', i.e., ensure the
call to getRunDeviceCommand(pm, platformName, target) (or equivalent) supplies a
resolved target object and uses target.id when building args instead of omitting
the target; alternatively remove the custom simulator branch so Capacitor
handles selection — make the change at the call sites that construct
args/command alongside pm.runner and formatRunnerCommand to always include a
target.id when available.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3f3e57bf-06e3-41bf-b5b6-00d25d209a70

📥 Commits

Reviewing files that changed from the base of the PR and between 9a1523c and de87037.

📒 Files selected for processing (2)
  • src/init/command.ts
  • test/test-onboarding-run-targets.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/test-onboarding-run-targets.mjs

Comment thread src/init/command.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/init/command.ts (2)

2788-2840: Extract testRunDeviceCommand into a dedicated command module.

This handler is command-surface logic and would be easier to maintain/test if moved out of src/init/command.ts into a focused command module, then wired from src/index.ts.

As per coding guidelines, "When adding or changing a CLI command, prefer an exported command handler function in a dedicated module and wire it from src/index.ts".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/init/command.ts` around lines 2788 - 2840, Move the testRunDeviceCommand
function out of src/init/command.ts into a new dedicated module (e.g.,
src/commands/test-run-device.ts) and export it as the command handler; in the
new module import its dependencies (getPMAndCommand, normalizeRunDevicePlatform,
resolveRunDeviceCommand, runPackageRunnerSync, formatError,
pIntro/pOutro/pSpinner/pLog/pCancel/setInitScreen, exitCanceledRunDeviceTest and
any types like RunDeviceTestOptions) so the function remains self-contained;
then update src/index.ts to import and register/export the handler
(testRunDeviceCommand) from the new module so CLI wiring remains unchanged;
ensure any relative imports and exported types are adjusted and run tests/lint
to fix import paths.

2793-2807: Add an explicit non-TTY fallback before interactive iOS target selection.

Line 2807 enters interactive target resolution; add a non-interactive branch so scripted usage does not depend on prompt interaction.

💡 Suggested adjustment
 export async function testRunDeviceCommand(platformName?: string, options: RunDeviceTestOptions = {}) {
   try {
     const pm = getPMAndCommand()
     const platformNameChoice = normalizeRunDevicePlatform(platformName)

+    if ((!stdin.isTTY || !stdout.isTTY) && platformNameChoice === 'ios') {
+      pLog.info('Non-interactive mode: cannot prompt for iOS target selection.')
+      pLog.info(`Run manually with a concrete target, e.g. "${pm.runner} cap run ios --target <id>"`)
+      return
+    }
+
     pIntro('Run device test')

As per coding guidelines, "If a command may run in non-interactive mode, do not rely on spinner-only output; provide plain log output or a non-TTY fallback".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/init/command.ts` around lines 2793 - 2807, Before calling
resolveRunDeviceCommand, add a non-interactive (non-TTY) branch that avoids the
interactive target picker: detect non-interactive mode (e.g.,
!process.stdin.isTTY or an existing non-interactive flag), log a clear one-line
status via setInitScreen/pIntro, and produce a deterministic runCommand fallback
(for Android: construct the Capacitor run command; for iOS: pick a default
device/UDID or return a clear error instructing the caller to supply a target)
instead of entering resolveRunDeviceCommand's prompt flow; reference
resolveRunDeviceCommand, exitCanceledRunDeviceTest, platformNameChoice and
runCommand when adding this branch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Line 124: The README contains a duplicate top-level heading "## Options"
causing markdownlint MD024; locate the second occurrence of the "## Options"
heading and either rename it to a distinct title or reduce its level (e.g.,
change "## Options" to "### Options") so headings are unique and hierarchical,
ensuring any internal references or anchor links still make sense after the
change.

---

Nitpick comments:
In `@src/init/command.ts`:
- Around line 2788-2840: Move the testRunDeviceCommand function out of
src/init/command.ts into a new dedicated module (e.g.,
src/commands/test-run-device.ts) and export it as the command handler; in the
new module import its dependencies (getPMAndCommand, normalizeRunDevicePlatform,
resolveRunDeviceCommand, runPackageRunnerSync, formatError,
pIntro/pOutro/pSpinner/pLog/pCancel/setInitScreen, exitCanceledRunDeviceTest and
any types like RunDeviceTestOptions) so the function remains self-contained;
then update src/index.ts to import and register/export the handler
(testRunDeviceCommand) from the new module so CLI wiring remains unchanged;
ensure any relative imports and exported types are adjusted and run tests/lint
to fix import paths.
- Around line 2793-2807: Before calling resolveRunDeviceCommand, add a
non-interactive (non-TTY) branch that avoids the interactive target picker:
detect non-interactive mode (e.g., !process.stdin.isTTY or an existing
non-interactive flag), log a clear one-line status via setInitScreen/pIntro, and
produce a deterministic runCommand fallback (for Android: construct the
Capacitor run command; for iOS: pick a default device/UDID or return a clear
error instructing the caller to supply a target) instead of entering
resolveRunDeviceCommand's prompt flow; reference resolveRunDeviceCommand,
exitCanceledRunDeviceTest, platformNameChoice and runCommand when adding this
branch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a941b6b-6e8d-4612-a779-ccc2e70162c3

📥 Commits

Reviewing files that changed from the base of the PR and between 952a009 and 7439adc.

📒 Files selected for processing (21)
  • README.md
  • skills/usage/SKILL.md
  • src/docs.ts
  • src/index.ts
  • src/init/command.ts
  • src/init/index.ts
  • webdocs/account.mdx
  • webdocs/app.mdx
  • webdocs/build.mdx
  • webdocs/bundle.mdx
  • webdocs/channel.mdx
  • webdocs/doctor.mdx
  • webdocs/init.mdx
  • webdocs/key.mdx
  • webdocs/login.mdx
  • webdocs/organisation.mdx
  • webdocs/organization.mdx
  • webdocs/probe.mdx
  • webdocs/run-device.mdx
  • webdocs/star-all.mdx
  • webdocs/star.mdx
✅ Files skipped from review due to trivial changes (17)
  • webdocs/account.mdx
  • webdocs/organization.mdx
  • webdocs/channel.mdx
  • webdocs/organisation.mdx
  • webdocs/init.mdx
  • src/docs.ts
  • webdocs/star-all.mdx
  • webdocs/bundle.mdx
  • webdocs/star.mdx
  • webdocs/app.mdx
  • webdocs/login.mdx
  • webdocs/key.mdx
  • webdocs/build.mdx
  • webdocs/doctor.mdx
  • webdocs/probe.mdx
  • src/init/index.ts
  • webdocs/run-device.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • skills/usage/SKILL.md

Comment thread README.md Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7439adcbb0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/init/command.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb163217b1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/run/device.ts Outdated
@sonarqubecloud
Copy link
Copy Markdown

@riderx riderx merged commit 9cfb4a7 into main Apr 28, 2026
20 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Onboarding issue Step 9 Run on Device

1 participant