@salesforce/afv-skills 1.31.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/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/experience-ui-bundle-app-coordinate/SKILL.md +12 -9
- 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-project-generate/SKILL.md +111 -0
- package/skills/experience-ui-bundle-project-generate/scripts/flatten-project.mjs +33 -0
- 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-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-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,588 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# check_expiration.sh — Report when Salesforce orgs expire, prioritized by urgency.
|
|
4
|
+
#
|
|
5
|
+
# Determines expiration from the authoritative source per org kind:
|
|
6
|
+
# - Trial / Developer Edition orgs: Organization.TrialExpirationDate (SOQL).
|
|
7
|
+
# Null for paid/production orgs, which report "no trial expiration".
|
|
8
|
+
# - Scratch orgs: the expirationDate reported by `sf org list`.
|
|
9
|
+
#
|
|
10
|
+
# Output is sorted soonest-first (already-expired first) and grouped by
|
|
11
|
+
# urgency, with a one-line summary. Structured --json / --csv output is
|
|
12
|
+
# available for dashboards, alerts, and cron. Optional guidance:
|
|
13
|
+
# --preserve print commands to back up an at-risk org before it lapses
|
|
14
|
+
# --renew print how to extend / reactivate a trial or DE org
|
|
15
|
+
# --fail-if-expiring [N] exit non-zero if any org expires within N days
|
|
16
|
+
# (default 7) — for cron / CI gating
|
|
17
|
+
#
|
|
18
|
+
# Usage:
|
|
19
|
+
# check_expiration.sh [org-alias-or-username] # one org
|
|
20
|
+
# check_expiration.sh --all # every authenticated org
|
|
21
|
+
# check_expiration.sh # default org (target-org)
|
|
22
|
+
# check_expiration.sh --all --within 30 # expiring within 30 days
|
|
23
|
+
# check_expiration.sh --all --json # machine-readable
|
|
24
|
+
# check_expiration.sh --all --fail-if-expiring 7 # cron watchdog
|
|
25
|
+
#
|
|
26
|
+
# Options:
|
|
27
|
+
# --all, -a Check every authenticated org.
|
|
28
|
+
# --within <days>, -w Only show orgs expiring within <days> days
|
|
29
|
+
# (includes already-expired; omits paid/production).
|
|
30
|
+
# --json Emit a JSON array of org records (data only).
|
|
31
|
+
# --csv Emit CSV rows (data only).
|
|
32
|
+
# --preserve Print backup commands for expiring/expired orgs.
|
|
33
|
+
# --renew Print trial/DE extension & reactivation guidance.
|
|
34
|
+
# --fail-if-expiring[=N] Exit 3 if any org expires within N days (default 7).
|
|
35
|
+
# --no-scratch Exclude scratch orgs (trial/DE only).
|
|
36
|
+
# --help, -h Show this help.
|
|
37
|
+
#
|
|
38
|
+
# Exit codes:
|
|
39
|
+
# 0 success
|
|
40
|
+
# 1 an org could not be queried (auth/connection error)
|
|
41
|
+
# 2 bad usage / missing dependency (sf or jq)
|
|
42
|
+
# 3 --fail-if-expiring threshold breached (at least one org expiring)
|
|
43
|
+
|
|
44
|
+
set -uo pipefail
|
|
45
|
+
|
|
46
|
+
die() { echo "Error: $*" >&2; exit 2; }
|
|
47
|
+
|
|
48
|
+
command -v sf >/dev/null 2>&1 || die "Salesforce CLI ('sf') not found on PATH."
|
|
49
|
+
command -v jq >/dev/null 2>&1 || die "'jq' not found on PATH."
|
|
50
|
+
|
|
51
|
+
SEP="$(printf '\037')" # US (unit separator): non-whitespace so empty
|
|
52
|
+
# fields are preserved by `read` (a whitespace IFS
|
|
53
|
+
# like TAB collapses runs, dropping empty columns).
|
|
54
|
+
|
|
55
|
+
# Sentinels used so records sort predictably by "days remaining" (ascending):
|
|
56
|
+
# real days (negative = expired) sort first, then unparseable-date, then
|
|
57
|
+
# no-expiration, then auth errors. Distinct values keep same-group records
|
|
58
|
+
# contiguous so group headers are never duplicated.
|
|
59
|
+
DATEONLY_DAYS=999999997 # a date exists but could not be parsed
|
|
60
|
+
NO_EXP_DAYS=999999998 # paid/production (no TrialExpirationDate)
|
|
61
|
+
AUTH_DAYS=999999999 # org could not be queried
|
|
62
|
+
SENTINEL_MIN=999999997 # daysRemaining >= this is a sentinel, not real
|
|
63
|
+
SOON_DAYS=7 # threshold for the "expiring soon" warning
|
|
64
|
+
|
|
65
|
+
# --- option state --------------------------------------------------------
|
|
66
|
+
MODE="" # "all" | "" (single/default)
|
|
67
|
+
TARGET="" # org alias/username for single mode
|
|
68
|
+
WITHIN_DAYS="" # display filter (empty = show everything)
|
|
69
|
+
WITHIN_SEEN=0 # whether --within was passed (to reject empty value)
|
|
70
|
+
FAIL_SEEN=0 # whether --fail-if-expiring was passed
|
|
71
|
+
OUTPUT="human" # human | json | csv
|
|
72
|
+
DO_PRESERVE=0
|
|
73
|
+
DO_RENEW=0
|
|
74
|
+
FAIL_WITHIN="" # --fail-if-expiring threshold (empty = off)
|
|
75
|
+
INCLUDE_SCRATCH=1 # scratch orgs included by default (--no-scratch off)
|
|
76
|
+
|
|
77
|
+
# --- run state -----------------------------------------------------------
|
|
78
|
+
RECORDS="" # accumulated TSV rows (one org per line)
|
|
79
|
+
HAD_AUTH_ERR=0
|
|
80
|
+
MATCH_COUNT=0
|
|
81
|
+
# compute() outputs:
|
|
82
|
+
DAYS=""
|
|
83
|
+
STATUS=""
|
|
84
|
+
|
|
85
|
+
usage() {
|
|
86
|
+
sed -n '2,/^set -uo/p' "$0" | sed '/^set -uo/d; s/^# \{0,1\}//; s/^#//'
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# --- date helpers (macOS/BSD and GNU/Linux) ------------------------------
|
|
90
|
+
now_epoch() { date "+%s"; }
|
|
91
|
+
|
|
92
|
+
# Convert an ISO-ish date (YYYY-MM-DD[ T...]) to epoch seconds.
|
|
93
|
+
date_to_epoch() {
|
|
94
|
+
local d="$1"
|
|
95
|
+
d="${d%%T*}"; d="${d%% *}"
|
|
96
|
+
[ -z "$d" ] && return 1
|
|
97
|
+
if date -j >/dev/null 2>&1; then
|
|
98
|
+
date -j -f "%Y-%m-%d" "$d" "+%s" 2>/dev/null # BSD/macOS
|
|
99
|
+
else
|
|
100
|
+
date -d "$d" "+%s" 2>/dev/null # GNU/Linux
|
|
101
|
+
fi
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Given a date, set DAYS (integer; negative = expired) and STATUS.
|
|
105
|
+
# Sets STATUS=DATEONLY / DAYS=NO_EXP_DAYS when the date cannot be parsed.
|
|
106
|
+
compute() {
|
|
107
|
+
local d="$1" epoch now
|
|
108
|
+
epoch="$(date_to_epoch "$d")"
|
|
109
|
+
if [ -z "$epoch" ]; then DAYS="$DATEONLY_DAYS"; STATUS="DATEONLY"; return 0; fi
|
|
110
|
+
now="$(now_epoch)"
|
|
111
|
+
DAYS=$(( (epoch - now) / 86400 ))
|
|
112
|
+
if [ "$DAYS" -lt 0 ]; then STATUS="EXPIRED"
|
|
113
|
+
elif [ "$DAYS" -le "$SOON_DAYS" ]; then STATUS="SOON"
|
|
114
|
+
else STATUS="OK"
|
|
115
|
+
fi
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# Append a record. Args: days label kind exp status orgid errname errmsg
|
|
119
|
+
add_rec() {
|
|
120
|
+
RECORDS="${RECORDS}$(printf '%s\037%s\037%s\037%s\037%s\037%s\037%s\037%s' \
|
|
121
|
+
"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8")
|
|
122
|
+
"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# --- collection ----------------------------------------------------------
|
|
126
|
+
# Determine expiration for one org and record it.
|
|
127
|
+
# Args: label isScratch(true|false) listExpirationDate listOrgId
|
|
128
|
+
collect_one() {
|
|
129
|
+
local label="$1" is_scratch="$2" list_exp="$3" orgid="$4"
|
|
130
|
+
|
|
131
|
+
if [ "$is_scratch" = "true" ]; then
|
|
132
|
+
local d="${list_exp%%T*}"; d="${d%% *}"
|
|
133
|
+
if [ -z "$d" ] || [ "$d" = "null" ]; then
|
|
134
|
+
add_rec "$NO_EXP_DAYS" "$label" "scratch" "" "NONE" "$orgid" "" ""
|
|
135
|
+
else
|
|
136
|
+
compute "$d"
|
|
137
|
+
add_rec "$DAYS" "$label" "scratch" "$d" "$STATUS" "$orgid" "" ""
|
|
138
|
+
fi
|
|
139
|
+
return 0
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# Non-scratch: TrialExpirationDate is authoritative (null = paid/production).
|
|
143
|
+
local out rc
|
|
144
|
+
out="$(sf data query \
|
|
145
|
+
--query "SELECT Id, TrialExpirationDate FROM Organization" \
|
|
146
|
+
--target-org "$label" --json 2>/dev/null)"
|
|
147
|
+
rc=$?
|
|
148
|
+
if [ "$rc" -ne 0 ]; then
|
|
149
|
+
local en em
|
|
150
|
+
en="$(printf '%s' "$out" | jq -r '.name // empty' 2>/dev/null)"
|
|
151
|
+
em="$(printf '%s' "$out" | jq -r '.message // empty' 2>/dev/null | tr '\t\n' ' ')"
|
|
152
|
+
add_rec "$AUTH_DAYS" "$label" "unknown" "" "AUTH_ERROR" "" "$en" "$em"
|
|
153
|
+
HAD_AUTH_ERR=1
|
|
154
|
+
return 1
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
local id texp
|
|
158
|
+
id="$(printf '%s' "$out" | jq -r '.result.records[0].Id // empty')"
|
|
159
|
+
texp="$(printf '%s' "$out" | jq -r '.result.records[0].TrialExpirationDate // empty')"
|
|
160
|
+
[ -n "$id" ] && orgid="$id"
|
|
161
|
+
|
|
162
|
+
if [ -z "$texp" ] || [ "$texp" = "null" ]; then
|
|
163
|
+
add_rec "$NO_EXP_DAYS" "$label" "paid" "" "NONE" "$orgid" "" ""
|
|
164
|
+
else
|
|
165
|
+
local d="${texp%%T*}"; d="${d%% *}"
|
|
166
|
+
compute "$d"
|
|
167
|
+
add_rec "$DAYS" "$label" "trial" "$d" "$STATUS" "$orgid" "" ""
|
|
168
|
+
fi
|
|
169
|
+
return 0
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# Build a TSV table of authenticated orgs from `sf org list`.
|
|
173
|
+
# Columns: label username isScratch expirationDate orgId
|
|
174
|
+
org_table() {
|
|
175
|
+
local list
|
|
176
|
+
list="$(sf org list --json 2>/dev/null)" || return 1
|
|
177
|
+
printf '%s' "$list" | jq -r --arg sep "$SEP" '
|
|
178
|
+
.result
|
|
179
|
+
| [ (.nonScratchOrgs // []), (.scratchOrgs // []), (.sandboxes // []), (.other // []) ]
|
|
180
|
+
| add
|
|
181
|
+
| map(select((.alias // .username // "") != ""))
|
|
182
|
+
| unique_by(.username // .alias)
|
|
183
|
+
| .[]
|
|
184
|
+
| [ (.alias // .username), (.username // ""),
|
|
185
|
+
((.isScratch // false) | tostring),
|
|
186
|
+
(.expirationDate // ""), (.orgId // "") ]
|
|
187
|
+
| join($sep)'
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# --- output helpers ------------------------------------------------------
|
|
191
|
+
print_header() {
|
|
192
|
+
[ "$OUTPUT" = "human" ] || return 0
|
|
193
|
+
if [ -n "$WITHIN_DAYS" ]; then
|
|
194
|
+
echo "Orgs expiring within $WITHIN_DAYS day(s):"
|
|
195
|
+
elif [ "$1" = "all" ]; then
|
|
196
|
+
echo "Org expiration status for all authenticated orgs:"
|
|
197
|
+
else
|
|
198
|
+
echo "Org expiration status:"
|
|
199
|
+
fi
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
group_of() {
|
|
203
|
+
case "$1" in
|
|
204
|
+
EXPIRED) echo 1 ;;
|
|
205
|
+
SOON) echo 2 ;;
|
|
206
|
+
OK|DATEONLY) echo 3 ;;
|
|
207
|
+
NONE) echo 4 ;;
|
|
208
|
+
*) echo 5 ;;
|
|
209
|
+
esac
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
group_header() {
|
|
213
|
+
case "$1" in
|
|
214
|
+
1) echo "Expired:" ;;
|
|
215
|
+
2) echo "Expiring soon (within $SOON_DAYS day(s)):" ;;
|
|
216
|
+
3) echo "Active (not expiring soon):" ;;
|
|
217
|
+
4) echo "No trial expiration (paid/production):" ;;
|
|
218
|
+
5) echo "Could not query:" ;;
|
|
219
|
+
esac
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
# Actionable authentication guidance for an org that could not be queried.
|
|
223
|
+
auth_help() {
|
|
224
|
+
local label="$1" err_name="$2" err_msg="$3"
|
|
225
|
+
case "$err_name" in
|
|
226
|
+
NamedOrgNotFoundError|NoOrgFound*)
|
|
227
|
+
printf " %-30s not authenticated — no saved credentials for this org\n" "$label" ;;
|
|
228
|
+
*)
|
|
229
|
+
printf " %-30s could not authenticate to org\n" "$label" ;;
|
|
230
|
+
esac
|
|
231
|
+
[ -n "$err_msg" ] && printf " %-30s (%s)\n" "" "$err_msg"
|
|
232
|
+
echo
|
|
233
|
+
echo " To authenticate, run one of:"
|
|
234
|
+
echo " sf org login web --alias \"$label\" # interactive browser login"
|
|
235
|
+
echo " sf org login web --alias <my-alias> --instance-url https://test.salesforce.com # sandbox/My Domain"
|
|
236
|
+
echo " Then re-run this check. List existing logins with: sf org list"
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
kind_label() {
|
|
240
|
+
case "$1" in
|
|
241
|
+
trial) echo "trial/DE edition" ;;
|
|
242
|
+
scratch) echo "scratch org" ;;
|
|
243
|
+
*) echo "" ;;
|
|
244
|
+
esac
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
print_line() {
|
|
248
|
+
local days="$1" label="$2" kind="$3" exp="$4" status="$5" en="$6" em="$7"
|
|
249
|
+
local k; k="$(kind_label "$kind")"
|
|
250
|
+
case "$status" in
|
|
251
|
+
EXPIRED) printf " %-30s %s expired %s (EXPIRED %s day(s) ago)\n" "$label" "$k" "$exp" "$(( -days ))" ;;
|
|
252
|
+
SOON)
|
|
253
|
+
if [ "$days" -eq 0 ]; then
|
|
254
|
+
printf " %-30s %s expires %s (EXPIRES TODAY Warning)\n" "$label" "$k" "$exp"
|
|
255
|
+
else
|
|
256
|
+
printf " %-30s %s expires %s (expires in %s day(s) Warning)\n" "$label" "$k" "$exp" "$days"
|
|
257
|
+
fi ;;
|
|
258
|
+
OK) printf " %-30s %s expires %s (expires in %s day(s))\n" "$label" "$k" "$exp" "$days" ;;
|
|
259
|
+
DATEONLY) printf " %-30s %s expires %s\n" "$label" "$k" "$exp" ;;
|
|
260
|
+
NONE) printf " %-30s no trial expiration (paid/production org)\n" "$label" ;;
|
|
261
|
+
AUTH_ERROR) auth_help "$label" "$en" "$em" ;;
|
|
262
|
+
esac
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
sort_records() {
|
|
266
|
+
printf '%s' "$RECORDS" | grep -v "^[[:space:]]*$" | sort -t"$SEP" -k1,1n
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
# jq program that turns the sorted TSV into structured records (with optional
|
|
270
|
+
# --within filtering applied via $within).
|
|
271
|
+
JQ_RECORDS='
|
|
272
|
+
def dnum($d): ($d|tonumber) as $n | if $n >= 999999997 then null else $n end;
|
|
273
|
+
split("\n") | map(select(length>0)) | map(split($sep))
|
|
274
|
+
| map({
|
|
275
|
+
org: .[1], kind: .[2],
|
|
276
|
+
expirationDate: (if .[3]=="" then null else .[3] end),
|
|
277
|
+
daysRemaining: dnum(.[0]),
|
|
278
|
+
status: (.[4] | if .=="EXPIRED" then "expired"
|
|
279
|
+
elif .=="SOON" then "expiring_soon"
|
|
280
|
+
elif .=="OK" or .=="DATEONLY" then "active"
|
|
281
|
+
elif .=="NONE" then "no_expiration"
|
|
282
|
+
else "auth_error" end),
|
|
283
|
+
orgId: (if .[5]=="" then null else .[5] end)
|
|
284
|
+
})
|
|
285
|
+
| (if $within == null then .
|
|
286
|
+
else map(select(.daysRemaining != null and .daysRemaining <= $within)) end)'
|
|
287
|
+
|
|
288
|
+
render_json() {
|
|
289
|
+
sort_records | jq -R -s --arg sep "$SEP" --argjson within "${WITHIN_DAYS:-null}" "$JQ_RECORDS"
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
render_csv() {
|
|
293
|
+
printf 'org,kind,expiration_date,days_remaining,status,org_id\n'
|
|
294
|
+
sort_records | jq -R -s -r --arg sep "$SEP" --argjson within "${WITHIN_DAYS:-null}" \
|
|
295
|
+
"$JQ_RECORDS"' | .[]
|
|
296
|
+
| [ .org, .kind, (.expirationDate // ""),
|
|
297
|
+
(.daysRemaining | if .==null then "" else tostring end),
|
|
298
|
+
.status, (.orgId // "") ] | @csv'
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
print_filter_summary() {
|
|
302
|
+
[ -n "$WITHIN_DAYS" ] || return 0
|
|
303
|
+
echo
|
|
304
|
+
if [ "$MATCH_COUNT" -eq 0 ]; then
|
|
305
|
+
echo "No orgs expire within $WITHIN_DAYS day(s)."
|
|
306
|
+
else
|
|
307
|
+
echo "$MATCH_COUNT org(s) expire within $WITHIN_DAYS day(s)."
|
|
308
|
+
fi
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
# Human, prioritized, grouped output (soonest/expired first).
|
|
312
|
+
render_human() {
|
|
313
|
+
local sorted; sorted="$(sort_records)"
|
|
314
|
+
print_header "${1:-single}"
|
|
315
|
+
[ -n "$WITHIN_DAYS" ] && echo
|
|
316
|
+
|
|
317
|
+
local prev="" n_exp=0 n_soon=0 n_ok=0 n_none=0 n_auth=0
|
|
318
|
+
local days label kind exp status orgid errname errmsg grp
|
|
319
|
+
while IFS="$SEP" read -r days label kind exp status orgid errname errmsg; do
|
|
320
|
+
[ -z "${label:-}" ] && continue
|
|
321
|
+
|
|
322
|
+
if [ -n "$WITHIN_DAYS" ]; then
|
|
323
|
+
case "$status" in EXPIRED|SOON|OK) ;; *) continue ;; esac
|
|
324
|
+
[ "$days" -gt "$WITHIN_DAYS" ] && continue
|
|
325
|
+
MATCH_COUNT=$(( MATCH_COUNT + 1 ))
|
|
326
|
+
print_line "$days" "$label" "$kind" "$exp" "$status" "$errname" "$errmsg"
|
|
327
|
+
continue
|
|
328
|
+
fi
|
|
329
|
+
|
|
330
|
+
grp="$(group_of "$status")"
|
|
331
|
+
if [ "$grp" != "$prev" ]; then
|
|
332
|
+
printf '\n%s\n' "$(group_header "$grp")"
|
|
333
|
+
prev="$grp"
|
|
334
|
+
fi
|
|
335
|
+
print_line "$days" "$label" "$kind" "$exp" "$status" "$errname" "$errmsg"
|
|
336
|
+
|
|
337
|
+
case "$status" in
|
|
338
|
+
EXPIRED) n_exp=$(( n_exp + 1 )) ;;
|
|
339
|
+
SOON) n_soon=$(( n_soon + 1 )) ;;
|
|
340
|
+
OK|DATEONLY) n_ok=$(( n_ok + 1 )) ;;
|
|
341
|
+
NONE) n_none=$(( n_none + 1 )) ;;
|
|
342
|
+
AUTH_ERROR) n_auth=$(( n_auth + 1 )) ;;
|
|
343
|
+
esac
|
|
344
|
+
done <<EOF
|
|
345
|
+
$sorted
|
|
346
|
+
EOF
|
|
347
|
+
|
|
348
|
+
if [ -n "$WITHIN_DAYS" ]; then
|
|
349
|
+
print_filter_summary
|
|
350
|
+
else
|
|
351
|
+
echo
|
|
352
|
+
local summary="Summary: $n_exp expired, $n_soon expiring within $SOON_DAYS day(s), $n_ok active, $n_none with no expiration"
|
|
353
|
+
[ "$n_auth" -gt 0 ] && summary="$summary, $n_auth unreachable"
|
|
354
|
+
echo "$summary."
|
|
355
|
+
fi
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
# --preserve: backup commands for expiring/expired orgs (human mode only).
|
|
359
|
+
render_preserve() {
|
|
360
|
+
[ "$OUTPUT" = "human" ] || return 0
|
|
361
|
+
local sorted; sorted="$(sort_records)"
|
|
362
|
+
local printed=0 days label kind exp status orgid errname errmsg
|
|
363
|
+
while IFS="$SEP" read -r days label kind exp status orgid errname errmsg; do
|
|
364
|
+
[ -z "${label:-}" ] && continue
|
|
365
|
+
case "$status" in EXPIRED|SOON) ;; *) continue ;; esac
|
|
366
|
+
if [ "$printed" -eq 0 ]; then
|
|
367
|
+
echo
|
|
368
|
+
echo "── Preserve your work (at-risk orgs) ────────────────────────────────"
|
|
369
|
+
echo "When an org lapses you lose access to its metadata and data. Back it up:"
|
|
370
|
+
printed=1
|
|
371
|
+
fi
|
|
372
|
+
echo
|
|
373
|
+
echo " $label:"
|
|
374
|
+
echo " # 1. Capture a manifest of all metadata, then retrieve it locally:"
|
|
375
|
+
echo " sf project generate manifest --from-org \"$label\" --name package.xml"
|
|
376
|
+
echo " sf project retrieve start --target-org \"$label\" --manifest package.xml --output-dir \"./backup-$label\""
|
|
377
|
+
echo " # 2. Export record data per object (repeat for each object you need):"
|
|
378
|
+
echo " sf data export bulk --target-org \"$label\" --query \"SELECT Id, Name FROM Account\" --output-file \"./backup-$label/Account.csv\" --wait 10"
|
|
379
|
+
done <<EOF
|
|
380
|
+
$sorted
|
|
381
|
+
EOF
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
# --renew: trial/DE extension & reactivation guidance (human mode only).
|
|
385
|
+
render_renew() {
|
|
386
|
+
[ "$OUTPUT" = "human" ] || return 0
|
|
387
|
+
echo
|
|
388
|
+
echo "── Extend / renew a Salesforce trial or Developer Edition org ────────"
|
|
389
|
+
echo
|
|
390
|
+
echo " Partners — extend a Trial Org up to +12 months"
|
|
391
|
+
echo " (eligible while active or expired < 30 days; not for LDV orgs):"
|
|
392
|
+
echo " 1. Log in to https://partners.salesforce.com"
|
|
393
|
+
echo " 2. Click \"Ask Agentforce\" (bottom-right of the page)"
|
|
394
|
+
echo " 3. Say: \"I want to extend my Trial Org\""
|
|
395
|
+
echo " 4. Provide your 15- or 18-character Org ID (shown below if known)"
|
|
396
|
+
echo " You'll get an email once the extension is confirmed."
|
|
397
|
+
echo " Ref: Salesforce Help article 000387818"
|
|
398
|
+
echo
|
|
399
|
+
echo " Nonprofits — trial extension (works even if already expired):"
|
|
400
|
+
echo " Email your Account Executive (Setup > Your Account) with the"
|
|
401
|
+
echo " subject \"Trial Extension\" and include:"
|
|
402
|
+
echo " - Email of the customer that started the trial"
|
|
403
|
+
echo " - Org ID (or your org's name if you can't access the Org ID)"
|
|
404
|
+
echo " - Username"
|
|
405
|
+
echo " AMER: PowerOfUsDesk@salesforce.com"
|
|
406
|
+
echo " Other regions: myaccount@salesforce.com or 1-800-NO-SOFTWARE"
|
|
407
|
+
echo " Ref: Salesforce Help article 004754220"
|
|
408
|
+
echo
|
|
409
|
+
echo " Developer Edition orgs:"
|
|
410
|
+
echo " DE orgs have no subscription clock, but are deactivated after a"
|
|
411
|
+
echo " prolonged period (~180 days) with no login. Log in periodically to"
|
|
412
|
+
echo " keep yours active. If it is locked for inactivity (not yet deleted),"
|
|
413
|
+
echo " open a case with Salesforce Customer Support to reactivate it — once"
|
|
414
|
+
echo " permanently deleted an org cannot be recovered."
|
|
415
|
+
echo
|
|
416
|
+
echo " To keep a standard trial's data and configuration, convert/subscribe"
|
|
417
|
+
echo " to a paid edition before it lapses."
|
|
418
|
+
|
|
419
|
+
# Surface Org IDs for at-risk orgs so the steps above are actionable.
|
|
420
|
+
local sorted ids="" days label kind exp status orgid errname errmsg
|
|
421
|
+
sorted="$(sort_records)"
|
|
422
|
+
while IFS="$SEP" read -r days label kind exp status orgid errname errmsg; do
|
|
423
|
+
[ -z "${label:-}" ] && continue
|
|
424
|
+
case "$status" in EXPIRED|SOON) ;; *) continue ;; esac
|
|
425
|
+
[ -n "$orgid" ] && ids="${ids} ${label}: ${orgid}
|
|
426
|
+
"
|
|
427
|
+
done <<EOF
|
|
428
|
+
$sorted
|
|
429
|
+
EOF
|
|
430
|
+
if [ -n "$ids" ]; then
|
|
431
|
+
echo
|
|
432
|
+
echo " Org IDs for your at-risk orgs:"
|
|
433
|
+
printf '%s' "$ids"
|
|
434
|
+
fi
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
# --fail-if-expiring: exit 3 if any org expires within FAIL_WITHIN days.
|
|
438
|
+
check_fail_threshold() {
|
|
439
|
+
[ -n "$FAIL_WITHIN" ] || return 0
|
|
440
|
+
local sorted breach="" days label kind exp status orgid errname errmsg
|
|
441
|
+
sorted="$(sort_records)"
|
|
442
|
+
while IFS="$SEP" read -r days label kind exp status orgid errname errmsg; do
|
|
443
|
+
[ -z "${label:-}" ] && continue
|
|
444
|
+
case "$status" in EXPIRED|SOON|OK) ;; *) continue ;; esac
|
|
445
|
+
[ "$days" -le "$FAIL_WITHIN" ] && breach="${breach} ${label}"
|
|
446
|
+
done <<EOF
|
|
447
|
+
$sorted
|
|
448
|
+
EOF
|
|
449
|
+
if [ -n "$breach" ]; then
|
|
450
|
+
echo "ALERT: org(s) expiring within $FAIL_WITHIN day(s):${breach}" >&2
|
|
451
|
+
return 3
|
|
452
|
+
fi
|
|
453
|
+
return 0
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
# Render whichever output mode is selected. Args: context ("all"|"single")
|
|
457
|
+
render() {
|
|
458
|
+
case "$OUTPUT" in
|
|
459
|
+
json) render_json ;;
|
|
460
|
+
csv) render_csv ;;
|
|
461
|
+
*)
|
|
462
|
+
render_human "$1"
|
|
463
|
+
[ "$DO_PRESERVE" -eq 1 ] && render_preserve
|
|
464
|
+
[ "$DO_RENEW" -eq 1 ] && render_renew
|
|
465
|
+
;;
|
|
466
|
+
esac
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
# --- argument parsing ----------------------------------------------------
|
|
470
|
+
while [ $# -gt 0 ]; do
|
|
471
|
+
case "$1" in
|
|
472
|
+
--all|-a) MODE="all"; shift ;;
|
|
473
|
+
--within|-w)
|
|
474
|
+
shift
|
|
475
|
+
[ $# -gt 0 ] || die "--within requires a number of days (e.g. --within 30)."
|
|
476
|
+
WITHIN_DAYS="$1"; WITHIN_SEEN=1; shift ;;
|
|
477
|
+
--within=*) WITHIN_DAYS="${1#*=}"; WITHIN_SEEN=1; shift ;;
|
|
478
|
+
--json) OUTPUT="json"; shift ;;
|
|
479
|
+
--csv) OUTPUT="csv"; shift ;;
|
|
480
|
+
--preserve) DO_PRESERVE=1; shift ;;
|
|
481
|
+
--renew) DO_RENEW=1; shift ;;
|
|
482
|
+
--no-scratch) INCLUDE_SCRATCH=0; shift ;;
|
|
483
|
+
--fail-if-expiring)
|
|
484
|
+
shift
|
|
485
|
+
FAIL_SEEN=1
|
|
486
|
+
if [ $# -gt 0 ] && printf '%s' "$1" | grep -qE '^[0-9]+$'; then
|
|
487
|
+
FAIL_WITHIN="$1"; shift
|
|
488
|
+
else
|
|
489
|
+
FAIL_WITHIN="$SOON_DAYS"
|
|
490
|
+
fi ;;
|
|
491
|
+
--fail-if-expiring=*) FAIL_WITHIN="${1#*=}"; FAIL_SEEN=1; shift ;;
|
|
492
|
+
--help|-h) usage; exit 0 ;;
|
|
493
|
+
--) shift; break ;;
|
|
494
|
+
-*) die "Unknown option: $1 (try --help)" ;;
|
|
495
|
+
*)
|
|
496
|
+
[ -n "$TARGET" ] && die "Specify only one org (or use --all). Got extra: $1"
|
|
497
|
+
TARGET="$1"; shift ;;
|
|
498
|
+
esac
|
|
499
|
+
done
|
|
500
|
+
|
|
501
|
+
# Validate integer flags. Validate whenever the flag was seen (so an empty
|
|
502
|
+
# value from --within= / --fail-if-expiring= is rejected, not silently ignored).
|
|
503
|
+
if [ "$WITHIN_SEEN" -eq 1 ]; then
|
|
504
|
+
case "$WITHIN_DAYS" in
|
|
505
|
+
''|*[!0-9]*) die "--within expects a non-negative integer number of days (got: '$WITHIN_DAYS')." ;;
|
|
506
|
+
esac
|
|
507
|
+
fi
|
|
508
|
+
if [ "$FAIL_SEEN" -eq 1 ]; then
|
|
509
|
+
case "$FAIL_WITHIN" in
|
|
510
|
+
''|*[!0-9]*) die "--fail-if-expiring expects a non-negative integer number of days (got: '$FAIL_WITHIN')." ;;
|
|
511
|
+
esac
|
|
512
|
+
fi
|
|
513
|
+
|
|
514
|
+
if [ "$OUTPUT" != "human" ]; then
|
|
515
|
+
if [ "$DO_PRESERVE" -eq 1 ] || [ "$DO_RENEW" -eq 1 ]; then
|
|
516
|
+
echo "Note: --preserve/--renew produce human-readable guidance and are ignored with --json/--csv." >&2
|
|
517
|
+
fi
|
|
518
|
+
fi
|
|
519
|
+
|
|
520
|
+
# --- dispatch ------------------------------------------------------------
|
|
521
|
+
[ "$MODE" = "all" ] && [ -n "$TARGET" ] && \
|
|
522
|
+
die "Cannot combine --all with a specific org ($TARGET)."
|
|
523
|
+
|
|
524
|
+
if [ "$MODE" = "all" ]; then
|
|
525
|
+
ORG_TSV="$(org_table)" || die "Could not list orgs (is the Salesforce CLI configured?)."
|
|
526
|
+
if [ "$INCLUDE_SCRATCH" -eq 0 ]; then
|
|
527
|
+
ORG_TSV="$(printf '%s' "$ORG_TSV" | awk -F"$SEP" '$3 != "true"')"
|
|
528
|
+
fi
|
|
529
|
+
if [ -z "$ORG_TSV" ]; then
|
|
530
|
+
# Machine-readable modes must stay parseable even with nothing to report.
|
|
531
|
+
case "$OUTPUT" in
|
|
532
|
+
json) echo "[]"; exit 0 ;;
|
|
533
|
+
csv) echo "org,kind,expiration_date,days_remaining,status,org_id"; exit 0 ;;
|
|
534
|
+
esac
|
|
535
|
+
if [ "$INCLUDE_SCRATCH" -eq 0 ]; then
|
|
536
|
+
echo "No authenticated non-scratch orgs found."
|
|
537
|
+
else
|
|
538
|
+
echo "No authenticated orgs found."
|
|
539
|
+
fi
|
|
540
|
+
echo
|
|
541
|
+
echo "To authenticate, run: sf org login web --alias <my-alias>"
|
|
542
|
+
exit 1
|
|
543
|
+
fi
|
|
544
|
+
while IFS="$SEP" read -r label username is_scratch list_exp orgid; do
|
|
545
|
+
[ -z "${label:-}" ] && continue
|
|
546
|
+
collect_one "$label" "$is_scratch" "$list_exp" "$orgid" || true
|
|
547
|
+
done <<EOF
|
|
548
|
+
$ORG_TSV
|
|
549
|
+
EOF
|
|
550
|
+
render all
|
|
551
|
+
rc=0; [ "$HAD_AUTH_ERR" -eq 1 ] && rc=1
|
|
552
|
+
check_fail_threshold || rc=3
|
|
553
|
+
exit "$rc"
|
|
554
|
+
fi
|
|
555
|
+
|
|
556
|
+
# Single org (explicit or default). Look it up in `sf org list` to learn
|
|
557
|
+
# whether it is a scratch org and to pick up its expirationDate / orgId.
|
|
558
|
+
if [ -z "$TARGET" ]; then
|
|
559
|
+
TARGET="$(sf config get target-org --json 2>/dev/null | jq -r '.result[0].value // empty')"
|
|
560
|
+
if [ -z "$TARGET" ]; then
|
|
561
|
+
echo "No org specified and no default 'target-org' set." >&2
|
|
562
|
+
echo >&2
|
|
563
|
+
echo "Either pass an org alias/username, use --all, or set a default:" >&2
|
|
564
|
+
echo " sf org login web --alias <my-alias> # authenticate a new org" >&2
|
|
565
|
+
echo " sf config set target-org <my-alias> # make it the default" >&2
|
|
566
|
+
exit 2
|
|
567
|
+
fi
|
|
568
|
+
fi
|
|
569
|
+
|
|
570
|
+
ORG_TSV="$(org_table 2>/dev/null || true)"
|
|
571
|
+
match="$(printf '%s' "$ORG_TSV" | awk -F"$SEP" -v t="$TARGET" '$1==t || $2==t {print; exit}')"
|
|
572
|
+
if [ -n "$match" ]; then
|
|
573
|
+
is_scratch="$(printf '%s' "$match" | awk -F"$SEP" '{print $3}')"
|
|
574
|
+
list_exp="$(printf '%s' "$match" | awk -F"$SEP" '{print $4}')"
|
|
575
|
+
orgid="$(printf '%s' "$match" | awk -F"$SEP" '{print $5}')"
|
|
576
|
+
if [ "$INCLUDE_SCRATCH" -eq 0 ] && [ "$is_scratch" = "true" ]; then
|
|
577
|
+
die "'$TARGET' is a scratch org and --no-scratch was given."
|
|
578
|
+
fi
|
|
579
|
+
collect_one "$TARGET" "$is_scratch" "$list_exp" "$orgid" || true
|
|
580
|
+
else
|
|
581
|
+
# Not in the org list — treat as a direct username; SOQL surfaces auth errors.
|
|
582
|
+
collect_one "$TARGET" "false" "" "" || true
|
|
583
|
+
fi
|
|
584
|
+
|
|
585
|
+
render single
|
|
586
|
+
rc=0; [ "$HAD_AUTH_ERR" -eq 1 ] && rc=1
|
|
587
|
+
check_fail_threshold || rc=3
|
|
588
|
+
exit "$rc"
|
|
@@ -3,14 +3,17 @@ name: experience-ui-bundle-app-coordinate
|
|
|
3
3
|
description: "MUST activate when the user wants to build, create, or generate a React application, React app, web application, single-page application (SPA), or frontend application — even if no project files exist yet. MUST also activate when the project contains a uiBundles/*/src/ directory or sfdx-project.json and the prompt says create, build, construct, or generate a new app, site, or page from scratch — even if the prompt also describes visual styling. MUST also activate when the task spans more than one ui-bundle skill. Use this skill when building a complete app end-to-end. Do NOT use for Lightning Experience apps with custom objects (use platform-lightning-app-coordinate). Do NOT use for single-concern edits to an existing page (use experience-ui-bundle-frontend-generate)."
|
|
4
4
|
metadata:
|
|
5
5
|
version: "1.0"
|
|
6
|
-
relatedSkills:
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
6
|
+
relatedSkills:
|
|
7
|
+
- "experience-ui-bundle-project-generate"
|
|
8
|
+
- "experience-ui-bundle-metadata-generate"
|
|
9
|
+
- "experience-ui-bundle-features-generate"
|
|
10
|
+
- "experience-ui-bundle-salesforce-data-access"
|
|
11
|
+
- "experience-ui-bundle-frontend-generate"
|
|
12
|
+
- "experience-ui-bundle-agentforce-client-generate"
|
|
13
|
+
- "experience-ui-bundle-file-upload-generate"
|
|
14
|
+
- "experience-ui-bundle-deploy"
|
|
15
|
+
- "experience-ui-bundle-site-generate"
|
|
16
|
+
- "experience-ui-bundle-custom-app-generate"
|
|
14
17
|
---
|
|
15
18
|
|
|
16
19
|
# Building a UI Bundle App
|
|
@@ -126,7 +129,7 @@ Search, describe, and install features (auth, shadcn, search, navigation, GraphQ
|
|
|
126
129
|
v
|
|
127
130
|
Resolve conflicts (two-pass: --on-conflict error, then --conflict-resolution)
|
|
128
131
|
v
|
|
129
|
-
Integrate
|
|
132
|
+
Integrate __examples__ files into target files (verify build succeeds), then delete them
|
|
130
133
|
```
|
|
131
134
|
|
|
132
135
|
Installs pre-built, tested feature packages. See "Prompt Classification Keywords" above for the full trigger keyword list and negative-phrasing handling — these features provide the foundation that UI components build on top of.
|