Skip to content

Commit e15145a

Browse files
kanu-shubhamShubham AgarwalCopilot
authored
Support on-demand JavaScript dependencies in mobile apps (#358)
* Support on-demand JavaScript dependencies in mobile apps * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Validate transitive native dependencies * Generalize JavaScript dependency hints * Generalize JavaScript dependency builder guidance * Use explicit approval for JavaScript dependencies --------- Co-authored-by: Shubham Agarwal <agarwalshub+microsoft@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent c1e101b commit e15145a

15 files changed

Lines changed: 372 additions & 70 deletions

File tree

plugins/mobile-apps/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Do not add preparation rewrites for `scheme`, `package`, `bundleIdentifier`, `sr
4848
## Guiding Principles
4949

5050
1. **Connector-first for data** — All Power Platform data access goes through connectors and generated services in `src/generated/`. No direct Graph / Azure REST calls.
51-
2. **Native APIs via Expo modules + RN libraries — allowlist-bounded.** Native capabilities backed by Expo modules and any RN UI/runtime libraries with native assumptions are limited to modules actually shipped by `template/package.json` from the synced `pa-wrap-tools` main template. The rewrap binary is built from a pre-built base, so the runtime knows ONLY about modules the upstream template includes. Do not propose, install, or import modules absent from that package list (notably `expo-notifications` and RN native libraries not already present). Calendar management views may use `react-native-calendars` only when it is present in the template/project `package.json`; otherwise planner/builders must fall back to timeline/list UI or block with a template-update request. `expo-haptics` remains runtime-banned even if it appears in a future template (see [`agents/screen-builder.md`](agents/screen-builder.md) HARD RULE). The canonical list and reconciliation rule are in [`skills/add-native/SKILL.md`](skills/add-native/SKILL.md).
51+
2. **Native code is allowlist-bounded; pure JavaScript is app-scoped.** Expo modules and packages that ship native source, a podspec, codegen configuration, an Expo module/config plugin, or platform projects must already exist in `template/package.json`. The rewrap binary is built from a pre-built base, so adding those packages to an app cannot add their native code. Do not classify a package from its name alone: a `react-native-*` package can still be pure JavaScript. For an explicit library request or an approved use case that benefits from an established library, the planner may select a compatible pure-JavaScript package, pin it in the app's `package.json`, and install it before builders use it; no Android/iOS rebuild is required. Do not bundle optional libraries such as `react-native-calendars` in the base template. Follow [`shared/references/javascript-dependency-planning.md`](shared/references/javascript-dependency-planning.md). `expo-haptics` remains runtime-banned even if it appears in a future template (see [`agents/screen-builder.md`](agents/screen-builder.md) HARD RULE). The native boundary and reconciliation rule are in [`skills/add-native/SKILL.md`](skills/add-native/SKILL.md).
5252
3. **Fresh-template mode**`/create-mobile-app` validates and prepares an existing fresh Expo standalone template working directory. Do not silently copy the bundled `template/` snapshot over the user's folder.
5353
4. **Safety guardrails** — Confirm before deploys, before global installs, before edits outside the project root.
5454
5. **Memory bank** — Persist `memory-bank.md` in the project root.

plugins/mobile-apps/agents/native-app-planner.md

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,17 @@ The orchestrator's Step 3 has a documented inline-gate fallback for exactly this
6161
Read these references once before doing anything else:
6262

6363
- `${PLUGIN_ROOT}/AGENTS.md` — plugin conventions
64-
- `${PLUGIN_ROOT}/template/package.json`**the native-capability allowlist**. The set of native modules in this file is fixed by the rewrap pipeline; you may NEVER propose a capability whose module is not present here. See Step 3 for how this list is enforced.
64+
- `${PLUGIN_ROOT}/template/package.json`**the native-code allowlist**. The set of modules with native code/config is fixed by the rewrap pipeline; you may NEVER propose a native capability whose module is not present here. Pure-JavaScript app dependencies are planned separately by `screen-planner` under `## Screens` and need not be bundled in this template.
6565

6666
Do NOT attempt to read `app.config.js` from the working directory — scaffolding has not run yet. Reading `template/package.json` from `${PLUGIN_ROOT}` IS allowed and IS required.
6767

6868
From the planner prompt extract:
6969
- **Target platforms** — iOS + Android by default. If the user picked just one platform, native modules need `Platform.OS` branching notes in the screen plan.
7070
- **Native capability hints** — words like "scan", "photo", "camera" -> `expo-camera`; "pick file", "upload PDF", "import document", "attach file" -> `expo-document-picker`; "generate PDF", "export report", "print report", "evidence packet" -> `pdf-report` (`expo-print` plus optional `expo-sharing`); "view PDF", "open PDF", "preview PDF" -> `native-pdf-viewer` for HTTPS URLs or local `file://` URIs with `@microsoft/power-apps-native-pdf-viewer` 0.2.9+; "signature", "sign off", "approval", "pen", "ink", "draw" -> `pen-input` with `@microsoft/power-apps-native-pen-input`; "track location", "background location", "GPS tracking", "follow my route", "breadcrumb", "field worker location" -> `geolocation` with `@microsoft/power-apps-native-bglocation` (continuous/background tracking + Dataverse sync); "where am I", "current location", "one-shot location", "tag this with my coordinates" -> one-shot `location` with `expo-location`; "save token", "credentials" -> `expo-secure-store`; "share / send" -> `expo-sharing`; "save file / download" -> `expo-file-system`. **Capability hints that the template does NOT ship** (including PDF viewer, PDF report, sharing, pen, or geolocation packages when absent) are surfaced to the user as transparency notes per Step 3 - never silently promoted into the plan. If the request is generated-report-shaped and the Power Apps PDF viewer package is absent, fall back to `pdf-report` only when `expo-print` is present; otherwise drop the PDF capability.
71+
- **Pure-JavaScript dependency hints** — pass any explicit JavaScript-library request, or any feature that may benefit from an established JS-only package instead of custom code, to `screen-planner`. These are app dependencies, not native capabilities. The screen planner reuses suitable installed packages first; otherwise it follows the canonical candidate-selection workflow and records the selected package with an exact version under `## Screens → ### JavaScript Dependencies`.
7172
- **Industry confirmed** — if the prompt contains a line `Industry confirmed: <slug>`, the orchestrator already ran the industry-confidence check (see Step 3c). Treat that slug as the locked industry for Step 3c — skip detection, skip the confidence check, jump straight to mapping the industry to aesthetic direction / palette / tone.
7273

73-
Capture these for the native capabilities section in Step 4.
74+
Carry each input into its owning planning step: native hints into `## Native Capabilities`, pure-JavaScript dependency hints into the `screen-planner` prompt, and the confirmed industry into design planning.
7475

7576
## Step 2 — Spawn `data-model-architect` + inline planning in parallel
7677

@@ -112,12 +113,12 @@ Build the native capabilities matrix yourself (this is a small enough surface to
112113

113114
### Step 3.0 — Build the allowlist (MANDATORY, before any cap is proposed)
114115

115-
The set of native modules the rewrap pipeline supports is FIXED by `${PLUGIN_ROOT}/template/package.json`. You may NEVER propose a capability whose underlying module is not present there — the customer's binary is built from a pre-built base, not from their `package.json`. Adding a module to the plan that's not shipped means a downstream `/add-native` call WILL stop, and the orchestrator's whole flow stalls at Step 9.
116+
The set of modules with native code/config that the rewrap pipeline supports is FIXED by `${PLUGIN_ROOT}/template/package.json`. You may NEVER propose a native capability whose underlying module is not present there — the customer's binary is built from a pre-built base, not from their `package.json`. Adding a native module to the plan that's not shipped means a downstream `/add-native` call WILL stop, and the orchestrator's whole flow stalls at Step 9. This restriction does not apply to verified pure-JavaScript dependencies; do not infer native code from a package-name prefix.
116117

117118
Read the template's `package.json`:
118119

119120
```bash
120-
node -e "const p = require('${PLUGIN_ROOT}/template/package.json'); const deps = Object.keys({...p.dependencies, ...p.devDependencies}); console.log(deps.filter(d => d.startsWith('expo-') || d.startsWith('react-native-') || d.startsWith('@react-native-community/') || d.startsWith('@microsoft/extension-') || d === '@microsoft/power-apps-native-bglocation').join('\n'));"
121+
node -e "const p = require('${PLUGIN_ROOT}/template/package.json'); console.log(Object.keys({...p.dependencies, ...p.devDependencies}).sort().join('\n'));"
121122
```
122123

123124
Map each shipped module to a user-facing capability slug. Use this known mapping table, but still gate every row against the live allowlist output; a listed capability is supported only when its exact package appears in `template/package.json` and is not runtime-banned.
@@ -134,7 +135,6 @@ Map each shipped module to a user-facing capability slug. Use this known mapping
134135
| `secure-store` | `expo-secure-store` ||
135136
| `file-system` | `expo-file-system` ||
136137
| `sharing` | `expo-sharing` ||
137-
| `calendar-management-view` | `react-native-calendars` ||
138138
| `location` | `expo-location` | `/add-native location` |
139139
| `biometrics` / `local-authentication` | `expo-local-authentication` | `/add-native biometrics` |
140140
| `clipboard` | `expo-clipboard` | `/add-native clipboard` |
@@ -169,23 +169,11 @@ PDF/pen inference rules:
169169
- `geolocation` means continuous/background GPS tracking with durable storage and inline Dataverse sync via `@microsoft/power-apps-native-bglocation`. Auth is MSAL-only; native uploads each fix to an existing Dataverse table (default entity set `msdyn_locationrecords`). It is distinct from one-shot `location` (`expo-location`). Plan it only for continuous tracking or durable upload, require `/add-native geolocation` to verify the target table exists before use, and never propose the `GeolocationExtension`/HostingSDK path.
170170
- The Power Apps extensions are use-case-specific, not generic replacements for Expo modules. For other native needs, choose the relevant Expo module or dependency already present in `template/package.json` and still enforce the allowlist.
171171

172-
**Capabilities not present or runtime-banned** — do not propose: anything whose exact package is absent, `expo-notifications` unless a future template ships it, Bluetooth/NFC/BLE/AR without a shipped package, and `expo-haptics` unless the screen-builder hard rule is explicitly removed.
172+
**Capabilities not present or runtime-banned** — do not propose: anything with required native code/config whose exact package is absent, `expo-notifications` unless a future template ships it, Bluetooth/NFC/BLE/AR without a shipped package, and `expo-haptics` unless the screen-builder hard rule is explicitly removed.
173173

174-
### Calendar management view capability
174+
### Pure-JavaScript dependency handoff
175175

176-
If requirements mention calendar management, scheduling, appointment calendars, personal/team/POS calendar views, month/week/day views, agenda, availability, visits, routes by date, or field-service schedules, propose `calendar-management-view` when `react-native-calendars` is present in `${PLUGIN_ROOT}/template/package.json`. This is a UI library capability, not an Expo permission capability: it needs no `/add-native` wrapper, no `app.config.js` permission changes, and no native skill invocation.
177-
178-
The native-capability matrix row MUST use:
179-
180-
| Field | Required value |
181-
|---|---|
182-
| Capability | `calendar-management-view` |
183-
| Module | `react-native-calendars` |
184-
| Used by screens | every calendar/agenda/schedule screen, such as personal calendar, team calendar, POS calendar, appointment list |
185-
| Justification | render real mobile calendar/agenda surfaces instead of generic FlatList-only date groupings |
186-
| Dedicated skill | blank / `None — UI library, screen-builder imports directly` |
187-
188-
If `react-native-calendars` is absent from the template/package allowlist, do NOT silently plan generic calendar widgets. Add a transparency note: `> Excluded — requirements suggested calendar management views, but this template does not ship react-native-calendars. Update the template/package.json or use timeline/list scheduling screens until the template includes it.`
176+
Do not put JS-only libraries in `## Native Capabilities` and do not route them through `/add-native`. Pass explicit JavaScript package requests and use cases that may benefit from an established library to `screen-planner`, which follows [`shared/references/javascript-dependency-planning.md`](${PLUGIN_ROOT}/shared/references/javascript-dependency-planning.md), chooses a compatible JS-only package, and records an exact approved version under `## Screens → ### JavaScript Dependencies`. `/create-mobile-app` installs that table before screen builders run. Package-specific examples belong in the canonical reference; every library uses the same generic selection gate.
189177

190178
If the requirements imply one of these, DROP the capability and add a transparency note to the `## Native Capabilities` section so the user sees what was excluded and why:
191179

@@ -454,6 +442,8 @@ Plugin root: ${PLUGIN_ROOT}
454442
455443
Expand each screen in the locked graph into a compact delta spec. Do NOT repeat values already present in Shared Conventions, Design Direction, brand/design-system.md, or universal builder rules. Write Standard Imports ONCE near the top. Per-spec Resolved Imports list only entity-specific additions. Cap Open Questions at 3.
456444
445+
Apply the canonical JavaScript dependency workflow for both explicit package requests and use-case-driven needs. Research read-only, emit exact versions plus JS-only evidence, and do not install anything.
446+
457447
Style-picker + preview rules unchanged — honour the same `skip_preview` policy as the legacy single-pass mode (default `skip_preview: true` when `Design vibe opt-in: deferred`).
458448
459449
Return per AGENTS.md rule #10.

plugins/mobile-apps/agents/screen-builder.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ You will be invoked by `/create-mobile-app` Step 11 or `/edit-app` screen-rebuil
201201

202202
- **Native capabilities: use `src/native/` wrappers, NOT raw Expo modules.** `/add-native` creates typed wrappers under `src/native/` (e.g., `camera.ts`, `cameraUpload.ts`, `secureStore.ts`, `documentPicker.ts`, `pdfReport.ts`, `pdfViewer.ts`, `penInput.ts`, `geolocation.ts`). For non-Dataverse native workflows, always import from these wrappers — never import `expo-camera`, `expo-image-picker`, `expo-document-picker`, `expo-print`, `expo-secure-store`, `expo-file-system`, `expo-sharing`, `@microsoft/power-apps-native-pdf-viewer`, `@microsoft/power-apps-native-pen-input`, or `@microsoft/power-apps-native-bglocation` directly in screen files. The wrappers handle permissions, iOS/Android platform differences, URL validation, and return discriminated-union results (`{ ok: true, ... } | { ok: false, reason }`). If a wrapper doesn't exist yet, write the screen with the expected import path and a `// TODO(native-not-yet-added): run /add-native <capability> to create src/native/<wrapper>.ts` comment. For `camera.ts`, use `/add-native camera`; for `barcodeScanner.tsx`, use `/add-native barcode-scanner`; for `pdfReport.ts`, use `/add-native pdf-report`; for `pdfViewer.ts`, use `/add-native pdf-viewer` or `/add-native @microsoft/power-apps-native-pdf-viewer`; for `penInput.ts`, use `/add-native pen-input` or `/add-native @microsoft/power-apps-native-pen-input`; for `geolocation.ts`, use `/add-native geolocation` or `/add-native @microsoft/power-apps-native-bglocation`. **`expo-notifications` and `expo-haptics` are NOT available** — per AGENTS.md §2 and the HARD RULE below for haptics. If the plan tells you to use an unavailable capability, return `NEEDS_CONTEXT` — do not import it.
203203

204+
- **Planned pure-JavaScript dependencies may be imported directly.** Follow `${PLUGIN_ROOT}/shared/references/javascript-dependency-planning.md`'s Builder Contract. Before importing any non-template package, verify it appears with an exact version in `## Screens → ### JavaScript Dependencies` and in the project's `package.json` `dependencies`, and that `require.resolve('<package>', { paths: [working_dir] })` succeeds. If the plan lists it but installation is missing, return `BLOCKED [<screen_name>]: approved JavaScript dependency <package>@<version> is not installed — orchestrator must install dependencies before builders run.` If it is not in the approved table, return `NEEDS_CONTEXT` instead of adding it yourself. Builders never select packages, edit `package.json`, or run installs. Import and use only the package APIs named by the approved per-screen spec.
205+
204206
- **PDF and pen capability behavior.** Native PDF viewer actions MUST call `openHttpsPdf(url)`, which supports `https://` URLs and local `file://` URIs with viewer 0.2.9+. Reject or disable actions for `content://`, `blob:`, `http://`, or empty inputs. Pen capture cancellation (`USER_CANCELLED`) is not an error; leave the screen state unchanged. Handle `NATIVE_MODULE_MISSING`, `VIEWER_FAILED`, `CAPTURE_FAILED`, `uploadFailed`, and `invalidUrl` with visible inline states rather than silent returns.
205207

206208
- **Pen signatures and generated PDFs follow Dataverse artifact boundaries.** Pen input returns `data:image/png;base64,...`; for Image columns, normalize to the generated service payload shape and strip the prefix when raw base64 is required. Generated PDFs and signature PNGs stored in File columns are uploaded only after the parent row exists and the create/update result is successful. If the spec says `Artifact persistence: child Evidence/Attachment table`, create that child row first, then upload File bytes or write the Image payload against the child row ID. Never include File bytes in create/update JSON.
@@ -1123,7 +1125,7 @@ Follow these whenever the spec touches navigation, list rows, or modals. Recipes
11231125

11241126
Without layout animations, new rows appear instantly and deleted rows leave a gap that closes with a jump — the #2 tell that an app isn't native (iOS `UITableView` animates by default). `LinearTransition` makes sibling rows shift smoothly when one is added or removed. Cap `entering` delay at index 5 (rest render instantly — avoids slow initial paint on long lists).
11251127

1126-
44. **Native date/time pickers — NEVER use a Sheet calendar or plain Input for date fields.** If a form field maps to a `datetime` or `DateOnly` Dataverse column, you MUST use `@react-native-community/datetimepicker` (already in template). The recipe in rule 27 (DateTimePicker component) is the ONLY acceptable pattern. The planner spec may say "date picker Sheet" or "date picker" — both mean the native picker, not a custom Tamagui Sheet with a calendar grid. Specifically forbidden:
1128+
44. **Native date/time pickers — NEVER use a Sheet calendar or plain Input for date fields.** If a form field maps to a `datetime` or `DateOnly` Dataverse column, you MUST use `@react-native-community/datetimepicker` (already in template). The recipe in rule 27 (DateTimePicker component) is the ONLY acceptable form-field pattern. This does not prohibit an approved `react-native-calendars` calendar-management screen; that library is for browsing/managing schedules, not editing one Dataverse date field. The planner spec may say "date picker Sheet" or "date picker" — both mean the native picker, not a custom Tamagui Sheet with a calendar grid. Specifically forbidden:
11271129
- `<Sheet>` containing a custom calendar component
11281130
- `<Input type="date">` (not a React Native date control)
11291131
- `<Input>` with manual date string parsing

0 commit comments

Comments
 (0)