assemble-ppmplugin
Assemble the final `.ppmplugin` binary bundle for a PAM native extension and verify its contents. First **reconciles** the manifest's declared `entr…
它会碰到什么
这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。
技能内容
/assemble-ppmplugin
The final step: take the label (manifest.json from [/generate-ppmplugin-manifest](../generate-ppmplugin-manifest/SKILL.md)) and the binaries the build skills produced, zip them into the single <name>.ppmplugin file, and verify the box contains exactly the right items. The output is the deliverable — the file you can hand off / upload. Before zipping, it reconciles the manifest's declared platforms against the binaries that actually built, so the shipped bundle never claims a platform it doesn't contain.
Read [shared/ppmplugin-format.md](../../shared/ppmplugin-format.md) §1 — the bundle layout this skill produces and verifies.
What this skill does NOT do
- Does not author the manifest or build any binary — it consumes the staged outputs of the prior third-party-control skills (manifest + the build skill(s)).
- Does not upload to Dataverse / wire into a canvas app (Stage 3 — deferred).
- Does not build any binary — it consumes whatever the build skills staged (
android/<Pascal>Plugin.dexfrom/build-android-binaryand/orios/<Pascal>Plugin.framework/from/build-ios-binary) and bundles those present.
Step 1 — Read shared docs + prereq block
- Read [
shared/shared-instructions.md](../../shared/shared-instructions.md) and [shared/ppmplugin-format.md](../../shared/ppmplugin-format.md). - Prereq:
jar(ships with the JDK). Print the visible block (shared-instructions §9.2):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Prereq check — /assemble-ppmplugin
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🟢 ✓ jar (JDK) available
🟢 1 check passed, 0 failed. Ready to proceed.
If jar is missing, STOP with BLOCKED: jar not found — install a JDK (JDK 17).
Step 2 — Reconcile declared entrypoints against staged binaries (the gate)
The shipped bundle's manifest.json MUST declare exactly the platforms whose binaries are in the zip — no more, no less. The manifest was authored from intent (target choice); this step makes it match reality (what actually built). This is the one place that sees the final set of binaries, so it owns consistency.
- Read
ppmplugin/staging/manifest.json— else STOP withNEEDS_CONTEXT: manifest missing — run /generate-ppmplugin-manifest. Readnamefor the output filename<name>.ppmplugin(the version is NOT in the filename — it lives in the manifest'sversionfield; the wrap pipeline reads it from there. Still readversionto show it in the deliverable report). - Declared platforms: is
entrypoints.androidpresent?entrypoints.ios? - Staged binaries:
- Android:
ppmplugin/staging/android/<dex>exists, where<dex>=entrypoints.android.dex. - iOS:
ppmplugin/staging/ios/<framework>.framework/exists (a flat.framework, NOT an.xcframework— [§5b](../../shared/ppmplugin-format.md)), where<framework>=entrypoints.ios.framework. If an.xcframeworkis staged instead, surface it as a gate — the wrap CI can't ingest it; re-run/build-ios-binaryfor the flat device-slice framework.
- Reconcile, per platform:
| Declared | Staged | Action |
|---|---|---|
| yes | yes | ship it ✓ |
| yes | no | MISMATCH → gate (below) |
| no | yes | binary present but the manifest won't route it — surface; offer to re-run /generate-ppmplugin-manifest to declare it, or leave it out |
| no | no | not part of this bundle — ignore |
- If nothing is both declared AND staged → STOP with
NEEDS_CONTEXT: no built binary to ship — run a build skill first.
The mismatch gate (declared but not staged). Do NOT silently ship a manifest pointing at a missing binary. The situation is genuinely ambiguous (changed-my-mind vs forgot-to-build), so surface it and ask via AskUserQuestion:
> "Manifest declares <platform> but no <platform> binary is staged."
> - Build <platform> first — run the build skill (/build-android-binary, or /build-ios-binary for iOS, Mac-only) [invoke it via the Skill tool — execute, don't describe]
> - Ship without <platform> — remove entrypoints.<platform> from the staged manifest.json, ship the platforms that ARE built
> - Stop
If the user picks "Ship without", edit the staged manifest.json to drop that entrypoint before continuing. After this step, the manifest's entrypoints set equals the staged-binary set exactly.
Step 3 — Final validation pass
Re-run the [ppmplugin-format §4](../../shared/ppmplugin-format.md) validation rules on the reconciled staged manifest.json (it may have been edited in Step 2 or by hand). Also cross-check, for each shipped platform:
- Android:
entrypoints.android.dexexactly matches the staged DEX filename. - iOS:
entrypoints.ios.frameworkmatches the staged…/<framework>.frameworkdirectory name, and that.framework/carries the binary +Headers/<framework>.h+Modules/module.modulemap+Info.plist(the wrap-CI requirements —/audit-ppmplugindoes the deep check; flag here if any are obviously absent).
If validation fails, STOP with BLOCKED: manifest validation — <rule> and do not produce the
bundle. A .ppmplugin that fails the local compatibility checks is not ready for upload.
Step 4 — Zip + verify
Before zipping: if the output ppmplugin/<name>.ppmplugin already exists, do NOT silently overwrite it — ask via AskUserQuestion: Replace [default] / Keep existing (stop, leave the prior bundle untouched). Proceed to zip only on Replace.
- Zip the manifest plus only the platform folder(s) reconciled as shipped in Step 2. Pass them explicitly so the build dirs (
android-build/,ios-build/) are never swept in.jar(JDK) recurses directories, so it handles the iOS.frameworktree, and it behaves identically on every OS — only the shell glue differs (§5):
macOS / Linux (bash):
mkdir -p ppmplugin
# list only the shipped platforms, e.g. `android` for Android-only, `android ios` for Both:
( cd ppmplugin/staging && jar cMf "../<name>.ppmplugin" manifest.json android ios )
Windows (PowerShell):
New-Item -ItemType Directory -Force ppmplugin | Out-Null
Push-Location ppmplugin\staging
jar cMf ..\<name>.ppmplugin manifest.json android ios
Pop-Location
(-M = no JAR manifest entry; the bundle's manifest.json is our own. Drop ios (or android) from the argument list if that platform isn't shipped.) On Replace (confirmed above), the prior bundle is overwritten.
- Verify layout — list and assert it matches the reconciled manifest exactly:
jar tf ppmplugin/<name>.ppmplugin
Android-only expects exactly:
manifest.json
android/<Pascal>Plugin.dex
A Both bundle also has ios/<Pascal>Plugin.framework/… entries (flat framework — binary + Headers/ + Modules/module.modulemap + Info.plist). STOP with BLOCKED: unexpected bundle contents (and the actual listing) if: a build dir leaked in (android-build/, ios-build/), a stray file appears (.DS_Store, META-INF/), an ios/<…>.xcframework/ is present (must be a flat .framework), or a declared platform's binary is missing. The bundle must contain exactly the manifest + the entrypoints' binaries — nothing else.
Step 5 — Report
Update the ## ppmplugin (third-party controls) block in .extension-state.md: Bundle: <name>.ppmplugin assembled <ISO timestamp> (v<version>, platforms: <android[,ios]>). Print the deliverable as a visible fenced block (shared-instructions §9.1, informational form):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
.ppmplugin ready
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ppmplugin/pen-input.ppmplugin (v0.1.4, Android-only)
Contents:
manifest.json
android/PenInputPlugin.dex
Next: /audit-ppmplugin — verify the bundle is upload-ready before shipping it.
(Then: deploy the dispatcher PCF via /publish-pcf-companion, and upload the
.ppmplugin via the wrap wizard — Stage 3, not yet a skill.)
Then offer the next step via AskUserQuestion (shared-instructions §9.1 — invoke the chosen skill via the Skill tool; execute, don't describe):
- Run /audit-ppmplugin (recommended — the final upload-readiness gate: validator rules + DEX SDK-leakage scan + iOS framework checks)
- Run /publish-pcf-companion (deploy the dispatcher PCF to a Power Platform env)
- Stay — I'll inspect the bundle first
(When /assemble-ppmplugin runs as an internal stage of /generate-ppmplugin, the orchestrator invokes /audit-ppmplugin automatically and this gate is skipped.) Return DONE with the bundle path.
想直接用这个技能?
本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。
它属于哪个仓库
plugins/power-apps-mobile-extension/skills/assemble-ppmplugin/SKILL.md