Activates and provisions a Power Pages website in a Power Platform environment via the Power Platform REST API. Use when the user wants to activate, provision, turn on, or enable a Power Pages website or portal.
日本語の概要は準備中です。原文の説明を表示しています。
Use when the user wants to seed Dataverse tables with realistic sample records so a freshly-scaffolded code app shows real-looking data on first launch. Generates contextually appropriate rows from each table's schema and inserts them in dependency order. Mirrors microsoft/power-platform-skills/power-pages/add-sample-data, adapted for mobile apps.
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
Plugin check: Run
node "${PLUGIN_ROOT}/scripts/check-version.js"- if it outputs a message, show it to the user before proceeding.
📋 Shared instructions: shared-instructions.md — read first.
App root: before any project read or command, execute
app-working-directory.md.
Use its resolved absolute working_dir for every shell call and file tool,
including media paths and retries; never inherit a prior cd.
Populate Dataverse tables with realistic sample records so a freshly-scaffolded code app shows real-looking data on first launch. Generates rows from each table's schema and inserts them in dependency order. Use after /add-dataverse (or /setup-datamodel) has created the tables.
cr3e9_sitename column in an inspection app gets "Westside Construction Site", not "Sample Name 1".native-app-plan.md when present, especially ### Shared Conventions and per-screen Operational pattern values defined in screen-templates.md; otherwise use the current data request and verified schema. Seed rows should exercise the app's actual workflow: statuses, dates, relationships, priority/severity, media metadata, and edge cases that make the planned first viewport light up.memory-bank.md's seeded-data table and skips records already inserted.--solution <uniqueName> so records land in our solution, not the default.Inputs are skill arguments, not flags for dataverse-request.js:
--working-dir <absolute-root>: inherit the caller's root; reject conflicting
explicit/inherited roots. Never default to shell cwd in a nested invocation.--tables <comma-separated-logical-names>: the exact approved seed-table
allowlist. Required for every orchestrated call, including fresh creation.--exclude-tables <comma-separated-logical-names>: retiring table names from
the approved edit; omit or pass an explicit empty string only when none retire.For an orchestrated call, require the scoped handoff and matching --tables
before auth, record-count queries, or generation. A missing or malformed
allowlist returns NEEDS_CONTEXT; never fall back to all manifest tables.
An explicitly empty allowlist is a no-op: report no approved seed tables and
return without cloud calls or writes.
Validate logical names against the manifest and the approved plan/caller scope.
Build retiringTables from the caller's retirement set plus any pending removals
recorded in the current plan/history; include these in --exclude-tables.
If an allowlisted name is absent/unverified or overlaps retiringTables, stop
before insertion and return the scope mismatch. Do not silently drop unknown
names or infer permission from a transitional manifest entry.
For a standalone request, honor explicit --tables and exclusions. If no table
list was supplied, discover candidates in Step 2 and ask the user to approve the
specific table set/counts before Step 5, then freeze that selection as seedTables.
For this standalone discovery path, validate against verified metadata when the
local manifest is absent; never treat the discovery result itself as approval.
Pending retirement always excludes a
candidate; if that state is unclear, ask rather than treating the manifest as
approval. Read-only fallback discovery is not permission to seed the environment.
Keep a fixed seedTables allowlist throughout the invocation. All later
selection, batches, media jobs, and resume operations must remain within it.
Do not edit .datamodel-manifest.json or the app plan to make an excluded table
eligible. Expanding scope requires returning to the owning approval gate.
For --plan-only or a planning-phase handoff, use the supplied proposed table
scope for read-only checks and return the proposed counts, dependency needs, and
media policy before Step 5. Planning approval is not insertion approval.
Do not generate media files, insert/update/upload records, or change the app
plan, manifest, or seeded-data history on this path.
--from-seed is used by /prototype-to-real-app after a mock prototype is converted to Dataverse. In this mode, prefer existing prototype seed files before generating new rows:
src/generated/services/*/*.seed.json
src/generated/services/*.seed.json
Map only seedTables objects to Dataverse payloads using .datamodel-manifest.json;
prototype seed files cannot widen the approved set:
<schemaName>@odata.bind keys from the manifest.If a seed file cannot be mapped safely, fall back to generated contextual sample rows for that table and record DONE_WITH_CONCERNS in the summary. --from-seed is a preference, not permission to insert malformed data.
Run app-local commands from the resolved working_dir in each shell call.
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
if [ ! -f power.config.json ] || [ ! -f app.config.js ]; then
echo "BLOCKED: working_dir is not an initialized app" >&2
exit 1
fi
environment_id="$(node -p "require('./power.config.json').environmentId || ''")" || exit 1
if [ -z "$environment_id" ]; then
printf '%s\n' 'ERROR: selected app has no environmentId' >&2
exit 1
fi
node "${PLUGIN_ROOT}/scripts/resolve-environment.js" "$environment_id" --no-cache --require-tenant
Capture the environment URL, environment ID, and tenant ID for
subsequent script calls; require a match with the selected app and any supplied
owner context. Incomplete or conflicting identity returns NEEDS_CONTEXT after
bounded read-only recovery. Do not remove the safety flags, select another
environment, or persist resolver output to recover.
Bind every subsequent Dataverse read, batch, PATCH, media upload, token refresh,
and retry to that exact environment URL and tenant ID. For each
dataverse-request.js invocation, pass
--tenant-id '<tenantId-from-resolve-environment>' explicitly; substitute the
validated Step 1 value again in every fresh shell call. Do not depend on a
previous shell export, challenge discovery, or the active Azure CLI tenant.
Missing or conflicting tenant context returns NEEDS_CONTEXT before the call.
Verify Azure CLI auth (the script needs an Azure CLI token):
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
az account show --query "user.name" -o tsv
If empty, instruct az login and stop.
Telemetry checkpoint: discover_dataverse_tables
.datamodel-manifest.json (preferred)cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
test -f .datamodel-manifest.json
If present, parse the JSON. It contains logicalName, displayName, status
(new / extended / reused), and columns for the verified app inventory.
This is the preferred path -- fast, no API calls. For scoped calls, take only
the validated seedTables entries before any per-table metadata/count query.
For standalone discovery, exclude retiring tables from the candidate list.
Keep unrelated manifest entries as inventory only; do not pass them to the record-count, generation, or insertion loops.
Skip Step 2b.
If .datamodel-manifest.json is missing in an orchestrated call, return BLOCKED
to the owner for verified inventory recovery; do not broaden discovery or invent
schema facts. For a standalone request with an explicit allowlist, fetch metadata
only for those logical names. The following broad discovery is for a standalone
request without a table list, to propose candidates for approval:
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET \
"EntityDefinitions?\$select=LogicalName,DisplayName,EntitySetName&\$filter=IsCustomEntity eq true" \
--tenant-id '<tenantId-from-resolve-environment>'
For each candidate that the project uses (or each explicitly scoped table), fetch its custom columns:
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET \
"EntityDefinitions(LogicalName='<table>')/Attributes?\$select=LogicalName,DisplayName,AttributeType,RequiredLevel&\$filter=IsCustomAttribute eq true" \
--tenant-id '<tenantId-from-resolve-environment>'
Build the same { logicalName, displayName, columns: [...] } shape the manifest provides.
Evaluate only the validated seed allowlist, including reused tables only when
they are explicitly in that set. For standalone discovery, use only the proposed
non-retiring candidates and obtain the selection approval before insertion.
Never seed standard system tables (e.g. contact, account, systemuser)
without the additional explicit shared-environment confirmation below.
Pre-seeding row-count check (HARD — runs for every table before generating any rows):
For each scoped table, query its current record count using the verified entity
set name from the manifest, or fetch that name from metadata as in Step 5a.
Never derive it by appending s to a logical name.
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET \
"<entitySetName>?\$top=5&\$select=<primaryKeyColumn>" \
--tenant-id '<tenantId-from-resolve-environment>'
Count the rows returned in the value array.
| Existing record count | Action |
|---|---|
| ≥5 | Skip this table entirely. Log: ↷ <table> (≥5 records exist, skipping). Do not generate or insert any rows. |
| <5 | Seed enough new rows to reach the per-class target count. If some records already exist (e.g. 2), generate only the gap (e.g. 3 more to reach 5). |
If all eligible selected tables already have ≥5 records, report that nothing in the approved seed scope needs seeding and stop.
Per-table count by class (classify each table from manifest signals before generating; this beats a uniform 5 because reference tables don't need volume and transactional tables need state spread):
| Class | Heuristic | Default count | Rationale |
|---|---|---|---|
| Reference | No status / state column; columns are descriptive (name, address, phone). Often Tier 0. | 3 | Stores, customers, sites, products. Small stable set. |
| Junction | Two-or-more lookups, no other meaningful columns. Often Tier 1. | 3 × parent count, capped at 9 | Store-Assignment, Project-User. Needs to span the join. |
| Transactional | Has a status / state / phase choice column AND a date column (createdon, submittedat, completedat). | 5 | Audits, inspections, orders, tickets. Need state mix to make tiles light up. |
| Detail / line-item | Lookup back to a transactional parent, no own state column. | 2-3 per parent | Audit zones, order line items, inspection findings. |
| Issue / finding | Lookup back to a transactional parent + has status (Open / Resolved) AND severity (Critical / Moderate / Minor). | 3-4 per transactional parent | Issues, defects, observations. Mix severities + statuses (see Step 4a). |
| Evidence / attachment | Has a File / Image column + lookup to issue/inspection. | 1 per ~30% of parents | Photo evidence, document uploads. Seed metadata rows by default; seed file/image bytes only when brand/media-policy.md or the user's request says sample media is needed. |
| Log / event / audit-trail | Append-only with eventtype enum + timestamp + actor lookup. | 2 per transactional parent | Audit log events, activity stream. Mix at least 2 event types per parent. |
| Override / approval | Lookup to transactional parent + status (Pending / Approved / Rejected). | 1 per ~20% of parents | Override requests, approval queue. At least 1 row in Pending so queue tab shows content. |
Counts are intentionally minimal. Goal: every screen has SOMETHING to render, not a demo dataset.
Print a one-line summary and continue:
→ Seeding <total> records into <N> tables (coverage-first; counts auto-tuned per class).
For the selected tables, build a dependency graph from lookup columns:
If a selected table references an UNSELECTED parent, reuse a verified existing
parent record through a bounded read when that lookup is within the approved
feature. Reading a lookup parent is not permission to insert/update it. If no
suitable record exists, return NEEDS_CONTEXT to the owner (or ask standalone)
to extend the seed scope or explicitly omit an optional lookup. Never auto-add
a parent to seedTables, create a retiring parent, or omit a required lookup.
Retiring lookup targets block that dependent seed until the plan is reconciled.
Telemetry checkpoint: generate_and_review_sample_records
For each selected table, generate N rows. Match values to column names + types:
| Column type | Generation approach |
|---|---|
| String | Match the column name's semantic. *name, *title → realistic names from the requirements brief context. *email → firstname.lastname@example.com. *phone → (555) 123-NNNN. *address → realistic street + city. Otherwise: short context-appropriate text. |
| Memo (multi-line text) | 1-3 sentences relevant to the column name (e.g. *notes, *description). |
| Integer / Decimal / Currency | Reasonable range based on column name. *amount, *price → realistic dollars. *count, *quantity → small integers (1-100). |
| DateTime / DateOnly | Recent ISO dates spanning past 30 days to next 14 days. Vary across rows. |
| Boolean | Mix true/false (~70/30 favoring true for is_active style names). |
| Choice (Picklist) | Query options first (Step 4b), then pick from valid integer values. |
| MultiSelect Choice | Pick 1-3 valid values per row from the option set. |
| Lookup | Reference a verified existing parent or one inserted within the approved seed scope. Track live parent GUIDs; never seed an unapproved parent just to satisfy a child. |
| Image / File | Default: skip — leave null. If media seeding is enabled and the column is business data (product image, inspection evidence, NC proof), use generated/synthetic local files from assets/sample-* and record provenance. Never upload decorative UI hero assets to Dataverse. |
Media seeding policy (business data only, only if needed):
imageurl, photourl). Do not put CDN URLs into File/Image columns.assets/images/asset-manifest.json or assets/sample-media/asset-manifest.json with file, purpose, source/license, and safety notes.Media volume limits (HARD):
/add-sample-data run without explicit user approval.How sample images are inserted:
BATCH-RECORDS result, then upload the generated file to (recordId, columnName) in Step 5d.sample media skipped — upload helper missing. Never fake File/Image data with a URL string.Pull context from the requirements brief. The user described what the app does (e.g. "HVAC inspection app for field technicians"); use that to flavor the data — sites named after streets typical for the user's industry, statuses in the right vocabulary. Generic Lorem Ipsum is the failure mode.
Per-parent fanout floor (HARD). For every child table in Tier K+, generate AT LEAST 1 row per parent row from Tier K-1 unless the relationship is explicitly optional (RequiredLevel: None in the manifest AND the column name doesn't imply 1-to-many like *audit*, *inspection*, *order*). Without this floor, random lookup distribution leaves some parents with zero children and the parent's detail screen renders empty. Concrete rule: if generating audit_zones and there are 5 audits, generate AT LEAST 5 zones (one per audit), then add 0-2 more per audit until you hit the per-class count target. Never the reverse — never generate N total and let chance decide which parent each row picks.
State / status distribution (HARD for transactional, issue, override classes). If a table has a status / state / phase / severity / priority choice column, distribute rows across at least 2 distinct values — never all-Open, never all-InProgress. Concrete rules:
audit, inspection, order): mix at least 3 lifecycle states from the option set if available — typically 1 row in an early state (Draft / InProgress), 1 in a mid state (Submitted / PendingReview), and the rest in a terminal state (Signed / Completed / Closed). If only 2 states exist, split ~60/40.Open AND ≥1 Resolved.Pending) so the queue/inbox tab shows content; remainder distributed across Approved / Rejected.eventtype values per parent (e.g. Created + StatusChanged).Date distribution (transactional / log only). If the table has a createdon / submittedat / completedat / eventtimestamp column, spread rows across today + last 14 days (not all today, not all 30 days ago). Distribution: ~30% today/yesterday (drives "Recent activity" tiles), ~50% last 7 days, ~20% 8-14 days. Reference and detail tables can use any reasonable date — only transactional/log need temporal spread.
Scenario archetype edge coverage (HARD when detectable). Use the selected Power Apps scenario archetype to ensure at least one row exercises each critical state the app UI promises:
For every choice column in the selected tables, query its option set before generating rows:
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET \
"EntityDefinitions(LogicalName='<table>')/Attributes(LogicalName='<column>')/Microsoft.Dynamics.CRM.PicklistAttributeMetadata?\$expand=OptionSet" \
--tenant-id '<tenantId-from-resolve-environment>'
Use the actual Value integers from the response. Don't hardcode 100000000-style values — they vary per environment.
For each table, show a markdown table previewing the rows directly in the conversation:
### Job Site (cr3e9_jobsite) — 5 records
| Site Name | Address | Square Feet | Active |
|---|---|---|---|
| Westside Construction Site | 4521 Industrial Pkwy | 12500 | true |
| Downtown Office Building | 188 Main St | 3200 | true |
| Eastgate Warehouse | 9047 Logistics Way | 28000 | false |
| Riverside Retail Plaza | 320 River Rd | 6800 | true |
| North Hills Distribution | 1612 Highland Ave | 18900 | true |
For tables with lookups, also show which parent record each child references:
cr3e9_inspection rows reference cr3e9_jobsite records by SiteName above.
For --plan-only or a planning-phase handoff, return the preview and STOP here;
neither an earlier approval nor a populated manifest overrides that boundary.
Proceed without another prompt only when the exact seed tables/count policy and any media writes are already approved in the current scoped handoff or explicit standalone request. Otherwise obtain explicit approval of the preview first. Row counts prevent duplicate volume; they are not consent. Cancellation stops. If dependencies or rows require a wider scope, return to the owner rather than approving the expansion inside an orchestrated leaf.
Telemetry checkpoint: insert_sample_records
Print before starting:
"→ Inserting <total> records across <N> tables in dependency-tier order (parallel within each tier, cap 5 concurrent)…"
Insert in the tier order from Step 3c. Within a tier, parallelize across both tables and rows via the script's BATCH-RECORDS mode — single Node process, Promise.all with concurrency cap of 5. Across tiers stays sequential (children need parent GUIDs from prior tier's responses).
⚠️ Parallelism applies ONLY to record inserts. Schema operations (table / column / relationship creation) MUST stay sequential — see
/add-dataverseStep 5 concurrency rule. Records have no metadata lock; metadata writes do. Mixing them up returns 429 /MetadataLockHeldException.
For each table, get its EntitySetName (the URL-path name, usually plural — e.g. cr3e9_jobsites). Read from .datamodel-manifest.json if it carries this; otherwise:
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET \
"EntityDefinitions(LogicalName='<table>')?\$select=EntitySetName" \
--tenant-id '<tenantId-from-resolve-environment>'
Cache the result.
⚠️ Resolve EntitySetName for BOTH sides of every lookup. You need the entity set name not only for the table you're inserting into (the
entitySetfield in BATCH-RECORDS), but also for every lookup target referenced in@odata.bindvalues (Step 5c). Entity set names are independent of logical names — Dataverse pluralises irregularly and version suffixes pass through verbatim. Examples that bite:cr3e9_inspectionv3→cr3e9_inspectionv3s(NOTcr3e9_inspections);cr3e9_inquiry→cr3e9_inquiries;cr3e9_status→cr3e9_statuses. Never construct the path as<logicalName>s— always read it from EntityDefinitions.
For each tier from 0 → N:
Before constructing or submitting a batch, re-check every target logical name
against seedTables and retiringTables. Resolve its exact entity set, and
reject the entire proposed batch if any insert/update targets an unapproved or
retiring table. Apply the same guard before media PATCH/upload and every retry;
an out-of-scope operation is a scope error, not a record failure to continue past.
Build the operations array. Collect every (entitySet, body) pair across all tables in this tier. Tag each with a unique index you'll use to map results back to your row identity.
[
{ "index": 0, "entitySet": "cr3e9_jobsites", "body": { "cr3e9_sitename": "Westside Construction Site", "cr3e9_address": "4521 Industrial Pkwy", "cr3e9_squarefeet": 12500, "cr3e9_active": true } },
{ "index": 1, "entitySet": "cr3e9_jobsites", "body": { "cr3e9_sitename": "Downtown Office Building", "cr3e9_address": "188 Main St", "cr3e9_squarefeet": 3200, "cr3e9_active": true } },
{ "index": 2, "entitySet": "cr3e9_inspectors", "body": { "cr3e9_fullname": "Jane Smith", "cr3e9_email": "jane.smith@example.com" } }
// ... all rows for tables in this tier
]
Maintain a side-map { index → { table, rowSemantic } } so you can correlate results back to your tracking.
Fire BATCH-RECORDS once per tier. The script handles concurrency, retry, GUID extraction, and adaptive throttling internally:
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> BATCH-RECORDS \
"Tier <N>" \
--operations '<json-from-step-1>' \
--concurrency 5 \
--solution '<solution-uniquename-from-memory-bank>' \
--tenant-id '<tenantId-from-resolve-environment>'
Output is { "status": 200, "data": [{ "index": 0, "status": 204, "recordId": "<guid>" }, ...] }. Results are ordered by input index (stable across parallel execution).
Capture parent GUIDs. For every successful row in the response, store recordId indexed by your row identity. Tier N+1's @odata.bind values come from this map.
Print one line per inserted record (iterate the response array in input-index order so output reads sequentially):
→ ✓ <table>: <primary-name-value> (<guid>)
Handle failures. If any operation in the tier returned non-2xx or error, skip child rows whose parent failed but continue to the next tier with the rows that DID succeed. Rationale: aborting Tier 1 leaves Tiers 2+ empty, defeating the coverage contract. Document each skipped child and tier knock-on in the Step 6 summary.
For Tier 1+ tables, build each row's body with @odata.bind referencing the parent GUID captured in the prior tier. Same BATCH-RECORDS call shape:
[
{
"index": 0,
"entitySet": "cr3e9_inspections",
"body": {
"cr3e9_inspectionnumber": "INS-001",
"cr3e9_status": 100000000,
"cr3e9_Site@odata.bind": "/cr3e9_jobsites(<parent-guid-from-tier-0>)"
}
}
]
Then:
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> BATCH-RECORDS \
"Tier 1" \
--operations '<json-with-bound-lookups>' \
--concurrency 5 \
--solution '<solution-uniquename-from-memory-bank>' \
--tenant-id '<tenantId-from-resolve-environment>'
⚠️ Lookup write syntax (HARD — wrong shape silently saves null OR loudly 404s):
- The property name on the LEFT of
@odata.bindis the PascalCase nav property, e.g.cr3e9_Site(not_cr3e9_siteid_value, which is read-only).- The value is the entity-set path:
/<entitySetName>(<guid>). Note the leading/.<entitySetName>is the EntitySetName of the LOOKUP TARGET table, fetched via Step 5a — NOT the column's logical name withsappended. Constructing it as<logicalName>sreturnsEntity '<targetTable>' With Id = <guid> Does Not Existeven when the row exists, because Dataverse can't resolve the wrong entity set to the right table. Versioned tables (cr3e9_inspectionv3→cr3e9_inspectionv3s) and irregular plurals (cr3e9_inquiry→cr3e9_inquiries) are the common traps.<guid>MUST come from a live query in the current process — either the parent's BATCH-RECORDS response (Step 5b/5c) or, on resume, a fresh GET against the parent table (Step 5f). Never copy-paste GUIDs from a prior session's stdout.- Wrong shapes either silently drop the relationship (record lands without parent FK, app shows orphaned rows) or 404 the whole tier. See
references/dataverse-reference.md§ Setting Lookups for the canonical pattern.
Run this step only when Step 4a created media jobs for business Image/File columns. Never run it for decorative UI assets.
Every media job's target table must still be in seedTables and outside
retiringTables; a previously captured GUID does not authorize a new target.
Build a mediaJobs sidecar while generating rows:
[
{
"table": "cr3e9_product",
"rowIndex": 2,
"recordId": "<filled-after-BATCH-RECORDS>",
"columnName": "cr3e9_productimage",
"columnType": "Image",
"filePath": "assets/sample-media/gatorade-aseptic.png",
"fileName": "gatorade-aseptic.png",
"purpose": "product photo"
}
]
After each tier's BATCH-RECORDS response, fill recordId from the in-memory { index → recordId } map, then upload media by column type:
dataverse-request.js require the same --tenant-id argument.
If a File upload helper cannot enforce that tenant binding, do not invoke it
or fall back to ambient credentials: leave bytes unset, report
sample media skipped — tenant-bound upload helper missing, and return a
media concern with the preserved metadata rows.Service.upload(recordId, columnName, file, fileDisplayName?); for CLI seeding, use a dedicated helper that performs the same Dataverse file upload flow. The JSON-only dataverse-request.js BATCH-RECORDS mode is not a binary upload mechanism.Hard failure rule: if media upload fails for a sample row, keep the metadata row, record the media failure in Step 6, and continue. Do not delete the row or rerun schema creation. The app should still have usable list/detail data with a placeholder image fallback.
Never do these:
columnName; use .datamodel-manifest.json / field_bindings.file_columns exact logical names.The BATCH-RECORDS response is your tracking source. For each tier's response array:
status 200-299, recordId present) → append to your in-memory { index → { table, primaryNameValue, recordId } } map.status 0 / 4xx / 5xx with error) → append to a per-tier failure list for the Step 6 summary.After all tiers complete (or after a strict-default stop), batch-write to memory-bank.md under ## Seeded sample data so subsequent runs are idempotent. One row per table per run:
## Seeded sample data
| Date | Table | Records inserted | First GUID | Last GUID |
|---|---|---|---|---|
| <ISO> | cr3e9_jobsite | 5 | <guid1> | <guid5> |
Write all rows in a single Edit call after the run, not per-tier — avoids race-on-file-write across iterations and keeps the audit log atomic.
If a tier fails partway and you need to retry, do NOT write a hand-rolled seed-resume.js that hardcodes parent GUIDs from the prior run's stdout. That pattern is the #1 source of Entity '<table>' With Id = <guid> Does Not Exist 404s, because (a) the prior run may not have actually committed the parent rows it printed, and (b) GUIDs from a re-created table are stale immediately.
The only safe resume pattern:
Reconfirm the current approved seedTables and retirement exclusions before
resuming. Prior memory-bank successes or seed files do not authorize tables
removed from the current scope; never retry a retiring table.
Re-query parent GUIDs by a stable business key. For every parent table referenced in the failed tier's @odata.bind values, run a fresh GET filtered by the row's natural identifier (name, tail-number, code — whatever you used as the primary name when seeding). Example:
cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET \
"<parentEntitySet>?\$select=<parentIdColumn>,<naturalKey>&\$filter=startswith(<naturalKey>,'<seed prefix>')&\$top=50" \
--tenant-id '<tenantId-from-resolve-environment>'
Build a fresh { naturalKey → guid } map from the response.
Re-query EntitySetName for every lookup target (Step 5a). Don't trust a cached value from the prior session — table EntitySetName is stable, but the cache file may be from a different project.
If the parent query returns fewer rows than expected, STOP. Don't proceed with a partial map — surface the count to the user:
⛔ Resume aborted: expected <N> parent rows in <table>, found <K>. Re-run /add-sample-data from Tier 0 (don't trust the prior session's GUIDs).
Re-issue the failed tier as a normal Step 5b/5c BATCH-RECORDS call with the freshly-queried GUIDs and EntitySetNames substituted into the operations array. Same --solution flag, explicit --tenant-id from the validated Step 1 identity, and concurrency rules; never switch tenants to recover.
Continue forward through subsequent tiers using the new in-memory { index → recordId } map seeded from this resume's response.
Why no
--resumeflag exists today: the strict-default failure mode ("stop the tier, surface failures, let user re-run") combined with the live-query rule above is the resume mechanism. A flag would imply the script can magically figure out what's already there — it can't, because partial commits and concurrent edits make any cache lie. The user owns the recovery decision; the agent's job is to follow the live-query pattern, never to invent a stateful resume helper.
✅ Sample data seeded
─────────────────────────────────────────────
Environment : <envUrl>
Solution : <solution>
Seed scope : <approved targets; excluded/retiring targets>
Tables seeded : <list with counts, e.g. cr3e9_jobsite (5), cr3e9_inspection (5)>
Total records : <N>
Failures : <K> (see list below if K > 0)
Next steps:
npm run dev # Open the app — home screen now shows real data
/preview-screens # Generate static HTML preview with sample data
─────────────────────────────────────────────
If any record failed, print a sub-table of the failures with the error messages so the user can diagnose.
Return a non-success/concern status for partial results; never describe unseeded
or excluded tables as successfully populated. Seeding does not change the plan's
schema or remove transitional entries from .datamodel-manifest.json.
Open, never all-InProgress, never all-Pending. See Step 4a for per-class targets.BATCH-RECORDS mode for the actual inserts — single Node process, parallel within a tier, ordered results, adaptive concurrency on 429. Don't fire per-row node dataverse-request.js POST ... invocations: each cold-start is ~150-300ms and the whole point of the batch mode is to amortize that.--concurrency higher unless you've measured and verified the env's service-protection ceiling.EntityDefinitions, Attributes, RelationshipDefinitions POSTs) MUST stay sequential — Dataverse metadata lock. The existing /add-dataverse Step 5 concurrency rule is unchanged.contact, account, incident, etc.) by default — they're shared with other apps in the env. If the user explicitly selects them, surface a confirmation: "These records will be visible to all apps in this env. Continue?"--solution so records land in our solution.@odata.bind with PascalCase nav property name + /entitySet(guid) value. Anything else either silently drops the relationship, 400s, or 404s with Entity '<target>' With Id = <guid> Does Not Exist. The BATCH-RECORDS mode passes the body through verbatim — it doesn't validate @odata.bind shape, that's the caller's job.<logicalName>s is wrong for versioned tables (cr3e9_inspectionv3s) and irregular plurals (cr3e9_inquiries, cr3e9_statuses). Always read EntitySetName from EntityDefinitions (Step 5a) for every lookup target referenced in @odata.bind values.@odata.bind come from live queries in the current process — never from a prior session's stdout. On resume, re-query parents by their natural key (Step 5e); never paste GUIDs into a hand-rolled seed-resume.js..tmp/seed-resume.js with hardcoded inspGuids = [...] is a guaranteed 404.Value from the option set, not labels. Query the option set first (Step 4b).skills/add-dataverse/references/dataverse-reference.md — Setting Lookups, Choice fields, Formatted Valuesscripts/dataverse-request.js — bundled HTTP helper with --solution, --include-headers, --body flagsまだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Activates and provisions a Power Pages website in a Power Platform environment via the Power Platform REST API. Use when the user wants to activate, provision, turn on, or enable a Power Pages website or portal.
日本語の概要は準備中です。原文の説明を表示しています。
Integrates Power Pages generative-AI summarization APIs (PREVIEW) into a Single Page Application (SPA) site — the Search Summary API and the Data Summarization API — on any record-detail or list page. Generates per-target service code (CSRF-handled) and AI site settings; delegates Web API settings, table permissions, and web roles to `/integrate-webapi` and `/create-webroles`. Use whenever a user wants AI/Copilot output that condenses Dataverse content on a Power Pages site — an AI summary, AI-generated overview or "key insights" across a record or list, a search-results summary, a case/incident summary, or recommendation-chip refinement — even when phrased as "AI-generated paragraph", "insights", or "overview". Do NOT use for: generative pages in model-driven apps (use the model-apps `genpage` skill), Copilot Studio agents/chatbots, summarizing documents or PDFs, Power BI dashboards, plain keyword search with no AI summary, or plain Dataverse CRUD (use `/integrate-webapi`).
日本語の概要は準備中です。原文の説明を表示しています。
Adds Azure DevOps connector to a Power Apps code app. Use when querying work items, creating bugs, managing pipelines, or making ADO API calls.
日本語の概要は準備中です。原文の説明を表示しています。
Internal implementation skill invoked by /add-native for camera, image picker, barcode scanner, QR scanner, and camera/gallery Dataverse artifact workflows.
日本語の概要は準備中です。原文の説明を表示しています。
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.
日本語の概要は準備中です。原文の説明を表示しています。
Adds any Power Platform connector to a Power Apps code app. Generic fallback for connectors not covered by a specific skill.
日本語の概要は準備中です。原文の説明を表示しています。