Compare commits

...

16 Commits

Author SHA1 Message Date
nkurapati-sfdx
756518d0a1
Merge 98a5200c50 into 84ee08cd47 2026-05-12 18:37:38 +05:30
sparamesh-personal
84ee08cd47
@W-21860796 Adds media-management skill with download script (#238)
* @W-21860796 Adds media-management skill with download script

* chore: retrigger CLA check

* chore: retrigger CLA validation

* fix: use relative path for download script

* fix: add metadata block and quote description to pass skill validation

---------

Co-authored-by: Shruthi Paramesh <281795489+sparamesh-personal@users.noreply.github.com>
Co-authored-by: Hemant Singh Bisht <hsinghbisht@salesforce.com>
2026-05-08 00:54:31 +05:30
npiccolo
9b9161959b
feat: (developing-agentforce) use sf org create agent-user command (#234)
* feat(developing-agentforce): use sf org create agent-user command

Replace the legacy multi-step Einstein Agent User creation flow
(profile query + record creation + permset assignment) with the
new unified `sf org create agent-user` command available in SF CLI
2.131.7+. The new command works across all org types and auto-assigns
required permission sets.

Closes W-22190552

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update skills/developing-agentforce/references/agent-user-setup.md

Co-authored-by: Steve Hetzel <shetzel@salesforce.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Hemant Singh Bisht <hsinghbisht@salesforce.com>
Co-authored-by: Steve Hetzel <shetzel@salesforce.com>
2026-05-08 00:30:23 +05:30
chandresh-patelsf
9edf77bd6e
Update getting datacloud schema (#243)
* fix: update getting-datacloud-schema skill path references

Replace relative ./scripts/ paths with <skill_dir>/scripts/ to correctly resolve script location regardless of working directory. Remove metadata version field from frontmatter.

* fix: restore metadata version field in getting-datacloud-schema skill

* fix: move requirements.txt to project root in directory structure diagrams
2026-05-07 11:11:09 +05:30
Hemant Singh Bisht
98a5200c50
Merge branch 'develop' into create-b2b-open-code-component-skill 2026-04-30 17:49:02 +05:30
nkurapati
d08549956f adding rule to for agent 2026-04-11 21:12:57 +05:30
nkurapati
893aaecead fix skill validations errors 2026-04-10 23:03:16 +05:30
nkurapati
de106d7db8 revert manifest changes 2026-04-10 22:35:26 +05:30
nkurapati
57b4dcd3a6 reduce the scope of skill 2026-04-10 22:28:01 +05:30
nkurapati
a17ce24147 refactor skill 2026-04-10 22:25:34 +05:30
nkurapati
714f32e947 Refine B2B Commerce Open Code Integration skill
- Fix empty Specification heading and add missing allowed-tools to frontmatter
- Add internet connectivity requirement and rollback safety guidance
- Replace hardcoded /tmp/ path with .tmp/ for cross-platform compatibility
- Add repo structure verification after clone
- Condense use case workflows by 50 lines using task sequence notation
- Add example interaction showing agent dialogue and progress updates
2026-04-10 22:25:34 +05:30
nkurapati
3e6485001a Add B2B Commerce Open Code Integration skill 2026-04-10 22:25:34 +05:30
nkurapati
133aafe7a3 Refactor Commerce B2B skill: rename and flatten directory structure
- Rename skill from create-b2b-commerce-storefront to creating-b2b-commerce-store to better reflect what users actually create (the Store, not the Storefront)
- Flatten directory from skills/commerce/create-b2b-commerce-storefront/ to skills/creating-b2b-commerce-store/ to match repository pattern
- Remove old prompts and rules consolidated into skill
- Update manifest.json with new skill name and paths
2026-04-10 22:25:34 +05:30
nkurapati
6c46507a0b Refactor Commerce B2B skill: rename and flatten directory structure
- Rename skill from create-b2b-commerce-storefront to creating-b2b-commerce-store to better reflect what users actually create (the Store, not the Storefront)
- Flatten directory from skills/commerce/create-b2b-commerce-storefront/ to skills/creating-b2b-commerce-store/ to match repository pattern
- Remove old prompts and rules consolidated into skill
- Remove Commerce prompt and rule entries from manifest.json (consolidated into skill)
2026-04-10 22:25:34 +05:30
nkurapati
97390ed880 update rule and sf commands 2026-04-10 22:25:34 +05:30
nkurapati
3c36149e62 Add instructions to create commerce b2b store from vibes 2026-04-10 22:25:34 +05:30
10 changed files with 401 additions and 138 deletions

View File

@ -122,7 +122,11 @@ sf data query --json -q "SELECT Username FROM User WHERE Profile.UserLicense.Nam
**If results are returned:** Ask which username to use. Record choice in the Agent Spec Configuration section. Verify permissions per [Agent User Setup & Permissions](agent-user-setup.md).
**If no results are returned:** STOP. Do NOT invent a username. Ask if you should create a new user, then read [Agent User Setup & Permissions](agent-user-setup.md) for user creation instructions.
**If no results are returned:** STOP. Do NOT invent a username. Ask if you should create a new user. If yes, use:
```bash
sf org create agent-user --target-org TARGET_ORG --first-name <AgentName> --last-name Agent --json
```
Then read the generated username from `result.username`. See [Agent User Setup & Permissions](agent-user-setup.md) for the complete provisioning workflow.
**WRONG:** Fabricating a username when query returns nothing
```

View File

@ -33,32 +33,23 @@ sf data query --json \
-o TARGET_ORG
# Step 2: Create Einstein Agent User (2 minutes)
# Get Profile ID (read result.records[0].Id from JSON response)
sf data query --json \
--query "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'" \
-o TARGET_ORG
# Use the new dedicated command — works in all org types (scratch, sandbox, production)
# Automatically assigns Einstein Agent User profile + AgentforceServiceAgentBase,
# AgentforceServiceAgentUser, and EinsteinGPTPromptTemplateUser permission sets
sf org create agent-user \
--target-org TARGET_ORG \
--first-name <AgentName> \
--last-name Agent
# For Production/Sandbox (non-scratch org):
# Use the ProfileId from the query above
sf data create record --json --sobject User --values \
"Username=<agent_name>_user@<orgId>.ext \
LastName=<AgentName> \
Email=admin@example.com \
Alias=<alias> \
TimeZoneSidKey=America/Los_Angeles \
LocaleSidKey=en_US \
EmailEncodingKey=UTF-8 \
ProfileId=<PROFILE_ID> \
LanguageLocaleKey=en_US" \
-o TARGET_ORG
# For Scratch Orgs (use user definition file):
# sf org create user --definition-file config/einstein-agent-user.json -o TARGET_ORG
# Capture the username from the command output (result.username) — it is generated
# with a unique GUID suffix, e.g. agent_agent@00Dxx.org.salesforce.com-abc123
# Step 3: Assign System Permission Set (1 minute)
# NOTE: AgentforceServiceAgentUser is already assigned by sf org create agent-user.
# This step is only needed if you created the user manually (legacy method).
sf org assign permset --json \
--name AgentforceServiceAgentUser \
--on-behalf-of <agent_name>_user@<orgId>.ext \
--on-behalf-of <agent_name_from_output> \
-o TARGET_ORG
# Step 4: Deploy Custom Permission Set (3 minutes)
@ -102,11 +93,12 @@ sf agent activate --json \
```
Critical notes:
- For **scratch orgs**, use `sf org create user --definition-file`
- For **production/sandbox**, use `sf data create record` as shown above
- `sf org create user` only works in scratch orgs — it will fail in production/sandbox
- `sf org create agent-user` works in **all org types** (scratch, sandbox, production) — use it instead of the legacy `sf org create user` or `sf data create record` approach
- The command auto-assigns `AgentforceServiceAgentBase`, `AgentforceServiceAgentUser`, and `EinsteinGPTPromptTemplateUser` — no separate permset assignment needed
- The command may exit non-zero with `PermissionSetAssignmentError` if a permset license is exhausted, **even when the user was created successfully**. Always inspect `result.username` and `result.permissionSetErrors[]` from the JSON output. If the only failure is `EinsteinGPTPromptTemplateUser` and your agent has no Prompt Template actions, you can proceed. Otherwise, free a license (or use `--base-username` to retry against a different license pool) before continuing.
- Capture the generated username from the command output (`result.username`) and use it for `default_agent_user`
- Always test with preview BEFORE publishing to avoid version management overhead
- Assign `AgentforceServiceAgentUser` BEFORE publishing to prevent "Internal Error"
- Assign any custom permission sets (`{AgentName}_Access`) BEFORE publishing to prevent "Internal Error"
- Publishing does NOT activate — you must run `sf agent activate` separately
---
@ -117,12 +109,6 @@ Critical notes:
Service agents need a dedicated service account with consistent permissions.
**Get Org ID first** (needed for username format):
```bash
sf org display --json -o TARGET_ORG
# Read result.id from the JSON response
```
**Query existing Einstein Agent Users** (skip creation if one exists):
```bash
sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true" -o TARGET_ORG
@ -130,58 +116,30 @@ sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Prof
**Create the user** (if none exists):
1. Get the Einstein Agent User profile ID:
```bash
sf data query --json --query "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'" -o TARGET_ORG
```
Use the dedicated command — works in all org types (scratch, sandbox, production):
2. Create a user definition file (`config/einstein-agent-user.json`):
```json
{
"Username": "{agent_name}_agent@{orgId}.ext",
"LastName": "{AgentName} Agent",
"Email": "placeholder@example.com",
"Alias": "agntuser",
"ProfileId": "<profile-id-from-step-1>",
"TimeZoneSidKey": "America/Los_Angeles",
"LocaleSidKey": "en_US",
"EmailEncodingKey": "UTF-8",
"LanguageLocaleKey": "en_US",
"UserPermissionsKnowledgeUser": true
}
```
```bash
sf org create agent-user \
--target-org TARGET_ORG \
--first-name <AgentName> \
--last-name Agent
```
3. Create the user:
This command:
- Creates a user with the "Einstein Agent User" profile
- Automatically assigns `AgentforceServiceAgentBase`, `AgentforceServiceAgentUser`, and `EinsteinGPTPromptTemplateUser` permission sets
- Returns a unique generated username in `result.username` — record this for `default_agent_user`
**Option A: Scratch Org (Definition File)**
```bash
sf org create user --json \
--definition-file config/einstein-agent-user.json \
-o TARGET_ORG
```
Optional flags:
- `--base-username <email>` — sets the base portion of the username (a unique suffix is always appended)
- `--json` — output as JSON for scripting
**Option B: Production/Sandbox (Direct Record Creation)**
```bash
# Get Profile ID first
# Get Profile ID (read result.records[0].Id from JSON response)
sf data query --json \
--query "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'" \
-o TARGET_ORG
**Verify creation:**
```bash
sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true ORDER BY CreatedDate DESC LIMIT 5" -o TARGET_ORG
```
# Create user directly (use ProfileId from query above)
sf data create record --json --sobject User --values \
"Username='{agent_name}_agent@{orgId}.ext' LastName='{AgentName} Agent' Email='placeholder@example.com' Alias='agntuser' ProfileId='<PROFILE_ID>' TimeZoneSidKey='America/Los_Angeles' LocaleSidKey='en_US' EmailEncodingKey='UTF-8' LanguageLocaleKey='en_US'" \
-o TARGET_ORG
```
**Note**: `sf org create user` only works in scratch orgs. For production/sandbox, use `sf data create record`. Attempting `sf org create user` in a non-scratch org fails with an authorization error.
4. Verify creation:
```bash
sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Username = '{agent_name}_agent@{orgId}.ext'" -o TARGET_ORG
```
**Username format**: `{agent_name}_agent@{orgId}.ext` (production) or `{agent_name}.{suffix}@{orgfarm}.salesforce.com` (dev/scratch). Always query the target org to confirm the exact format.
**Note**: The generated username has a GUID suffix for global uniqueness (e.g. `agentname_agent@orgid.salesforce.com-abc123`). Always read the username from command output rather than constructing it manually.
---
@ -189,18 +147,22 @@ sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Prof
Critical: Must be assigned BEFORE publishing the agent. Without it, publish fails with "Internal Error".
**If you used `sf org create agent-user` (recommended):** `AgentforceServiceAgentUser` is assigned automatically — skip to Step 3.
**If you created the user manually (legacy):**
Via Setup UI:
1. Setup > Permission Sets > search "AgentforceServiceAgentUser"
2. Manage Assignments > Add Assignments > select the Einstein Agent User > Save
Via CLI:
```bash
sf org assign permset --json --name AgentforceServiceAgentUser --on-behalf-of "{agent_name}_agent@{orgId}.ext" -o TARGET_ORG
sf org assign permset --json --name AgentforceServiceAgentUser --on-behalf-of "{agent_name_from_output}" -o TARGET_ORG
```
Verify assignment:
```bash
sf data query --json --query "SELECT Id, PermissionSet.Name FROM PermissionSetAssignment WHERE Assignee.Username = '{agent_name}_agent@{orgId}.ext' AND PermissionSet.Name = 'AgentforceServiceAgentUser'" -o TARGET_ORG
sf data query --json --query "SELECT Id, PermissionSet.Name FROM PermissionSetAssignment WHERE Assignee.Username = '{agent_name_from_output}' AND PermissionSet.Name = 'AgentforceServiceAgentUser'" -o TARGET_ORG
```
---
@ -460,9 +422,9 @@ Checklist:
- **Prevention:** Deploy → Test → Publish workflow (Step 6.1-6.3)
- **Result:** No version management overhead during development
### 4. Wrong User Creation Command
- **Cause:** Using `sf org create user` in non-scratch orgs
- **Prevention:** Step 1 provides correct commands for each org type (Option A vs B)
### 4. Wrong User Creation Command (Legacy)
- **Cause:** Using `sf org create user` in non-scratch orgs, or manually constructing user records with `sf data create record`
- **Prevention:** Use `sf org create agent-user --target-org TARGET_ORG` — works in all org types and auto-assigns required permission sets
- **Result:** User created successfully without authorization errors
### 5. Auto-Generated Permission Set Gaps
@ -486,7 +448,7 @@ Checklist:
| "invocable action does not exist" | Apex class not in custom PS (auto-generated PS incomplete) | Create custom `{AgentName}_Access` with all `<classAccesses>` (Step 3) |
| "Invalid default_agent_user" | Username typo or user not active | Query Einstein Agent Users, verify exact username + `IsActive = true` |
| Agent runs but returns wrong data | Employee agent using wrong user context | Verify `agent_type` — Service agents use dedicated user, Employee agents use logged-in user |
| `sf org create user` fails | Used in production/sandbox org | Use `sf data create record` instead (Step 1, Option B) |
| `sf org create user` fails | Used in production/sandbox org | Use `sf org create agent-user --target-org TARGET_ORG` instead (Step 1) |
---
@ -526,4 +488,6 @@ Checklist:
---
*Validated against: ORM1, ORM2, AutomotiveSupport, SalesforceProductAssistant agents. Last validated: 2026-03-07.*
*Validated against: ORM1, ORM2, AutomotiveSupport, SalesforceProductAssistant agents. Last validated: 2026-03-07.
Updated to use `sf org create agent-user` (SF CLI 2.131.7+)
2026-04-30.*

View File

@ -331,53 +331,27 @@ If `TotalLicenses > UsedLicenses`, a license is available and a new Einstein Age
### Creating an Einstein Agent User
#### Step 1: Query for the Einstein Agent User profile ID
Use the dedicated command — works in all org types (scratch, sandbox, production). It automatically assigns the Einstein Agent User profile and the required permission sets (`AgentforceServiceAgentBase`, `AgentforceServiceAgentUser`, `EinsteinGPTPromptTemplateUser`).
```bash
sf data query --json -q "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'"
sf org create agent-user \
--target-org <TARGET_ORG> \
--first-name <AgentName> \
--last-name Agent \
--json
```
#### Step 2: Create a User import JSON file (e.g., `data-import/User.json`)
Optional: `--base-username <email>` sets the base portion of the username (a unique suffix is always appended).
```json
{
"records": [
{
"attributes": {
"type": "User",
"referenceId": "AgentUserRef1"
},
"ProfileId": "<PROFILE_ID_FROM_STEP_1>",
"Username": "<UNIQUE_USERNAME>",
"Alias": "AgntUsr",
"CommunityNickname": "Agent User<UNIQUE_STRING>",
"Email": "noreply@example.com",
"FirstName": "Agent",
"LastName": "User",
"IsActive": true,
"ForecastEnabled": false,
"EmailEncodingKey": "UTF-8",
"LanguageLocaleKey": "en_US",
"LocaleSidKey": "en_US",
"TimeZoneSidKey": "America/Los_Angeles"
}
]
}
```
**Capture the generated username** from `result.username` in the output — use it as `default_agent_user` in the `.agent` config.
#### Step 3: Import the user record
```bash
sf data import tree --json --files data-import/User.json
```
#### Step 4: Verify the user was created
#### Verify the user was created
```bash
sf data query --json -q "SELECT Username FROM User WHERE Profile.UserLicense.Name = 'Einstein Agent' AND IsActive = true LIMIT 5"
```
After creating the user, continue with permission setup in [Agent User Setup & Permissions](agent-user-setup.md).
After creating the user, continue with custom permission set setup in [Agent User Setup & Permissions](agent-user-setup.md).
---

View File

@ -83,8 +83,8 @@ sf data-code-extension function init --package-dir <directory>
my-transform/ # Project root
├── payload/ # CRITICAL: This is what --package-dir must point to for deploy
│ ├── entrypoint.py # Main transformation code
│ ├── requirements.txt # Python dependencies
│ └── config.json # Code extension configuration
├── requirements.txt # Python dependencies
└── README.md
```

View File

@ -139,8 +139,8 @@ After `init`, you'll have:
my-transform/
├── payload/
│ ├── entrypoint.py # Your transformation code
── config.json # Permissions and configuration
│ └── requirements.txt # Python dependencies
── config.json # Permissions and configuration
├── requirements.txt # Python dependencies
└── README.md
```

View File

@ -219,8 +219,8 @@ sf data-code-extension script scan --entrypoint ./payload/entrypoint.py
my-project/
├── payload/
│ ├── entrypoint.py # Main code
── config.json # Auto-generated permissions
│ └── requirements.txt # Auto-generated dependencies
── config.json # Auto-generated permissions
├── requirements.txt # Auto-generated dependencies
└── README.md
```

View File

@ -0,0 +1,73 @@
---
name: generating-images
description: "Generates high-fidelity visual assets, logos, and UI mockups using the media-management MCP server. Trigger this skill whenever the user asks to generate an image, create a logo, produce a hero banner, design a UI icon, or build a visual asset. It is explicitly designed to handle technical specifications including file formats (PNG, JPEG, WEBP), specific dimensions (e.g. 1024x1024), and transparency requirements. Use this skill when the user needs to integrate generated imagery into application code or web pages. It ensures consistent output quality and provides a standardized SVG fallback if the generation tool is unavailable."
metadata:
version: "1.0"
---
# Generating Images
## Goal
To programmatically generate, download, and preview visual assets requested by the user, ensuring specific format and quality standards are met while providing a robust fallback mechanism.
## Workflow
1. Check if the `media-management` MCP server is configured and its `create_image` tool is available.
2. If available, use `create_image` to generate the image.
3. If not available, use the placeholder fallback below.
## MCP: media-management
**Tool:** `create_image`
Check your available tools. If `create_image` is present, use it as the primary image generation method — pass the natural language prompt and applicable parameters from the table below. (`media-management` here refers to the MCP server name, not this skill.)
If `create_image` is not in your tool list, the `media-management` MCP is not configured — use the placeholder fallback below.
## Image Generation Parameters
Use these defaults unless the user specifies otherwise:
| Parameter | Default | Options |
|---|---|---|
| `model` | `Standard` | `Standard`, `Premium` |
| `size` | `auto` | `auto`, `1024x1024`, `1536x1024`, `1024x1536` (pick closest to user-requested size) |
| `quality` | `medium` | `low`, `medium`, `high` |
| `outputCompression` | `75` | `0100` (webp/jpeg only) |
| `outputFormat` | `webp` | `webp`, `jpeg`, `png` |
| `background` | `auto` | `auto`, `transparent`, `opaque` |
**Format rule:** If `outputFormat` is `png`, set `outputCompression` to `100`.
## After Successful Generation
Run `download-image.sh` (located in this skill's `scripts/` directory) to download and preview the image:
```bash
bash scripts/download-image.sh \
--url "<image_url_from_response>" \
--id "<responseId>" \
--format "<outputFormat>" \
--preview
```
The script handles credential retrieval, download, and VS Code preview. Pass `--output-dir <dir>` to override the default `generatedimages/` directory.
**Never resize or post-process the generated image with external tools.** To control display dimensions, use CSS properties (e.g. `width`, `height`, `object-fit`) at the point of use.
## Fallback: Use placeholder URL
If image generation fails or is not enabled, return the following URL as the image source — do not download it, do not save it locally:
```
https://cdn.scs.static.lightning.force.com/content/assets/d5222d4a11e6c2b735152d7eea824ce4/placeholder.svg
```
Use this URL directly wherever the image is referenced in code (e.g. as a `src` attribute or CSS `url()`).
## Placeholder Policy
There is only one placeholder URL. Do not download it, modify it, or generate alternative placeholders using Python, ImageMagick, or any other tool.
If the user requests a placeholder of a specific size or format, inform them that only this placeholder URL is available and direct them to use CSS properties (e.g. `width`, `height`, `object-fit`) to scale it at the point of use.

View File

@ -0,0 +1,84 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<EOF
Usage: $(basename "$0") --url <image_url> --id <response_id> --format <output_format> [--output-dir <dir>] [--preview]
Required:
--url URL of the generated image to download
--id Response ID used as the output filename
--format Output format (webp, jpeg, png)
Optional:
--output-dir Directory to save the image (default: generatedimages)
--preview Open the image in VS Code after download
EOF
exit 1
}
OUTPUT_DIR="generatedimages"
PREVIEW=false
URL=""
RESPONSE_ID=""
FORMAT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--url) URL="$2"; shift 2 ;;
--id) RESPONSE_ID="$2"; shift 2 ;;
--format) FORMAT="$2"; shift 2 ;;
--output-dir) OUTPUT_DIR="$2"; shift 2 ;;
--preview) PREVIEW=true; shift ;;
*) usage ;;
esac
done
if [[ -z "$URL" || -z "$RESPONSE_ID" || -z "$FORMAT" ]]; then
usage
fi
case "$FORMAT" in
webp|jpeg|png) ;;
*) echo "Error: invalid format '$FORMAT'. Must be webp, jpeg, or png." >&2; exit 1 ;;
esac
if [[ "$RESPONSE_ID" == */* || "$RESPONSE_ID" == *..* ]]; then
echo "Error: invalid response ID '$RESPONSE_ID'. Must not contain '/' or '..'." >&2
exit 1
fi
if [[ ! "$URL" =~ ^https:// ]]; then
echo "Error: URL must start with https://" >&2
exit 1
fi
TARGET_ORG=$(sf config get target-org --json | jq -r '.result[0].value')
if [[ -z "$TARGET_ORG" || "$TARGET_ORG" == "null" ]]; then
echo "Error: no target-org configured. Run 'sf config set target-org <org>'" >&2
exit 1
fi
ACCESS_TOKEN=$(sf org display --target-org "$TARGET_ORG" --json | jq -r '.result.accessToken')
if [[ -z "$ACCESS_TOKEN" || "$ACCESS_TOKEN" == "null" ]]; then
echo "Error: failed to retrieve access token for org '$TARGET_ORG'" >&2
exit 1
fi
mkdir -p "$OUTPUT_DIR"
OUTPUT_FILE="${OUTPUT_DIR}/${RESPONSE_ID}.${FORMAT}"
if ! curl -fsS -H "Authorization: Bearer $ACCESS_TOKEN" -o "$OUTPUT_FILE" -- "$URL"; then
rm -f "$OUTPUT_FILE"
echo "Error: failed to download image from $URL" >&2
exit 1
fi
echo "$OUTPUT_FILE"
if [[ "$PREVIEW" == true ]]; then
code "$OUTPUT_FILE"
fi

View File

@ -67,30 +67,28 @@ sf org login web --alias <org_alias>
### Step 3a: Execute DLO Schema Script
Use the Python script to retrieve DLO information:
The Python scripts are bundled with this skill. They live in the `scripts/` subdirectory of the same directory that contains this SKILL.md file. Use the absolute path to that directory — do NOT use `./scripts/` as that resolves relative to the current working directory, not the skill directory.
**To list all DLOs:**
```bash
python3 ./scripts/get_dlo_schema.py <org_alias>
python3 <skill_dir>/scripts/get_dlo_schema.py <org_alias>
```
**To get specific DLO schema:**
```bash
python3 ./scripts/get_dlo_schema.py <org_alias> <dlo_name>
python3 <skill_dir>/scripts/get_dlo_schema.py <org_alias> <dlo_name>
```
### Step 3b: Execute DMO Schema Script
Use the Python script to retrieve DMO information:
**To list all DMOs:**
```bash
python3 ./scripts/get_dmo_schema.py <org_alias>
python3 <skill_dir>/scripts/get_dmo_schema.py <org_alias>
```
**To get specific DMO schema:**
```bash
python3 ./scripts/get_dmo_schema.py <org_alias> <dmo_name>
python3 <skill_dir>/scripts/get_dmo_schema.py <org_alias> <dmo_name>
```
### Step 4: Present Results
@ -227,7 +225,7 @@ User: "Show me all DLOs in afvibe org"
Response:
1. Run sf org list to discover connected org alias
2. Authenticate to afvibe
3. Run: python3 ./scripts/get_dlo_schema.py afvibe
3. Run: python3 <skill_dir>/scripts/get_dlo_schema.py afvibe
4. Display formatted list of DLOs
```
@ -238,7 +236,7 @@ User: "Get the schema for Employee__dll in afvibe"
Response:
1. Run sf org list to discover connected org alias
2. Authenticate to afvibe
3. Run: python3 ./scripts/get_dlo_schema.py afvibe Employee__dll
3. Run: python3 <skill_dir>/scripts/get_dlo_schema.py afvibe Employee__dll
4. Display field schema with types and metadata
```
@ -261,7 +259,7 @@ User: "Show me all DMOs in afvibe org"
Response:
1. Run sf org list to discover connected org alias
2. Authenticate to afvibe
3. Run: python3 ./scripts/get_dmo_schema.py afvibe
3. Run: python3 <skill_dir>/scripts/get_dmo_schema.py afvibe
4. Display formatted list of DMOs
```
@ -272,7 +270,7 @@ User: "Get the schema for Individual__dlm in afvibe"
Response:
1. Run sf org list to discover connected org alias
2. Authenticate to afvibe
3. Run: python3 ./scripts/get_dmo_schema.py afvibe Individual__dlm
3. Run: python3 <skill_dir>/scripts/get_dmo_schema.py afvibe Individual__dlm
4. Display field schema with types and metadata
```

View File

@ -0,0 +1,166 @@
---
name: integrating-b2b-commerce-open-code-components
description: Integrate Salesforce B2B Commerce open source components from GitHub into B2B Commerce stores. Use when users mention "integrate open code components", "open source B2B commerce", "add open code components", "forcedotcom/b2b-commerce-open-source-components", or want to add open source commerce components to their store. Copies all components and labels so they become available in Experience Builder.
license: Apache-2.0
compatibility: Requires Salesforce CLI (sf), Git, B2B Commerce license, Experience Builder access, and internet connectivity
allowed-tools: Bash Read Write
metadata:
author: afv-library
version: "1.0"
---
## When to Use This Skill
Use this skill when you need to:
- Integrate all open source B2B Commerce components into a store
- Add open source components to a new or existing B2B Commerce store
- Make open code components available in Experience Builder
## Rules
1. **Always explain before executing.** Before running any command, you MUST tell the user what the command does and why you are running it. Never just show a raw command and ask for permission. The user should be able to read your explanation and understand the purpose before approving.
## Overview
This skill copies all open source B2B Commerce components from the official Salesforce repository (https://github.com/forcedotcom/b2b-commerce-open-source-components) into a B2B Commerce store's site metadata. After integration, the components appear in the Experience Builder component palette.
---
## Startup Flow
When this skill is triggered, perform these checks automatically before copying.
### Check 1: Open Source Repository
Verify the repo is cloned at `.tmp/b2b-commerce-open-source-components`:
1. **If directory does not exist:** Tell user: "I'm cloning the official B2B Commerce open source components repository from GitHub into a local `.tmp/` folder. This gives us access to all the open code components."
Then run: `git clone https://github.com/forcedotcom/b2b-commerce-open-source-components .tmp/b2b-commerce-open-source-components`
2. **If directory exists** and contains `force-app/main/default/sfdc_cms__lwc` and `sfdc_cms__label`, present options:
> "Open source repository is already cloned. How would you like to proceed?"
> 1. **Reuse existing** — Use the already cloned repository
> 2. **Re-clone** — Remove and clone fresh from GitHub
3. **If directory exists but structure is invalid:** Tell user: "The cloned repository has an unexpected structure. I'll remove it and clone a fresh copy."
Then remove and re-clone.
4. **If clone fails:** inform user and abort
### Check 2: Store and Site Metadata
Verify a store is selected and site metadata is available locally:
1. Tell user: "I'm checking if your project already has B2B store metadata locally."
Check if `force-app/main/default/digitalExperiences/site/` contains any store directories.
2. **If store metadata exists:** use it. If multiple stores found, ask user to select one.
3. **If no store metadata found:** Tell user: "No store metadata found locally. I'll help you create or select a B2B store and retrieve its metadata."
Then delegate to the **creating-b2b-commerce-store** skill (`skills/creating-b2b-commerce-store/SKILL.md`).
**Required state** after both checks:
- **Store name** — the selected `fullName` value (e.g., `My_B2B_Store1`)
- **Site metadata path**`force-app/main/default/digitalExperiences/site/<store-name>/`
- **Repo path**`.tmp/b2b-commerce-open-source-components/`
---
## Integration Task
Copy all components and labels from cloned repo to site directory:
- **Source:** `.tmp/b2b-commerce-open-source-components/force-app/main/default/sfdc_cms__lwc/*` and `sfdc_cms__label/*`
- **Destination:** `force-app/main/default/digitalExperiences/site/<store-name>/sfdc_cms__lwc/` and `sfdc_cms__label/`
**Steps:**
1. Tell user: "I'm checking if open code components already exist in your store's site metadata."
Check if destination directories already contain files.
2. If files exist, present options:
> "Components already exist in **{store-name}**. How would you like to proceed?"
> 1. **Overwrite all** — Replace all existing components with latest from repo
> 2. **Copy only new** — Skip existing components, copy only ones not yet present
3. Tell user: "I'm now copying all open code LWC components from the cloned repository into your store's site metadata directory."
Copy all component directories from source to destination.
4. Tell user: "I'm copying the associated label files that these components need."
Copy all label directories from source to destination.
5. Report: "Copied X components and Y label sets"
**Output:**
```
✅ Integration Complete!
Copied: X components and Y label sets to <store-name>
Next Steps:
1. Deploy: sf project deploy start -d force-app/main/default/digitalExperiences/site/<store-name>
2. Open Experience Builder and use new components from the palette
3. Publish your site when ready
```
---
## Example Interaction
**User:** "Integrate open code components to my store"
**Agent:** "I'm checking if the open source components repository is already cloned locally..."
**Agent:** _(repo exists)_
> "Open source repository is already cloned. How would you like to proceed?"
> 1. **Reuse existing** — Use the already cloned repository
> 2. **Re-clone** — Remove and clone fresh from GitHub
**User:** "1"
**Agent:** "I'm checking if your project already has B2B store metadata locally..."
- ✓ Found store metadata for My_B2B_Store1
**Agent:** "I'm checking if open code components already exist in your store's site metadata..."
**Agent:** _(files exist)_
> "Components already exist in **My_B2B_Store1**. How would you like to proceed?"
> 1. **Overwrite all** — Replace all existing components with latest from repo
> 2. **Copy only new** — Skip existing components, copy only ones not yet present
**User:** "1"
**Agent:** "I'm now copying all open code LWC components from the cloned repository into your store's site metadata directory..."
**Agent:** "I'm copying the associated label files that these components need..."
- ✓ Copied 45 components and 38 label sets
```
✅ Integration Complete!
Copied: 45 components and 38 label sets to My_B2B_Store1
Next Steps:
1. Deploy: sf project deploy start -d force-app/main/default/digitalExperiences/site/My_B2B_Store1
2. Open Experience Builder and use new components from the palette
3. Publish your site when ready
```
---
## Error Handling
| Error | Message | Action |
|-------|---------|--------|
| Store not found | "Store '{name}' not found in org." | List stores again |
| Git clone failed | "Failed to clone repository. Check internet connection." | Retry or abort |
| Invalid repo structure | "Repository structure has changed. Expected sfdc_cms__lwc and sfdc_cms__label." | Warn user, abort |
| File copy failed | "Failed to copy files. Check file permissions." | Show error details |
---
## Verification Checklist
- [ ] Startup Flow completed: repo cloned, store metadata available
- [ ] Components copied to correct destination path (`sfdc_cms__lwc/`)
- [ ] Labels copied to correct destination path (`sfdc_cms__label/`)
- [ ] No file permission errors during copy
- [ ] Deployment command provided and user informed about testing
---
## Anti-Patterns
**DO NOT:** copy without checking for existing files first, modify component code or labels from the open source repo, add components to wrong site directory, deploy without user confirmation.
**DO:** warn before overwriting existing files, verify paths before operations, report count of copied components and labels, inform user of next steps.