diff --git a/plugins/mobile-apps/AGENTS.md b/plugins/mobile-apps/AGENTS.md index 67981985b..28d2c93d6 100644 --- a/plugins/mobile-apps/AGENTS.md +++ b/plugins/mobile-apps/AGENTS.md @@ -32,7 +32,7 @@ hooks/ ← Telemetry start hooks plus validators invoked ## Template source -The Expo template snapshot ships bundled inside this plugin at `template/`. It is synced from `pa-wrap-tools-1` / `pa-wrap-tools` `main`, `templates/expo-app-standalone/`. `/create-mobile-app` does not silently copy the bundled template over a user's folder; it expects a fresh installed template working directory and applies these preparation edits there: +The Expo template snapshot ships bundled inside this plugin at `template/`. It is synced from `microsoft/power-platform-skills` `main`, `plugins/mobile-apps/template/`. `/create-mobile-app` does not silently copy the bundled template over a user's folder; it expects a fresh installed template working directory and applies these preparation edits there: | Edit | Purpose | |---|---| @@ -93,7 +93,7 @@ Mobile Apps bundles the canonical stdlib-only telemetry helpers from the repo-ro - ✅ Connection model: per-environment connections, with platform-specific auth (`expo-msal-intune` on native, `expo-auth-session` on web) - ✅ 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. - ✅ `/add-native` v0 scope: camera, location, push, biometrics, secure-store (already in template) -- ✅ 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`. +- ✅ Template is supplied as a fresh `microsoft/power-platform-skills/plugins/mobile-apps/template#main` 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`. - ✅ `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. - ✅ 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. - ✅ Custom filter mode (`recorddistributioncriteria=3`, `profileitemrule` → `savedquery`) is **deferred to v0.5**. v0.1 supports Related-rows-only / All-records / Organization-rows radio options only. diff --git a/plugins/mobile-apps/agents/native-app-planner.md b/plugins/mobile-apps/agents/native-app-planner.md index 5d824f448..1dc83678b 100644 --- a/plugins/mobile-apps/agents/native-app-planner.md +++ b/plugins/mobile-apps/agents/native-app-planner.md @@ -726,7 +726,7 @@ Sections approved: Next steps for the orchestrator: 1. Auth + environment selection - 2. Use the user-prepared fresh template folder materialized from `pa-wrap-tools/templates/expo-app-standalone` with `degit` + 2. Use the user-prepared fresh template folder materialized from `microsoft/power-platform-skills/plugins/mobile-apps/template#main` with `degit` 3. npx power-apps init -t MobileApp --display-name --environment-id --non-interactive 4. Apply data model via /add-dataverse using the plan 5. Apply native capabilities via /add-native using the plan diff --git a/plugins/mobile-apps/hooks/validate-protected-paths.js b/plugins/mobile-apps/hooks/validate-protected-paths.js index d842f6ab8..b19622820 100644 --- a/plugins/mobile-apps/hooks/validate-protected-paths.js +++ b/plugins/mobile-apps/hooks/validate-protected-paths.js @@ -6,7 +6,7 @@ * Blocks writes to: * - any path under `src/generated/` (regenerated by `npx power-apps add-data-source`) * - any `power.config.json` (regenerated by `npx power-apps init`) - * - any `vendor/.tgz` (sourced from upstream pa-wrap-tools) + * - any `vendor/.tgz` (sourced from plugins/mobile-apps/template) * * Manual edits to these files are silently lost on the next CLI run, so it's * almost always wrong. Block with a clear message pointing to the right tool. @@ -34,7 +34,7 @@ const PROTECTED = [ { rx: /(^|\/)vendor\/[^/]+\.tgz$/, reason: - '`vendor/*.tgz` files are sourced from upstream `pa-wrap-tools`. Update them via the upstream repo, not by editing in-project.', + '`vendor/*.tgz` files are sourced from https://github.com/microsoft/power-platform-skills/tree/main/plugins/mobile-apps/template. Update them there, not by editing in-project.', }, ]; diff --git a/plugins/mobile-apps/skills/add-native/add-camera/SKILL.md b/plugins/mobile-apps/skills/add-native/add-camera/SKILL.md index 510bfe05e..4e67548a7 100644 --- a/plugins/mobile-apps/skills/add-native/add-camera/SKILL.md +++ b/plugins/mobile-apps/skills/add-native/add-camera/SKILL.md @@ -19,7 +19,7 @@ model: sonnet Generate typed camera + image-picker wrappers, an optional barcode/QR scanner control, and optional custom-upload guidance for Dataverse image/file workflows. -This skill **only writes JS files under `src/native/`**. It does not install modules and does not touch `package.json` or `app.config.js` — the underlying Expo modules (`expo-camera`, `expo-image-picker`) and their config plugins must already be shipped by the upstream `pa-wrap-tools/templates/expo-app-standalone` template. If they're missing, STOP and tell the user the template doesn't ship them yet. +This skill **only writes JS files under `src/native/`**. It does not install modules and does not touch `package.json` or `app.config.js` — the underlying Expo modules (`expo-camera`, `expo-image-picker`) and their config plugins must already be shipped by the `microsoft/power-platform-skills/plugins/mobile-apps/template#main` template. If they're missing, STOP and tell the user the template doesn't ship them yet. Why: customer binaries are built from a pre-built rewrap base, not from the customer's `package.json`. Adding a native module here would compile against modules the binary doesn't actually contain, causing runtime crashes after rewrap. See [`/add-native`](../SKILL.md) for the same hard rules. @@ -50,7 +50,7 @@ If any file is missing, report and STOP — this skill requires an initialized P Both `expo-camera` and `expo-image-picker` must already be in `package.json`. Do **not** install them — if they're missing, the upstream template hasn't shipped them yet, and this skill STOPs. ```bash -node -e "const p = require('./package.json'); const need = ['expo-camera','expo-image-picker']; const missing = need.filter(m => !p.dependencies?.[m]); if (missing.length) { console.error('MISSING from package.json: ' + missing.join(', ') + '. The upstream template must ship these for /add-native camera to run. Do NOT install them yourself — file an issue at the template repo (pa-wrap-tools/templates/expo-app-standalone) instead.'); process.exit(1); } console.log('OK: both modules present');" +node -e "const p = require('./package.json'); const need = ['expo-camera','expo-image-picker']; const missing = need.filter(m => !p.dependencies?.[m]); if (missing.length) { console.error('MISSING from package.json: ' + missing.join(', ') + '. The upstream template must ship these for /add-native camera to run. Do NOT install them yourself — file an issue at the template repo (plugins/mobile-apps/template) instead.'); process.exit(1); } console.log('OK: both modules present');" ``` If the check fails, STOP. Print the error verbatim. Do not run `npx expo install`. Do not edit `app.config.js`. Tell the user the template version they scaffolded from doesn't include the camera modules — they need to wait for a newer template release or open a request upstream. diff --git a/plugins/mobile-apps/skills/create-mobile-app/SKILL.md b/plugins/mobile-apps/skills/create-mobile-app/SKILL.md index 7d8d7ed9d..4df8cc170 100644 --- a/plugins/mobile-apps/skills/create-mobile-app/SKILL.md +++ b/plugins/mobile-apps/skills/create-mobile-app/SKILL.md @@ -20,9 +20,9 @@ Top-level orchestrator. Owns the user-visible flow; delegates planning to the `n ## Fresh-template working-directory mode -This skill assumes the user already has a **fresh** `pa-wrap-tools/templates/expo-app-standalone` template materialized with `degit` in the target working directory and has already run `npm install` there. The skill turns that fresh template into an app; it does not clone, degit, or copy a template itself. +This skill assumes the user already has a **fresh** `microsoft/power-platform-skills/plugins/mobile-apps/template#main` template materialized with `degit` in the target working directory and has already run `npm install` there. The skill turns that fresh template into an app; it does not clone, degit, or copy a template itself. -**Fresh template required.** If the working directory is not a template, or if it already looks like an app created by this skill, STOP and tell the user to materialize a fresh `expo-app-standalone` template with `degit` into a new folder, run `npm install`, then rerun `/create-mobile-app --working-dir `. +**Fresh template required.** If the working directory is not a template, or if it already looks like an app created by this skill, STOP and tell the user to materialize a fresh `microsoft/power-platform-skills/plugins/mobile-apps/template#main` template with `degit` into a new folder, run `npm install`, then rerun `/create-mobile-app --working-dir `. Use these markers: @@ -31,7 +31,7 @@ Use these markers: | Fresh template | `package.json`, `app.config.js`, `auth.config.json`, `tamagui.config.ts` exist; `node_modules/expo` exists; `memory-bank.md`, `native-app-plan.md`, `.datamodel-manifest.json`, and generated Dataverse services are absent | Proceed. | | Template not installed | Fresh-template files exist but `node_modules/expo` is absent | STOP: ask user to run `npm install` in the template folder, then rerun. Do not provision ADO npm tokens here. | | Already-created app | `memory-bank.md`, `native-app-plan.md`, `.datamodel-manifest.json`, or `src/generated/services/*.ts` exists | STOP: this is not a fresh create target. Ask user to materialize a fresh template folder with `degit`. | -| Not template | Required template files are missing | STOP: ask user to materialize `pa-wrap-tools/templates/expo-app-standalone` into the working directory with `degit` and run `npm install`. | +| Not template | Required template files are missing | STOP: ask user to materialize `microsoft/power-platform-skills/plugins/mobile-apps/template#main` into the working directory with `degit` and run `npm install`. | This gate is intentionally simple: `/create-mobile-app` creates a new app from a fresh template. It does not adopt, repair, resume, or overwrite an already-created app. @@ -82,10 +82,10 @@ After the resume check, run the **fresh-template gate** from the section above. - If `memory-bank.md` exists and the user confirms resume, resume as documented above. - If any already-created-app marker exists and there is no approved resume path, STOP and tell the user to materialize a fresh template into a new folder with `degit`. -- If required template files are missing, STOP and tell the user to materialize `pa-wrap-tools/templates/expo-app-standalone` into the working directory with `degit` and run `npm install`. +- If required template files are missing, STOP and tell the user to materialize `microsoft/power-platform-skills/plugins/mobile-apps/template#main` into the working directory with `degit` and run `npm install`. - If `node_modules/expo` is missing, STOP and tell the user to run `npm install` in that template folder before rerunning this skill. -**Do not silently copy a bundled template over the user's folder.** A fresh `pa-wrap-tools-1` template may contain placeholder `power.config.json` with an empty `environmentId`; Step 5 removes that placeholder immediately before Step 6 runs `npx power-apps init`. +**Do not silently copy a bundled template over the user's folder.** A fresh `plugins/mobile-apps/template` template may contain placeholder `power.config.json` with an empty `environmentId`; Step 5 removes that placeholder immediately before Step 6 runs `npx power-apps init`. After the fresh-template gate succeeds, or after the user confirms a resume, initialize the app identity before continuing: diff --git a/plugins/mobile-apps/skills/design-system/SKILL.md b/plugins/mobile-apps/skills/design-system/SKILL.md index b4fc6f2b9..4ebf1479b 100644 --- a/plugins/mobile-apps/skills/design-system/SKILL.md +++ b/plugins/mobile-apps/skills/design-system/SKILL.md @@ -182,7 +182,7 @@ Persist choice to `memory-bank.md`: `visual_companion: ` **Source-of-truth lookup order for the preset bundle:** 1. If the user passed `--direction ` (e.g. `inspection`, `saas`, `product`), load `${CLAUDE_SKILL_DIR}/references/vibe/direction-.md` and use its tokens. 2. **Airline / aviation / commercial-flight carve-out (HARD RULE).** If the brief contains any of `airline`, `aviation`, `flight`, `aircraft`, `carrier`, `pilot`, `cabin crew`, `boarding`, `departure`, `tarmac`, `turnaround`, `ground ops`, OR the app name contains those tokens, DO NOT load the `signature` preset (safety-orange would clash with airline brand expectations). Instead **load [`${CLAUDE_SKILL_DIR}/references/vibe/direction-airline.md`](./references/vibe/direction-airline.md)** — deep aviation blue (`#0A4F8F`), white surfaces, hi-vis status pills, hairline borders. Token bundle is the canonical FlightCheck tokens (proven in production). Record in `memory-bank.md` as `direction: airline`. - 3. **Else (true "all defaults" path) → load [`${CLAUDE_SKILL_DIR}/references/vibe/direction-polished-inspection.md`](./references/vibe/direction-polished-inspection.md) as the canonical `polished-inspection` preset** — white surface, Power-Platform green `#007d48` accent (sourced from `pa-wrap-tools-1/templates/equipment-inspector`), status-stripe cards, soft-tinted status pills, large tap targets. This is the polished MVP default that fits any inspection / field-ops / asset-tracking app (~70% of mobile-app traffic) AND demos cleanly to enterprise stakeholders. The previous `signature` preset (slate dark + safety orange, sourced from `uber-design.md`) is now opt-in via `--direction inspection` for true outdoor-only field apps. + 3. **Else (true "all defaults" path) → load [`${CLAUDE_SKILL_DIR}/references/vibe/direction-polished-inspection.md`](./references/vibe/direction-polished-inspection.md) as the canonical `polished-inspection` preset** — white surface, Power-Platform green `#007d48` accent (Power Platform–aligned default), status-stripe cards, soft-tinted status pills, large tap targets. This is the polished MVP default that fits any inspection / field-ops / asset-tracking app (~70% of mobile-app traffic) AND demos cleanly to enterprise stakeholders. The previous `signature` preset (slate dark + safety orange, sourced from `uber-design.md`) is now opt-in via `--direction inspection` for true outdoor-only field apps. 4. As a last fallback, if the source file is unreadable, use the inspection direction inlined in [`references/design-system-schema.md`](./references/design-system-schema.md). Skip the full `brand/design-system.md` write — only `brand/tokens.ts` is needed. Record the chosen source in `memory-bank.md` under `## Design`: `direction: polished-inspection (default — white + Power-Platform green, demo-friendly enterprise polish)` so future runs know what was picked. diff --git a/plugins/mobile-apps/skills/design-system/references/vibe/direction-polished-inspection.md b/plugins/mobile-apps/skills/design-system/references/vibe/direction-polished-inspection.md index 0fa07bcc0..2c2d6a36b 100644 --- a/plugins/mobile-apps/skills/design-system/references/vibe/direction-polished-inspection.md +++ b/plugins/mobile-apps/skills/design-system/references/vibe/direction-polished-inspection.md @@ -6,7 +6,7 @@ ## Reference apps -Microsoft Dynamics 365 Field Service mobile, Salesforce Field Service, ServiceTitan (light theme), the equipment-inspector Power Apps template (`pa-wrap-tools-1/templates/equipment-inspector`), Procore (light), Notion enterprise +Microsoft Dynamics 365 Field Service mobile, Salesforce Field Service, ServiceTitan (light theme), the equipment-inspector Power Apps template (`plugins/mobile-apps/template`), Procore (light), Notion enterprise ## Gestalt @@ -43,7 +43,7 @@ tone: professional-utilitarian ## Provenance -- **Brand color `#007d48`** — pulled directly from `pa-wrap-tools-1/templates/equipment-inspector/src/components/EquipmentRow.tsx` line 7 ("Active — success green"). Identical to / adjacent to Microsoft Power Platform green family. Production-validated. +- **Brand color `#007d48`** — pulled directly from `plugins/mobile-apps/template` line 7 ("Active — success green"). Identical to / adjacent to Microsoft Power Platform green family. Production-validated. - **Danger color `#d30005`** — same source, line 9 ("Out of Service — danger red"). Production-validated. - **Muted text `#707072`** — same source, line 8 ("Retired — muted"). - **Icon-only `#9e9ea0`** — same source, line 70 (chevron-forward color). diff --git a/plugins/mobile-apps/skills/setup-offline-profile/SKILL.md b/plugins/mobile-apps/skills/setup-offline-profile/SKILL.md index c44308e8c..ac9b6a566 100644 --- a/plugins/mobile-apps/skills/setup-offline-profile/SKILL.md +++ b/plugins/mobile-apps/skills/setup-offline-profile/SKILL.md @@ -527,7 +527,7 @@ After confirmed success, re-GET the profile and check `publishedon` for the arti "appConfig": { "enabled": true, "serverRowLimit": 2000, - "/* BEGIN OFFLINE-CONFIG-WORKAROUND */": "remove when SDK gaps are fixed upstream — tracked in pa-wrap-tools (instanceUrl) + PowerApps-Client (useDda + entitiesIncluded). Bracket exists so the future cleanup diff is mechanical.", + "/* BEGIN OFFLINE-CONFIG-WORKAROUND */": "remove when SDK gaps are fixed upstream — tracked in microsoft/power-platform-skills/plugins/mobile-apps/template#main (instanceUrl) + PowerApps-Client (useDda + entitiesIncluded). Bracket exists so the future cleanup diff is mechanical.", "useDda": false, "entitiesIncluded": ["", "", "..."], "instanceUrl": "", @@ -579,7 +579,7 @@ node -e ' }; // BEGIN OFFLINE-CONFIG-WORKAROUND (remove when underlying SDK gaps are fixed - // upstream — tracked separately in pa-wrap-tools and PowerApps-Client). + // upstream — tracked separately in plugins/mobile-apps/template and PowerApps-Client). appConfig.useDda = false; appConfig.entitiesIncluded = [/* logicalName for each table in the profile */]; appConfig.instanceUrl = ""; @@ -607,7 +607,7 @@ Field rationale: | `appConfig.serverRowLimit` | A (genuine) | Mirrors Image 2's "Data row limit" field (2000 default). For v0 it's a config-only value — runtime enforcement is a Layer B concern. | | `appConfig.useDda` | **OFFLINE-CONFIG-WORKAROUND** | Forces the SDK off its broken `shouldUseDda` gate (entity-set vs logical-name mismatch). Remove when that gate is reconciled in `@microsoft/react-native-dataverse-offline` (tracked in PowerApps-Client). | | `appConfig.entitiesIncluded` | **OFFLINE-CONFIG-WORKAROUND** | The SDK's offline bootstrap reads this list to know which entity logical names participate in the profile. Currently required because the SDK doesn't derive it from the published profile manifest at runtime. Populate with one logical name per table in the profile (i.e. the `logicalName` field of each `tables[]` entry below). | -| `appConfig.instanceUrl` | **OFFLINE-CONFIG-WORKAROUND** | Enables offline cold-start by giving the SDK a static org name without needing an `api.powerplatform.com` round-trip while offline. Value is the same `` captured in Step 1 (e.g. `https://orgXXX.crm.dynamics.com`). Was previously written into `power.config.json.databaseReferences[*].databaseDetails.linkedEnvironmentMetadata.instanceUrl`; runtime now reads from `appConfig.instanceUrl` here. Tracked upstream in pa-wrap-tools. | +| `appConfig.instanceUrl` | **OFFLINE-CONFIG-WORKAROUND** | Enables offline cold-start by giving the SDK a static org name without needing an `api.powerplatform.com` round-trip while offline. Value is the same `` captured in Step 1 (e.g. `https://orgXXX.crm.dynamics.com`). Was previously written into `power.config.json.databaseReferences[*].databaseDetails.linkedEnvironmentMetadata.instanceUrl`; runtime now reads from `appConfig.instanceUrl` here. Tracked upstream in plugins/mobile-apps/template. | > **Do NOT touch `power.config.json` from this skill.** Earlier drafts wrote the same fields into `power.config.json.offline.*` and `databaseReferences[*].databaseDetails.linkedEnvironmentMetadata.instanceUrl`. That was reverted because `power.config.json` is generated by `npx power-apps init`, whose schema we don't control — adding custom fields there means re-init can wipe them and upstream schema changes can break this skill. If you find a code path here that still mutates `power.config.json`, treat it as a bug.