Skip to content

Commit d44759b

Browse files
ergonza93Copilot
andauthored
feat(code-apps): support dual pa/power-apps CLI binaries with grouped flag renames (#321)
* feat(code-apps): support dual pa/power-apps CLI binaries with grouped flag renames The Power Apps CLI now ships two binaries from one package: grouped `pa` (preferred) and flat `power-apps` (fallback). This migrates the code-apps plugin to author every command in the canonical grouped `pa` form and resolve/translate the binary at run time. - Add shared/cli-binary.md: probe-based detection (.bin/pa -> .bin/power-apps), npx --no-install security rule, and full command + flag mapping tables. - Account for the live grouped_flag_renames mechanism: on `pa` the selector flags are renamed and short aliases dropped (--connector/--api-id, --table/--resource-name, --name/--data-source-name, --procedure/--sql-stored-procedure, --connection-ref alias dropped). Translation to flat converts both verb path and flags. - Migrate all 15 skills + references + agent guide + shared docs from flat `npx power-apps <verb>` to canonical grouped form. - Bump plugin version 1.0.0 -> 1.1.0 (both plugin.json mirrors). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(code-apps): address PR review - restore Grep -A flags, correct stale -a/-t prose, fix $PA expansion note Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(code-apps): address 2nd review round - Windows .cmd probe + explicit $PA resolution at CLI call sites Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(code-apps): note flat power-apps auth verb translations (logout/auth-status) in prose Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3babfe8 commit d44759b

25 files changed

Lines changed: 257 additions & 104 deletions

File tree

plugins/code-apps/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "code-apps-preview",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "Build and deploy Power Apps code apps using React, Vite, and Power Platform connectors.",
55
"author": {
66
"name": "Microsoft",

plugins/code-apps/.plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "code-apps-preview",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "Build and deploy Power Apps code apps using React, Vite, and Power Platform connectors.",
55
"author": {
66
"name": "Microsoft",

plugins/code-apps/AGENTS.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This file provides guidance to AI Agents when working with the **power-apps** pl
44

55
## What This Plugin Is
66

7-
A plugin for building and deploying Power Apps code apps using React + Vite + TypeScript, connected to Power Platform via connectors (Dataverse, SharePoint, Teams, Azure DevOps, OneDrive, Excel, Office 365, and more). Apps are deployed via the Power Apps NPX CLI (`npx power-apps push`).
7+
A plugin for building and deploying Power Apps code apps using React + Vite + TypeScript, connected to Power Platform via connectors (Dataverse, SharePoint, Teams, Azure DevOps, OneDrive, Excel, Office 365, and more). Apps are deployed via the Power Apps NPX CLI (`pa app push`).
88

99
## Local Development
1010

@@ -89,20 +89,20 @@ Power Apps code apps run in a sandbox — direct HTTP calls (`fetch`, `axios`, G
8989

9090
### Generated Services
9191

92-
`npx power-apps add-data-source` generates typed TypeScript services in `src/generated/`:
92+
`pa app add data-source` generates typed TypeScript services in `src/generated/`:
9393
- `src/generated/models/{Name}Model.ts` — TypeScript interfaces
9494
- `src/generated/services/{Name}Service.ts` — CRUD methods
9595

9696
Always use generated services for data access.
9797

9898
### CLI
9999

100-
The Power Apps CLI (`@microsoft/power-apps-cli`) is installed locally via `npm install` as part of the app template. All commands use `npx power-apps <verb>` from within the project directory — runs natively in bash on all platforms, no PowerShell wrapper needed.
100+
The Power Apps CLI (`@microsoft/power-apps-cli`) is installed locally via `npm install` as part of the app template. It ships two binaries — grouped **`pa`** (preferred) and flat **`power-apps`** (fallback). **Resolve which one the project has via [shared/cli-binary.md](./shared/cli-binary.md) first**, then invoke it with `npx --no-install <pa|power-apps>` from the project directory — runs natively in bash on all platforms, no PowerShell wrapper needed. Commands below use the canonical grouped `pa` form:
101101

102102
```bash
103-
npx power-apps push # Deploy app
104-
npx power-apps add-data-source -a ... # Add connector
105-
npx power-apps list-connections # List connections
103+
pa app push # Deploy app
104+
pa app add data-source --connector ... # Add connector
105+
pa connection list # List connections
106106
```
107107

108108
### Scaffolding
@@ -120,4 +120,4 @@ After modifying this plugin:
120120
1. Run `claude --debug` to see plugin loading details
121121
2. Test skill invocation with `/create-code-app`
122122
3. Verify connector-first guardrails are enforced
123-
4. Test CLI commands (`npx power-apps push`, `npx power-apps add-data-source`, etc.)
123+
4. Test CLI commands (`pa app push`, `pa app add data-source`, etc.)

plugins/code-apps/agents/code-app-architect.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ The Power Apps CLI is installed automatically via `npm install` from the app tem
6666

6767
**If none of the specific skills match**, invoke `/add-connector` — it handles any connector not covered above. Browse available connectors at https://learn.microsoft.com/en-us/connectors/connector-reference/ to find the correct API name. **If no connector exists for the required functionality, tell the user clearly and do not implement a direct API call as a workaround — it will not work in production.**
6868

69-
**Connection IDs**: All non-Dataverse connectors require a connection ID (`-c` flag). Run `/list-connections` to find it, then run `npx power-apps add-data-source -a <connector> -c <connection-id>`.
69+
**Connection IDs**: All non-Dataverse connectors require a connection ID (`-c` flag). Run `/list-connections` to find it, then run `pa app add data-source --connector <connector> -c <connection-id>`.
7070

7171
### Generated Code Pattern
7272

73-
Code apps use `npx power-apps add-data-source` to generate typed services:
73+
Code apps use `pa app add data-source` to generate typed services:
7474
- `src/generated/models/{Table}Model.ts` -- TypeScript interfaces
7575
- `src/generated/services/{Table}Service.ts` -- CRUD methods
7676

@@ -89,7 +89,7 @@ npm install
8989
After scaffolding, initialize:
9090

9191
```bash
92-
npx power-apps init -n '{app-name}' -e <environment-id>
92+
pa app init -n '{app-name}' -e <environment-id>
9393
```
9494

9595
### Dataverse Gotchas
@@ -106,33 +106,33 @@ npx power-apps init -n '{app-name}' -e <environment-id>
106106
- **Azure DevOps**: HttpRequest method requires renaming `parameters` to `body` in 3 generated files.
107107
- **SharePoint/Excel**: Tabular datasources need `--dataset` and `--table` parameters when adding.
108108
- **Excel Online**: Body is a flat key-value object -- no `{ items: ... }` wrapper.
109-
- **Work IQ** (`shared_a365copilotchatmcp`): stateless-tolerant MCP connector — the connection is created with `npx power-apps create-connection` (browser OAuth) and it needs the `McpSession` wrapper (send **no** session id on `initialize`). See the `/add-workiq` skill for setup steps.
109+
- **Work IQ** (`shared_a365copilotchatmcp`): stateless-tolerant MCP connector — the connection is created with `pa connection create` (browser OAuth) and it needs the `McpSession` wrapper (send **no** session id on `initialize`). See the `/add-workiq` skill for setup steps.
110110

111111
### Default Environment
112112

113113
Check `power.config.json` in the project root for an `environmentId` — use it if present. Otherwise ask the user which environment to use. Only use a different environment if the user explicitly requests it.
114114

115115
### CLI Commands
116116

117-
The Power Apps CLI (`@microsoft/power-apps-cli`) installs locally via `npm install`. Use `npx power-apps` from within the project directory works natively in bash on all platforms:
117+
The Power Apps CLI (`@microsoft/power-apps-cli`) installs locally via `npm install`. It ships two binaries — grouped **`pa`** (preferred) and flat **`power-apps`** (fallback). **Resolve which one the project has via [cli-binary.md](../shared/cli-binary.md) before running any command**, then invoke it with `npx --no-install <pa|power-apps>` from the project directory (works natively in bash on all platforms). Commands below are shown in the canonical grouped `pa` form:
118118

119119
```bash
120-
npx power-apps push # Deploy
121-
npx power-apps add-data-source -a <api> -c <id> # Add connector
122-
npx power-apps list-connections # List connections
123-
npx power-apps list-datasets -a <api> -c <id> # List datasets
124-
npx power-apps list-tables -a <api> -c <id> -d <ds> # List tables
125-
npx power-apps logout # Log out
120+
pa app push # Deploy
121+
pa app add data-source --connector <api> -c <id> # Add connector
122+
pa connection list # List connections
123+
pa connector list-datasets --connector <api> -c <id> # List datasets
124+
pa connector list-tables --connector <api> -c <id> -d <ds> # List tables
125+
pa auth logout # Log out
126126
```
127127

128128
**Auth**: MSAL-based — browser popup on first command requiring auth. No separate auth setup needed.
129129

130-
**Environment**: Set once via `npx power-apps init -e <env-id>`, stored in `power.config.json`.
130+
**Environment**: Set once via `pa app init -e <env-id>`, stored in `power.config.json`.
131131

132132
### Build Requirements
133133

134134
Key rules:
135-
- Always `npm run build` before `npx power-apps push`
135+
- Always `npm run build` before `pa app push`
136136
- Remove unused imports (TS6133 strict mode)
137137
- Don't edit files in `src/generated/` unless fixing known issues
138138
- Node.js 22+ required — `add-data-source` rejects older versions
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# CLI Binary Resolution (`pa` preferred, `power-apps` fallback)
2+
3+
**This file is the single source of truth for which CLI binary to run and how to translate commands.** Every skill that runs a Power Apps CLI command MUST resolve the binary using the algorithm below **before** running any command, and MUST author commands in the canonical grouped **`pa`** form (see the mapping table).
4+
5+
---
6+
7+
## Why two binaries
8+
9+
`@microsoft/power-apps-cli` ships two executables from the **same package**:
10+
11+
| Binary | Syntax | Example |
12+
| ------------ | ------- | ------------------------------------------ |
13+
| `pa` | grouped | `pa app add data-source --connector ...` |
14+
| `power-apps` | flat | `power-apps add-data-source -a ...` |
15+
16+
Both are installed together, so a project's `node_modules/.bin/pa` shim exists **only if** the installed CLI version is new enough to include the grouped `pa` binary. Older projects have only `power-apps`. We therefore **prefer `pa`** and **fall back to `power-apps`**.
17+
18+
**Two things differ between the binaries — the verb structure AND some flags:**
19+
20+
1. **Verb structure** — grouped noun-verb (`pa app push`) vs flat (`power-apps push`). See the command mapping table.
21+
2. **Flag renames** — the grouped `pa` surface renames several customer-facing selector flags and **drops their short aliases** (the "Phase 2" `grouped_flag_renames` mechanism, now live). The flat `power-apps` surface keeps the original flags byte-identical. See the flag mapping table.
22+
23+
When translating a canonical `pa` command to flat `power-apps`, you must convert **both** the verb path and any renamed flags.
24+
25+
---
26+
27+
## Resolution algorithm (run once per session, then cache)
28+
29+
Resolve from the **project root** (the directory containing `package.json` / `power.config.json`):
30+
31+
```bash
32+
# Prefer the grouped `pa` binary; fall back to flat `power-apps`.
33+
# --no-install is REQUIRED: it stops npx from silently fetching a remote
34+
# package named `pa`/`power-apps` from the registry if no local shim exists.
35+
# Probe both the extensionless shim (bash/sh) and the `.cmd` shim that
36+
# package managers create on Windows, so a valid install is never missed.
37+
if [ -e node_modules/.bin/pa ] || [ -e node_modules/.bin/pa.cmd ]; then
38+
PA="npx --no-install pa" # grouped syntax → use the "pa" column below
39+
PA_KIND="pa"
40+
elif [ -e node_modules/.bin/power-apps ] || [ -e node_modules/.bin/power-apps.cmd ]; then
41+
PA="npx --no-install power-apps" # flat syntax → translate via the mapping table
42+
PA_KIND="power-apps"
43+
else
44+
# Neither shim present → the CLI is not installed yet.
45+
# Run `npm install` in the project root (per the normal scaffold flow), then re-probe.
46+
PA=""
47+
PA_KIND="none"
48+
fi
49+
```
50+
51+
Rules:
52+
53+
1. **Probe by file presence only** — do not pin or parse a version. A shim (`.bin/pa` or, on Windows, `.bin/pa.cmd`) existing == the grouped binary is available. This is deterministic and cheaper than spawning `--version`. Always check the `.cmd` variant too: npm/pnpm/yarn/bun create `pa.cmd`/`power-apps.cmd` on Windows and an extensionless-only probe would misclassify a valid install as `none`.
54+
2. **Always use `npx --no-install`.** Never run a bare `npx pa ...`: if the local shim is missing, npx would try to download and execute an unrelated remote package named `pa`. `--no-install` fails closed instead.
55+
3. **Cache the result** in the project memory bank (`CLI Binary` row — see `memory-bank.md`) so subsequent skills/commands in the session don't re-probe. Re-probe only after an `npm install` that could have changed the installed CLI.
56+
4. **`none` → install first.** If neither shim exists, the CLI isn't installed; run the project's `npm install` (already part of the scaffold flow) and re-probe before running any command.
57+
58+
---
59+
60+
## Authoring rule for skills
61+
62+
- **Author every command in the canonical grouped `pa` form** (the left/`pa` column below), using the **renamed `pa` flags** from the flag mapping table, e.g. `pa app push`, `pa app add data-source --connector shared_office365 -c <conn-id>`.
63+
- Substitute the resolved `$PA` prefix (which already contains `npx --no-install`) for the binary at run time. When `PA_KIND=pa`, run the canonical command as-is: `$PA app push``npx --no-install pa app push`. When `PA_KIND=power-apps`, translate the verb path (and renamed flags) per the next rule before running: `$PA push``npx --no-install power-apps push`.
64+
- **If `PA_KIND` is `power-apps`, translate each grouped command to its flat equivalent before running it — convert BOTH the verb path AND any renamed flags.** The flat binary does **not** understand the grouped noun-verb form (`power-apps app push` is invalid — it must become `power-apps push`), and it does **not** accept the renamed long flags (`--connector` must become `--api-id`/`-a`, `--table` must become `--resource-name`/`-t`, etc.).
65+
- **Most flags are unchanged** — only the selector flags in the flag mapping table are renamed on `pa`. Connection ID (`-c`), dataset (`-d`), environment (`-e`), and display name (`-n` on `init`/`connection create`) are identical on both binaries.
66+
67+
---
68+
69+
## Command mapping table (grouped `pa` ↔ flat `power-apps`)
70+
71+
| Operation | Canonical (`pa`) | Flat (`power-apps`) |
72+
| ------------------------ | --------------------------------- | --------------------------------- |
73+
| Initialize project | `pa app init` | `power-apps init` |
74+
| Deploy / push | `pa app push` | `power-apps push` |
75+
| Local dev server | `pa app run` | `power-apps run` |
76+
| List code apps | `pa app list` | `power-apps list-codeapps` |
77+
| Add data source | `pa app add data-source` | `power-apps add-data-source` |
78+
| Add Dataverse API | `pa app add dataverse-api` | `power-apps add-dataverse-api` |
79+
| Add flow | `pa app add flow` | `power-apps add-flow` |
80+
| Remove data source | `pa app remove data-source` | `power-apps delete-data-source` |
81+
| Remove flow | `pa app remove flow` | `power-apps remove-flow` |
82+
| Refresh data source | `pa app refresh data-source` | `power-apps refresh-data-source` |
83+
| Find Dataverse API | `pa app find-dataverse-api` | `power-apps find-dataverse-api` |
84+
| List environment vars | `pa app list-environment-variables` | `power-apps list-environment-variables` |
85+
| List flows | `pa app list-flows` | `power-apps list-flows` |
86+
| List connections | `pa connection list` | `power-apps list-connections` |
87+
| List connection refs | `pa connection list-references` | `power-apps list-connection-references` |
88+
| Create connection | `pa connection create` | `power-apps create-connection` |
89+
| List connectors | `pa connector list` | `power-apps list-connectors` |
90+
| List datasets | `pa connector list-datasets` | `power-apps list-datasets` |
91+
| List tables | `pa connector list-tables` | `power-apps list-tables` |
92+
| List stored procedures | `pa connector list-procedures` | `power-apps list-sqlStoredProcedures` |
93+
| Sign in | `pa auth login` | `power-apps login` |
94+
| Sign out | `pa auth logout` | `power-apps logout` |
95+
| Auth status | `pa auth status` | `power-apps auth-status` |
96+
| Switch account | `pa auth switch` | `power-apps auth-switch` |
97+
| Telemetry enable | `pa telemetry enable` | `power-apps telemetry --enable` |
98+
| Telemetry disable | `pa telemetry disable` | `power-apps telemetry --disable` |
99+
| Telemetry status | `pa telemetry status` | `power-apps telemetry --show-settings` |
100+
101+
> **Note:** the operations above differ only in verb structure. Renamed **flags** (which apply to several of these operations) are listed separately in the flag mapping table below.
102+
103+
---
104+
105+
## Flag mapping table (grouped `pa` ↔ flat `power-apps`)
106+
107+
The grouped `pa` surface renames these customer-facing selector flags and **drops their short aliases**. The flat `power-apps` surface keeps the original flag names and aliases. All other flags are identical on both binaries.
108+
109+
| Selector | Canonical (`pa`) | Flat (`power-apps`) | Used by |
110+
| ----------------------- | -------------------- | ---------------------------------- | --------------------------------------------------- |
111+
| Connector / API | `--connector` | `--api-id` (alias `-a`) | `add data-source`, `connector list-*`, `connection create` |
112+
| Table / resource | `--table` | `--resource-name` (alias `-t`) | `add data-source` |
113+
| Data source name | `--name` | `--data-source-name` (alias `-n`) | `add data-source`, `refresh data-source` |
114+
| SQL stored procedure | `--procedure` | `--sql-stored-procedure` (alias `-sp`) | `connector list-procedures` |
115+
| Connection reference | `--connection-ref` | `--connection-ref` (alias `-cr`) | `add data-source` (Dataverse) — **alias `-cr` dropped on `pa`, long flag unchanged** |
116+
117+
**Unchanged on both binaries** (do NOT rewrite these): `--connection-id`/`-c`, `--dataset`/`-d`, `--environment-id`/`-e`, `--display-name`/`-n` (on `init` and `connection create`), `--solution-id`, `--search`, `--cloud`.
118+
119+
> ⚠️ **`-n` is context-dependent.** On `add data-source`/`refresh data-source`, `-n` is the (renamed) `data-source-name``--name`. On `init` and `connection create`, `-n` is `display-name`, which is **not** renamed. Translate based on the verb, not the letter.
120+
121+
---
122+
123+
## `npx` prefix note
124+
125+
Skill examples elsewhere in the plugin are written in the **canonical grouped `pa` form** (e.g. `pa app push`). These are authoring shorthand — read them as the **canonical operation**, resolve `$PA`, and run the resolved form with the required `npx --no-install` prefix:
126+
127+
- resolved `pa``npx --no-install pa <noun> <verb> ...`
128+
- resolved `power-apps` → translate via the mapping table, then `npx --no-install power-apps <verb> ...`

plugins/code-apps/shared/connector-reference.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ Applies to all connector skills (`/add-azuredevops`, `/add-teams`, `/add-excel`,
44

55
## Connection ID (Required)
66

7-
All non-Dataverse connectors require a **connection ID** (`-c`) when adding via `npx power-apps add-data-source`. Without it, the command fails with: `CONNECTION_ID argument is required for connector data sources`.
7+
All non-Dataverse connectors require a **connection ID** (`-c`) when adding via `pa app add data-source`. Without it, the command fails with: `CONNECTION_ID argument is required for connector data sources`.
88

99
### Step 1: List Existing Connections
1010

11-
Run the `/list-connections` skill. It runs `npx power-apps list-connections` and returns a table of connection IDs and connector names.
11+
Run the `/list-connections` skill. It runs `pa connection list` and returns a table of connection IDs and connector names.
1212

1313
Look for the connector in the output. Note the **ConnectionId** column value.
1414

@@ -27,11 +27,14 @@ The user must create one first:
2727
Always pass `-c <connection-id>` when adding a connector:
2828

2929
```bash
30+
# Commands shown in canonical `pa` form — resolve the binary via shared/cli-binary.md
31+
# and translate to flat `power-apps add-data-source ...` when only `power-apps` is installed.
32+
3033
# Non-tabular connectors
31-
npx power-apps add-data-source -a <api-name> -c <connection-id>
34+
pa app add data-source --connector <api-name> -c <connection-id>
3235

3336
# Tabular connectors (also need -d and -t)
34-
npx power-apps add-data-source -a <api-name> -c <connection-id> -d '<dataset>' -t '<table>'
37+
pa app add data-source --connector <api-name> -c <connection-id> -d '<dataset>' --table '<table>'
3538
```
3639

3740

0 commit comments

Comments
 (0)