@salesforce/afv-skills 1.30.0 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/agentforce-bot-upgrade/SKILL.md +217 -0
- package/skills/agentforce-bot-upgrade/references/extraction-blueprint.md +242 -0
- package/skills/agentforce-bot-upgrade/references/generate-agent-spec.md +128 -0
- package/skills/agentforce-bot-upgrade/references/handoff-output-format.md +208 -0
- package/skills/agentforce-bot-upgrade/references/input-contract.md +101 -0
- package/skills/agentforce-bot-upgrade/references/mapping-rules.md +113 -0
- package/skills/agentforce-bot-upgrade/references/planner-workflow-reference.md +78 -0
- package/skills/agentforce-bot-upgrade/references/post-conversion-enhancements-reference.md +67 -0
- package/skills/agentforce-bot-upgrade/references/quality-checklist.md +33 -0
- package/skills/agentforce-bot-upgrade/references/sf-cli-bot-reference.md +116 -0
- package/skills/data360-code-extension-generate/SKILL.md +15 -2
- package/skills/dx-devops-work-item-manage/SKILL.md +270 -0
- package/skills/dx-devops-work-item-manage/examples/common-workflows.md +479 -0
- package/skills/dx-devops-work-item-manage/references/cli-commands.md +476 -0
- package/skills/dx-org-manage/SKILL.md +8 -5
- package/skills/dx-org-trial-expiration-check/SKILL.md +239 -0
- package/skills/dx-org-trial-expiration-check/scripts/check_expiration.sh +588 -0
- package/skills/dx-pkg-post-install-configure/SKILL.md +184 -0
- package/skills/experience-ui-bundle-app-coordinate/SKILL.md +202 -35
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.sh +26 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.sh +15 -0
- package/skills/experience-ui-bundle-custom-app-generate/SKILL.md +29 -5
- package/skills/experience-ui-bundle-custom-app-generate/references/configure-metadata-custom-application.md +1 -1
- package/skills/experience-ui-bundle-custom-app-generate/scripts/resolve-uibundle-path.sh +30 -0
- package/skills/experience-ui-bundle-features-generate/SKILL.md +86 -11
- package/skills/experience-ui-bundle-features-generate/references/conflict-resolution-schema.json +20 -0
- package/skills/experience-ui-bundle-features-generate/scripts/verify-react-bundle.sh +14 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +6 -1
- package/skills/experience-ui-bundle-frontend-generate/references/component.md +34 -1
- package/skills/experience-ui-bundle-frontend-generate/references/page.md +1 -1
- package/skills/experience-ui-bundle-metadata-generate/SKILL.md +19 -8
- package/skills/experience-ui-bundle-metadata-generate/references/csp-metadata-format.md +2 -2
- package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.sh +30 -0
- package/skills/experience-ui-bundle-project-generate/SKILL.md +111 -0
- package/skills/experience-ui-bundle-project-generate/scripts/flatten-project.mjs +33 -0
- package/skills/platform-custom-field-generate/SKILL.md +12 -11
- package/skills/platform-custom-field-generate/references/advanced-picklists.md +17 -17
- package/skills/platform-custom-lightning-type-generate/SKILL.md +9 -14
- package/skills/platform-custom-lightning-type-generate/references/widget-rendition.md +27 -111
- package/skills/platform-custom-report-type-generate/SKILL.md +259 -0
- package/skills/platform-custom-report-type-generate/examples/AccountProjectsWithTasks.reportType-meta.xml +51 -0
- package/skills/platform-custom-report-type-generate/examples/AccountsWithIndustry.reportType-meta.xml +27 -0
- package/skills/platform-custom-report-type-generate/examples/AccountsWithProjects.reportType-meta.xml +44 -0
- package/skills/platform-custom-report-type-generate/references/category-values.md +32 -0
- package/skills/platform-custom-report-type-generate/references/errors-and-troubleshooting.md +24 -0
- package/skills/platform-dataspace-access-configure/SKILL.md +318 -0
- package/skills/platform-docs-get/SKILL.md +4 -0
- package/skills/platform-docs-get/scripts/extract_salesforce_doc.py +78 -13
- package/skills/platform-encryption-configure/SKILL.md +122 -0
- package/skills/platform-encryption-configure/assets/EncryptionKey.settings-meta.xml +17 -0
- package/skills/platform-encryption-configure/assets/PlatformEncryption.settings-meta.xml +15 -0
- package/skills/platform-encryption-configure/assets/encrypted-field.field-meta.xml +22 -0
- package/skills/platform-encryption-configure/examples/cache-only-keys.settings-meta.xml +11 -0
- package/skills/platform-encryption-configure/references/encryption-schemes.md +34 -0
- package/skills/platform-encryption-configure/references/key-models.md +34 -0
- package/skills/platform-encryption-configure/references/tenant-secret-lifecycle.md +23 -0
- package/skills/platform-encryption-configure/scripts/validate-encryption-metadata.sh +54 -0
- package/skills/platform-lightning-type-widget-coordinate/SKILL.md +214 -0
- package/skills/platform-lightning-type-widget-coordinate/examples/existing-lightning-type-with-widget-prompt.md +80 -0
- package/skills/platform-lightning-type-widget-coordinate/examples/new-lightning-type-with-widget-prompt.md +75 -0
- package/skills/platform-lightning-type-widget-coordinate/references/build-plan-format.md +67 -0
- package/skills/platform-lightning-type-widget-coordinate/references/lightning-type-discovery.md +124 -0
- package/skills/platform-lightning-type-widget-coordinate/references/validation-gates.md +130 -0
- package/skills/platform-metadata-api-context-get/SKILL.md +13 -10
- package/skills/platform-sharing-owd-configure/SKILL.md +142 -0
- package/skills/platform-sharing-owd-configure/examples/get_owd_output.md +38 -0
- package/skills/platform-sharing-owd-configure/examples/update_owd_output.md +44 -0
- package/skills/platform-sharing-owd-configure/references/access_levels.md +49 -0
- package/skills/platform-sharing-owd-configure/references/metadata_api_approach.md +69 -0
- package/skills/platform-sharing-rules-generate/SKILL.md +89 -19
- package/skills/platform-sharing-rules-generate/examples/test-cases.md +381 -0
- package/skills/platform-widget-generate/SKILL.md +241 -0
- package/skills/platform-widget-generate/examples/conditional.json +73 -0
- package/skills/platform-widget-generate/examples/list-with-foreach.json +66 -0
- package/skills/platform-widget-generate/examples/single-object.json +64 -0
- package/skills/platform-widget-generate/references/schema-from-lightning-type.md +76 -0
- package/skills/platform-widget-generate/references/widget-bundle-layout.md +116 -0
- package/skills/platform-widget-generate/references/widget-meta-directives.md +130 -0
- package/skills/sales-agentforce-pipeline-management-configure/SKILL.md +268 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/field-completion-template.genAiPromptTemplate-meta.xml +141 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/pipeline_management_flow.flow-meta.xml +548 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/sales_management_agent.agent +2938 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/sales_management_agent.bundle-meta.xml +4 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/sfdx-project.json +12 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/stage-descriptions/bant.txt +11 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/stage-descriptions/meddic.txt +11 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/stage-descriptions/spiced.txt +11 -0
- package/skills/sales-agentforce-pipeline-management-configure/examples/custom-prompt-instructions.md +317 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/admin-communication.md +355 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/agent-creation.md +383 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/auth-and-cli.md +146 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/automation-matrix.md +23 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/autonomous-updates.md +215 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/canonical-agent-path.md +75 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/data-sources.md +155 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/field-completion-prompt-template.md +120 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/field-completion-prompts.md +149 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/flags.md +13 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/flow-clone-from-template.md +447 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/metadata-inventory.md +330 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/opportunity-stages.md +246 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/repair-diagnostics.md +265 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/setup-order.md +263 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/soap-api-enablement.md +528 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/CHANGES.md +180 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/README.md +56 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/add-field-suggestion.sh +679 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/create-agent.sh +302 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/create-flow.sh +250 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/define-agent-access.sh +430 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/deploy-settings.sh +77 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/enable-deal-agent.sh +241 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/enable-prerequisites.sh +538 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/flow-debug-and-verify.sh +385 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/retrieve-settings.sh +131 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/setup-all.sh +2791 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/agent-bundle-publish.sh +189 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/agent-detection.sh +239 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/flow-builder.sh +238 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/psg.sh +48 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/soap.sh +140 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/stage-descriptions.sh +448 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/test-opp.sh +166 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/verify-all.sh +636 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/verify-prompt-generation.sh +346 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
3
|
+
<fullName>{FIELD_API_NAME}__c</fullName>
|
|
4
|
+
<label>{FIELD_LABEL}</label>
|
|
5
|
+
<type>{FIELD_TYPE}</type>
|
|
6
|
+
<length>{LENGTH}</length>
|
|
7
|
+
<encryptionScheme>ProbabilisticEncryption</encryptionScheme>
|
|
8
|
+
</CustomField>
|
|
9
|
+
<!--
|
|
10
|
+
TEMPLATE NOTES — delete this comment block before delivering the file.
|
|
11
|
+
|
|
12
|
+
<type>: Text for string fields up to 255 chars; LongTextArea only for 256+.
|
|
13
|
+
"long text up to 255 characters" is Text, NOT LongTextArea.
|
|
14
|
+
<encryptionScheme> must be exactly one of:
|
|
15
|
+
ProbabilisticEncryption strongest; NOT filterable/sortable/groupable
|
|
16
|
+
CaseSensitiveDeterministicEncryption filterable; exact-case equality
|
|
17
|
+
CaseInsensitiveDeterministicEncryption filterable; case-normalized equality
|
|
18
|
+
None removes encryption
|
|
19
|
+
Only deterministic schemes support filter / sort / group. A query that filters
|
|
20
|
+
a probabilistically-encrypted field is REJECTED with INVALID_FIELD.
|
|
21
|
+
-->
|
|
22
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
Worked example: enabling Cache-Only Keys WITH replay detection.
|
|
4
|
+
Note the ordering guarantee — enableCacheOnlyKeys=true is present, which is
|
|
5
|
+
the precondition for enableReplayDetection=true. Removing enableCacheOnlyKeys
|
|
6
|
+
(or setting it false) while keeping enableReplayDetection=true is invalid.
|
|
7
|
+
-->
|
|
8
|
+
<EncryptionKeySettings xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
9
|
+
<enableCacheOnlyKeys>true</enableCacheOnlyKeys>
|
|
10
|
+
<enableReplayDetection>true</enableReplayDetection>
|
|
11
|
+
</EncryptionKeySettings>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Encryption Schemes
|
|
2
|
+
|
|
3
|
+
Shield Platform Encryption offers two families of scheme, exposed on `CustomField.encryptionScheme` (Metadata API 44.0+). Choosing between them is a trade-off between cryptographic strength and queryability.
|
|
4
|
+
|
|
5
|
+
## Valid `encryptionScheme` values
|
|
6
|
+
|
|
7
|
+
| Value | Filterable / sortable / groupable | When to use |
|
|
8
|
+
|-------|:--:|-------------|
|
|
9
|
+
| `ProbabilisticEncryption` | **No** | Default and strongest. Same plaintext encrypts to different ciphertext each time, so no two values are comparable. Use unless the field must be queried. |
|
|
10
|
+
| `CaseSensitiveDeterministicEncryption` | Yes | Same plaintext always encrypts to the same ciphertext, preserving exact case. Use for exact-match filters where case matters (e.g. codes, tokens). |
|
|
11
|
+
| `CaseInsensitiveDeterministicEncryption` | Yes | Deterministic with case normalized before encryption. Use for equality filters on human-entered text (names, emails) where case should not matter. |
|
|
12
|
+
| `None` | n/a | Removes encryption from the field. |
|
|
13
|
+
|
|
14
|
+
Only these four strings are accepted. Any other value fails deployment.
|
|
15
|
+
|
|
16
|
+
## Deterministic vs Probabilistic — the decision
|
|
17
|
+
|
|
18
|
+
- **Need to filter, sort, group, or use the field in a WHERE clause?** → a deterministic scheme. Deterministic encryption preserves equality so the index can be used.
|
|
19
|
+
- **No query requirement?** → probabilistic. It is cryptographically stronger because identical plaintexts produce different ciphertexts, defeating frequency analysis.
|
|
20
|
+
- **Case matters in matching?** → `CaseSensitive...`. Otherwise `CaseInsensitive...`.
|
|
21
|
+
|
|
22
|
+
Enabling the deterministic scheme at the org level also requires `enableDeterministicEncryption=true` in `PlatformEncryptionSettings`.
|
|
23
|
+
|
|
24
|
+
## Query behavior of encrypted fields — the failure mode
|
|
25
|
+
|
|
26
|
+
A common misconception is that filtering or sorting on a **probabilistically**-encrypted field silently drops the clause or returns zero rows. It does not.
|
|
27
|
+
|
|
28
|
+
The platform **rejects the query** with an `INVALID_FIELD` error:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
INVALID_FIELD: field '<FieldName>' can not be sorted / filtered / grouped in a query call
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This is enforced server-side (see the platform's `QueryBlockingTest` coverage). The correct guidance to a user hitting this is: the query failed because the field is probabilistically encrypted — re-encrypt it with a deterministic scheme if it must be queryable, or remove the field from the filter/sort/group clause. Never tell the user the query "returns nothing" — it errors.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Key Management Models
|
|
2
|
+
|
|
3
|
+
Shield Platform Encryption supports several ways to source and control the key material that protects encrypted data. They differ in *where the key material lives* and *who controls it*.
|
|
4
|
+
|
|
5
|
+
## The models
|
|
6
|
+
|
|
7
|
+
| Model | Where key material lives | Who controls it | Metadata / setting |
|
|
8
|
+
|-------|--------------------------|-----------------|--------------------|
|
|
9
|
+
| Salesforce-derived (default) | Salesforce, derived from a tenant secret | Salesforce derivation | none — default |
|
|
10
|
+
| **BYOK** (Bring Your Own Key) | Salesforce, but from *customer-supplied* material | Customer uploads key material; Salesforce stores it | `canOptOutOfDerivationWithBYOK` controls per-key derivation opt-out |
|
|
11
|
+
| **BYOKMS / EKM** (External Key Management) | An *external* key store the customer runs | Customer; Salesforce calls out to the KMS | `canExternalKeyManagement` (API 63.0+) |
|
|
12
|
+
| **Cache-Only Keys** | Outside Salesforce entirely; fetched on demand per callout | Customer hosts a key service; Salesforce caches, never persists | `enableCacheOnlyKeys`, `enableReplayDetection` |
|
|
13
|
+
| **Data 360 keys** | Salesforce, dedicated Data 360 root key | Customer-managed root key | `canManageDataCloudKeys` (API 63.0+) |
|
|
14
|
+
| **Transactional DB** | Salesforce | Org policy | `canEncryptTransactionalDatabase` (API 63.0+) |
|
|
15
|
+
|
|
16
|
+
## BYOK vs BYOKMS/EKM — the distinction users get wrong
|
|
17
|
+
|
|
18
|
+
- **BYOK**: you generate key material and *upload* it. Salesforce stores it and uses it like a derived key. The trust boundary still includes Salesforce storing the material.
|
|
19
|
+
- **BYOKMS / EKM**: key material *never leaves your external KMS*. Salesforce makes a callout to the KMS to wrap/unwrap. This keeps the material entirely under your control.
|
|
20
|
+
|
|
21
|
+
## Cache-Only Keys and replay detection
|
|
22
|
+
|
|
23
|
+
Cache-Only Keys go further than EKM: Salesforce fetches key material on every use and never persists it — only caches it transiently.
|
|
24
|
+
|
|
25
|
+
`enableReplayDetection` protects those callouts against replay attacks using a nonce. The contract is a **one-way dependency**:
|
|
26
|
+
|
|
27
|
+
> *Requires `enableCacheOnlyKeys=true` before setting `enableReplayDetection` to true.*
|
|
28
|
+
|
|
29
|
+
Two consequences the agent must respect:
|
|
30
|
+
|
|
31
|
+
1. Enabling Cache-Only Keys does **not** auto-enable replay detection. You must set `enableReplayDetection=true` explicitly.
|
|
32
|
+
2. An org can validly run Cache-Only Keys with replay detection **off**. It is not required.
|
|
33
|
+
|
|
34
|
+
Setting `enableReplayDetection=true` without `enableCacheOnlyKeys=true` is an invalid combination and will be rejected.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Tenant Secret Lifecycle
|
|
2
|
+
|
|
3
|
+
A **tenant secret** is the per-org root from which Shield derives (or wraps) data encryption keys. Its lifecycle operations are **UI/REST-only** — there is no `*.settings-meta.xml` for rotating, destroying, or uploading a tenant secret. When a user asks about these, return guidance and point them at Setup or the REST/Tooling API, not a metadata file.
|
|
4
|
+
|
|
5
|
+
## Operations
|
|
6
|
+
|
|
7
|
+
| Operation | What it does | Surface |
|
|
8
|
+
|-----------|--------------|---------|
|
|
9
|
+
| Generate | Creates a new active tenant secret for a key type | Setup → Key Management, or REST |
|
|
10
|
+
| Rotate | Generates a new tenant secret; existing data stays readable under prior secrets | Setup / REST |
|
|
11
|
+
| Destroy | Permanently destroys key material; data encrypted under it becomes unrecoverable | Setup (destructive, requires confirmation) |
|
|
12
|
+
| BYOK upload | Uploads customer-supplied key material as the tenant secret | Setup / REST |
|
|
13
|
+
| Cache-Only callout setup | Configures the named credential / callout endpoint the key service is fetched from | Setup (Named Credentials) |
|
|
14
|
+
|
|
15
|
+
## Rotation semantics
|
|
16
|
+
|
|
17
|
+
Rotating a tenant secret makes a new secret **active**; prior secrets are retained as **archived** so existing ciphertext stays readable. New writes use the active secret. To move existing data onto the new secret, run **background encryption** (a.k.a. the sync/re-encrypt process) — rotation alone does not re-encrypt existing rows.
|
|
18
|
+
|
|
19
|
+
For BYOK specifically, the sequence is: rotate to (upload) the new key material, then run background encryption to apply it. Uploading new material does not retroactively re-encrypt existing data on its own.
|
|
20
|
+
|
|
21
|
+
## Destruction semantics
|
|
22
|
+
|
|
23
|
+
Destroying a tenant secret is **irreversible**. Any data whose keys derive from that secret and has not been re-encrypted under another active secret becomes permanently unreadable. This is intentional (right-to-be-forgotten / crypto-shredding) but must be surfaced as a hard warning — there is no recovery path.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Validate a Shield Platform Encryption settings/field XML file for the two
|
|
3
|
+
# deterministic contracts this skill must never get wrong:
|
|
4
|
+
# 1. enableReplayDetection=true requires enableCacheOnlyKeys=true (one-way dependency)
|
|
5
|
+
# 2. encryptionScheme must be one of the four valid enum values
|
|
6
|
+
#
|
|
7
|
+
# Usage: validate-encryption-metadata.sh <file.xml>
|
|
8
|
+
# validate-encryption-metadata.sh --help
|
|
9
|
+
# Output: prints "OK" on success; prints ERROR lines to stderr and exits 1 on failure.
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
|
14
|
+
echo "Usage: validate-encryption-metadata.sh <file.xml>"
|
|
15
|
+
echo "Checks: replay-detection dependency, encryptionScheme enum."
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
FILE="${1:-}"
|
|
20
|
+
if [[ -z "$FILE" ]]; then
|
|
21
|
+
echo "ERROR: no file given. Usage: validate-encryption-metadata.sh <file.xml>" >&2
|
|
22
|
+
exit 1
|
|
23
|
+
fi
|
|
24
|
+
if [[ ! -f "$FILE" ]]; then
|
|
25
|
+
echo "ERROR: file not found: $FILE" >&2
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
errors=0
|
|
30
|
+
|
|
31
|
+
# 1. Replay-detection one-way dependency.
|
|
32
|
+
if grep -q '<enableReplayDetection>true</enableReplayDetection>' "$FILE"; then
|
|
33
|
+
if ! grep -q '<enableCacheOnlyKeys>true</enableCacheOnlyKeys>' "$FILE"; then
|
|
34
|
+
echo "ERROR: enableReplayDetection=true requires enableCacheOnlyKeys=true in the same file." >&2
|
|
35
|
+
errors=$((errors + 1))
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# 2. encryptionScheme enum.
|
|
40
|
+
scheme=$(grep -oE '<encryptionScheme>[^<]*</encryptionScheme>' "$FILE" | sed -E 's/<\/?encryptionScheme>//g' || true)
|
|
41
|
+
if [[ -n "$scheme" ]]; then
|
|
42
|
+
case "$scheme" in
|
|
43
|
+
ProbabilisticEncryption|CaseSensitiveDeterministicEncryption|CaseInsensitiveDeterministicEncryption|None) ;;
|
|
44
|
+
*)
|
|
45
|
+
echo "ERROR: invalid encryptionScheme '$scheme'. Must be one of: ProbabilisticEncryption, CaseSensitiveDeterministicEncryption, CaseInsensitiveDeterministicEncryption, None." >&2
|
|
46
|
+
errors=$((errors + 1))
|
|
47
|
+
;;
|
|
48
|
+
esac
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if [[ "$errors" -gt 0 ]]; then
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
echo "OK"
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: platform-lightning-type-widget-coordinate
|
|
3
|
+
description: "Orchestrate Apex-backed Lightning Type + HXL widget generation. TRIGGER only when the prompt EXPLICITLY invokes Lightning Types: user says 'Lightning Type', 'CLT', 'Custom Lightning Type', 'Apex-backed type', references '@apexClassType/...', asks to build a widget or card for a named Lightning Type, asks to create a new Lightning Type and widget together, or grounds a widget in a specific Apex class as its schema. DO NOT TRIGGER when the prompt names only a subject, domain, feature, or entity noun. Also DO NOT TRIGGER when: authoring only a Custom Lightning Type (use platform-custom-lightning-type-generate), only an Apex class (use platform-apex-generate), editing an existing widget without any Lightning Type change, or grounding a widget on an object/JSON-based Lightning Type (lightning__objectType with primitives)."
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.1"
|
|
6
|
+
minApiVersion: "68.0"
|
|
7
|
+
relatedSkills:
|
|
8
|
+
- "platform-widget-generate"
|
|
9
|
+
- "platform-custom-lightning-type-generate"
|
|
10
|
+
- "platform-apex-generate"
|
|
11
|
+
cliTools:
|
|
12
|
+
- tool: ["jq"]
|
|
13
|
+
semver: ">=1.6.0"
|
|
14
|
+
- tool: ["sf"]
|
|
15
|
+
semver: ">=2.0.0"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Building a Lightning Type With a Widget
|
|
19
|
+
|
|
20
|
+
Coordinate Lightning Type, Apex class, and HXL widget generation across the two paths below. This skill never authors content directly — it loads and invokes leaf skills in dependency order, gates progress on user approval, and runs validation gates before reporting completion.
|
|
21
|
+
|
|
22
|
+
## Scope
|
|
23
|
+
|
|
24
|
+
Apex-backed Lightning Types only — root `lightning:type` of the form `@apexClassType/<namespace>__<ClassName>` (outer class). The class itself carries the `@AuraEnabled` fields that define the payload shape; nested list-element types live as inner classes referenced by `List<Inner>` fields on the outer class. Object/JSON-based Lightning Types (root `lightning__objectType` with primitive `properties`) are out of scope; route those to `platform-custom-lightning-type-generate` and `platform-widget-generate` separately.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Phase Graph
|
|
29
|
+
|
|
30
|
+
| Phase | Purpose | Runs in | Output |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| 1 — Path selection | Pick the path (`existing-lightning-type-with-widget` · `new-lightning-type-with-widget`) from the user prompt. | All paths | `path` |
|
|
33
|
+
| 2 — Lightning Type discovery | Local project first; then `sf project retrieve --metadata LightningTypeBundle:<name>`; ambiguity resolution; in-scope verification. | **`existing-lightning-type-with-widget` only** | `lightningTypeSchema` (path + SHA-256 + Apex class FQN) |
|
|
34
|
+
| 3 — Build plan | Print the plan in full; proceed unless the next reply explicitly pushes back. | All paths | printed plan |
|
|
35
|
+
| 4 — Generation | Load and invoke leaf skills per path. | All paths | files written |
|
|
36
|
+
| 5 — Validation | Run hard gates (block) and warn gates (advisory). | All paths | gate report |
|
|
37
|
+
| 6 — Summary | Files, validations, preview readiness, next steps. | All paths | summary |
|
|
38
|
+
|
|
39
|
+
**Per-phase pattern:**
|
|
40
|
+
|
|
41
|
+
| Step | What to do |
|
|
42
|
+
|---|---|
|
|
43
|
+
| 1. Load skill | Invoke the named skill. Even if you remember its content, skills evolve — always load fresh. |
|
|
44
|
+
| 2. Execute | Follow the loaded skill's workflow. |
|
|
45
|
+
| 3. Verify | Confirm outputs exist and match the spec. |
|
|
46
|
+
| 4. Checkpoint | Confirm phase completion before moving on. |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Phase 1 — Path selection
|
|
51
|
+
|
|
52
|
+
Determine the path from the user prompt and pick the corresponding leaf-skill load order:
|
|
53
|
+
|
|
54
|
+
| Path | Trigger | Phase 4 sub-skill load order |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `existing-lightning-type-with-widget` | Prompt names a Lightning Type and treats it as existing (no *create*, *generate*, or *new* qualifier on the type). Phase 2 confirms it exists and is in scope. | `platform-widget-generate` (renderer wiring is authored inline per the Phase 4 "Renderer.json wiring step" — no separate skill load) |
|
|
57
|
+
| `new-lightning-type-with-widget` | Prompt asks for a new Lightning Type (verbs: *create*, *generate*, *build*, *make a new*) **or** Phase 2 finds nothing in the local project or in the org. | `platform-apex-generate` → `platform-custom-lightning-type-generate` (schema authoring) → `platform-widget-generate` (renderer wiring authored inline afterwards per the Phase 4 "Renderer.json wiring step") |
|
|
58
|
+
|
|
59
|
+
If the prompt names no Lightning Type at all (just a widget against prompt-provided fields or sample data), this orchestrator should not have been triggered — route the user to `platform-widget-generate` directly.
|
|
60
|
+
|
|
61
|
+
If the prompt is ambiguous between the two paths, ask **one** clarifying question max and pick. The `new-lightning-type-with-widget` path's `platform-apex-generate` step is engaged automatically — do not prompt the user to confirm Apex.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Phase 2 — Lightning Type discovery (`existing-lightning-type-with-widget` only)
|
|
66
|
+
|
|
67
|
+
Skipped for `new-lightning-type-with-widget` (the Lightning Type does not yet exist).
|
|
68
|
+
|
|
69
|
+
**For `existing-lightning-type-with-widget`, FIRST Read `references/lightning-type-discovery.md` (REQUIRED — do NOT skip; do not run Phase 2 from this summary alone), then execute its find → verify → ensure-class procedure step by step.** The bullets below are a reminder, not a substitute for the reference:
|
|
70
|
+
|
|
71
|
+
- Local project first: search `force-app/**/lightningTypes/<TypeName>/schema.json`.
|
|
72
|
+
- If not found, run `sf project retrieve --metadata LightningTypeBundle:<TypeName>` against the connected org.
|
|
73
|
+
- If multiple candidates surface, list them with FQNs and paths. Ask the user to pick.
|
|
74
|
+
- After locating the schema, verify it is in scope (root `lightning:type` starts with `@apexClassType/`). If the type is object/JSON-based, surface that and stop.
|
|
75
|
+
- **Ensure the backing Apex class is in the local project.** Parse `<ClassName>` from the `@apexClassType/<ns>__<ClassName>` root. If `<pkgDir>/classes/<ClassName>.cls` is absent, run `sf project retrieve --metadata ApexClass:<ClassName>`. This runs whether the Lightning Type was found locally or retrieved from the org — a locally-present Lightning Type can still reference an absent class. If the class exists nowhere, surface it and stop (the type is unrenderable). See the reference for the full procedure.
|
|
76
|
+
- If retrieval fails, surface the CLI error and offer: (a) ask the user to run retrieve manually and re-run, or (b) downgrade to `new-lightning-type-with-widget` if appropriate. Never silently downgrade.
|
|
77
|
+
- If retrieval finds nothing, prompt the user to confirm flipping to `new-lightning-type-with-widget` before continuing.
|
|
78
|
+
|
|
79
|
+
Capture the Lightning Type `schema.json` SHA-256 and the Apex class FQN (parsed from `@apexClassType/...`) at the end of this phase. The Phase 5 `lightning-type-unchanged` gate compares the SHA against the on-disk SHA at end of Phase 4 to enforce no silent schema edits.
|
|
80
|
+
|
|
81
|
+
> Staleness: do NOT maintain a cross-session cache. Always read the local project fresh and always re-retrieve from the org per session.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Phase 3 — Build plan + approval gate
|
|
86
|
+
|
|
87
|
+
Print a build plan using the template in `references/build-plan-format.md`. The plan must list:
|
|
88
|
+
|
|
89
|
+
- A one-line developer-facing summary of what will be built (the `PLAN:` line in the template).
|
|
90
|
+
- Lightning Type name and source (existing in local project · retrieved from org · newly created), plus the Apex class FQN it references.
|
|
91
|
+
- Files about to be created or modified, with absolute paths.
|
|
92
|
+
- Sub-skills that will run after approval.
|
|
93
|
+
- Validations that will run after generation.
|
|
94
|
+
|
|
95
|
+
The plan is read by the developer. Keep it concrete: name the artifacts, files, sub-skills, and validations.
|
|
96
|
+
|
|
97
|
+
**Print the plan in full, then proceed unless the user's next reply explicitly pushes back.** Explicit pushback = `no`, `stop`, `wait`, `change X`, `use Y instead`, or an equivalent rejection / revision request. Explicit approval (`yes`, `approve`, `go`, `looks good`, `ok`) is welcome but NOT required — silence, an unrelated follow-up, or the natural continuation of a single-turn eval all count as implicit approval. The plan being visible in the transcript is the invariant; blocking on interactive approval is not. If pushback arrives, revise the plan and re-print before moving on.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Phase 4 — Generation
|
|
102
|
+
|
|
103
|
+
Execute the sub-skill load order from the chosen path's row in the Phase 1 table. For each sub-skill:
|
|
104
|
+
|
|
105
|
+
1. Load the skill.
|
|
106
|
+
2. Execute the leaf skill's authoring workflow against the spec from Phase 3. The leaf skill is authoritative for its own deliverables.
|
|
107
|
+
3. Verify the outputs match what the build plan promised.
|
|
108
|
+
4. Checkpoint before invoking the next sub-skill.
|
|
109
|
+
|
|
110
|
+
**`new-lightning-type-with-widget` handoff contract:**
|
|
111
|
+
|
|
112
|
+
- Apex authors a class whose `@AuraEnabled` fields define the desired Lightning Type shape. Inner classes are used only for nested list-element types. Capture the **outer class FQN** (`<namespace>__<ClassName>`).
|
|
113
|
+
- The Custom Lightning Type references the outer class via `lightning:type: "@apexClassType/<namespace>__<ClassName>"`.
|
|
114
|
+
- Widget grounds on the outer class's `@AuraEnabled` fields and binds attributes via `{!$attrs.X}`.
|
|
115
|
+
- After the widget bundle is written, author the Lightning Type's renderer wiring per the **renderer.json wiring step** below.
|
|
116
|
+
|
|
117
|
+
**`existing-lightning-type-with-widget` handoff contract:**
|
|
118
|
+
|
|
119
|
+
- Hand the widget skill the Lightning Type `schema.json` path and the Apex class FQN captured in Phase 2. The widget skill derives its own `schema.json` from the Apex class's `@AuraEnabled` fields (see `platform-widget-generate/references/schema-from-lightning-type.md`).
|
|
120
|
+
- After the widget bundle is written, author the Lightning Type's renderer wiring per the **renderer.json wiring step** below. The Lightning Type `schema.json` is NOT modified (`lightning-type-unchanged` enforces this) — only `lightningDesktopGenAi/renderer.json` is written.
|
|
121
|
+
|
|
122
|
+
**Renderer.json wiring step (BOTH flows — never optional):**
|
|
123
|
+
|
|
124
|
+
**First, Read `platform-custom-lightning-type-generate/references/widget-rendition.md` (REQUIRED — do NOT skip; do not author `renderer.json` from memory or by copying an existing project sample, which may use a deprecated shape).**
|
|
125
|
+
|
|
126
|
+
After the widget bundle exists, author `<pkgDir>/lightningTypes/<TypeName>/lightningDesktopGenAi/renderer.json` using the **widget-rendition pattern** documented in `platform-custom-lightning-type-generate/references/widget-rendition.md`. The renderer file is a thin wrapper — its first child references the widget via `"definition": "@widget/c/<widgetName>"` and maps **every widget schema property** to the Lightning Type instance's matching attribute via `{!$attrs.<schemaPropertyName>}`. Do **NOT** duplicate the widget body inside `renderer.json`; the widget bundle is the single source of truth for the rendering tree.
|
|
127
|
+
|
|
128
|
+
Existing-renderer handling (`existing-lightning-type-with-widget` only): if `renderer.json` already exists at the target path, read it first.
|
|
129
|
+
|
|
130
|
+
- If it already references the same widget (same `@widget/c/<widgetName>`) with the same attribute mapping, leave it alone.
|
|
131
|
+
- If it references a **different** widget OR uses a custom-LWC root override (`c/<componentName>`), STOP and surface the conflict to the user before overwriting. Do not silently replace the user's existing rendition.
|
|
132
|
+
- If the file exists but is not a widget-rendition (e.g. property-level overrides only), surface that and ask whether to merge or replace.
|
|
133
|
+
|
|
134
|
+
Without this wiring the widget is unreachable from the Lightning Type — the widget bundle ships dead. `renderer-wires-widget` enforces existence and binding correctness.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Phase 5 — Validation gates
|
|
139
|
+
|
|
140
|
+
Read `references/validation-gates.md` and **run every gate**. The orchestrator runs cross-skill gates only — widget-bundle-internal checks (schema parse, root keys, leaf `lightning:type`, `{!$attrs.X}` resolution, `.uiwidget-meta.xml` well-formedness, `<UiWidgetBundle>` root, `<masterLabel>`, `<description>`, and `<widgetType>JSON</widgetType>`) are owned by `platform-widget-generate` and run as part of its own self-validation step.
|
|
141
|
+
|
|
142
|
+
**Hard — block on failure:**
|
|
143
|
+
|
|
144
|
+
1. `lightning-type-unchanged` — **`existing-lightning-type-with-widget` only.** Recompute SHA-256 of the on-disk Lightning Type `schema.json` and compare against the SHA captured in Phase 2. Mismatch = orchestrator silently edited the type.
|
|
145
|
+
2. `renderer-wires-widget` — **both paths.** Confirm `<pkgDir>/lightningTypes/<TypeName>/lightningDesktopGenAi/renderer.json` exists, parses as JSON, wires this widget via `componentOverrides["$"].definition === "@widget/c/<widgetName>"`, and `componentOverrides["$"].attributes` binds every widget schema property as `{!$attrs.<schemaPropertyName>}`. See "renderer.json wiring step" in Phase 4 and `validation-gates.md` for the required shape.
|
|
146
|
+
|
|
147
|
+
**Warn — advisory:**
|
|
148
|
+
|
|
149
|
+
1. `field-trace` — **both paths.** RUN the trace procedure in `references/validation-gates.md` (grep `@AuraEnabled` from the outer .cls, `jq` widget schema property keys, print both lists, classify INVENTED vs OMITTED). PRINT both lists in the gate report — asserting `pass` without printing the lists is a hard violation. Silent omissions (Apex field absent from widget AND absent from the Phase 3 `Properties omitted:` plan) warn.
|
|
150
|
+
2. `deploy-check` — **`new-lightning-type-with-widget` only.** RUN `sf project deploy --check-only --source-dir <pkgDir>/classes/<ClassName>.cls,<pkgDir>/lightningTypes/<TypeName>` and report the result. Reporting `pass` without running this command is a hard violation. See `validation-gates.md` for the "not yet deployed is not a valid skip reason" rule.
|
|
151
|
+
|
|
152
|
+
Report each gate result by name in Phase 6 (`pass`, `fail (<reason>)`, `warn (<reason>)`, `not run`). Do **not** summarize as "all passed" — list each gate explicitly.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Phase 6 — Summary
|
|
157
|
+
|
|
158
|
+
Report. The summary is read by the developer — list only the files actually written; group by bundle so the developer can locate them quickly.
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
Lightning Type + Widget Build Complete: <widgetName>
|
|
162
|
+
|
|
163
|
+
FILES GENERATED:
|
|
164
|
+
Widget bundle:
|
|
165
|
+
<pkgDir>/uiWidgets/<widgetName>/<widgetName>.json
|
|
166
|
+
<pkgDir>/uiWidgets/<widgetName>/schema.json
|
|
167
|
+
<pkgDir>/uiWidgets/<widgetName>/<widgetName>.uiwidget-meta.xml
|
|
168
|
+
|
|
169
|
+
Lightning Type bundle:
|
|
170
|
+
<pkgDir>/lightningTypes/<TypeName>/schema.json # only when newly created
|
|
171
|
+
<pkgDir>/lightningTypes/<TypeName>/lightningDesktopGenAi/renderer.json # always — wires the Lightning Type to the widget
|
|
172
|
+
|
|
173
|
+
Apex (only when newly created):
|
|
174
|
+
<pkgDir>/classes/<ClassName>.cls
|
|
175
|
+
<pkgDir>/classes/<ClassName>.cls-meta.xml
|
|
176
|
+
|
|
177
|
+
VALIDATIONS:
|
|
178
|
+
widget self-validation (platform-widget-generate gates): <pass | fail — see sub-skill report>
|
|
179
|
+
Lightning Type schema unchanged from before this run: <pass | fail | n/a (newly created)>
|
|
180
|
+
Lightning Type renderer wires this widget: <pass | fail (<reason>)>
|
|
181
|
+
widget↔apex field trace (INVENTED + OMITTED lists printed): <pass | warn (<reason>) | fail (invented: <list>)>
|
|
182
|
+
sf project deploy --check-only: <pass | warn | n/a (no new Apex or Lightning Type to deploy)>
|
|
183
|
+
|
|
184
|
+
NEXT STEPS:
|
|
185
|
+
- Deploy: sf project deploy start --source-dir <pkgDir>
|
|
186
|
+
- Preview: <preview-surface guidance>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Hard Rules (always apply)
|
|
192
|
+
|
|
193
|
+
1. **Plan-first, then proceed.** Print the full Phase 3 build plan before writing any file. If the next turn contains explicit rejection or a change request, stop and revise; otherwise continue to Phase 4. The invariant is the plan being visible in the transcript — not an interactive human approval — so this rule holds in manual chat, in agent-to-agent flows, and in single-turn eval runs where no follow-up user message arrives.
|
|
194
|
+
2. **No silent schema edits** to existing Lightning Types. Phase 5 `lightning-type-unchanged` enforces this for `existing-lightning-type-with-widget`.
|
|
195
|
+
3. **No silent Apex changes** to existing Apex. If Phase 4 needs to modify a pre-existing class, surface it in Phase 3. **A leaf skill that hits a shape gap mid-Phase-4 MUST stop and surface to the orchestrator instead of editing `.cls` directly** — Phase 3 covers gaps the orchestrator already knew about; this clause covers gaps discovered later by a leaf skill.
|
|
196
|
+
4. **No invented fields, no silent omissions.** Every `{!$attrs.X}` must trace to the widget `schema.json`, and the widget `schema.json` must be a subset of the Apex class's `@AuraEnabled` fields. Default disposition for every Apex field is **include**; omission requires the field to appear in the Phase 3 build plan's `Properties omitted:` section with a rationale the user has approved. `field-trace` prints both APEX_FIELDS and WIDGET_PROPS lists and warns on silent omissions. `List<InnerClass>` fields are NEVER candidates for silent omission.
|
|
197
|
+
5. **One clarification at most** when Lightning Type lookup is ambiguous.
|
|
198
|
+
6. **Always load the leaf skill** before generation. Do not author from memory.
|
|
199
|
+
7. **Out-of-scope types stop the orchestrator.** If Phase 2 discovers an object/JSON-based Lightning Type, route the user to `platform-custom-lightning-type-generate` and `platform-widget-generate` separately.
|
|
200
|
+
8. **Run gates, do not describe them.** Phase 5 gates are concrete checks/commands. Reporting `pass` without executing the gate is a hard violation; report `not run` instead.
|
|
201
|
+
9. **Lightning Type rendition is mandatory, never optional.** Both paths end with `<pkgDir>/lightningTypes/<TypeName>/lightningDesktopGenAi/renderer.json` wiring the Lightning Type to the widget via `@widget/c/<widgetName>` with attribute mapping per the widget-rendition pattern. Without this, the widget bundle ships dead. `renderer-wires-widget` enforces existence and binding.
|
|
202
|
+
10. **No shell metacharacters that trigger the Vibes safe-shell filter.** In every `Bash` tool call emitted by this orchestrator and by any leaf skill it invokes, do NOT use command substitution (`$(…)` or backticks), process substitution (`<(…)`, `>(…)`), brace expansion (`{a,b,c}` or `{1..N}`), or `eval` / `exec`. These patterns force manual approval even under Bypass mode and stall the eval. Instead: run separate commands (`mkdir -p a && mkdir -p b`, not `mkdir -p {a,b}`); print each intermediate value with its own command and reason about the result rather than capturing it (`jq … file` on its own, not `X=$(jq … file)`); use plain shell variables (`X=literal`) or here-strings when a value must be reused across commands.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Reference File Index
|
|
207
|
+
|
|
208
|
+
| File | When to read |
|
|
209
|
+
|------|--------------|
|
|
210
|
+
| `references/lightning-type-discovery.md` | Phase 2 — local-project scan, org retrieve, ambiguity handling, in-scope verification, and ensuring the backing Apex class is in the local project. |
|
|
211
|
+
| `references/build-plan-format.md` | Phase 3 — plan template the model fills before STOP. |
|
|
212
|
+
| `references/validation-gates.md` | Phase 5 — full hard / warn gate table with error→fix mapping. |
|
|
213
|
+
| `examples/existing-lightning-type-with-widget-prompt.md` | Phase 3 — before drafting the build plan, read this for a complete `existing-lightning-type-with-widget` walkthrough. |
|
|
214
|
+
| `examples/new-lightning-type-with-widget-prompt.md` | Phase 3 — before drafting the build plan, read this for a complete `new-lightning-type-with-widget` walkthrough. |
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Worked Example — Render an Existing Apex-Backed Lightning Type
|
|
2
|
+
|
|
3
|
+
## User prompt
|
|
4
|
+
|
|
5
|
+
> Build a widget for the OrderSummary Lightning Type — show order id, customer, total, and a list of line items.
|
|
6
|
+
|
|
7
|
+
## Walkthrough
|
|
8
|
+
|
|
9
|
+
**Phase 1 — Path selection.** The prompt names a Lightning Type (`OrderSummary`) and treats it as existing → pick the `existing-lightning-type-with-widget` path. Phase 4 will load `platform-widget-generate` only, after Phase 2 confirms the type is Apex-backed.
|
|
10
|
+
|
|
11
|
+
**Phase 2 — Lightning Type discovery.** Find first, verify after.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
$ rg -l 'lightning:type' force-app/**/lightningTypes/OrderSummary/
|
|
15
|
+
force-app/main/default/lightningTypes/OrderSummary/schema.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Found in the local project. Now verify in scope — read `schema.json`. Root is `"lightning:type": "@apexClassType/orders__OrderSummary"`. Apex-backed → continue. Capture path + SHA-256 + Apex class FQN `orders__OrderSummary` (outer-class form; an inner-class root like `orders__OrderResponses$CreateResult` is also in scope and would scope the trace to that inner class). Source = `existing in local project`.
|
|
19
|
+
|
|
20
|
+
> If the root had been `lightning__objectType` (object/JSON-based), the orchestrator would have stopped here and routed the user to use `platform-custom-lightning-type-generate` and `platform-widget-generate` separately.
|
|
21
|
+
|
|
22
|
+
**Phase 3 — Build plan.** Print:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
Lightning Type + Widget Build Plan: orderSummaryWidget
|
|
26
|
+
|
|
27
|
+
PLAN: Generate a widget that renders the existing OrderSummary Lightning Type.
|
|
28
|
+
|
|
29
|
+
LIGHTNING TYPE:
|
|
30
|
+
Name: OrderSummary
|
|
31
|
+
Source: existing in local project
|
|
32
|
+
Path: force-app/main/default/lightningTypes/OrderSummary/schema.json
|
|
33
|
+
Renderer (wires the Lightning Type to the widget): force-app/main/default/lightningTypes/OrderSummary/lightningDesktopGenAi/renderer.json
|
|
34
|
+
Schema fingerprint (captured before any sub-skill runs): <hex>
|
|
35
|
+
Apex class FQN: orders__OrderSummary
|
|
36
|
+
|
|
37
|
+
WIDGET:
|
|
38
|
+
Name: orderSummaryWidget
|
|
39
|
+
Output:
|
|
40
|
+
force-app/main/default/uiWidgets/orderSummaryWidget/orderSummaryWidget.json
|
|
41
|
+
force-app/main/default/uiWidgets/orderSummaryWidget/schema.json
|
|
42
|
+
force-app/main/default/uiWidgets/orderSummaryWidget/orderSummaryWidget.uiwidget-meta.xml
|
|
43
|
+
Schema source: derived from Apex class @AuraEnabled fields via the Lightning Type
|
|
44
|
+
Layout intent: card with header (id + customer), body (total + shipping-address fields), footer (line items list with forEach)
|
|
45
|
+
Properties omitted: lastUpdatedTime (audit field, not relevant to render — proposed omission)
|
|
46
|
+
|
|
47
|
+
SUB-SKILLS THAT WILL RUN:
|
|
48
|
+
platform-widget-generate
|
|
49
|
+
|
|
50
|
+
VALIDATIONS THAT WILL RUN AFTER GENERATION:
|
|
51
|
+
Widget bundle self-validation (run by platform-widget-generate):
|
|
52
|
+
- widget schema.json parses, root keys correct, every leaf has lightning:type
|
|
53
|
+
- every {!$attrs.X} (and {!$attrs.shippingAddress.city} for the singular nested address object) resolves
|
|
54
|
+
- <name>.uiwidget-meta.xml is well-formed XML, root is <UiWidgetBundle>, and declares <widgetType>JSON</widgetType>
|
|
55
|
+
Cross-skill checks (run by this orchestrator):
|
|
56
|
+
- lightning-type-unchanged: existing schema.json is byte-identical to the captured fingerprint
|
|
57
|
+
- renderer-wires-widget: renderer.json references @widget/c/orderSummaryWidget with one {!$attrs.<schemaPropertyName>} mapping per widget schema property
|
|
58
|
+
- field-trace: print @AuraEnabled fields, widget properties (with nested dot paths and list-item paths expanded), and the diff
|
|
59
|
+
|
|
60
|
+
----------------------------------------------------------------
|
|
61
|
+
STOP — wait for the user to Approve or Decline.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
User picks Approve.
|
|
65
|
+
|
|
66
|
+
**Phase 4 — Generation.** Load `platform-widget-generate`. Hand it the Lightning Type schema path, the Apex class FQN (`orders__OrderSummary`), and the widget name. The widget skill derives its `schema.json` from the Apex class's `@AuraEnabled` fields:
|
|
67
|
+
|
|
68
|
+
- Primitive fields → primitive `lightning:type`.
|
|
69
|
+
- Singular nested inner class (e.g. `Address shippingAddress`) → `lightning__objectType`; bound in the widget body via dot-notation `{!$attrs.shippingAddress.city}`, `{!$attrs.shippingAddress.zip}`.
|
|
70
|
+
- `List<LineItem> lineItems` → `lightning__listType`; iterated with `forEach`/`forItem` and bound via `{!$item.<innerField>}`.
|
|
71
|
+
|
|
72
|
+
The skill omits `lastUpdatedTime` per the build plan and writes the three widget files. Then author `force-app/main/default/lightningTypes/OrderSummary/lightningDesktopGenAi/renderer.json` using the widget-rendition pattern, binding each widget attribute via `{!$attrs.<schemaPropertyName>}`. (If `renderer.json` already exists referencing a different widget or a custom LWC, STOP and surface the conflict.)
|
|
73
|
+
|
|
74
|
+
**Phase 5 — Validation.** The widget skill reports its own self-validation results. This orchestrator runs:
|
|
75
|
+
|
|
76
|
+
- `lightning-type-unchanged` — confirms the Lightning Type was untouched.
|
|
77
|
+
- `renderer-wires-widget` — confirms the renderer points at this widget and binds every widget schema property.
|
|
78
|
+
- `field-trace` — prints APEX_FIELDS / WIDGET_PROPS / INVENTED / OMITTED. The omission of `lastUpdatedTime` is in the build plan and emits no warning.
|
|
79
|
+
|
|
80
|
+
**Phase 6 — Summary.** Print files generated and each validation result by name (`lightning-type-unchanged: pass`, `renderer-wires-widget: pass`, `field-trace: pass`), followed by the deploy command.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Worked Example — Create a New Apex-Backed Lightning Type With a Widget
|
|
2
|
+
|
|
3
|
+
## User prompt
|
|
4
|
+
|
|
5
|
+
> Generate a Lightning Type and a widget for an account briefing — fields: account name, owner, last activity date, top three open opportunities.
|
|
6
|
+
|
|
7
|
+
> Note: the user did not mention Apex. This orchestrator only supports Apex-backed Lightning Types, so the `new-lightning-type-with-widget` path implicitly engages `platform-apex-generate` because the new typed Lightning Type requires a backing Apex class. The orchestrator surfaces this Apex step in the Phase 3 build plan so the developer sees what it intends to do.
|
|
8
|
+
|
|
9
|
+
## Walkthrough
|
|
10
|
+
|
|
11
|
+
**Phase 1 — Path selection.** User asks for a new Lightning Type plus a widget. Pick the `new-lightning-type-with-widget` path: `platform-apex-generate` → `platform-custom-lightning-type-generate` → `platform-widget-generate`. Apex backing for the typed payload is implied; do not ask the user to confirm Apex is wanted.
|
|
12
|
+
|
|
13
|
+
**Phase 2 — Lightning Type discovery.** **Skipped.** The prompt is explicit about creating a new Lightning Type, so there is no existing schema to discover and no fingerprint to capture.
|
|
14
|
+
|
|
15
|
+
**Phase 3 — Build plan.** Print:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
Lightning Type + Widget Build Plan: accountBriefingWidget
|
|
19
|
+
|
|
20
|
+
PLAN: Create a new Apex class, Lightning Type, and widget for AccountBriefing.
|
|
21
|
+
|
|
22
|
+
LIGHTNING TYPE:
|
|
23
|
+
Name: AccountBriefing
|
|
24
|
+
Source: newly created
|
|
25
|
+
Path: force-app/main/default/lightningTypes/AccountBriefing/schema.json
|
|
26
|
+
Renderer (wires the Lightning Type to the widget): force-app/main/default/lightningTypes/AccountBriefing/lightningDesktopGenAi/renderer.json
|
|
27
|
+
Apex class FQN: c__AccountBriefing
|
|
28
|
+
|
|
29
|
+
APEX (only when creating a new Lightning Type — auto-engaged because this orchestrator only supports Apex-backed Lightning Types):
|
|
30
|
+
Class name: AccountBriefing
|
|
31
|
+
Class FQN: c__AccountBriefing
|
|
32
|
+
Shape: outer class with @AuraEnabled fields (accountName, ownerName, lastActivityDate, primaryContact: Contact, openOpportunities: List<OpenOpportunity>). Contact is an inner class for a singular nested object. OpenOpportunity is an inner class for nested list elements. The Apex shape itself is owned by platform-apex-generate.
|
|
33
|
+
Returns: typed payload shaped to AccountBriefing
|
|
34
|
+
|
|
35
|
+
WIDGET:
|
|
36
|
+
Name: accountBriefingWidget
|
|
37
|
+
Output:
|
|
38
|
+
force-app/main/default/uiWidgets/accountBriefingWidget/accountBriefingWidget.json
|
|
39
|
+
force-app/main/default/uiWidgets/accountBriefingWidget/schema.json
|
|
40
|
+
force-app/main/default/uiWidgets/accountBriefingWidget/accountBriefingWidget.uiwidget-meta.xml
|
|
41
|
+
Schema source: derived from Apex class @AuraEnabled fields via the Lightning Type
|
|
42
|
+
Layout intent: header card (name + owner + last activity + primary contact name/title via dot-notation), body list (top opportunities with forEach over List<OpenOpportunity>)
|
|
43
|
+
Properties omitted: none
|
|
44
|
+
|
|
45
|
+
SUB-SKILLS THAT WILL RUN:
|
|
46
|
+
platform-apex-generate
|
|
47
|
+
platform-custom-lightning-type-generate
|
|
48
|
+
platform-widget-generate
|
|
49
|
+
|
|
50
|
+
VALIDATIONS THAT WILL RUN AFTER GENERATION:
|
|
51
|
+
Widget bundle self-validation (run by platform-widget-generate):
|
|
52
|
+
- widget schema.json parses, root keys correct, every leaf has lightning:type
|
|
53
|
+
- every {!$attrs.X} (and {!$attrs.primaryContact.name} for the singular nested contact object, {!$item.X} inside forEach) resolves
|
|
54
|
+
- <name>.uiwidget-meta.xml is well-formed XML, root is <UiWidgetBundle>, and declares <masterLabel>, <description>, and <widgetType>JSON</widgetType>
|
|
55
|
+
Cross-skill checks (run by this orchestrator):
|
|
56
|
+
- renderer-wires-widget: renderer.json references @widget/c/accountBriefingWidget with one {!$attrs.<schemaPropertyName>} mapping per widget schema property
|
|
57
|
+
- field-trace: print @AuraEnabled fields from AccountBriefing plus inner classes Contact and OpenOpportunity, widget properties (with nested dot paths and list-item paths expanded), and the diff
|
|
58
|
+
- deploy-check: `sf project deploy --check-only --source-dir force-app/main/default/classes/AccountBriefing.cls,force-app/main/default/lightningTypes/AccountBriefing` (RUN the command — do not assume).
|
|
59
|
+
|
|
60
|
+
----------------------------------------------------------------
|
|
61
|
+
STOP — wait for the user to Approve or Decline.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
User picks Approve.
|
|
65
|
+
|
|
66
|
+
**Phase 4 — Generation.**
|
|
67
|
+
|
|
68
|
+
1. Load `platform-apex-generate`. Author `AccountBriefing.cls` (outer class with `@AuraEnabled` fields including `Contact primaryContact` as a singular nested object and `List<OpenOpportunity> openOpportunities` as a list-element collection; `Contact` and `OpenOpportunity` are inner classes). Capture FQN `c__AccountBriefing` (outer-class form for this example).
|
|
69
|
+
2. Load `platform-custom-lightning-type-generate`. Author `lightningTypes/AccountBriefing/schema.json` with `lightning:type: "@apexClassType/c__AccountBriefing"` (outer-class form).
|
|
70
|
+
3. Load `platform-widget-generate`. Pass the Lightning Type schema path, the Apex class FQN, and the widget name. The widget skill derives its `schema.json` and writes the three widget files. `Contact primaryContact` becomes a `lightning__objectType` property bound via `{!$attrs.primaryContact.name}` etc.; `List<OpenOpportunity>` becomes a `lightning__listType` property whose body iterates with `forEach`/`forItem` and binds `{!$item.<innerField>}`.
|
|
71
|
+
4. Author `lightningTypes/AccountBriefing/lightningDesktopGenAi/renderer.json` using the **widget rendition pattern** (see `platform-custom-lightning-type-generate/SKILL.md` step 4): a thin wrapper whose first child is `"definition": "@widget/c/accountBriefingWidget"` with attribute mappings binding each widget attribute to a Lightning Type schema property via `{!$attrs.<schemaPropertyName>}`.
|
|
72
|
+
|
|
73
|
+
**Phase 5 — Validation.** The widget skill reports its own self-validation results. This orchestrator runs `renderer-wires-widget`, `field-trace`, and `deploy-check` (the `sf project deploy --check-only ...` command above). Reporting `pass` without running `deploy-check` is a hard violation — report `not run` instead.
|
|
74
|
+
|
|
75
|
+
**Phase 6 — Summary.** Print each validation result by name and value (`renderer-wires-widget: pass`, `field-trace: pass`, `deploy-check: pass`), files generated, and the deploy command.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Build Plan Format
|
|
2
|
+
|
|
3
|
+
Use this template in Phase 3 to print the plan before the STOP gate. Fill every section. Do not abbreviate.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
Lightning Type + Widget Build Plan: <widgetName>
|
|
9
|
+
|
|
10
|
+
PLAN: <one line in developer-facing terms, e.g.:
|
|
11
|
+
"Generate a widget that renders the existing OrderStatusResponse Lightning Type"
|
|
12
|
+
OR
|
|
13
|
+
"Create a new Apex class, Lightning Type, and widget for AppointmentSummary">
|
|
14
|
+
|
|
15
|
+
LIGHTNING TYPE:
|
|
16
|
+
Name: <TypeName>
|
|
17
|
+
Source: <existing in local project | retrieved from org | newly created>
|
|
18
|
+
Path: <pkgDir>/lightningTypes/<TypeName>/schema.json
|
|
19
|
+
Renderer (wires the Lightning Type to the widget): <pkgDir>/lightningTypes/<TypeName>/lightningDesktopGenAi/renderer.json
|
|
20
|
+
Schema fingerprint (captured before any sub-skill runs): <hex SHA-256> # omit when source is "newly created"
|
|
21
|
+
Apex class FQN: <namespace>__<ClassName>[$<InnerClass>] # outer-class form, or inner-class form when the CLT roots on a specific inner class
|
|
22
|
+
|
|
23
|
+
APEX (only when creating a new Lightning Type — auto-engaged because this orchestrator only supports Apex-backed Lightning Types):
|
|
24
|
+
Class name: <ClassName>
|
|
25
|
+
Class FQN: <namespace>__<ClassName>
|
|
26
|
+
Shape: outer class with @AuraEnabled fields matching the desired Lightning Type payload. Inner classes are used for nested list-element types (e.g. List<OpenOpportunity>) and for singular nested objects (e.g. Address address). The Apex shape itself is owned by platform-apex-generate; this plan records the FQN and field summary, not the class body.
|
|
27
|
+
Returns: typed payload shaped to <TypeName>
|
|
28
|
+
|
|
29
|
+
WIDGET:
|
|
30
|
+
Name: <widgetName>
|
|
31
|
+
Output:
|
|
32
|
+
<pkgDir>/uiWidgets/<widgetName>/<widgetName>.json
|
|
33
|
+
<pkgDir>/uiWidgets/<widgetName>/schema.json
|
|
34
|
+
<pkgDir>/uiWidgets/<widgetName>/<widgetName>.uiwidget-meta.xml
|
|
35
|
+
Schema source: <derived from Apex class @AuraEnabled fields via the Lightning Type | derived from prompt fields>
|
|
36
|
+
Layout intent: <one-line description of the widget composition>
|
|
37
|
+
Properties omitted: <list any Apex class fields the widget intentionally drops, e.g. lastUpdatedTime, audit fields — or "none">
|
|
38
|
+
|
|
39
|
+
SUB-SKILLS THAT WILL RUN:
|
|
40
|
+
<list per the chosen path's row in SKILL.md — skill IDs only>
|
|
41
|
+
|
|
42
|
+
VALIDATIONS THAT WILL RUN AFTER GENERATION:
|
|
43
|
+
Widget bundle self-validation (run by platform-widget-generate):
|
|
44
|
+
- widget schema.json parses and has the required root keys
|
|
45
|
+
- every leaf in properties has a lightning:type
|
|
46
|
+
- every {!$attrs.X} (and {!$attrs.<outer>.<inner>} for nested objects, {!$item.X} inside forEach) resolves
|
|
47
|
+
- <name>.uiwidget-meta.xml is well-formed XML, root is <UiWidgetBundle>, and declares <widgetType>JSON</widgetType>
|
|
48
|
+
Cross-skill checks (run by this orchestrator):
|
|
49
|
+
- lightning-type-unchanged: when an existing Lightning Type was used as input, its schema.json is byte-identical to the version captured before this run
|
|
50
|
+
- renderer-wires-widget: the Lightning Type's renderer.json exists and references this widget via `@widget/c/<widgetName>`, with one {!$attrs.<schemaPropertyName>} mapping per widget schema property
|
|
51
|
+
- field-trace (advisory): print the @AuraEnabled fields from the outer Apex class plus every inner class referenced as a singular nested object or List<InnerClass>; print the widget schema properties (expanded for nested objects and list items); print the diff. Invented widget fields fail; omissions not declared above warn.
|
|
52
|
+
- deploy-check (advisory, new-type path only): `sf project deploy --check-only --source-dir <pkgDir>/classes/<ClassName>.cls,<pkgDir>/lightningTypes/<TypeName>` is run and the result reported.
|
|
53
|
+
|
|
54
|
+
----------------------------------------------------------------
|
|
55
|
+
STOP — wait for the user to Approve or Decline.
|
|
56
|
+
The host surface may render Approve/Decline as buttons; a text reply ("approve", "yes", "go") is also accepted.
|
|
57
|
+
A Decline (or edits to the plan) reprints the plan; the orchestrator does not write any file until an explicit Approve.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Notes for the model
|
|
63
|
+
|
|
64
|
+
- If the user replies with edits or declines, revise the plan and reprint it. Do not assume which sections changed.
|
|
65
|
+
- Approval applies only to the plan as printed. If the user later asks for additional widgets or Lightning Types, start a new planning cycle for the new ask.
|
|
66
|
+
- Do not print this plan inside a code fence that the user might mistake for output. The plan is conversational, not a file.
|
|
67
|
+
- "Properties omitted" makes intentional drops explicit. Examples of fields that often do not belong on a render surface: `lastUpdatedTime`, `createdBy`, audit timestamps, internal IDs.
|