[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M699S2F98R956TA0QEMSP59A":3,"skill-same:01M699S2F98R956TA0QEMSP59A":98},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":26,"publishedAt":48,"linkOnly":49,"markdownContent":50,"markdownBody":51,"frontMatter":52,"refName":55,"commitSha":56,"skillDirectory":57,"forksCount":58,"repositoryHtmlUrl":59,"repositoryHomepageUrl":60,"ownerHtmlUrl":61,"ownerBlogUrl":62,"ownerDescription":63,"updatedAt":64,"install":65,"resources":77},"01M699S2F98R956TA0QEMSP59A","add-cloud-flow",null,"Integrates Power Automate cloud flows into a Power Pages site. Lists available flows, suggests relevant ones based on intent, identifies scenarios and web roles, creates metadata files, and generates client-side code to call flows. Handles both new flow registration and adding already-registered flows to additional pages without re-creating metadata. Use when the user wants to add, connect, register, or link a Power Automate cloud flow to their site.","microsoft\u002Fpower-platform-skills","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M699JVYJFB75D9JM70BN4H0Q",1146,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpower-pages\u002Fskills\u002Fadd-cloud-flow\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47],"add cloud flow","cloud","flow","add","power","opus","re","relevant","client","register","roles","call","registration","files","web","use","edit","write","read","connect","power pages","2026-11-10 10:12:30",false,"---\nname: add-cloud-flow\ndescription: >-\n  Integrates Power Automate cloud flows into a Power Pages site. Lists available flows,\n  suggests relevant ones based on intent, identifies scenarios and web roles, creates metadata\n  files, and generates client-side code to call flows. Handles both new flow registration and\n  adding already-registered flows to additional pages without re-creating metadata. Use when\n  the user wants to add, connect, register, or link a Power Automate cloud flow to their site.\nuser-invocable: true\nallowed-tools: Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion, Skill, Task, TaskCreate, TaskUpdate, TaskList\nmodel: opus\n---\n\n> **Plugin check**: Run `node \"${PLUGIN_ROOT}\u002Fscripts\u002Fcheck-version.js\"` — if it outputs a message, show it to the user before proceeding.\n\n# Add Cloud Flow\n\nConnect one or more Power Automate cloud flows to a Power Pages SPA site, or wire already-registered flows into additional pages\u002Fcomponents. For new flows this skill:\n- Creates the `adx_cloudflowconsumer` metadata YAML in `.powerpages-site\u002Fcloud-flow-consumer\u002F`\n- Assigns web roles based on the flow's scenario and target audience\n- Generates client-side TypeScript\u002FJavaScript service code to trigger the flow with CSRF authentication\n\nFor already-registered flows, the skill skips metadata and role creation and goes straight to client-side integration — wiring the existing flow into new UI locations.\n\n## Core Principles\n\n- **Multiple flows in one run**: The user can add several flows at once. All flows are planned together and implemented together before asking for deployment.\n- **Ask before acting**: Present a full HTML plan (all flows, roles, reasoning) before creating any files.\n- **Web roles drive access**: Every flow must have at least one web role. Anonymous Users role is valid but must be confirmed.\n- **Scenario determines roles**: Understand what each flow does and who triggers it before picking roles.\n- **Use TaskCreate\u002FTaskUpdate**: Track all phases upfront before starting any work.\n- **Preserve site integrity**: Before wiring a flow into a page or component, read `${PLUGIN_ROOT}\u002Freferences\u002Fsite-modification-integrity.md`; localize every new visible state when configured and keep the UI bidirectional and expansion-safe.\n\n> **Prerequisites:**\n> - An existing Power Pages SPA site with `.powerpages-site` deployed\n> - PAC CLI authenticated (`pac auth who` must succeed)\n> - Azure CLI authenticated (`az login --allow-no-subscriptions` works whether or not your account has an Azure subscription — Dataverse and Power Platform tokens are AAD-scoped)\n\n**Initial request:** $ARGUMENTS\n\n---\n\n## Workflow\n\n1. **Verify Prerequisites** — Locate the project, confirm `.powerpages-site` exists, inventory web roles and existing flows\n2. **List Available Flows** — Fetch flows from the Power Automate Flow RP API\n3. **Select Flows & Understand Scenarios** — User picks one or more flows; determine scenario and audience for each\n4. **Determine Web Roles** — Propose minimum roles per flow with reasoning\n5. **Review Plan** — Render HTML plan for all flows; get user approval\n6. **Create Metadata** — Write `.cloudflowconsumer.yml` for each flow; create missing web roles first\n7. **Client-Side Integration** — Generate typed service code to call each flow from the frontend\n8. **Verify & Summarize** — Validate all YAMLs, record skill usage, offer deployment\n\n---\n\n## Phase 1: Verify Prerequisites\n\n**Goal**: Locate the Power Pages project and confirm all prerequisites are met\n\n**Actions**:\n\n1. Create todo list with all 8 phases (see [Progress Tracking](#progress-tracking) table)\n\n### 1.1 Locate Project\n\nLook for `powerpages.config.json` in the current directory or immediate subdirectories.\n\n**If not found**: Tell the user to create a site first with `\u002Fcreate-site`.\n\n### 1.2 Read Config\n\nRead `powerpages.config.json` to get the `siteName` (used for display and plan rendering).\n\n### 1.3 Check `.powerpages-site` Exists\n\nLook for the `.powerpages-site` folder in the project root.\n\n**If not found**:\n\n\u003C!-- gate: add-cloud-flow:1.3.deploy-first | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:1.3.deploy-first):** `.powerpages-site` missing — cloud flow YAML lives inside it. Deploy first or stop.\n>\n> **Trigger:** Phase 1.3 found no `.powerpages-site` directory.\n> **Why we ask:** Cloud flow YAML written to a non-existent path will never deploy.\n> **Cancel leaves:** Nothing — no YAML files written.\n\nUse `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| `.powerpages-site` is required to add cloud flows. Would you like to deploy the site now? | Yes, deploy now (Required), Cancel |\n\n**If \"Yes, deploy now\"**: Invoke `\u002Fdeploy-site` first, then continue to Phase 2.\n**If \"Cancel\"**: Stop.\n\n### 1.4 Read Existing Web Roles\n\nRead all `.webrole.yml` files from `.powerpages-site\u002Fweb-roles\u002F` to inventory available roles. Note each role's `id`, `name`, `adx_anonymoususersrole`, and `adx_authenticatedusersrole`.\n\n### 1.5 Check Existing Cloud Flows\n\nCheck `.powerpages-site\u002Fcloud-flow-consumer\u002F` for existing `.cloudflowconsumer.yml` files. For each file, read:\n- `processid` — the flow's `workflowEntityId`\n- `name` — the flow's display name\n- `adx_CloudFlowConsumer_adx_webrole` — assigned web role UUIDs\n\nStore these as the **already-registered flows** list. These flows already have metadata and web roles configured but may need additional frontend integration on other pages or components.\n\n### 1.6 Detect Frontend Framework\n\nRead `package.json` to detect the framework (React, Vue, Angular, Astro). Note the framework and its conventions for Phase 7. See `${PLUGIN_ROOT}\u002Freferences\u002Fframework-conventions.md` for the detection mapping.\n\n**Output**: Project root, site name, framework, available web roles, already-registered flows (with processid, name, and web roles)\n\n---\n\n## Phase 2: List Available Flows\n\n**Goal**: Fetch all Power Automate cloud flows that have a PowerPages trigger\n\n**Actions**:\n\nRun the list-cloud-flows script (reads environment from `pac auth who` internally):\n\n```bash\nnode \"${PLUGIN_ROOT}\u002Fskills\u002Fadd-cloud-flow\u002Fscripts\u002Flist-cloud-flows.js\"\n```\n\nThis calls the **Power Automate Flow RP API** with the filter `properties\u002FdefinitionSummary\u002Ftriggers\u002Fany(t: t\u002Fkind eq 'powerpages')`. Results include:\n\n| Field | Source | Used for |\n|-------|--------|----------|\n| `id` | `properties.workflowEntityId` | `processid` in YAML; URL in client-side API call |\n| `flowRpName` | `flow.name` | Flow RP identifier |\n| `displayName` | `properties.displayName` | Shown to user; written as `name` in YAML |\n| `description` | `properties.description` | Shown to user |\n| `state` | `properties.state` | Shown to user (Active\u002FDraft) |\n\n**Separate into two lists**:\n- **Unregistered flows**: Flows whose `id` does NOT match any `processid` from Phase 1.5 — these need full setup (metadata + roles + client-side)\n- **Already-registered flows**: Flows whose `id` matches a `processid` from Phase 1.5 — these already have metadata and roles but can be integrated into additional pages\u002Fcomponents\n\n**Handle errors**:\n- Exit code 1 with auth message → prompt the user to run `az login --allow-no-subscriptions`\n- Zero flows from API (no flows with a PowerPages trigger exist at all) → tell the user that no Power Automate flows with a PowerPages trigger were found in this environment. Guide them to create a flow first:\n\n  > \"No Power Automate cloud flows with a PowerPages trigger were found in this environment. To use this skill, you first need to create a flow in [Power Automate](https:\u002F\u002Fmake.powerautomate.com) with the **\"When a Power Pages flow step is run\"** trigger, then run this skill again to connect it to your site.\"\n\n  **Stop the workflow** — do not continue to Phase 3.\n\n- Zero unregistered flows but already-registered flows exist → do **not** stop. Continue to Phase 3 with only the already-registered flows available (for additional frontend integration).\n\n**Output**: List of unregistered flows and list of already-registered flows\n\n---\n\n## Phase 3: Select Flows & Understand Scenarios\n\n**Goal**: Understand the user's intent, suggest the most relevant flows (including already-registered ones for additional integration), let the user confirm or adjust, and determine the scenario for each selected flow\n\n**Actions**:\n\n### 3.1 Analyze User Intent & Suggest Flows\n\nBefore showing the full list, analyze the user's initial request (`$ARGUMENTS`) against **both** the unregistered flows and the already-registered flows. Match the user's described need to specific flows using display name, description, and scenario inference.\n\nWhen matching intent, check already-registered flows first — the user may be asking to wire an existing flow into a new page or component, not register a new one.\n\n- **If the user described a specific need** (e.g., \"add automation for the contact form\", \"connect the email notification flow\"): Identify flows whose name or description closely match the request and present them as **recommended** picks, explaining why each is a good match. Also show the remaining flows as additional options in case the suggestion is wrong.\n\n  ```\n  Based on your request, I recommend:\n    ⭐ 1. Contact Form Submission — Sends an email when a contact form is submitted (Active)\n         → Matches your request to add automation for the contact form\n\n  Other available flows:\n    2. Support Ticket Handler — Creates a case record from user input (Active)\n    3. Newsletter Signup — Adds the user's email to a mailing list (Draft)\n  ```\n\n- **If the user's request is generic** (e.g., \"add a cloud flow\", \"connect some flows\"): Fall back to presenting the full list without recommendations.\n\n  ```\n  Available flows:\n    1. Contact Form Submission — Sends an email when a contact form is submitted (Active)\n    2. Support Ticket Handler — Creates a case record from user input (Active)\n    3. Newsletter Signup — Adds the user's email to a mailing list (Draft)\n  ```\n\nPresent both categories clearly when both exist:\n\n```\nNew flows (not yet registered):\n  1. Newsletter Signup — Adds the user's email to a mailing list (Active)\n\nAlready registered (available for additional frontend integration):\n  2. Contact Form Submission — Already connected, can be wired into more pages\n  3. Support Ticket Handler — Already connected, can be wired into more pages\n```\n\n\u003C!-- gate: add-cloud-flow:3.1.select-flows | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:3.1.select-flows):** Multi-select over discovered + already-registered flows. Drives the rest of Phases 4–7.\n>\n> **Trigger:** Phase 2 list-cloud-flows returned at least one flow.\n> **Why we ask:** Wrong flows get registered (new `.cloudflowconsumer.yml` files written) or wrong existing flows get re-wired into the frontend.\n> **Cancel leaves:** Nothing — no YAML or client code written yet.\n\nUse `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| Which flows would you like to add or integrate? You can select from both new and already-registered flows. | (list or multi-select of flow names, with recommended flows pre-highlighted if applicable) |\n\nIf more than 10 flows are available, ask the user to type names or numbers (comma-separated for multiple).\n\n### 3.2 Tag Selected Flows\n\nFor each selected flow, tag it based on its source:\n\n| Tag | Meaning | Phases to execute |\n|-----|---------|-------------------|\n| **`new`** | Unregistered flow — needs full setup | Phases 4 → 5 → 6 → 7 (metadata + roles + client-side) |\n| **`integration-only`** | Already registered — metadata and roles exist | Skip to Phase 7 (client-side integration only) |\n\n### 3.3 Determine Scenario Per Flow\n\nFor each selected flow, identify its scenario from the name and description:\n\n| Scenario type | Examples | Who triggers it |\n|--------------|----------|-----------------|\n| **Form submission** | Contact form, feedback, survey | Authenticated or anonymous visitors |\n| **User self-service** | Profile update, request, leave application | Authenticated users only |\n| **Admin action** | Bulk processing, content approval, data export | Admins \u002F specific roles only |\n| **Background \u002F system** | Scheduled sync, enrichment | Not triggered by portal users directly |\n\n\u003C!-- not-a-gate: per-flow scenario clarification — data-gathering for Phase 4 role assignment; no destructive action -->\n\nIf a flow's scenario is unclear, use `AskUserQuestion` per flow:\n\n| Question | Context |\n|----------|---------|\n| What does \"[flow name]\" do on your site? Who triggers it? | Needed for role assignment |\n\nFor **`integration-only`** flows, the scenario is still needed to guide where and how the flow is wired into the frontend (Phase 7).\n\n### 3.4 Determine Client-Side Function Name Per Flow\n\nFor each flow, derive a camelCase function name for the client-side service:\n- Strip special characters and connector words from the display name\n- Example: \"PowerPages -> Send an email notification (V3)\" → `sendEmailNotification`\n- Example: \"Contact Form Submission\" → `submitContactForm`\n\nFor **`integration-only`** flows, check whether a trigger function already exists in the codebase (from a previous run of this skill). If it does, reuse that function name — do not create a duplicate. Only create a new function if one doesn't exist yet.\n\n**Output**: Selected flows list, each with tag (`new` or `integration-only`), scenario, target audience, and client-side function name\n\n---\n\n## Phase 4: Determine Web Roles\n\n**Goal**: Propose the minimum set of web roles for each **`new`** flow based on its scenario\n\n> **Skip for `integration-only` flows** — these already have web roles assigned in their `.cloudflowconsumer.yml`. Do not re-propose or modify roles for them.\n\n**Actions**:\n\n### 4.1 Analyze Role Requirements Per Flow (New Flows Only)\n\n| Scenario | Recommended roles |\n|----------|-------------------|\n| Any visitor (including unauthenticated) | `Anonymous Users` (confirm — security implication) |\n| Only logged-in users | `Authenticated Users` |\n| Only specific groups | Custom role(s) matching the group |\n\n**Do NOT assign all roles by default.** Use the minimum set per flow. Different flows in the same batch can have different role sets.\n\n### 4.2 Match Against Existing Roles\n\nFor each proposed role across all flows, check whether it exists in `.powerpages-site\u002Fweb-roles\u002F`. Mark roles as **existing** or **proposed\u002Fnew**.\n\n### 4.3 Compose Per-Role Reasoning\n\nFor each role assigned to each flow, write one sentence explaining why:\n\n- `Authenticated Users` on a profile form: \"Only logged-in users can update their profile.\"\n- `Anonymous Users` on a contact form: \"Unauthenticated visitors must be able to submit a contact request.\"\n- `Blog Authors` on an email flow: \"Blog Authors are the primary actors who submit posts triggering this notification.\"\n\n### 4.4 Flag Anonymous Roles\n\nIf any flow has `Anonymous Users` assigned, note this — the HTML plan renders a warning banner and the confirm step must explicitly surface it.\n\n**Output**: Per-flow role sets with reasoning, list of roles that need creating\n\n---\n\n## Phase 5: Review Plan\n\n**Goal**: Render the HTML plan for all flows and get user approval before writing any files\n\n**Actions**:\n\n### 5.1 Build Plan Data\n\nAssemble the plan JSON (kept in memory — not written to disk). Include all selected flows in `CLOUD_FLOWS_DATA`, distinguishing `new` from `integration-only`:\n\n```json\n{\n  \"SITE_NAME\": \"\u003Csite name>\",\n  \"PLAN_TITLE\": \"Cloud Flow Integration Plan\",\n  \"SUMMARY\": \"\u003CN new flows + M integration-only flows, scenarios, key role assignments>\",\n  \"WEB_ROLES_DATA\": [\n    {\n      \"id\": \"\u003Cuuid or temp-id>\",\n      \"name\": \"\u003Crole name>\",\n      \"desc\": \"\u003Cdescription>\",\n      \"builtin\": false,\n      \"isNew\": true,\n      \"isAnonymous\": false,\n      \"color\": \"#0078d4\"\n    }\n  ],\n  \"CLOUD_FLOWS_DATA\": [\n    {\n      \"flowId\": \"\u003CworkflowEntityId>\",\n      \"name\": \"\u003Cflow display name>\",\n      \"displayName\": \"\u003Cflow display name>\",\n      \"description\": \"\u003Cflow description>\",\n      \"state\": \"Active\",\n      \"tag\": \"new | integration-only\",\n      \"scenario\": \"\u003Cscenario type>\",\n      \"rationale\": \"\u003Cwhy this flow is being added or where it will be additionally integrated>\",\n      \"webRoles\": [\n        { \"id\": \"\u003Crole-uuid>\", \"reasoning\": \"\u003Cwhy this role>\" }\n      ]\n    }\n  ],\n  \"RATIONALE_DATA\": [\n    { \"icon\": \"⚡\", \"title\": \"\u003Ctitle>\", \"desc\": \"\u003Creasoning>\" }\n  ]\n}\n```\n\nFor **`integration-only`** flows, `webRoles` should reflect the existing roles from the `.cloudflowconsumer.yml` (read-only — not being changed). The `rationale` should describe where the flow will be additionally integrated (e.g., \"Wiring existing Contact Form flow into the support page\").\n\n### 5.2 Render HTML Plan\n\n```bash\nnode \"${PLUGIN_ROOT}\u002Fscripts\u002Frender-cloudflow-plan.js\" \\\n  --output \"\u003CPROJECT_ROOT>\u002Fdocs\u002Fcloud-flow-plan.html\" \\\n  --data-inline '\u003Cjson>'\n```\n\nThe render script refuses to overwrite existing files. Before calling it, check if the default output path (`\u003CPROJECT_ROOT>\u002Fdocs\u002Fcloud-flow-plan.html`) already exists. If it does, choose a new descriptive filename based on context — e.g., `cloud-flow-plan-contact-form.html`, `cloud-flow-plan-apr-2026.html`. Pass the chosen name via `--output`.\n\nOpen the rendered file in the default browser (`open` on macOS, `start` on Windows, `xdg-open` on Linux).\n\n### 5.3 Confirm with User\n\nGive a brief CLI summary: number of flows, scenarios, role count, any anonymous-role warnings.\n\n\u003C!-- gate: add-cloud-flow:5.3.plan-approval | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:5.3.plan-approval):** Final sign-off on the rendered HTML plan before any web role \u002F `.cloudflowconsumer.yml` \u002F client code is written.\n>\n> **Trigger:** Phase 5.2 rendered the HTML plan.\n> **Why we ask:** Wrong web role assignments committed (especially Anonymous Users on auth-protected flows); orphaned YAML files in `.powerpages-site\u002Fcloud-flow-consumer\u002F`.\n> **Cancel leaves:** Nothing — no YAML or frontend changes yet.\n\nUse `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| Review the cloud flow plan in the browser. Does it look correct? | Approve and implement (Recommended), Request changes, Cancel |\n\n**If \"Request changes\"**: Ask what to change, update, re-render, and present again.\n**If \"Cancel\"**: Stop.\n\n**Output**: User-approved plan for all flows\n\n---\n\n## Phase 6: Create Metadata\n\n**Goal**: Create web roles (if any are new) then write a `.cloudflowconsumer.yml` for every **`new`** flow in the approved plan\n\n> **Skip for `integration-only` flows** — these already have `.cloudflowconsumer.yml` and web roles. Do not recreate or modify their metadata. They will be handled in Phase 7 (client-side integration only).\n\nIf the approved plan contains **only** `integration-only` flows (no `new` flows), skip this entire phase and proceed to Phase 7.\n\n**Actions**:\n\n### 6.1 Create Missing Web Roles\n\nIf the approved plan includes roles that do not yet exist (for `new` flows), invoke `\u002Fcreate-webroles` now.\n\nAfter it completes, re-read `.powerpages-site\u002Fweb-roles\u002F` to collect `id` values for all new roles.\n\n### 6.2 Process Each New Flow\n\nRepeat steps 6.3–6.4 for every **`new`** flow in the approved plan.\n\n### 6.3 Determine Flow API URL\n\n```\n\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>\n```\n\n### 6.4 Run the Create Metadata Script\n\n```bash\nnode \"${PLUGIN_ROOT}\u002Fskills\u002Fadd-cloud-flow\u002Fscripts\u002Fcreate-cloud-flow-metadata.js\" \\\n  --projectRoot \"\u003CPROJECT_ROOT>\" \\\n  --fileSlug \"\u003Curl-safe-slug>\" \\\n  --flowName \"\u003Cflow-display-name>\" \\\n  --flowId \"\u003CworkflowEntityId>\" \\\n  --flowTriggerUrl \"\" \\\n  --flowApiUrl \"\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>\" \\\n  --webRoleIds \"\u003Cuuid1>,\u003Cuuid2>\" \\\n  --metadata \"\u003Cflow-display-name>\"\n```\n\n`--fileSlug`: lowercase display name, special characters replaced with hyphens, max 50 chars.\n`--flowName`: display name written as-is into the `name` YAML field.\n\nThe generated YAML (PAC CLI SPA git format):\n- `adx_*` scalar prefix stripped: `adx_flowapiurl` → `flowapiurl`, `adx_processid` → `processid`\n- `adx_cloudflowconsumerid` → `id`; `adx_websiteid` omitted\n- M2M key `adx_CloudFlowConsumer_adx_webrole` kept as-is\n- `statecode`\u002F`statuscode` defaults omitted; empty strings written as `''`\n- Fields alphabetically sorted\n\n### 6.5 Git Commit\n\nAfter all YAML files (and any new web roles) are created, do a single git commit. Include the HTML plan file (use the actual output path from the render script's JSON response).\n\n**Output**: One `.cloudflowconsumer.yml` per `new` flow, committed (skipped for `integration-only` flows)\n\n---\n\n## Phase 7: Client-Side Integration\n\n**Goal**: Generate typed service code that calls each registered flow from the site's frontend\n\nCloud flows are invoked via an authenticated POST to `\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>`. The request must include a CSRF token fetched from `\u002F_layout\u002Ftokenhtml`, and the payload must be wrapped in an `eventData` key as a JSON-stringified string.\n\n**Actions**:\n\n### 7.1 Discover Existing Frontend Patterns\n\nUse the Explore agent to scan the site:\n\n> \"Check the Power Pages site frontend for existing patterns. Look for:\n> 1. Any existing API service files in `src\u002Fshared\u002F`, `src\u002Fservices\u002F`, `src\u002Fapi\u002F`, or similar\n> 2. Existing CSRF token handling (`__RequestVerificationToken`, `_layout\u002Ftokenhtml`)\n> 3. The framework (React \u002F Vue \u002F Angular \u002F Astro) and its conventions (hooks, composables, services)\n> 4. Any existing cloud flow calls (`\u002F_api\u002Fcloudflow\u002F`) already in the codebase — note which flows are already called and from which pages\u002Fcomponents\n> Report all findings.\"\n\nFor **`integration-only`** flows, the Explore agent's findings in point 4 are critical — they reveal where the flow is already wired in, so the new integration targets a different page\u002Fcomponent without duplicating existing call sites.\n\n### 7.2 Create or Update the Cloud Flow Service\n\n> **Do not use the site's existing OData fetch wrapper for cloud flow triggers.**\n>\n> If the site has a centralized API client (e.g. `powerPagesFetch`) that targets the Dataverse Web API, do not use it here. Cloud flow trigger URLs (`\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F...`) are a different endpoint that does not accept OData-specific request headers. Using an OData wrapper will cause the request to fail.\n>\n> Use direct `fetch` or an equivalent low-level HTTP client (for example, Angular's `HttpClient`) for cloud flow calls. Do not use any OData-specific wrappers or helpers that automatically add Dataverse Web API headers. You may reuse the site's existing CSRF token helper if one is exported — but perform the HTTP request via `fetch` or the chosen low-level client directly.\n\nBased on the framework and existing patterns:\n\n**If the site already has an API service layer**: add the new flow functions to it.\n**If no service layer exists**: create `src\u002Fservices\u002FcloudFlowService.{ts,js}` (or framework equivalent).\n\nFor **`integration-only`** flows: if a trigger function already exists in the service file, do **not** create a duplicate — reuse it. Only add a new trigger function if the flow has no existing function in the codebase.\n\n#### Service structure\n\n> **REQUIRED for every flow trigger call — without these headers the request returns a 500 error:**\n> - `__RequestVerificationToken`: CSRF token fetched from `\u002F_layout\u002Ftokenhtml`\n> - `X-Requested-With`: `XMLHttpRequest`\n\n> **The payload must be wrapped in `eventData` as a JSON-stringified string** — this is the shape the Power Pages cloud flow endpoint expects:\n> ```json\n> { \"eventData\": \"{\\\"Email\\\":\\\"abc@contoso.com\\\"}\" }\n> ```\n\nThe service file must contain a `getCsrfToken` helper and one trigger function per flow. If a `getCsrfToken` helper already exists in the codebase, reuse it; otherwise create it. Either way, every trigger function **must** call it and include both headers shown above.\n\n**CSRF helper** (reuse existing or create):\n\n```typescript\nasync function getCsrfToken(): Promise\u003Cstring> {\n  const res = await fetch('\u002F_layout\u002Ftokenhtml');\n  const html = await res.text();\n  const match = html.match(\u002Fvalue=\"([^\"]+)\"\u002F);\n  if (!match) throw new Error('CSRF token not found');\n  return match[1];\n}\n```\n\n**Per-flow trigger function** (one per registered flow):\n\n```typescript\n\u002F\u002F Trigger: \u003Cflow display name>\n\u002F\u002F API: \u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>\nexport async function \u003CcamelCaseFunctionName>(payload: Record\u003Cstring, unknown> = {}): Promise\u003Cunknown> {\n  const token = await getCsrfToken();\n  const response = await fetch('\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n      '__RequestVerificationToken': token,\n      'X-Requested-With': 'XMLHttpRequest',\n    },\n    body: JSON.stringify({ eventData: JSON.stringify(payload) }),\n  });\n  if (!response.ok) {\n    throw new Error(`Cloud flow trigger failed: ${response.status} ${response.statusText}`);\n  }\n  \u002F\u002F 202 Accepted = flow has no Response action (fire-and-forget); 200 OK = flow returns data\n  if (response.status === 202) return null;\n  return response.json();\n}\n```\n\n**Framework-specific patterns:**\n\n| Framework | Convention | Output |\n|-----------|-----------|--------|\n| React | Custom hook `useCloudFlow\u003CName>()` wrapping the service function with loading\u002Ferror state | `src\u002Fhooks\u002FuseCloudFlow.ts` |\n| Vue | Composable `useCloudFlow\u003CName>()` with `ref` for loading\u002Ferror | `src\u002Fcomposables\u002FuseCloudFlow.ts` |\n| Angular | Injectable `CloudFlowService` that wraps the same raw `fetch` trigger function shown above (do not switch to `HttpClient` unless you preserve the exact headers and `eventData` payload shape) | `src\u002Fapp\u002Fservices\u002Fcloud-flow.service.ts` |\n| Astro | Plain async utility functions (no framework wrapper needed) | `src\u002Futils\u002FcloudFlow.ts` |\n\nGroup all flow functions together in one file. Do not create a separate file per flow.\n\n### 7.3 Wire into UI\n\nRead the relevant pages\u002Fcomponents, add call sites, loading states, success\u002Ferror feedback. Replace any placeholder or mock handlers that are meant to be backed by the flows.\n\nFor **`integration-only`** flows, this is the primary deliverable of the entire skill run. Identify the **new** target page or component where the flow should be integrated (based on the user's request and the scenario from Phase 3.3), import the existing trigger function, and wire it in with proper loading\u002Ferror handling. Do **not** modify existing call sites that already work.\n\n### 7.4 Git Commit\n\nCommit service file and any UI changes.\n\n**Output**: `cloudFlowService.{ts,js}` (or equivalent) created\u002Fupdated, UI wired\n\n---\n\n## Phase 8: Verify & Summarize\n\n**Goal**: Validate all created YAMLs, record skill usage, present summary, offer deployment\n\n**Actions**:\n\n### 8.1 Validate Each YAML\n\n> **Skip for `integration-only` flows** — their YAML was not created or modified by this run. Only validate YAMLs for `new` flows.\n\nFor each created `.cloudflowconsumer.yml`, verify:\n\n- [ ] `id` is a valid UUID\n- [ ] `processid` matches the flow's `workflowEntityId`\n- [ ] `adx_CloudFlowConsumer_adx_webrole` is non-empty\n- [ ] All role UUIDs in the array correspond to existing `.webrole.yml` files\n- [ ] `name` equals the flow's display name\n- [ ] No `adx_`-prefixed scalar fields (no `adx_processid`, `adx_websiteid`, `adx_name`)\n- [ ] `statecode` and `statuscode` are absent\n\n### 8.1b Validate Client-Side Integration\n\nRead the service file created in Phase 7 and verify:\n\n- [ ] Service file exists at the expected path (e.g. `src\u002Fservices\u002FcloudFlowService.ts` or framework equivalent)\n- [ ] A `getCsrfToken` helper is present — either defined in the file or imported from another module\n- [ ] Every registered flow has a corresponding exported trigger function\n- [ ] Each trigger function calls `getCsrfToken()` and sets **both** required headers:\n  - `__RequestVerificationToken` set to the CSRF token value\n  - `X-Requested-With: XMLHttpRequest`\n- [ ] Each trigger function's fetch URL exactly matches `\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>` for the correct flow\n- [ ] The request body wraps the payload as `JSON.stringify({ eventData: JSON.stringify(payload) })` — not a bare `JSON.stringify(payload)`\n- [ ] No OData-specific wrapper (e.g. `powerPagesFetch`) is used — raw `fetch` only\n- [ ] At least one UI component or page imports and calls the trigger function(s)\n\nIf any check fails, fix the issue in the service file or UI before continuing.\n\n### 8.1c Final site-integrity gate\n\nAfter all cloud-flow UI integration and skill-specific verification are complete, run:\n\n```bash\nnode \"${PLUGIN_ROOT}\u002Fscripts\u002Fvalidate-site-integrity.js\" --projectRoot \"\u003CPROJECT_ROOT>\"\n```\n\nFix every blocking error before presenting completion or asking to deploy. Inspect and report\nreview findings in both directions and with expanded content. Rerun this gate after any later\nsource change.\n\n### 8.2 Record Skill Usage\n\n> Reference: `${PLUGIN_ROOT}\u002Freferences\u002Fskill-tracking-reference.md`\n\nUse `--skillName \"AddCloudFlow\"`.\n\n### 8.3 Present Summary\n\n| Step | Status | Details |\n|------|--------|---------|\n| New flows added | Done \u002F N\u002FA | List each `new` flow name (or \"N\u002FA\" if all were integration-only) |\n| Integration-only flows | Done \u002F N\u002FA | List each `integration-only` flow name and target page\u002Fcomponent |\n| Scenarios | Identified | One line per flow |\n| Web roles | Created\u002FExisting\u002FSkipped | List role names (skipped for integration-only) |\n| Metadata files | Created\u002FSkipped | List each `.cloudflowconsumer.yml` path (skipped for integration-only) |\n| Client service | Created\u002FUpdated | Path to service file |\n| UI integration | Done | Components\u002Fpages updated (new call sites for all flows) |\n| HTML Plan | Created | Actual path from render script output |\n\n### 8.4 Ask to Deploy\n\n\u003C!-- gate: add-cloud-flow:8.4.deploy | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:8.4.deploy):** Post-implementation deploy prompt — flows don't trigger until deployed.\n>\n> **Trigger:** All flow YAML + client integration in place.\n> **Why we ask:** Auto-deploy picks wrong env.\n> **Cancel leaves:** Nothing — artifacts stay on disk; no deploy fired.\n\nUse `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| Everything is ready. Deploy the site to make the flows live? | Yes, deploy now (Recommended), No, I'll deploy later |\n\n\u003C!-- gate: add-cloud-flow:8.4.test | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:8.4.test):** Post-deploy validation prompt — invokes `\u002Ftest-site` to confirm the flow trigger endpoint returns 202\u002F200.\n>\n> **Trigger:** Deploy from the previous gate succeeded.\n> **Why we ask:** Skipping is harmless (manual test still possible); auto-invoking `\u002Ftest-site` adds runtime and Playwright traffic.\n> **Cancel leaves:** Nothing — deploy has already completed.\n\n**If \"Yes\"**: Invoke `\u002Fdeploy-site`. After it succeeds, use `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| Would you like to run `\u002Ftest-site` to verify the cloud flow integration end-to-end? | Yes, run tests, No, I'll test manually |\n\n**If \"Yes, run tests\"**: Invoke `\u002Ftest-site` with context: test the scenario where the flow API is triggered — perform the action on the site (e.g. submit the form, click the button) that calls `\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>`, confirm the request returns 202 Accepted or 200 OK, and check Power Automate run history to confirm the flow executed.\n\n**If \"No\"**: Remind the user that flows and client-side calls won't work until deployed, and suggest running `\u002Ftest-site` later to validate the flow trigger works correctly in the deployed environment.\n\n### 8.5 Post-Deploy Notes\n\n- **Flow trigger URL**: Populated automatically by the portal runtime after deploy. Check Power Pages design studio to confirm.\n- **Testing**: Use `\u002Ftest-site` to verify the integration. Sign in as a user with the assigned role, trigger the flow action, confirm `\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003Cid>` returns 202\u002F200, and check Power Automate run history.\n- **Anonymous flows**: Test in an incognito window.\n- **Role changes**: Edit `adx_CloudFlowConsumer_adx_webrole` in the YAML, then redeploy.\n- **Adding more flows later**: Run this skill again — new flows are available for full setup, and already-registered flows are available for additional frontend integration on other pages.\n\n---\n\n## Important Notes\n\n### Throughout All Phases\n\n- **Multiple flows**: Process all flows in the approved plan before committing or moving to Phase 7\n- **Minimum roles**: Never assign all roles by default; use only what the scenario requires\n- **Anonymous Users**: Always surface explicitly in plan and confirm step\n- **Trigger URL blank at creation**: Expected — set by the portal runtime at deploy time\n- **fileSlug vs flowName**: `--fileSlug` is the filename only; `--flowName` is the `name` YAML field\n- **Client service file**: Group all flows into one service file, not one file per flow; always wire into the UI without asking\n- **CSRF headers are mandatory**: Every flow trigger function must call `getCsrfToken()` and send both `__RequestVerificationToken` and `X-Requested-With: XMLHttpRequest` — omitting either causes a 500 error\n- **Payload shape**: The request body must be `JSON.stringify({ eventData: JSON.stringify(payload) })` — the cloud flow endpoint expects the payload nested under an `eventData` key as a double-stringified JSON string\n- **Integration-only flows**: Already-registered flows skip Phases 4–6 (roles and metadata). Their primary deliverable is new frontend call sites in Phase 7. Do not modify existing `.cloudflowconsumer.yml` files or web role assignments for these flows. Reuse existing trigger functions when they already exist in the service file — only add new UI call sites.\n- **No flows available**: When no flows with a PowerPages trigger exist in the environment (zero results from API), stop the workflow and direct the user to create a flow in Power Automate with the \"When a Power Pages flow step is run\" trigger first.\n\n### Key Decision Points (Wait for User)\n\n1. Phase 1.3: Deploy now or cancel (if `.powerpages-site` missing)\n2. Phase 3.1: Which flows to add or integrate (new and\u002For already-registered)\n3. Phase 3.3: Clarify scenario \u002F audience per flow (if unclear)\n4. Phase 5.3: Approve HTML plan before writing any files\n5. Phase 8.4: Deploy now or later\n\n### Progress Tracking\n\nBefore starting Phase 1, create a task list with all phases using `TaskCreate`:\n\n| Task subject | activeForm | Description |\n|-------------|------------|-------------|\n| Verify prerequisites | Verifying prerequisites | Locate project, confirm .powerpages-site, read web roles and existing flows, detect framework |\n| List available flows | Fetching cloud flows | Call Flow RP API to get flows with PowerPages trigger |\n| Select flows and understand scenarios | Gathering scenario details | User picks one or more flows; determine scenario and function names |\n| Determine web roles | Analyzing role requirements | Propose minimum roles per flow with per-role reasoning |\n| Review plan | Reviewing plan with user | Render HTML plan for all flows and get approval |\n| Create metadata | Writing cloud flow metadata | Create missing web roles then write YAML for each flow |\n| Client-side integration | Generating client-side code | Create typed service functions and wire into UI |\n| Verify and summarize | Validating and summarizing | Validate YAMLs, record skill usage, present summary, offer deployment |\n\nMark each task `in_progress` when starting and `completed` when done via `TaskUpdate`.\n\n---\n\n**Begin with Phase 1: Verify Prerequisites**\n","> **Plugin check**: Run `node \"${PLUGIN_ROOT}\u002Fscripts\u002Fcheck-version.js\"` — if it outputs a message, show it to the user before proceeding.\n\n# Add Cloud Flow\n\nConnect one or more Power Automate cloud flows to a Power Pages SPA site, or wire already-registered flows into additional pages\u002Fcomponents. For new flows this skill:\n- Creates the `adx_cloudflowconsumer` metadata YAML in `.powerpages-site\u002Fcloud-flow-consumer\u002F`\n- Assigns web roles based on the flow's scenario and target audience\n- Generates client-side TypeScript\u002FJavaScript service code to trigger the flow with CSRF authentication\n\nFor already-registered flows, the skill skips metadata and role creation and goes straight to client-side integration — wiring the existing flow into new UI locations.\n\n## Core Principles\n\n- **Multiple flows in one run**: The user can add several flows at once. All flows are planned together and implemented together before asking for deployment.\n- **Ask before acting**: Present a full HTML plan (all flows, roles, reasoning) before creating any files.\n- **Web roles drive access**: Every flow must have at least one web role. Anonymous Users role is valid but must be confirmed.\n- **Scenario determines roles**: Understand what each flow does and who triggers it before picking roles.\n- **Use TaskCreate\u002FTaskUpdate**: Track all phases upfront before starting any work.\n- **Preserve site integrity**: Before wiring a flow into a page or component, read `${PLUGIN_ROOT}\u002Freferences\u002Fsite-modification-integrity.md`; localize every new visible state when configured and keep the UI bidirectional and expansion-safe.\n\n> **Prerequisites:**\n> - An existing Power Pages SPA site with `.powerpages-site` deployed\n> - PAC CLI authenticated (`pac auth who` must succeed)\n> - Azure CLI authenticated (`az login --allow-no-subscriptions` works whether or not your account has an Azure subscription — Dataverse and Power Platform tokens are AAD-scoped)\n\n**Initial request:** $ARGUMENTS\n\n---\n\n## Workflow\n\n1. **Verify Prerequisites** — Locate the project, confirm `.powerpages-site` exists, inventory web roles and existing flows\n2. **List Available Flows** — Fetch flows from the Power Automate Flow RP API\n3. **Select Flows & Understand Scenarios** — User picks one or more flows; determine scenario and audience for each\n4. **Determine Web Roles** — Propose minimum roles per flow with reasoning\n5. **Review Plan** — Render HTML plan for all flows; get user approval\n6. **Create Metadata** — Write `.cloudflowconsumer.yml` for each flow; create missing web roles first\n7. **Client-Side Integration** — Generate typed service code to call each flow from the frontend\n8. **Verify & Summarize** — Validate all YAMLs, record skill usage, offer deployment\n\n---\n\n## Phase 1: Verify Prerequisites\n\n**Goal**: Locate the Power Pages project and confirm all prerequisites are met\n\n**Actions**:\n\n1. Create todo list with all 8 phases (see [Progress Tracking](#progress-tracking) table)\n\n### 1.1 Locate Project\n\nLook for `powerpages.config.json` in the current directory or immediate subdirectories.\n\n**If not found**: Tell the user to create a site first with `\u002Fcreate-site`.\n\n### 1.2 Read Config\n\nRead `powerpages.config.json` to get the `siteName` (used for display and plan rendering).\n\n### 1.3 Check `.powerpages-site` Exists\n\nLook for the `.powerpages-site` folder in the project root.\n\n**If not found**:\n\n\u003C!-- gate: add-cloud-flow:1.3.deploy-first | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:1.3.deploy-first):** `.powerpages-site` missing — cloud flow YAML lives inside it. Deploy first or stop.\n>\n> **Trigger:** Phase 1.3 found no `.powerpages-site` directory.\n> **Why we ask:** Cloud flow YAML written to a non-existent path will never deploy.\n> **Cancel leaves:** Nothing — no YAML files written.\n\nUse `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| `.powerpages-site` is required to add cloud flows. Would you like to deploy the site now? | Yes, deploy now (Required), Cancel |\n\n**If \"Yes, deploy now\"**: Invoke `\u002Fdeploy-site` first, then continue to Phase 2.\n**If \"Cancel\"**: Stop.\n\n### 1.4 Read Existing Web Roles\n\nRead all `.webrole.yml` files from `.powerpages-site\u002Fweb-roles\u002F` to inventory available roles. Note each role's `id`, `name`, `adx_anonymoususersrole`, and `adx_authenticatedusersrole`.\n\n### 1.5 Check Existing Cloud Flows\n\nCheck `.powerpages-site\u002Fcloud-flow-consumer\u002F` for existing `.cloudflowconsumer.yml` files. For each file, read:\n- `processid` — the flow's `workflowEntityId`\n- `name` — the flow's display name\n- `adx_CloudFlowConsumer_adx_webrole` — assigned web role UUIDs\n\nStore these as the **already-registered flows** list. These flows already have metadata and web roles configured but may need additional frontend integration on other pages or components.\n\n### 1.6 Detect Frontend Framework\n\nRead `package.json` to detect the framework (React, Vue, Angular, Astro). Note the framework and its conventions for Phase 7. See `${PLUGIN_ROOT}\u002Freferences\u002Fframework-conventions.md` for the detection mapping.\n\n**Output**: Project root, site name, framework, available web roles, already-registered flows (with processid, name, and web roles)\n\n---\n\n## Phase 2: List Available Flows\n\n**Goal**: Fetch all Power Automate cloud flows that have a PowerPages trigger\n\n**Actions**:\n\nRun the list-cloud-flows script (reads environment from `pac auth who` internally):\n\n```bash\nnode \"${PLUGIN_ROOT}\u002Fskills\u002Fadd-cloud-flow\u002Fscripts\u002Flist-cloud-flows.js\"\n```\n\nThis calls the **Power Automate Flow RP API** with the filter `properties\u002FdefinitionSummary\u002Ftriggers\u002Fany(t: t\u002Fkind eq 'powerpages')`. Results include:\n\n| Field | Source | Used for |\n|-------|--------|----------|\n| `id` | `properties.workflowEntityId` | `processid` in YAML; URL in client-side API call |\n| `flowRpName` | `flow.name` | Flow RP identifier |\n| `displayName` | `properties.displayName` | Shown to user; written as `name` in YAML |\n| `description` | `properties.description` | Shown to user |\n| `state` | `properties.state` | Shown to user (Active\u002FDraft) |\n\n**Separate into two lists**:\n- **Unregistered flows**: Flows whose `id` does NOT match any `processid` from Phase 1.5 — these need full setup (metadata + roles + client-side)\n- **Already-registered flows**: Flows whose `id` matches a `processid` from Phase 1.5 — these already have metadata and roles but can be integrated into additional pages\u002Fcomponents\n\n**Handle errors**:\n- Exit code 1 with auth message → prompt the user to run `az login --allow-no-subscriptions`\n- Zero flows from API (no flows with a PowerPages trigger exist at all) → tell the user that no Power Automate flows with a PowerPages trigger were found in this environment. Guide them to create a flow first:\n\n  > \"No Power Automate cloud flows with a PowerPages trigger were found in this environment. To use this skill, you first need to create a flow in [Power Automate](https:\u002F\u002Fmake.powerautomate.com) with the **\"When a Power Pages flow step is run\"** trigger, then run this skill again to connect it to your site.\"\n\n  **Stop the workflow** — do not continue to Phase 3.\n\n- Zero unregistered flows but already-registered flows exist → do **not** stop. Continue to Phase 3 with only the already-registered flows available (for additional frontend integration).\n\n**Output**: List of unregistered flows and list of already-registered flows\n\n---\n\n## Phase 3: Select Flows & Understand Scenarios\n\n**Goal**: Understand the user's intent, suggest the most relevant flows (including already-registered ones for additional integration), let the user confirm or adjust, and determine the scenario for each selected flow\n\n**Actions**:\n\n### 3.1 Analyze User Intent & Suggest Flows\n\nBefore showing the full list, analyze the user's initial request (`$ARGUMENTS`) against **both** the unregistered flows and the already-registered flows. Match the user's described need to specific flows using display name, description, and scenario inference.\n\nWhen matching intent, check already-registered flows first — the user may be asking to wire an existing flow into a new page or component, not register a new one.\n\n- **If the user described a specific need** (e.g., \"add automation for the contact form\", \"connect the email notification flow\"): Identify flows whose name or description closely match the request and present them as **recommended** picks, explaining why each is a good match. Also show the remaining flows as additional options in case the suggestion is wrong.\n\n  ```\n  Based on your request, I recommend:\n    ⭐ 1. Contact Form Submission — Sends an email when a contact form is submitted (Active)\n         → Matches your request to add automation for the contact form\n\n  Other available flows:\n    2. Support Ticket Handler — Creates a case record from user input (Active)\n    3. Newsletter Signup — Adds the user's email to a mailing list (Draft)\n  ```\n\n- **If the user's request is generic** (e.g., \"add a cloud flow\", \"connect some flows\"): Fall back to presenting the full list without recommendations.\n\n  ```\n  Available flows:\n    1. Contact Form Submission — Sends an email when a contact form is submitted (Active)\n    2. Support Ticket Handler — Creates a case record from user input (Active)\n    3. Newsletter Signup — Adds the user's email to a mailing list (Draft)\n  ```\n\nPresent both categories clearly when both exist:\n\n```\nNew flows (not yet registered):\n  1. Newsletter Signup — Adds the user's email to a mailing list (Active)\n\nAlready registered (available for additional frontend integration):\n  2. Contact Form Submission — Already connected, can be wired into more pages\n  3. Support Ticket Handler — Already connected, can be wired into more pages\n```\n\n\u003C!-- gate: add-cloud-flow:3.1.select-flows | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:3.1.select-flows):** Multi-select over discovered + already-registered flows. Drives the rest of Phases 4–7.\n>\n> **Trigger:** Phase 2 list-cloud-flows returned at least one flow.\n> **Why we ask:** Wrong flows get registered (new `.cloudflowconsumer.yml` files written) or wrong existing flows get re-wired into the frontend.\n> **Cancel leaves:** Nothing — no YAML or client code written yet.\n\nUse `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| Which flows would you like to add or integrate? You can select from both new and already-registered flows. | (list or multi-select of flow names, with recommended flows pre-highlighted if applicable) |\n\nIf more than 10 flows are available, ask the user to type names or numbers (comma-separated for multiple).\n\n### 3.2 Tag Selected Flows\n\nFor each selected flow, tag it based on its source:\n\n| Tag | Meaning | Phases to execute |\n|-----|---------|-------------------|\n| **`new`** | Unregistered flow — needs full setup | Phases 4 → 5 → 6 → 7 (metadata + roles + client-side) |\n| **`integration-only`** | Already registered — metadata and roles exist | Skip to Phase 7 (client-side integration only) |\n\n### 3.3 Determine Scenario Per Flow\n\nFor each selected flow, identify its scenario from the name and description:\n\n| Scenario type | Examples | Who triggers it |\n|--------------|----------|-----------------|\n| **Form submission** | Contact form, feedback, survey | Authenticated or anonymous visitors |\n| **User self-service** | Profile update, request, leave application | Authenticated users only |\n| **Admin action** | Bulk processing, content approval, data export | Admins \u002F specific roles only |\n| **Background \u002F system** | Scheduled sync, enrichment | Not triggered by portal users directly |\n\n\u003C!-- not-a-gate: per-flow scenario clarification — data-gathering for Phase 4 role assignment; no destructive action -->\n\nIf a flow's scenario is unclear, use `AskUserQuestion` per flow:\n\n| Question | Context |\n|----------|---------|\n| What does \"[flow name]\" do on your site? Who triggers it? | Needed for role assignment |\n\nFor **`integration-only`** flows, the scenario is still needed to guide where and how the flow is wired into the frontend (Phase 7).\n\n### 3.4 Determine Client-Side Function Name Per Flow\n\nFor each flow, derive a camelCase function name for the client-side service:\n- Strip special characters and connector words from the display name\n- Example: \"PowerPages -> Send an email notification (V3)\" → `sendEmailNotification`\n- Example: \"Contact Form Submission\" → `submitContactForm`\n\nFor **`integration-only`** flows, check whether a trigger function already exists in the codebase (from a previous run of this skill). If it does, reuse that function name — do not create a duplicate. Only create a new function if one doesn't exist yet.\n\n**Output**: Selected flows list, each with tag (`new` or `integration-only`), scenario, target audience, and client-side function name\n\n---\n\n## Phase 4: Determine Web Roles\n\n**Goal**: Propose the minimum set of web roles for each **`new`** flow based on its scenario\n\n> **Skip for `integration-only` flows** — these already have web roles assigned in their `.cloudflowconsumer.yml`. Do not re-propose or modify roles for them.\n\n**Actions**:\n\n### 4.1 Analyze Role Requirements Per Flow (New Flows Only)\n\n| Scenario | Recommended roles |\n|----------|-------------------|\n| Any visitor (including unauthenticated) | `Anonymous Users` (confirm — security implication) |\n| Only logged-in users | `Authenticated Users` |\n| Only specific groups | Custom role(s) matching the group |\n\n**Do NOT assign all roles by default.** Use the minimum set per flow. Different flows in the same batch can have different role sets.\n\n### 4.2 Match Against Existing Roles\n\nFor each proposed role across all flows, check whether it exists in `.powerpages-site\u002Fweb-roles\u002F`. Mark roles as **existing** or **proposed\u002Fnew**.\n\n### 4.3 Compose Per-Role Reasoning\n\nFor each role assigned to each flow, write one sentence explaining why:\n\n- `Authenticated Users` on a profile form: \"Only logged-in users can update their profile.\"\n- `Anonymous Users` on a contact form: \"Unauthenticated visitors must be able to submit a contact request.\"\n- `Blog Authors` on an email flow: \"Blog Authors are the primary actors who submit posts triggering this notification.\"\n\n### 4.4 Flag Anonymous Roles\n\nIf any flow has `Anonymous Users` assigned, note this — the HTML plan renders a warning banner and the confirm step must explicitly surface it.\n\n**Output**: Per-flow role sets with reasoning, list of roles that need creating\n\n---\n\n## Phase 5: Review Plan\n\n**Goal**: Render the HTML plan for all flows and get user approval before writing any files\n\n**Actions**:\n\n### 5.1 Build Plan Data\n\nAssemble the plan JSON (kept in memory — not written to disk). Include all selected flows in `CLOUD_FLOWS_DATA`, distinguishing `new` from `integration-only`:\n\n```json\n{\n  \"SITE_NAME\": \"\u003Csite name>\",\n  \"PLAN_TITLE\": \"Cloud Flow Integration Plan\",\n  \"SUMMARY\": \"\u003CN new flows + M integration-only flows, scenarios, key role assignments>\",\n  \"WEB_ROLES_DATA\": [\n    {\n      \"id\": \"\u003Cuuid or temp-id>\",\n      \"name\": \"\u003Crole name>\",\n      \"desc\": \"\u003Cdescription>\",\n      \"builtin\": false,\n      \"isNew\": true,\n      \"isAnonymous\": false,\n      \"color\": \"#0078d4\"\n    }\n  ],\n  \"CLOUD_FLOWS_DATA\": [\n    {\n      \"flowId\": \"\u003CworkflowEntityId>\",\n      \"name\": \"\u003Cflow display name>\",\n      \"displayName\": \"\u003Cflow display name>\",\n      \"description\": \"\u003Cflow description>\",\n      \"state\": \"Active\",\n      \"tag\": \"new | integration-only\",\n      \"scenario\": \"\u003Cscenario type>\",\n      \"rationale\": \"\u003Cwhy this flow is being added or where it will be additionally integrated>\",\n      \"webRoles\": [\n        { \"id\": \"\u003Crole-uuid>\", \"reasoning\": \"\u003Cwhy this role>\" }\n      ]\n    }\n  ],\n  \"RATIONALE_DATA\": [\n    { \"icon\": \"⚡\", \"title\": \"\u003Ctitle>\", \"desc\": \"\u003Creasoning>\" }\n  ]\n}\n```\n\nFor **`integration-only`** flows, `webRoles` should reflect the existing roles from the `.cloudflowconsumer.yml` (read-only — not being changed). The `rationale` should describe where the flow will be additionally integrated (e.g., \"Wiring existing Contact Form flow into the support page\").\n\n### 5.2 Render HTML Plan\n\n```bash\nnode \"${PLUGIN_ROOT}\u002Fscripts\u002Frender-cloudflow-plan.js\" \\\n  --output \"\u003CPROJECT_ROOT>\u002Fdocs\u002Fcloud-flow-plan.html\" \\\n  --data-inline '\u003Cjson>'\n```\n\nThe render script refuses to overwrite existing files. Before calling it, check if the default output path (`\u003CPROJECT_ROOT>\u002Fdocs\u002Fcloud-flow-plan.html`) already exists. If it does, choose a new descriptive filename based on context — e.g., `cloud-flow-plan-contact-form.html`, `cloud-flow-plan-apr-2026.html`. Pass the chosen name via `--output`.\n\nOpen the rendered file in the default browser (`open` on macOS, `start` on Windows, `xdg-open` on Linux).\n\n### 5.3 Confirm with User\n\nGive a brief CLI summary: number of flows, scenarios, role count, any anonymous-role warnings.\n\n\u003C!-- gate: add-cloud-flow:5.3.plan-approval | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:5.3.plan-approval):** Final sign-off on the rendered HTML plan before any web role \u002F `.cloudflowconsumer.yml` \u002F client code is written.\n>\n> **Trigger:** Phase 5.2 rendered the HTML plan.\n> **Why we ask:** Wrong web role assignments committed (especially Anonymous Users on auth-protected flows); orphaned YAML files in `.powerpages-site\u002Fcloud-flow-consumer\u002F`.\n> **Cancel leaves:** Nothing — no YAML or frontend changes yet.\n\nUse `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| Review the cloud flow plan in the browser. Does it look correct? | Approve and implement (Recommended), Request changes, Cancel |\n\n**If \"Request changes\"**: Ask what to change, update, re-render, and present again.\n**If \"Cancel\"**: Stop.\n\n**Output**: User-approved plan for all flows\n\n---\n\n## Phase 6: Create Metadata\n\n**Goal**: Create web roles (if any are new) then write a `.cloudflowconsumer.yml` for every **`new`** flow in the approved plan\n\n> **Skip for `integration-only` flows** — these already have `.cloudflowconsumer.yml` and web roles. Do not recreate or modify their metadata. They will be handled in Phase 7 (client-side integration only).\n\nIf the approved plan contains **only** `integration-only` flows (no `new` flows), skip this entire phase and proceed to Phase 7.\n\n**Actions**:\n\n### 6.1 Create Missing Web Roles\n\nIf the approved plan includes roles that do not yet exist (for `new` flows), invoke `\u002Fcreate-webroles` now.\n\nAfter it completes, re-read `.powerpages-site\u002Fweb-roles\u002F` to collect `id` values for all new roles.\n\n### 6.2 Process Each New Flow\n\nRepeat steps 6.3–6.4 for every **`new`** flow in the approved plan.\n\n### 6.3 Determine Flow API URL\n\n```\n\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>\n```\n\n### 6.4 Run the Create Metadata Script\n\n```bash\nnode \"${PLUGIN_ROOT}\u002Fskills\u002Fadd-cloud-flow\u002Fscripts\u002Fcreate-cloud-flow-metadata.js\" \\\n  --projectRoot \"\u003CPROJECT_ROOT>\" \\\n  --fileSlug \"\u003Curl-safe-slug>\" \\\n  --flowName \"\u003Cflow-display-name>\" \\\n  --flowId \"\u003CworkflowEntityId>\" \\\n  --flowTriggerUrl \"\" \\\n  --flowApiUrl \"\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>\" \\\n  --webRoleIds \"\u003Cuuid1>,\u003Cuuid2>\" \\\n  --metadata \"\u003Cflow-display-name>\"\n```\n\n`--fileSlug`: lowercase display name, special characters replaced with hyphens, max 50 chars.\n`--flowName`: display name written as-is into the `name` YAML field.\n\nThe generated YAML (PAC CLI SPA git format):\n- `adx_*` scalar prefix stripped: `adx_flowapiurl` → `flowapiurl`, `adx_processid` → `processid`\n- `adx_cloudflowconsumerid` → `id`; `adx_websiteid` omitted\n- M2M key `adx_CloudFlowConsumer_adx_webrole` kept as-is\n- `statecode`\u002F`statuscode` defaults omitted; empty strings written as `''`\n- Fields alphabetically sorted\n\n### 6.5 Git Commit\n\nAfter all YAML files (and any new web roles) are created, do a single git commit. Include the HTML plan file (use the actual output path from the render script's JSON response).\n\n**Output**: One `.cloudflowconsumer.yml` per `new` flow, committed (skipped for `integration-only` flows)\n\n---\n\n## Phase 7: Client-Side Integration\n\n**Goal**: Generate typed service code that calls each registered flow from the site's frontend\n\nCloud flows are invoked via an authenticated POST to `\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>`. The request must include a CSRF token fetched from `\u002F_layout\u002Ftokenhtml`, and the payload must be wrapped in an `eventData` key as a JSON-stringified string.\n\n**Actions**:\n\n### 7.1 Discover Existing Frontend Patterns\n\nUse the Explore agent to scan the site:\n\n> \"Check the Power Pages site frontend for existing patterns. Look for:\n> 1. Any existing API service files in `src\u002Fshared\u002F`, `src\u002Fservices\u002F`, `src\u002Fapi\u002F`, or similar\n> 2. Existing CSRF token handling (`__RequestVerificationToken`, `_layout\u002Ftokenhtml`)\n> 3. The framework (React \u002F Vue \u002F Angular \u002F Astro) and its conventions (hooks, composables, services)\n> 4. Any existing cloud flow calls (`\u002F_api\u002Fcloudflow\u002F`) already in the codebase — note which flows are already called and from which pages\u002Fcomponents\n> Report all findings.\"\n\nFor **`integration-only`** flows, the Explore agent's findings in point 4 are critical — they reveal where the flow is already wired in, so the new integration targets a different page\u002Fcomponent without duplicating existing call sites.\n\n### 7.2 Create or Update the Cloud Flow Service\n\n> **Do not use the site's existing OData fetch wrapper for cloud flow triggers.**\n>\n> If the site has a centralized API client (e.g. `powerPagesFetch`) that targets the Dataverse Web API, do not use it here. Cloud flow trigger URLs (`\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F...`) are a different endpoint that does not accept OData-specific request headers. Using an OData wrapper will cause the request to fail.\n>\n> Use direct `fetch` or an equivalent low-level HTTP client (for example, Angular's `HttpClient`) for cloud flow calls. Do not use any OData-specific wrappers or helpers that automatically add Dataverse Web API headers. You may reuse the site's existing CSRF token helper if one is exported — but perform the HTTP request via `fetch` or the chosen low-level client directly.\n\nBased on the framework and existing patterns:\n\n**If the site already has an API service layer**: add the new flow functions to it.\n**If no service layer exists**: create `src\u002Fservices\u002FcloudFlowService.{ts,js}` (or framework equivalent).\n\nFor **`integration-only`** flows: if a trigger function already exists in the service file, do **not** create a duplicate — reuse it. Only add a new trigger function if the flow has no existing function in the codebase.\n\n#### Service structure\n\n> **REQUIRED for every flow trigger call — without these headers the request returns a 500 error:**\n> - `__RequestVerificationToken`: CSRF token fetched from `\u002F_layout\u002Ftokenhtml`\n> - `X-Requested-With`: `XMLHttpRequest`\n\n> **The payload must be wrapped in `eventData` as a JSON-stringified string** — this is the shape the Power Pages cloud flow endpoint expects:\n> ```json\n> { \"eventData\": \"{\\\"Email\\\":\\\"abc@contoso.com\\\"}\" }\n> ```\n\nThe service file must contain a `getCsrfToken` helper and one trigger function per flow. If a `getCsrfToken` helper already exists in the codebase, reuse it; otherwise create it. Either way, every trigger function **must** call it and include both headers shown above.\n\n**CSRF helper** (reuse existing or create):\n\n```typescript\nasync function getCsrfToken(): Promise\u003Cstring> {\n  const res = await fetch('\u002F_layout\u002Ftokenhtml');\n  const html = await res.text();\n  const match = html.match(\u002Fvalue=\"([^\"]+)\"\u002F);\n  if (!match) throw new Error('CSRF token not found');\n  return match[1];\n}\n```\n\n**Per-flow trigger function** (one per registered flow):\n\n```typescript\n\u002F\u002F Trigger: \u003Cflow display name>\n\u002F\u002F API: \u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>\nexport async function \u003CcamelCaseFunctionName>(payload: Record\u003Cstring, unknown> = {}): Promise\u003Cunknown> {\n  const token = await getCsrfToken();\n  const response = await fetch('\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n      '__RequestVerificationToken': token,\n      'X-Requested-With': 'XMLHttpRequest',\n    },\n    body: JSON.stringify({ eventData: JSON.stringify(payload) }),\n  });\n  if (!response.ok) {\n    throw new Error(`Cloud flow trigger failed: ${response.status} ${response.statusText}`);\n  }\n  \u002F\u002F 202 Accepted = flow has no Response action (fire-and-forget); 200 OK = flow returns data\n  if (response.status === 202) return null;\n  return response.json();\n}\n```\n\n**Framework-specific patterns:**\n\n| Framework | Convention | Output |\n|-----------|-----------|--------|\n| React | Custom hook `useCloudFlow\u003CName>()` wrapping the service function with loading\u002Ferror state | `src\u002Fhooks\u002FuseCloudFlow.ts` |\n| Vue | Composable `useCloudFlow\u003CName>()` with `ref` for loading\u002Ferror | `src\u002Fcomposables\u002FuseCloudFlow.ts` |\n| Angular | Injectable `CloudFlowService` that wraps the same raw `fetch` trigger function shown above (do not switch to `HttpClient` unless you preserve the exact headers and `eventData` payload shape) | `src\u002Fapp\u002Fservices\u002Fcloud-flow.service.ts` |\n| Astro | Plain async utility functions (no framework wrapper needed) | `src\u002Futils\u002FcloudFlow.ts` |\n\nGroup all flow functions together in one file. Do not create a separate file per flow.\n\n### 7.3 Wire into UI\n\nRead the relevant pages\u002Fcomponents, add call sites, loading states, success\u002Ferror feedback. Replace any placeholder or mock handlers that are meant to be backed by the flows.\n\nFor **`integration-only`** flows, this is the primary deliverable of the entire skill run. Identify the **new** target page or component where the flow should be integrated (based on the user's request and the scenario from Phase 3.3), import the existing trigger function, and wire it in with proper loading\u002Ferror handling. Do **not** modify existing call sites that already work.\n\n### 7.4 Git Commit\n\nCommit service file and any UI changes.\n\n**Output**: `cloudFlowService.{ts,js}` (or equivalent) created\u002Fupdated, UI wired\n\n---\n\n## Phase 8: Verify & Summarize\n\n**Goal**: Validate all created YAMLs, record skill usage, present summary, offer deployment\n\n**Actions**:\n\n### 8.1 Validate Each YAML\n\n> **Skip for `integration-only` flows** — their YAML was not created or modified by this run. Only validate YAMLs for `new` flows.\n\nFor each created `.cloudflowconsumer.yml`, verify:\n\n- [ ] `id` is a valid UUID\n- [ ] `processid` matches the flow's `workflowEntityId`\n- [ ] `adx_CloudFlowConsumer_adx_webrole` is non-empty\n- [ ] All role UUIDs in the array correspond to existing `.webrole.yml` files\n- [ ] `name` equals the flow's display name\n- [ ] No `adx_`-prefixed scalar fields (no `adx_processid`, `adx_websiteid`, `adx_name`)\n- [ ] `statecode` and `statuscode` are absent\n\n### 8.1b Validate Client-Side Integration\n\nRead the service file created in Phase 7 and verify:\n\n- [ ] Service file exists at the expected path (e.g. `src\u002Fservices\u002FcloudFlowService.ts` or framework equivalent)\n- [ ] A `getCsrfToken` helper is present — either defined in the file or imported from another module\n- [ ] Every registered flow has a corresponding exported trigger function\n- [ ] Each trigger function calls `getCsrfToken()` and sets **both** required headers:\n  - `__RequestVerificationToken` set to the CSRF token value\n  - `X-Requested-With: XMLHttpRequest`\n- [ ] Each trigger function's fetch URL exactly matches `\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>` for the correct flow\n- [ ] The request body wraps the payload as `JSON.stringify({ eventData: JSON.stringify(payload) })` — not a bare `JSON.stringify(payload)`\n- [ ] No OData-specific wrapper (e.g. `powerPagesFetch`) is used — raw `fetch` only\n- [ ] At least one UI component or page imports and calls the trigger function(s)\n\nIf any check fails, fix the issue in the service file or UI before continuing.\n\n### 8.1c Final site-integrity gate\n\nAfter all cloud-flow UI integration and skill-specific verification are complete, run:\n\n```bash\nnode \"${PLUGIN_ROOT}\u002Fscripts\u002Fvalidate-site-integrity.js\" --projectRoot \"\u003CPROJECT_ROOT>\"\n```\n\nFix every blocking error before presenting completion or asking to deploy. Inspect and report\nreview findings in both directions and with expanded content. Rerun this gate after any later\nsource change.\n\n### 8.2 Record Skill Usage\n\n> Reference: `${PLUGIN_ROOT}\u002Freferences\u002Fskill-tracking-reference.md`\n\nUse `--skillName \"AddCloudFlow\"`.\n\n### 8.3 Present Summary\n\n| Step | Status | Details |\n|------|--------|---------|\n| New flows added | Done \u002F N\u002FA | List each `new` flow name (or \"N\u002FA\" if all were integration-only) |\n| Integration-only flows | Done \u002F N\u002FA | List each `integration-only` flow name and target page\u002Fcomponent |\n| Scenarios | Identified | One line per flow |\n| Web roles | Created\u002FExisting\u002FSkipped | List role names (skipped for integration-only) |\n| Metadata files | Created\u002FSkipped | List each `.cloudflowconsumer.yml` path (skipped for integration-only) |\n| Client service | Created\u002FUpdated | Path to service file |\n| UI integration | Done | Components\u002Fpages updated (new call sites for all flows) |\n| HTML Plan | Created | Actual path from render script output |\n\n### 8.4 Ask to Deploy\n\n\u003C!-- gate: add-cloud-flow:8.4.deploy | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:8.4.deploy):** Post-implementation deploy prompt — flows don't trigger until deployed.\n>\n> **Trigger:** All flow YAML + client integration in place.\n> **Why we ask:** Auto-deploy picks wrong env.\n> **Cancel leaves:** Nothing — artifacts stay on disk; no deploy fired.\n\nUse `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| Everything is ready. Deploy the site to make the flows live? | Yes, deploy now (Recommended), No, I'll deploy later |\n\n\u003C!-- gate: add-cloud-flow:8.4.test | category=plan | cancel-leaves=nothing -->\n\n> ? **Gate (plan · add-cloud-flow:8.4.test):** Post-deploy validation prompt — invokes `\u002Ftest-site` to confirm the flow trigger endpoint returns 202\u002F200.\n>\n> **Trigger:** Deploy from the previous gate succeeded.\n> **Why we ask:** Skipping is harmless (manual test still possible); auto-invoking `\u002Ftest-site` adds runtime and Playwright traffic.\n> **Cancel leaves:** Nothing — deploy has already completed.\n\n**If \"Yes\"**: Invoke `\u002Fdeploy-site`. After it succeeds, use `AskUserQuestion`:\n\n| Question | Options |\n|----------|---------|\n| Would you like to run `\u002Ftest-site` to verify the cloud flow integration end-to-end? | Yes, run tests, No, I'll test manually |\n\n**If \"Yes, run tests\"**: Invoke `\u002Ftest-site` with context: test the scenario where the flow API is triggered — perform the action on the site (e.g. submit the form, click the button) that calls `\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003CworkflowEntityId>`, confirm the request returns 202 Accepted or 200 OK, and check Power Automate run history to confirm the flow executed.\n\n**If \"No\"**: Remind the user that flows and client-side calls won't work until deployed, and suggest running `\u002Ftest-site` later to validate the flow trigger works correctly in the deployed environment.\n\n### 8.5 Post-Deploy Notes\n\n- **Flow trigger URL**: Populated automatically by the portal runtime after deploy. Check Power Pages design studio to confirm.\n- **Testing**: Use `\u002Ftest-site` to verify the integration. Sign in as a user with the assigned role, trigger the flow action, confirm `\u002F_api\u002Fcloudflow\u002Fv1.0\u002Ftrigger\u002F\u003Cid>` returns 202\u002F200, and check Power Automate run history.\n- **Anonymous flows**: Test in an incognito window.\n- **Role changes**: Edit `adx_CloudFlowConsumer_adx_webrole` in the YAML, then redeploy.\n- **Adding more flows later**: Run this skill again — new flows are available for full setup, and already-registered flows are available for additional frontend integration on other pages.\n\n---\n\n## Important Notes\n\n### Throughout All Phases\n\n- **Multiple flows**: Process all flows in the approved plan before committing or moving to Phase 7\n- **Minimum roles**: Never assign all roles by default; use only what the scenario requires\n- **Anonymous Users**: Always surface explicitly in plan and confirm step\n- **Trigger URL blank at creation**: Expected — set by the portal runtime at deploy time\n- **fileSlug vs flowName**: `--fileSlug` is the filename only; `--flowName` is the `name` YAML field\n- **Client service file**: Group all flows into one service file, not one file per flow; always wire into the UI without asking\n- **CSRF headers are mandatory**: Every flow trigger function must call `getCsrfToken()` and send both `__RequestVerificationToken` and `X-Requested-With: XMLHttpRequest` — omitting either causes a 500 error\n- **Payload shape**: The request body must be `JSON.stringify({ eventData: JSON.stringify(payload) })` — the cloud flow endpoint expects the payload nested under an `eventData` key as a double-stringified JSON string\n- **Integration-only flows**: Already-registered flows skip Phases 4–6 (roles and metadata). Their primary deliverable is new frontend call sites in Phase 7. Do not modify existing `.cloudflowconsumer.yml` files or web role assignments for these flows. Reuse existing trigger functions when they already exist in the service file — only add new UI call sites.\n- **No flows available**: When no flows with a PowerPages trigger exist in the environment (zero results from API), stop the workflow and direct the user to create a flow in Power Automate with the \"When a Power Pages flow step is run\" trigger first.\n\n### Key Decision Points (Wait for User)\n\n1. Phase 1.3: Deploy now or cancel (if `.powerpages-site` missing)\n2. Phase 3.1: Which flows to add or integrate (new and\u002For already-registered)\n3. Phase 3.3: Clarify scenario \u002F audience per flow (if unclear)\n4. Phase 5.3: Approve HTML plan before writing any files\n5. Phase 8.4: Deploy now or later\n\n### Progress Tracking\n\nBefore starting Phase 1, create a task list with all phases using `TaskCreate`:\n\n| Task subject | activeForm | Description |\n|-------------|------------|-------------|\n| Verify prerequisites | Verifying prerequisites | Locate project, confirm .powerpages-site, read web roles and existing flows, detect framework |\n| List available flows | Fetching cloud flows | Call Flow RP API to get flows with PowerPages trigger |\n| Select flows and understand scenarios | Gathering scenario details | User picks one or more flows; determine scenario and function names |\n| Determine web roles | Analyzing role requirements | Propose minimum roles per flow with per-role reasoning |\n| Review plan | Reviewing plan with user | Render HTML plan for all flows and get approval |\n| Create metadata | Writing cloud flow metadata | Create missing web roles then write YAML for each flow |\n| Client-side integration | Generating client-side code | Create typed service functions and wire into UI |\n| Verify and summarize | Validating and summarizing | Validate YAMLs, record skill usage, present summary, offer deployment |\n\nMark each task `in_progress` when starting and `completed` when done via `TaskUpdate`.\n\n---\n\n**Begin with Phase 1: Verify Prerequisites**\n",{"name":5,"model":32,"description":7,"allowed-tools":53,"user-invocable":54},"Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion, Skill, Task, TaskCreate, TaskUpdate, TaskList",true,"main","0a55a88fa2855404029d1e5450faf92878baf763","plugins\u002Fpower-pages\u002Fskills\u002Fadd-cloud-flow",230,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills","https:\u002F\u002Fmicrosoft.github.io\u002Fpower-platform-skills\u002F","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-11-14 02:26:14",{"source":8,"skillName":5,"commands":66,"prompt":76,"zipAvailable":54},[67,70,73],{"tool":68,"command":69},"npx","npx skills add microsoft\u002Fpower-platform-skills --skill add-cloud-flow",{"tool":71,"command":72},"bunx","bunx skills add microsoft\u002Fpower-platform-skills --skill add-cloud-flow",{"tool":74,"command":75},"pnpm","pnpm dlx skills add microsoft\u002Fpower-platform-skills --skill add-cloud-flow","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpower-pages\u002Fskills\u002Fadd-cloud-flow\u002FSKILL.md",[78,84,90,94],{"path":79,"resourceType":80,"resourceTypeDesc":81,"sizeBytes":82,"sourceHtmlUrl":83},"assets\u002Fcloud-flow-plan.html","ASSET","资产文件",17127,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpower-pages\u002Fskills\u002Fadd-cloud-flow\u002Fassets\u002Fcloud-flow-plan.html",{"path":85,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":88,"sourceHtmlUrl":89},"scripts\u002Fcreate-cloud-flow-metadata.js","SCRIPT","脚本",5166,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpower-pages\u002Fskills\u002Fadd-cloud-flow\u002Fscripts\u002Fcreate-cloud-flow-metadata.js",{"path":91,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":92,"sourceHtmlUrl":93},"scripts\u002Flist-cloud-flows.js",4893,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpower-pages\u002Fskills\u002Fadd-cloud-flow\u002Fscripts\u002Flist-cloud-flows.js",{"path":95,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":96,"sourceHtmlUrl":97},"scripts\u002Fvalidate-cloudflow.js",4488,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpower-pages\u002Fskills\u002Fadd-cloud-flow\u002Fscripts\u002Fvalidate-cloudflow.js",[99,118,141,159,173,183],{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":105,"publishedAt":48},"01M699WVHX0XN59EPBTTPEKYPG","setup","Use when Process Intelligence needs building, explicit cloud\u002Faccount\u002Fenvironment configuration, sign-in, connection diagnostics, or recovery from an authentication error.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Fsetup\u002FSKILL.md",[],[101,45,106,107,108,109,110,111,42,112,113,114,115,28,116,117],"when","connection","error","sign","intelligence","configuration","process","diagnostics","environment","authentication","recovery","Bash",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":129,"publishedAt":48},"01M699WSR9EX55YY1WD9J22FEG","report-issue","Use when the user wants a Process Intelligence bug-report draft or support summary for a failed operation.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Freport-issue\u002FSKILL.md",[124],{"categoryNo":125,"categoryName":126,"taxonomyType":127,"taxonomyTypeDesc":128},"01JBSEEDCAT000000000000034","行政与办公人员","PROFESSION","适用职业",[130,131,132,133,134,112,42,135,136,110,137,138,139,106,140],"report issue","report","issue","support","user","bug","summary","draft","operation","for","bug-report",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":147,"publishedAt":48},"01M699WR26YQ9Q21KE6MJF5B2G","investigate-process","Use when a broad Process Mining business question, observed pattern or competing explanation needs investigation across analytical perspectives.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Finvestigate-process\u002FSKILL.md",[],[112,148,149,150,106,151,152,153,154,45,155,42,156,157,158],"investigate","investigate process","mining","process mining","investigation","perspectives","question","business","pattern","across","analytical",{"skillNo":160,"name":161,"nameZh":6,"description":162,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":163,"categories":164,"keywords":165,"publishedAt":48},"01M699WP9SDG5ZR12P8VYNXKTN","derive-metric","Use when a requested measure is missing, a saved custom metric needs reuse, or an ephemeral formula or derived scalar is needed.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Fderive-metric\u002FSKILL.md",[],[166,167,45,42,168,169,170,171,172,106],"metric","derive metric","formula","missing","reuse","saved","custom",{"skillNo":174,"name":175,"nameZh":6,"description":176,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":177,"categories":178,"keywords":179,"publishedAt":48},"01M699WMG5R8P6SMTDAS1TKF9E","compare-cohorts","Use when comparing process cohorts, departments, periods or before-and-after results under matched definitions.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Fcompare-cohorts\u002FSKILL.md",[],[180,181,106,42,112,182,45],"compare","compare cohorts","results",{"skillNo":184,"name":185,"nameZh":6,"description":186,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":187,"categories":188,"keywords":189,"publishedAt":48},"01M699WJWNVTMP9XK3NCJHV14D","analyze-variants","Use when investigating common or slow variants, repeated work, unusual paths, or a specific Process Mining case.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-platform-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fprocess-intelligence\u002Fskills\u002Fanalyze-variants\u002FSKILL.md",[],[190,191,192,151,106,150,193,194,42,112,45,195,196],"analyze","variants","analyze variants","case","paths","work","common"]