Skip to content

Commit d4f908a

Browse files
author
Shubham Agarwal
committed
refactor(mobile-app): anchor Metro session on the dev-server port
Identify a Metro session by the port it listens on instead of a self-reported sessionId + heartbeat. The port is the number the QR encodes, the device dials, and the debugger probes, and it is the only session fact with external ground truth: the OS knows which process holds a listening socket. This catches a failure a heartbeat cannot. When our Metro dies and a different project's Metro takes over the port, the recorded state still "matches itself", so /debug-app would tail a stale log and report the app healthy. status now returns port-taken and the skill refuses to diagnose from it. Liveness collapses to one probe (lsof on POSIX, netstat -ano on Windows), replacing heartbeat freshness, ownership recheck, startup grace, and stale-marking. portListenerPids distinguishes confirmed-empty from unprobeable, so a host without lsof falls back to PID liveness rather than reporting false conflicts. Removed as redundant: - directory locks and reclaim tokens; a port bind is already an OS-level mutex, leaving a small start/stop lock - heartbeat interval, stateBlocksDuplicateStart, confirmOwnedProcess, markStaleIfNeeded - logGeneration counters and --generation; a cursor past EOF can only mean rotation - the clean verb; stop plus rm is equivalent - sessionId; runner-PID-scoped writes give the same clobber protection The capture pipe is unchanged and still load-bearing: Metro output exists only on its stdout, so the runner keeps owning the child and redacting before persisting. Redaction tests are untouched. Also fixes a handoff race introduced while reducing the runner: it claimed a session by writing its own PID over whatever it read, so a stale runner could adopt and clobber a newer session. It now waits until state already names its own PID and exits otherwise. Net -367 lines. 33/33 script tests and all repository validators pass.
1 parent d969aad commit d4f908a

6 files changed

Lines changed: 650 additions & 973 deletions

File tree

plugins/mobile-apps/AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Do not add preparation rewrites for `scheme`, `package`, `bundleIdentifier`, `sr
7373
- `DONE_WITH_CONCERNS` requires at least one concern. If none, use `DONE`.
7474
- Special early-return signals (`INDUSTRY_CONFIRM_REQUESTED:`, `DESIGN_VIBE_REQUESTED:`) pre-date this protocol and remain in effect — they are special-cased "ask the user one question and re-spawn me" handoffs, not terminal returns.
7575
- The canonical orchestrator handler lives in [`skills/create-mobile-app/SKILL.md`](./skills/create-mobile-app/SKILL.md) Step 3.0. Future skills that spawn agents should reference it rather than duplicating the switch.
76-
11. **Metro lifecycle is project-local**`/create-mobile-app` starts Metro through `scripts/metro-session.js`; `/debug-app` reads `.expo/metro-session/state.json` and the sanitized `metro.log` with a persisted byte cursor. Do not restore required `BashOutput`/terminal-ID behavior. Host terminal APIs may be optional conveniences only. Never write unsanitized Metro output to disk, and never signal a recorded PID unless the wrapper heartbeat proves ownership.
76+
11. **Metro lifecycle is project-local**`/create-mobile-app` starts Metro through `scripts/metro-session.js`; `/debug-app` reads `.expo/metro-session/state.json` and the sanitized `metro.log` with a persisted byte cursor. Do not restore required `BashOutput`/terminal-ID behavior. Host terminal APIs may be optional conveniences only. Never write unsanitized Metro output to disk, and never signal a recorded PID unless the port probe proves the process is still ours.
7777

7878
## Decisions made
7979

@@ -84,7 +84,7 @@ Do not add preparation rewrites for `scheme`, `package`, `bundleIdentifier`, `sr
8484
- ✅ Connection model: per-environment connections, with platform-specific auth (`expo-msal-intune` on native, `expo-auth-session` on web)
8585
- ✅ Auth: `/create-mobile-app` resolves the tenant from the selected Power Platform environment (`scripts/resolve-environment.js`), writes that tenant to `auth.config.json`, then lets the user paste an app registration client ID, create one from the Power Apps Wrap page and paste it, or skip auth for later. `/set-app-registration-native` is a manual helper for the same Wrap-page + pasted-client-ID flow.
8686
-`/add-native` v0 scope: camera, location, push, biometrics, secure-store (already in template)
87-
- ✅ Cross-host Metro session management: detached project-local process, heartbeat-based stale-PID protection, sanitized persisted logs, durable debug cursor, and explicit start/status/tail/stop/clean commands
87+
- ✅ Cross-host Metro session management: detached project-local process, port-probe liveness and stale-PID protection, sanitized persisted logs, durable debug cursor, and explicit start/status/tail/stop commands
8888
- ✅ Template is supplied as a fresh `pa-wrap-tools/templates/expo-app-standalone` folder before `/create-mobile-app` runs; users materialize it with `degit`, run `npm install`, then invoke the skill from that folder. The skill validates/prepares the folder and runs `npx power-apps init`.
8989
-`brand/` directory convention: `/design-system` (Step 6.75) writes `brand/design-system.md` (spec), `brand/tokens.ts` (importable Tamagui tokens), and `brand/design-system.html` (visual gallery). Screen-builders MUST read `brand/design-system.md` if present; `## Negatives` = HARD RULES. `/create-mobile-app` Step 9b imports `brand/tokens.ts` via `skills/design-system/references/tamagui-integration.md`. Projects without `brand/` fall back to `## Design Direction` only — no breakage.
9090
- ✅ Offline profile creation is **author-only in v0.1**`/setup-offline-profile` and `/enable-tables-offline` POST `mobileofflineprofile` / `mobileofflineprofileitem` / `mobileofflineprofileitemassociation` to Dataverse and write `offline-profile.json` to the project, but do NOT scaffold offline runtime code (SQLite store, sync engine, write queue) into the generated app. Runtime support is gated on upstream `@microsoft/power-apps-native-host` confirmation.

0 commit comments

Comments
 (0)