Skip to content

Commit 25d7631

Browse files
MelvinBoteh2077
andcommitted
Merge remote-tracking branch 'origin/main' into claude-migratedUserWelcomeModalV2
Co-authored-by: Eric Han <eh2077@users.noreply.github.com>
2 parents 6db8e12 + 7b2887d commit 25d7631

1,785 files changed

Lines changed: 614240 additions & 387331 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/commands/review-code-pr.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
allowed-tools: Bash(gh pr diff:*),Bash(gh pr view:*),Bash(check-compiler.sh:*)
3-
description: Review a code contribution pull request
3+
description: Run the coding-standards rule linter on a PR diff. Use when user wants to review their changes against our custom rules.
44
---
55

66
Perform a comprehensive PR review using a specialized subagent:
Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,98 @@
11
---
22
name: agent-device
33
description: Drive iOS and Android devices for the Expensify App - testing, debugging, performance profiling, bug reproduction, and feature verification. Use when the developer needs to interact with the mobile app on a device.
4-
allowed-tools: Bash(agent-device *) Bash(npm root *)
4+
allowed-tools: Bash(agent-device *) Bash(npm root *) Bash(scripts/is-hybrid-app.sh)
55
---
66

77
# agent-device
88

9-
## Pre-flight
9+
## Pre-flight (auto)
1010

11-
`agent-device` CLI version: !`agent-device --version 2>&1 || echo "NOT_INSTALLED"`
11+
These checks evaluate at skill load. If any line shows `FAIL`, stop and surface the fix before running any device command.
1212

13-
Canonical skill reference path (read these files directly for device automation guidance - bootstrap, exploration, verification, debugging): !`echo "$(npm root -g)/agent-device/skills/agent-device"`
13+
`agent-device` version: !`R=0.13.0; V=$(agent-device --version 2>/dev/null); [ -n "$V" ] && [ "$(printf '%s\n%s\n' "$R" "$V" | sort -V | head -1)" = "$R" ] && echo "OK ($V)" || echo "FAIL (need v$R+, got: ${V:-not installed}). Fix: npm install -g agent-device@latest"`
1414

15-
> If the version line above shows `NOT_INSTALLED` or a command-not-found error, **STOP** and instruct the developer to install it: `npm install -g agent-device`. All device interaction depends on it.
15+
Bundled CLI skills dir: !`D="$(npm root -g)/agent-device/skills/agent-device"; test -s "$D/SKILL.md" && echo "OK ($D)" || echo "FAIL (missing $D/SKILL.md). Fix: npm install -g agent-device@latest"`
16+
17+
HybridApp mode: !`M=$(scripts/is-hybrid-app.sh 2>/dev/null | tail -1); [ "$M" = "true" ] && echo "OK (HybridApp)" || echo "FAIL (got: ${M:-unknown}). This skill only supports the HybridApp build - ensure the Mobile-Expensify submodule is present."`
18+
19+
## Bring-up
20+
21+
Run this sequence the first time the user asks for device interaction in a session, before any `open` / `snapshot` / `replay`.
22+
23+
### 1. Platform
24+
25+
If the user prompt names `ios` or `android` explicitly, use it. Otherwise ask. Only iOS and Android are supported; reject other platforms.
26+
27+
### 2. Bundle ID
28+
29+
HybridApp dev builds only (the pre-flight gate enforces this).
30+
31+
| Platform | Bundle ID | Build script |
32+
| --------- | ------------------------------- | ----------------- |
33+
| `ios` | `com.expensify.expensifylite` | `npm run ios` |
34+
| `android` | `org.me.mobiexpensifyg.dev` | `npm run android` |
35+
36+
### 3. Confirm dev build is installed
37+
38+
```bash
39+
agent-device apps --user-installed --platform <p> --json
40+
```
41+
42+
If the resolved bundle ID is missing from the list, **STOP** and instruct the developer to run the matching build script from the table. HybridApp mobile builds **must** be initiated from `Mobile-Expensify/` (per project CLAUDE.md).
43+
44+
### 4. Metro
45+
46+
```bash
47+
agent-device metro prepare --public-base-url http://localhost:8081 --port 8081 --kind react-native
48+
```
49+
50+
If `metro prepare` fails, **STOP** and surface the error verbatim.
51+
52+
### 5. Pick a target device
53+
54+
```bash
55+
agent-device devices --platform <p> --json
56+
```
57+
58+
- Prefer the first device with `booted=true`.
59+
- If none are booted, choose the default target device (usually the first listed), then continue to step 6 to detect and clear any stale session bound to that device before opening.
60+
- If multiple are booted, ask the user which.
61+
62+
Capture the device name and (for iOS) the simulator UDID, or (for Android) the serial.
63+
64+
### 6. Session reuse vs reset
65+
66+
```bash
67+
agent-device session list --json
68+
```
69+
70+
For each entry whose `device_udid` (iOS) or `serial` (Android) matches the chosen device:
71+
72+
- If the session was created earlier in the **current** Claude invocation, reuse it silently.
73+
- Otherwise prompt: `reuse` (continue with the existing session) or `reset` (force-close it).
74+
- To reset: `agent-device close --shutdown --session <name>`. `--shutdown` also frees the simulator.
75+
76+
### 7. Open
77+
78+
```bash
79+
agent-device open <bundle-id> --platform <p> --device "<name>"
80+
```
81+
82+
If `open` errors with "app not installed", revisit step 3.
83+
84+
### 8. Sanity
85+
86+
```bash
87+
agent-device snapshot -i
88+
```
89+
90+
Confirm the app rendered. From here, follow the [Agent decision loop](flows/README.md) for repeatable flows or drive interactively.
91+
92+
### Canonical skill references
93+
94+
Read these files directly for device automation guidance (bootstrap, exploration, verification, debugging): !`echo "$(npm root -g)/agent-device/skills/agent-device"`
95+
96+
## Flows
97+
98+
Repeatable steps (sign-in, onboarding, etc.) are captured as composable `.ad` snippets under [`flows/`](flows/README.md). For interactive usage, propose and run only `flows/macros/` helpers. `flows/tests/` belongs to a separate QA workflow and must not be proposed by this skill; QA/perf runs execute them via `agent-device test <path>`.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Flows
2+
3+
## Directory layout
4+
5+
- `macros/` - reusable helpers for common setup/navigation actions that stop in a navigable state for further interactive work.
6+
- `tests/` - critical-scenario scripts for QA/perf verification that assert explicit outcomes (for example Sentry spans) and then stop.
7+
8+
Composable `.ad` snippets - bounded units of work. A flow may span one or multiple screens as long as it represents a coherent, reusable action with clear start (`@pre`) and completion (`@post`) checkpoints. Each flow advertises machine-matchable metadata (`@pre`, `@post`, `@tag`, `@param`) via `# @`-prefixed comment headers, while flow type is derived from location (`flows/macros/` or `flows/tests/`).
9+
10+
## Agent decision loop (interactive)
11+
12+
Before manually navigating, use this human-in-the-loop loop:
13+
14+
1. `agent-device snapshot -i` - see current state.
15+
2. `grep -H '^# @' .claude/skills/agent-device/flows/macros/*.ad` - interactive catalog.
16+
3. For each candidate flow, run `agent-device is exists "<selector>"` per `@pre`. Keep flows where every `@pre` passes.
17+
4. Rank survivors by goal closeness and present top macro candidates to the user with a short "why this flow" note:
18+
- Prefer flows whose `@post` selectors literally match destination language from the user request (same `text`, `label`, or selector phrase).
19+
5. Wait for user selection before replaying. **Auto-run is allowed only when there is exactly one survivor and it is an unambiguous match for an explicit user request.**
20+
- Only propose flows from `flows/macros/` in interactive usage.
21+
6. Scan selected flow `# @param` headers. Ask the user for any missing parameter values, then build explicit CLI args (`-e KEY=VALUE`) for replay.
22+
7. `agent-device replay <path> -e KEY=VALUE ...`.
23+
8. If the flow declares `@post`, verify each `@post` with `is exists`. On success, re-enter the loop only if the user's stated goal is not complete; otherwise stop and report completion. On failure, propose peer flow/manual fallback options and ask before continuing. If no `@post` is declared (utility flow), rely on explicit user confirmation or the next snapshot before continuing.
24+
25+
## QA workflow (separate)
26+
27+
`flows/tests/` is reserved for dedicated QA automation and should not be offered to users as part of the interactive helper loop above. Run these flows with the dedicated test runner:
28+
29+
```bash
30+
agent-device test .claude/skills/agent-device/flows/tests/<name>.ad -e KEY=VALUE ...
31+
```
32+
33+
## Metadata header spec
34+
35+
Each flow starts with `# @key value` comment lines. The `.ad` parser treats `#` lines as no-ops, so headers cost nothing at replay time.
36+
37+
| Field | Cardinality | Value |
38+
| -------- | ----------- | ------------------------------------------------------------------------------------------------ |
39+
| `@desc` | 1 | One-line human summary. |
40+
| `@pre` | 1..N | Selector that must resolve in the current snapshot. Multiple lines are ANDed. |
41+
| `@post` | 0..N | Selector expected after replay. Multiple lines are ANDed. Used for chaining + success. |
42+
| `@tag` | 0..N | Free-form category (`auth`, `onboarding`, ...) or scoped (`sentry-<spanName>`). |
43+
| `@param` | 0..N | Runtime input contract: `@param KEY description.` Use with `${KEY}` in flow body. |
44+
45+
Selector syntax matches the body: `id="..."`, `role="..." label="..."`, `text="..."`, `||` for fallbacks.
46+
47+
## Parametrization (`agent-device` v0.13.0+)
48+
49+
Declare runtime inputs via metadata (`@param`) and reference them in the body with `${VAR}` interpolation. Values are supplied by caller arguments (`-e`) or shell imports (`AD_VAR_*`) - never by in-file `env` directives.
50+
51+
| Construct | Where | Purpose |
52+
| ------------------ | ------------------------ | -------------------------------------------------------------------------------- |
53+
| `# @param KEY ...` | Metadata header comments | Declares expected input and documents meaning for the agent/user handoff. |
54+
| `${KEY}` | Body | Interpolation point. Resolves at replay time. |
55+
| `${KEY:-fallback}` | Body | Use `fallback` if `KEY` is unset. |
56+
| `\${KEY}` | Body | Literal `${KEY}` (escape). |
57+
58+
Resolution precedence (high to low): CLI `-e KEY=VALUE` (repeatable) > shell `AD_VAR_KEY=...` (auto-imported as `KEY`) > built-ins (`AD_PLATFORM`, `AD_SESSION`, `AD_FILENAME`, `AD_DEVICE`, `AD_ARTIFACTS`). Unresolved `${X}` errors with `file:line`.
59+
60+
Override at runtime without editing the file:
61+
62+
```bash
63+
agent-device replay <flow>.ad -e EMAIL=other@example.com
64+
```
65+
66+
## Authoring rules
67+
68+
- **No `open`, no `close`, no `context` header.** Caller owns lifecycle.
69+
- **No fixed `wait` calls.** `fill`/`press` resolve selectors with retry. Only add `wait <selector>` for real post-action blocks.
70+
- **Durable selectors.** Prefer `id=...` first, then `role=... label=...`, with `||` fallbacks. Avoid `@eN` refs.
71+
- **Every flow declares `@desc` and `@pre`.** Add `@post` for outcome-bearing flows; utility flows (for example `go-back`) may omit it. Add `@tag` when applicable.
72+
- **Choose directory intentionally.** Put reusable setup/navigation steps in `flows/macros/`; put outcome verification scenarios in `flows/tests/`.
73+
- **Keep scope coherent, not artificially tiny.** Flows can span multiple screens when that sequence is the reusable intent (for example "create and submit manual expense").
74+
- **Peers share `@pre` and differ on `@post`.** One flow per narrow outcome is better than a mega-flow with conditional branches.
75+
- **Use `@param` for substituted values.** If a literal is interpolated into the body, declare `# @param KEY description.` and reference it as `${KEY}`.
76+
- **Do not use `env` directives in repo flows.** Runtime values must come from `-e KEY=VALUE` (preferred) or `AD_VAR_KEY=...`.
77+
- **Use inline defaults sparingly.** Optional tuning values can use `${KEY:-fallback}` in the body; required values should have no fallback and must be provided by caller input.
78+
79+
## Recording a new flow
80+
81+
1. Drive the target screen manually.
82+
2. Start a session with `--save-script`:
83+
```bash
84+
agent-device open <app> --save-script .claude/skills/agent-device/flows/<kind>/<name>.ad
85+
```
86+
3. Perform the steps.
87+
4. `agent-device close` - flushes the `.ad`.
88+
5. Edit the generated file:
89+
- Delete the `context` line, leading `open ... --relaunch`, trailing `close`, and eyeballing `wait`s.
90+
- Move file to `flows/macros/` or `flows/tests/`, then add `@desc`, `@pre`, optional `@post`, optional `@tag`, and any needed `@param` headers.
91+
6. Verify: pre-check from a matching state, replay, post-check.
92+
93+
## Maintenance
94+
95+
Heal selector drift in place:
96+
97+
```bash
98+
agent-device replay -u .claude/skills/agent-device/flows/<kind>/<name>.ad
99+
```
100+
101+
Re-verify `@pre`/`@post` still hold, then commit. Note: `replay -u` can rewrite interpolated lines to concrete selectors/values; review diffs and restore `${KEY}` placeholders where needed. Keep runtime inputs in `@param` + `-e`/`AD_VAR_*`; do not reintroduce in-file `env` directives.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# @desc Complete onboarding with minimal choices (skip work email, pick "Something else" purpose, enter generic name). Lands on Home.
2+
# @pre text="What’s your work email?"
3+
# @post text="Home"
4+
# @post role="button" label="Search"
5+
# @tag onboarding
6+
# @param FIRST_NAME First name to enter on onboarding profile step.
7+
# @param LAST_NAME Last name to enter on onboarding profile step.
8+
9+
press "id=\"onboardingPrivateEmailSkipButton\" || role=\"button\" label=\"Skip\" || label=\"Skip\""
10+
press "role=\"button\" label=\"Something else\" || label=\"Something else\""
11+
fill "role=\"textfield\" label=\"First name\" editable=true || label=\"First name\" editable=true" "${FIRST_NAME}"
12+
fill "role=\"textfield\" label=\"Last name\" editable=true || label=\"Last name\" editable=true" "${LAST_NAME}"
13+
press "role=\"button\" label=\"Continue\" || label=\"Continue\""
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# @desc Generic back navigation via the HeaderWithBackButton chevron. Works on any screen that mounts HeaderWithBackButton (Create Expense, Search, Report details, settings pages, etc.).
2+
# @pre role="button" label="Back"
3+
# @tag navigation
4+
press "role=\"button\" label=\"Back\""
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# @desc Send a chat message from inside an already-open chat. Reusable helper for setting up state in other flows. Does not navigate or open a chat - assumes the composer is visible. For the QA scenario that exercises the ManualSendMessage Sentry span, see flows/tests/send-message.ad.
2+
# @pre label="Write something..." editable=true
3+
# @post label="Write something..." editable=true
4+
# @tag chat
5+
# @param MESSAGE Message text to send in the currently open chat.
6+
7+
is exists "label=\"Write something...\" editable=true"
8+
fill "label=\"Write something...\" editable=true" "${MESSAGE}"
9+
press "role=\"button\" label=\"Send\" || label=\"Send\""
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# @desc Sign in with the shared agent-device test account. Supports both new-account and returning-account outcomes. Caller MUST randomize EMAIL via `-e EMAIL=agent-device-testing+<9digits>@gmail.com` to avoid account flagging.
2+
# @pre role="textfield" label="Phone or email"
3+
# @pre role="button" label="Continue"
4+
# @post text="Welcome" || text="Home"
5+
# @post role="button" label="Join" || role="button" label="Search"
6+
# @tag auth
7+
# @param EMAIL Login email. Use randomized alias format `agent-device-testing+<9digits>@gmail.com` to avoid account flagging.
8+
9+
fill "id=\"username\" || role=\"textfield\" label=\"Phone or email\" editable=true || label=\"Phone or email\" editable=true" "${EMAIL}"
10+
press "role=\"button\" label=\"Continue\" || label=\"Continue\""
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# @desc Open Create Expense from the FAB, enter an amount on the Manual tab, fill the Merchant field, and submit. Supports configurable currency-aware submit button matching. Exercises the full submit-chain Sentry spans end-to-end. Assumes a workspace where Category is not required.
2+
# @pre role="button" label="Open actions menu"
3+
# @post text="Reports"
4+
# @post role="button" label="Expenses"
5+
# @tag iou
6+
# @tag navigation
7+
# @tag perf
8+
# @tag sentry-ManualCreateExpenseSubmit
9+
# @tag sentry-ManualSubmitToDestinationVisible
10+
# @tag sentry-ManualCreateExpenseServerResponse
11+
# @tag sentry-ManualConfirmationMount
12+
# @tag sentry-ManualConfirmationListReady
13+
# @tag sentry-ManualConfirmationReceiptLoad
14+
# @tag sentry-ManualGeolocationWait
15+
# @param AMOUNT Whole-number amount to type into the Manual amount input (for example `22`).
16+
# @param CURRENCY Currency symbol used by the submit CTA selector (for example `PLN` or `USD`).
17+
# @param MERCHANT Merchant name to populate before submit.
18+
19+
press "role=\"button\" label=\"Open actions menu\""
20+
press "role=\"button\" label=\"Create expense\" || label=\"Create expense\""
21+
press "label=\"Manual\""
22+
is exists "role=\"button\" label=\"Flip\""
23+
fill "editable=true" "${AMOUNT}"
24+
press "role=\"button\" label=\"Next\" || label=\"Next\""
25+
press "role=\"button\" label=\"Merchant\" || label=\"Merchant\""
26+
fill "role=\"text-field\" label=\"Merchant,\" editable=true || label=\"Merchant,\" editable=true" "${MERCHANT}"
27+
press "role=\"button\" label=\"Save\" || label=\"Save\""
28+
press "label=\"Create ${CURRENCY} ${AMOUNT}.00 expense\" || label=\"Create expense\""
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# @desc From the Inbox tab, open the FAB actions menu and tap "Create expense". Triggers the ManualOpenCreateExpense Sentry span (startMoneyRequest -> IOURequestStart/Participants/Confirmation page). Assumes the user is signed in and the Inbox bottom nav with the floating action button is visible.
2+
# @pre text="Inbox"
3+
# @pre role="button" label="Open actions menu"
4+
# @post text="Manual"
5+
# @tag iou
6+
# @tag navigation
7+
# @tag perf
8+
# @tag sentry-ManualOpenCreateExpense
9+
find "Inbox" "click"
10+
press "role=\"button\" label=\"Open actions menu\""
11+
press "role=\"button\" label=\"Create expense\" || label=\"Create expense\""
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# @desc From the Inbox tab, open a chat/report matching TARGET_CHAT in the LHN, with fallback to the first available chat row. Triggers the ManualOpenReport Sentry span (LHN row press -> report screen mounted with composer visible). Assumes the user is signed in with at least one chat in the Inbox.
2+
# @pre text="Inbox"
3+
# @pre role="button" label="Search"
4+
# @post role="textview" label="Write something..."
5+
# @tag chat
6+
# @tag navigation
7+
# @tag perf
8+
# @tag sentry-ManualOpenReport
9+
# @param TARGET_CHAT Visible report/chat title to open from Inbox LHN.
10+
11+
find "Inbox" "click"
12+
find "${TARGET_CHAT}" "click"

0 commit comments

Comments
 (0)