@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
package/skills/sales-agentforce-pipeline-management-configure/scripts/flow-debug-and-verify.sh
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# flow-debug-and-verify.sh — Verify Pipeline Management flow is working correctly
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# bash flow-debug-and-verify.sh <org-alias> [opportunity-id] # flow-debug-start: pick opp + print Debug URL
|
|
7
|
+
# bash flow-debug-and-verify.sh <org-alias> <opportunity-id> verify # verify: after the debug run
|
|
8
|
+
#
|
|
9
|
+
# ADMIN VERIFICATION TOOL: Verifies that Pipeline Management is configured
|
|
10
|
+
# correctly and generating field suggestions.
|
|
11
|
+
#
|
|
12
|
+
# The suggestion flow (Process_Field_Update_Suggestions) is a SCHEDULED
|
|
13
|
+
# record-triggered flow. Its $Record global is bound ONLY when the flow runs —
|
|
14
|
+
# by the platform scheduler at cron time, or by Flow Builder's Debug runner
|
|
15
|
+
# (which asks you to pick the record). Starting the interview manually from Apex
|
|
16
|
+
# leaves $Record null and the flow silently no-ops, so this tool drives it as a
|
|
17
|
+
# guided MANUAL step split into two phases:
|
|
18
|
+
#
|
|
19
|
+
# FLOW DEBUG START (default) — picks an eligible opportunity and prints the
|
|
20
|
+
# flow's Debug URL. You then run Debug against that
|
|
21
|
+
# opportunity in the browser (leave rollback mode
|
|
22
|
+
# UNCHECKED).
|
|
23
|
+
# VERIFY ("verify") — run after the debug run finishes; confirms the flow
|
|
24
|
+
# reached its action (agent user on the Opportunity Team)
|
|
25
|
+
# and polls for the generated AiGenActionItem suggestions.
|
|
26
|
+
#
|
|
27
|
+
# The wait between phases happens in the DRIVER (the human or the agent invoking
|
|
28
|
+
# this), not inside the script — so an agent can relay the URL, wait in the
|
|
29
|
+
# conversation for you to finish the debug run, then invoke the verify phase.
|
|
30
|
+
# When run in an interactive terminal, FLOW DEBUG START additionally offers to
|
|
31
|
+
# pause and chain straight into VERIFY for convenience.
|
|
32
|
+
#
|
|
33
|
+
set -euo pipefail
|
|
34
|
+
|
|
35
|
+
# sf CLI can emit ANSI color codes inside --json stdout, breaking jq parsing.
|
|
36
|
+
# 2>/dev/null only strips stderr; these env vars are the reliable fix (see PM notes).
|
|
37
|
+
export NO_COLOR=1
|
|
38
|
+
export FORCE_COLOR=0
|
|
39
|
+
|
|
40
|
+
# ============================================================
|
|
41
|
+
# Arguments
|
|
42
|
+
# ============================================================
|
|
43
|
+
ORG_ALIAS="${1:-}"
|
|
44
|
+
OPP_ID="${2:-}"
|
|
45
|
+
MODE="${3:-flow-debug-start}" # flow-debug-start (default) | verify
|
|
46
|
+
BASELINE_ARG="${4:-}" # verify: suggestion count captured BEFORE the debug run
|
|
47
|
+
FLOW_API_NAME="Process_Field_Update_Suggestions"
|
|
48
|
+
|
|
49
|
+
if [[ -z "$ORG_ALIAS" ]]; then
|
|
50
|
+
cat >&2 <<EOF
|
|
51
|
+
Usage:
|
|
52
|
+
$0 <org-alias> [opportunity-id] # FLOW DEBUG START: pick opp + print the Debug URL
|
|
53
|
+
$0 <org-alias> <opportunity-id> verify # VERIFY: run after the debug finishes
|
|
54
|
+
|
|
55
|
+
ADMIN VERIFICATION: Verifies the Pipeline Management suggestion flow works by
|
|
56
|
+
guiding you through a manual Flow Builder Debug run (the only on-demand path
|
|
57
|
+
that binds a real \$Record on a scheduled record-triggered flow), then checks
|
|
58
|
+
the resulting Opportunity Team membership and AiGenActionItem suggestions.
|
|
59
|
+
|
|
60
|
+
Arguments:
|
|
61
|
+
org-alias Salesforce org alias or username
|
|
62
|
+
opportunity-id (Optional in flow-debug-start) Specific opportunity to test.
|
|
63
|
+
If omitted, a test opportunity owned by the current user is
|
|
64
|
+
created (and a grounding Note seeded); otherwise falls back to
|
|
65
|
+
a user-owned open opportunity.
|
|
66
|
+
REQUIRED in verify (use the ID that flow-debug-start reported).
|
|
67
|
+
|
|
68
|
+
Two-phase flow:
|
|
69
|
+
1. FLOW DEBUG START prints the flow's Debug URL and the opportunity to select.
|
|
70
|
+
2. You open the URL, click Debug, pick that opportunity as the trigger
|
|
71
|
+
record, leave 'rollback mode' UNCHECKED, and Run.
|
|
72
|
+
3. VERIFY confirms the agent user joined the Opportunity Team and polls for
|
|
73
|
+
the generated suggestion(s).
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
$0 connected-seller-home
|
|
77
|
+
# ...run the debug in the browser against the reported opportunity...
|
|
78
|
+
$0 connected-seller-home 006SB00000J73XjYAJ verify
|
|
79
|
+
EOF
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# ============================================================
|
|
84
|
+
# Helper Functions
|
|
85
|
+
# ============================================================
|
|
86
|
+
log_info() { echo " [....] $*"; }
|
|
87
|
+
log_pass() { echo " [PASS] $*"; }
|
|
88
|
+
log_fail() { echo " [FAIL] $*" >&2; }
|
|
89
|
+
log_warn() { echo " [WARN] $*"; }
|
|
90
|
+
log_try() { echo " [TRY ] $*"; }
|
|
91
|
+
|
|
92
|
+
die() {
|
|
93
|
+
echo "Error: $*" >&2
|
|
94
|
+
exit 1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# Shared test-opp + grounding-note resolution (kept identical to
|
|
98
|
+
# verify-prompt-generation.sh via this one sourced shared library). Defines
|
|
99
|
+
# resolve_test_opportunity, which sets OPP_ID and seeds/refreshes the note.
|
|
100
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
101
|
+
source "$SCRIPT_DIR/shared/test-opp.sh"
|
|
102
|
+
|
|
103
|
+
# ============================================================
|
|
104
|
+
# VERIFY phase — check the flow reached its action + polled suggestions
|
|
105
|
+
# ============================================================
|
|
106
|
+
run_verify() {
|
|
107
|
+
local opp_id="$1"
|
|
108
|
+
local opp_name="$2"
|
|
109
|
+
local note_count="$3"
|
|
110
|
+
local baseline_count="$4"
|
|
111
|
+
|
|
112
|
+
echo ""
|
|
113
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
114
|
+
echo " VERIFY — checking the debug run's results"
|
|
115
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
116
|
+
echo ""
|
|
117
|
+
|
|
118
|
+
# The flow adds the agent user to the Opportunity Team BEFORE calling the
|
|
119
|
+
# suggestion action, within the same synchronous debug run. So once the debug
|
|
120
|
+
# run has finished, that membership must exist — its absence means the flow
|
|
121
|
+
# no-op'd (ineligible opp, missing agent user, inactive Bot, or rollback mode
|
|
122
|
+
# left on) rather than a timing issue.
|
|
123
|
+
log_info "Confirming the agent user joined the Opportunity Team..."
|
|
124
|
+
|
|
125
|
+
local agent_user_id
|
|
126
|
+
agent_user_id=$(sf data query -q "SELECT Id FROM User WHERE Username LIKE '%salesmanagementagentuser%' LIMIT 1" \
|
|
127
|
+
--target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.records[0].Id // empty')
|
|
128
|
+
|
|
129
|
+
if [[ -z "$agent_user_id" ]]; then
|
|
130
|
+
die "Agent user (salesmanagementagentuser) not found — Pipeline Management may not be fully provisioned."
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
local agent_otm
|
|
134
|
+
agent_otm=$(sf data query -q "SELECT TeamMemberRole, OpportunityAccessLevel FROM OpportunityTeamMember WHERE OpportunityId='$opp_id' AND UserId='$agent_user_id' LIMIT 1" \
|
|
135
|
+
--target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.records[0] // empty')
|
|
136
|
+
|
|
137
|
+
echo ""
|
|
138
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
139
|
+
echo " Results"
|
|
140
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
141
|
+
echo ""
|
|
142
|
+
|
|
143
|
+
if [[ -z "$agent_otm" ]]; then
|
|
144
|
+
log_fail "Agent user is NOT on the Opportunity Team for $opp_id."
|
|
145
|
+
echo ""
|
|
146
|
+
echo " The debug run did not reach the suggestion action. Rule out real gaps:"
|
|
147
|
+
echo " - Did you select this opportunity ($opp_id) as the trigger record?"
|
|
148
|
+
echo " - Was 'rollback mode' left UNCHECKED? (rollback discards the DML)"
|
|
149
|
+
echo " - Opportunity eligible? (IsClosed=false, CloseDate within 90 days)"
|
|
150
|
+
echo " - Agent user holds SalesManagementAgentUserPsg?"
|
|
151
|
+
echo " - Active BotDefinition/BotVersion for the Sales agent?"
|
|
152
|
+
echo " - Bot AgentTemplate matches the flow's SalesManagementAgentTemplate"
|
|
153
|
+
echo " (SalesMgmt__SalesAgent vs __NGASalesAgent) — a mismatch makes the"
|
|
154
|
+
echo " flow exit BEFORE the Opportunity Team step."
|
|
155
|
+
echo ""
|
|
156
|
+
die "Flow did not queue opportunity $opp_id for suggestion generation."
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
local otm_role otm_access
|
|
160
|
+
otm_role=$(echo "$agent_otm" | jq -r '.TeamMemberRole // "?"')
|
|
161
|
+
otm_access=$(echo "$agent_otm" | jq -r '.OpportunityAccessLevel // "?"')
|
|
162
|
+
log_pass "Agent user is on the Opportunity Team (role: $otm_role, access: $otm_access)"
|
|
163
|
+
log_pass "Flow reached its suggestion action for opportunity $opp_id."
|
|
164
|
+
echo ""
|
|
165
|
+
|
|
166
|
+
# The action writes AiGenActionItem asynchronously. On-org timing: 0 rows at
|
|
167
|
+
# 90s, suggestions landing ~165s — so poll to ~4 min before concluding failure
|
|
168
|
+
# (a short poll is the #1 false negative). Compare this opportunity's
|
|
169
|
+
# FIELD_UPDATE count against the baseline captured BEFORE the debug run.
|
|
170
|
+
log_info "Polling for generated suggestion(s) (up to ~4 min)..."
|
|
171
|
+
|
|
172
|
+
local suggestion_found=0 current_count
|
|
173
|
+
for _ in $(seq 1 16); do
|
|
174
|
+
sleep 15
|
|
175
|
+
# `|| echo` keeps a transient sf/network blip (ECONNRESET is a known flake on
|
|
176
|
+
# this org) from aborting the whole verify under `set -o pipefail`.
|
|
177
|
+
current_count=$(sf data query -q "SELECT COUNT() FROM AiGenActionItem WHERE ParentId='$opp_id' AND Type='FIELD_UPDATE'" \
|
|
178
|
+
--target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.totalSize // 0' || echo "$baseline_count")
|
|
179
|
+
if [[ "$current_count" -gt "$baseline_count" ]]; then
|
|
180
|
+
local delta=$((current_count - baseline_count))
|
|
181
|
+
log_pass "Generated $delta new suggestion(s) for $opp_id (AiGenActionItem)."
|
|
182
|
+
suggestion_found=1
|
|
183
|
+
break
|
|
184
|
+
fi
|
|
185
|
+
done
|
|
186
|
+
|
|
187
|
+
if [[ "$suggestion_found" -eq 0 ]]; then
|
|
188
|
+
if [[ "$note_count" -gt 0 ]]; then
|
|
189
|
+
log_warn "No new suggestions after ~4 min, though this opp has $note_count note(s)."
|
|
190
|
+
log_warn "Generation can lag; check Pipeline Inspection on $opp_name shortly. If it"
|
|
191
|
+
log_warn "stays empty, verify the field prompt templates are active and grounded."
|
|
192
|
+
else
|
|
193
|
+
log_info "No suggestions after ~4 min. Expected here — this opp has no notes to"
|
|
194
|
+
log_info "ground on. Link a ContentNote and re-run to see grounded suggestions."
|
|
195
|
+
fi
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
echo ""
|
|
199
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
200
|
+
echo " Verification Complete"
|
|
201
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
202
|
+
echo ""
|
|
203
|
+
echo "Test Opportunity: $opp_id ($opp_name)"
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# ============================================================
|
|
207
|
+
# Setup
|
|
208
|
+
# ============================================================
|
|
209
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
210
|
+
echo " Pipeline Management Flow Debug Verification"
|
|
211
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
212
|
+
echo ""
|
|
213
|
+
echo "Org: $ORG_ALIAS"
|
|
214
|
+
echo "Flow: $FLOW_API_NAME"
|
|
215
|
+
echo "Mode: $MODE"
|
|
216
|
+
echo ""
|
|
217
|
+
|
|
218
|
+
if [[ "$MODE" != "flow-debug-start" && "$MODE" != "verify" ]]; then
|
|
219
|
+
die "Unknown mode '$MODE'. Use 'flow-debug-start' (default) or 'verify'."
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
if [[ "$MODE" == "verify" && -z "$OPP_ID" ]]; then
|
|
223
|
+
die "verify mode requires an opportunity id: $0 <org-alias> <opportunity-id> verify [baseline]"
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
# ============================================================
|
|
227
|
+
# Resolve / validate the target opportunity
|
|
228
|
+
# ============================================================
|
|
229
|
+
if [[ -z "$OPP_ID" ]]; then
|
|
230
|
+
# Pipeline Inspection is owner-scoped, so a suggestion on an opp owned by someone
|
|
231
|
+
# else is invisible to the admin verifying. resolve_test_opportunity (shared lib)
|
|
232
|
+
# reuses/creates the stable [PM-TEST] opp owned by the current user, falls back to
|
|
233
|
+
# a user-owned open opp, and seeds/refreshes the grounding note on whichever
|
|
234
|
+
# resolved — the SAME opp + note the prompt-verification path uses.
|
|
235
|
+
log_info "No opportunity given — resolving a user-owned test opportunity..."
|
|
236
|
+
|
|
237
|
+
resolve_test_opportunity
|
|
238
|
+
|
|
239
|
+
if [[ -z "$OPP_ID" ]]; then
|
|
240
|
+
log_warn "No eligible opportunity found for the current user."
|
|
241
|
+
echo " To verify: create an open Opportunity owned by you with CloseDate within 90 days,"
|
|
242
|
+
echo " then re-run: $0 $ORG_ALIAS <opportunity-id>"
|
|
243
|
+
echo ""
|
|
244
|
+
log_info "Skipping output verification — no opportunity available"
|
|
245
|
+
exit 0
|
|
246
|
+
fi
|
|
247
|
+
else
|
|
248
|
+
log_info "Using opportunity: $OPP_ID"
|
|
249
|
+
|
|
250
|
+
# In flow-debug-start mode, warn if it doesn't meet flow criteria (verify mode
|
|
251
|
+
# trusts the id flow-debug-start already vetted).
|
|
252
|
+
if [[ "$MODE" != "verify" ]]; then
|
|
253
|
+
IS_ELIGIBLE=$(sf data query -q "SELECT Id FROM Opportunity WHERE Id='$OPP_ID' AND IsClosed=false AND CloseDate>=TODAY AND CloseDate<=NEXT_N_DAYS:90" \
|
|
254
|
+
--target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.records[0].Id // empty')
|
|
255
|
+
|
|
256
|
+
if [[ -z "$IS_ELIGIBLE" ]]; then
|
|
257
|
+
log_warn "Opportunity $OPP_ID may not meet flow criteria (must be open with CloseDate within 90 days)"
|
|
258
|
+
fi
|
|
259
|
+
fi
|
|
260
|
+
fi
|
|
261
|
+
|
|
262
|
+
# Opportunity details (name for messaging; note count feeds the suggestion check)
|
|
263
|
+
OPP_DETAILS=$(sf data query -q "SELECT Name, StageName, CloseDate FROM Opportunity WHERE Id='$OPP_ID'" \
|
|
264
|
+
--target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.records[0] // empty')
|
|
265
|
+
if [[ -z "$OPP_DETAILS" || "$OPP_DETAILS" == "null" ]]; then
|
|
266
|
+
die "Opportunity '$OPP_ID' not found in org '$ORG_ALIAS'. Check the id (a missing opp would otherwise look like a flow no-op)."
|
|
267
|
+
fi
|
|
268
|
+
OPP_NAME=$(echo "$OPP_DETAILS" | jq -r '.Name')
|
|
269
|
+
OPP_STAGE=$(echo "$OPP_DETAILS" | jq -r '.StageName')
|
|
270
|
+
OPP_CLOSE=$(echo "$OPP_DETAILS" | jq -r '.CloseDate')
|
|
271
|
+
|
|
272
|
+
NOTE_COUNT=$(sf data query -q "SELECT COUNT() FROM ContentDocumentLink WHERE LinkedEntityId='$OPP_ID'" \
|
|
273
|
+
--target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.totalSize // 0')
|
|
274
|
+
|
|
275
|
+
# The baseline must be the suggestion count BEFORE the debug run. flow-debug-start
|
|
276
|
+
# captures it here (pre-run) and prints it into the verify command; verify reuses
|
|
277
|
+
# that value. Re-querying in verify would fold the run's own output into the
|
|
278
|
+
# baseline, so the delta poll could never detect it — a guaranteed false negative.
|
|
279
|
+
# Scoped to THIS opp + FIELD_UPDATE so a concurrent run elsewhere can't false-positive.
|
|
280
|
+
if [[ "$MODE" == "verify" ]]; then
|
|
281
|
+
if [[ -n "$BASELINE_ARG" ]]; then
|
|
282
|
+
BASELINE_COUNT="$BASELINE_ARG"
|
|
283
|
+
else
|
|
284
|
+
# Standalone verify with no baseline: fall back to absolute detection (any
|
|
285
|
+
# FIELD_UPDATE item counts). Weaker than the delta, but never a false negative.
|
|
286
|
+
log_warn "No baseline passed; using absolute count (any FIELD_UPDATE suggestion = pass)."
|
|
287
|
+
BASELINE_COUNT=0
|
|
288
|
+
fi
|
|
289
|
+
run_verify "$OPP_ID" "$OPP_NAME" "$NOTE_COUNT" "$BASELINE_COUNT"
|
|
290
|
+
exit 0
|
|
291
|
+
fi
|
|
292
|
+
|
|
293
|
+
BASELINE_COUNT=$(sf data query -q "SELECT COUNT() FROM AiGenActionItem WHERE ParentId='$OPP_ID' AND Type='FIELD_UPDATE'" \
|
|
294
|
+
--target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.totalSize // 0')
|
|
295
|
+
|
|
296
|
+
# ============================================================
|
|
297
|
+
# FLOW DEBUG START mode: resolve the flow's Debug URL and hand off
|
|
298
|
+
# ============================================================
|
|
299
|
+
echo ""
|
|
300
|
+
echo "Test Opportunity:"
|
|
301
|
+
echo " ID: $OPP_ID"
|
|
302
|
+
echo " Name: $OPP_NAME"
|
|
303
|
+
echo " Stage: $OPP_STAGE"
|
|
304
|
+
echo " Close Date: $OPP_CLOSE"
|
|
305
|
+
echo " Notes: $NOTE_COUNT"
|
|
306
|
+
echo ""
|
|
307
|
+
|
|
308
|
+
if [[ "$NOTE_COUNT" -eq 0 ]]; then
|
|
309
|
+
log_warn "No ContentNotes linked to this opportunity - suggestions may be empty"
|
|
310
|
+
fi
|
|
311
|
+
|
|
312
|
+
# Instance URL for the Debug link.
|
|
313
|
+
INSTANCE_URL=$(sf org display --target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.instanceUrl // empty')
|
|
314
|
+
[[ -z "$INSTANCE_URL" ]] && die "Could not resolve instance URL for org '$ORG_ALIAS' — is it authenticated?"
|
|
315
|
+
INSTANCE_URL="${INSTANCE_URL%/}"
|
|
316
|
+
|
|
317
|
+
log_info "Locating flow '$FLOW_API_NAME'..."
|
|
318
|
+
|
|
319
|
+
# FlowDefinitionView has no 'ActiveVersion' relationship — use the scalar
|
|
320
|
+
# ActiveVersionId, then read VersionNumber from the Flow tooling object.
|
|
321
|
+
FLOW_DEF=$(sf data query -q "SELECT Id, ActiveVersionId, ProcessType, TriggerType FROM FlowDefinitionView WHERE ApiName='$FLOW_API_NAME' AND IsActive=true" \
|
|
322
|
+
--target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.records[0] // empty')
|
|
323
|
+
|
|
324
|
+
if [[ -z "$FLOW_DEF" || "$FLOW_DEF" == "null" ]]; then
|
|
325
|
+
die "Flow '$FLOW_API_NAME' not found or not active"
|
|
326
|
+
fi
|
|
327
|
+
|
|
328
|
+
FLOW_VERSION_ID=$(echo "$FLOW_DEF" | jq -r '.ActiveVersionId')
|
|
329
|
+
FLOW_PROCESS_TYPE=$(echo "$FLOW_DEF" | jq -r '.ProcessType')
|
|
330
|
+
FLOW_TRIGGER_TYPE=$(echo "$FLOW_DEF" | jq -r '.TriggerType // "None"')
|
|
331
|
+
|
|
332
|
+
FLOW_VERSION_NUM=$(sf data query -q "SELECT VersionNumber FROM Flow WHERE Id='$FLOW_VERSION_ID'" \
|
|
333
|
+
--target-org "$ORG_ALIAS" --use-tooling-api --json 2>/dev/null | jq -r '.result.records[0].VersionNumber // "?"')
|
|
334
|
+
|
|
335
|
+
log_pass "Flow found (version $FLOW_VERSION_NUM, type: $FLOW_PROCESS_TYPE, trigger: $FLOW_TRIGGER_TYPE)"
|
|
336
|
+
|
|
337
|
+
# Flow Builder opens on the active version by its FlowVersion (301) Id. From
|
|
338
|
+
# there the Debug button lets you pick the record to bind as $Record.
|
|
339
|
+
DEBUG_URL="${INSTANCE_URL}/builder_platform_interaction/flowBuilder.app?flowId=${FLOW_VERSION_ID}"
|
|
340
|
+
|
|
341
|
+
echo ""
|
|
342
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
343
|
+
echo " MANUAL STEP — Debug the flow in your browser"
|
|
344
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
345
|
+
echo ""
|
|
346
|
+
echo " This is a scheduled record-triggered flow, so \$Record is only bound"
|
|
347
|
+
echo " when you run it. Flow Builder's Debug runner lets you pick the record."
|
|
348
|
+
echo ""
|
|
349
|
+
echo " 1. Open the flow (active version $FLOW_VERSION_NUM):"
|
|
350
|
+
echo ""
|
|
351
|
+
echo " $DEBUG_URL"
|
|
352
|
+
echo ""
|
|
353
|
+
echo " 2. Click the Debug button (top-right in Flow Builder)."
|
|
354
|
+
echo " 3. In 'Debug the flow' → for the record that triggers the flow, select:"
|
|
355
|
+
echo ""
|
|
356
|
+
echo " $OPP_NAME"
|
|
357
|
+
echo " ($OPP_ID)"
|
|
358
|
+
echo ""
|
|
359
|
+
echo " 4. Leave 'Run the Flow in rollback mode' UNCHECKED so the DML persists,"
|
|
360
|
+
echo " then click Run."
|
|
361
|
+
echo " 5. Wait for the debug panel to show the run finished."
|
|
362
|
+
echo ""
|
|
363
|
+
echo " When the debug run is finished, verify the results with (the trailing"
|
|
364
|
+
echo " $BASELINE_COUNT is the pre-run suggestion baseline — keep it so the delta is exact):"
|
|
365
|
+
echo ""
|
|
366
|
+
echo " bash $0 $ORG_ALIAS $OPP_ID verify $BASELINE_COUNT"
|
|
367
|
+
echo ""
|
|
368
|
+
|
|
369
|
+
# Best-effort: open the URL in the default browser for convenience. Requires you
|
|
370
|
+
# to already be logged into this org in that browser, else it lands on login.
|
|
371
|
+
if command -v open >/dev/null 2>&1; then
|
|
372
|
+
open "$DEBUG_URL" >/dev/null 2>&1 || true
|
|
373
|
+
fi
|
|
374
|
+
|
|
375
|
+
# Convenience for a human at an interactive terminal: offer to pause here and
|
|
376
|
+
# chain into VERIFY. Gate on stdin being a real TTY (`-t 0`), NOT merely on
|
|
377
|
+
# /dev/tty existing — an agent driving this via a tool call has no interactive
|
|
378
|
+
# stdin, so it skips this and calls the verify command above once the user
|
|
379
|
+
# confirms in the conversation (no hang).
|
|
380
|
+
if [[ -t 0 ]]; then
|
|
381
|
+
printf ' Press ENTER once the debug run has finished to verify now (or Ctrl-C to verify later): '
|
|
382
|
+
if read -r _; then
|
|
383
|
+
run_verify "$OPP_ID" "$OPP_NAME" "$NOTE_COUNT" "$BASELINE_COUNT"
|
|
384
|
+
fi
|
|
385
|
+
fi
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Retrieve and display Pipeline Management settings status
|
|
4
|
+
# Uses SOAP readMetadata (reliable) instead of CLI retrieve (empty results for many settings)
|
|
5
|
+
# Usage: ./retrieve-settings.sh <org-alias>
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
# sf CLI can emit ANSI color codes inside --json stdout, breaking jq parsing.
|
|
10
|
+
# 2>/dev/null only strips stderr; these env vars are the reliable fix (see PM notes).
|
|
11
|
+
export NO_COLOR=1
|
|
12
|
+
export FORCE_COLOR=0
|
|
13
|
+
|
|
14
|
+
ORG_ALIAS="${1:-}"
|
|
15
|
+
|
|
16
|
+
if [[ -z "$ORG_ALIAS" ]]; then
|
|
17
|
+
echo "Error: Missing org alias"
|
|
18
|
+
echo "Usage: $0 <org-alias>"
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
echo "Retrieving Pipeline Management settings from org: $ORG_ALIAS"
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
# Get credentials
|
|
26
|
+
INSTANCE_URL=$(sf org display --target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.instanceUrl // empty' 2>/dev/null || echo "")
|
|
27
|
+
ACCESS_TOKEN=$(sf org display --target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.accessToken // empty' 2>/dev/null || echo "")
|
|
28
|
+
|
|
29
|
+
if [[ -z "$ACCESS_TOKEN" || "$ACCESS_TOKEN" == "null" || "$ACCESS_TOKEN" == *"REDACTED"* ]]; then
|
|
30
|
+
ACCESS_TOKEN=$(echo "y" | sf org auth show-access-token --target-org "$ORG_ALIAS" --no-prompt --json 2>/dev/null | jq -r '.result.accessToken // empty' 2>/dev/null || echo "")
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
if [[ -z "$INSTANCE_URL" || -z "$ACCESS_TOKEN" || "$ACCESS_TOKEN" == "null" ]]; then
|
|
34
|
+
echo "Error: Cannot connect to org. Run: sf org login web --alias $ORG_ALIAS"
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# SOAP readMetadata helper
|
|
39
|
+
soap_read() {
|
|
40
|
+
local TYPE="$1" NAME="$2"
|
|
41
|
+
curl -s "${INSTANCE_URL}/services/Soap/m/64.0" \
|
|
42
|
+
-H "Content-Type: text/xml; charset=UTF-8" \
|
|
43
|
+
-H "SOAPAction: readMetadata" \
|
|
44
|
+
-d "<?xml version='1.0' encoding='utf-8'?>
|
|
45
|
+
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:met='http://soap.sforce.com/2006/04/metadata'>
|
|
46
|
+
<soapenv:Header><met:SessionHeader><met:sessionId>${ACCESS_TOKEN}</met:sessionId></met:SessionHeader></soapenv:Header>
|
|
47
|
+
<soapenv:Body><met:readMetadata><met:type>${TYPE}</met:type><met:fullNames>${NAME}</met:fullNames></met:readMetadata></soapenv:Body>
|
|
48
|
+
</soapenv:Envelope>" 2>/dev/null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
check_setting() {
|
|
52
|
+
local LABEL="$1" TYPE="$2" NAME="$3" FIELD="$4"
|
|
53
|
+
printf " %-35s" "$LABEL:"
|
|
54
|
+
local RESPONSE
|
|
55
|
+
RESPONSE=$(soap_read "$TYPE" "$NAME")
|
|
56
|
+
local VALUE
|
|
57
|
+
VALUE=$(echo "$RESPONSE" | grep -o "<${FIELD}>[^<]*" | sed "s/<${FIELD}>//" | head -1 || echo "")
|
|
58
|
+
|
|
59
|
+
if [[ "$VALUE" == "true" ]]; then
|
|
60
|
+
echo "ENABLED"
|
|
61
|
+
elif [[ "$VALUE" == "false" ]]; then
|
|
62
|
+
echo "DISABLED"
|
|
63
|
+
elif [[ -z "$VALUE" ]]; then
|
|
64
|
+
echo "NOT FOUND (type may not exist in this org)"
|
|
65
|
+
else
|
|
66
|
+
echo "$VALUE"
|
|
67
|
+
fi
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
echo "=== Settings Status (via SOAP readMetadata) ==="
|
|
71
|
+
echo ""
|
|
72
|
+
|
|
73
|
+
check_setting "Einstein Generative AI" "EinsteinGptSettings" "EinsteinGpt" "enableEinsteinGptPlatform"
|
|
74
|
+
check_setting "Agentforce Agent (Copilot)" "EinsteinCopilotSettings" "EinsteinCopilot" "enableEinsteinGptCopilot"
|
|
75
|
+
check_setting "Pipeline Management" "SalesDealAgentSettings" "SalesDealAgent" "enableDealAgent"
|
|
76
|
+
check_setting "Auto-Approve All Tasks" "SalesDealAgentSettings" "SalesDealAgent" "enableDealAgentAutoApproveAllTasks"
|
|
77
|
+
check_setting "Pipeline Inspection" "OpportunitySettings" "Opportunity" "enablePipelineInspection"
|
|
78
|
+
check_setting "Enhanced Notes" "EnhancedNotesSettings" "EnhancedNotes" "enableEnhancedNotes"
|
|
79
|
+
check_setting "Enhanced Email" "EmailAdministrationSettings" "EmailAdministration" "enableEnhancedEmailEnabled"
|
|
80
|
+
check_setting "Opportunity Team Selling" "OpportunitySettings" "Opportunity" "enableOpportunityTeam"
|
|
81
|
+
|
|
82
|
+
echo ""
|
|
83
|
+
echo "=== Auto-Provisioned Components ==="
|
|
84
|
+
echo ""
|
|
85
|
+
|
|
86
|
+
# PSGs
|
|
87
|
+
PSG_RESULT=$(sf data query -q "SELECT DeveloperName FROM PermissionSetGroup WHERE DeveloperName IN ('SalesManagementUserPsg','SalesManagementAgentUserPsg')" --target-org "$ORG_ALIAS" --use-tooling-api --json 2>/dev/null | jq -r '.result.records[].DeveloperName' 2>/dev/null || echo "")
|
|
88
|
+
printf " %-35s" "Permission Set Groups:"
|
|
89
|
+
if [[ -n "$PSG_RESULT" ]]; then
|
|
90
|
+
echo "$PSG_RESULT" | tr '\n' ',' | sed 's/,$/\n/'
|
|
91
|
+
else
|
|
92
|
+
echo "NOT FOUND"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# Agent user
|
|
96
|
+
AGENT_USER=$(sf data query -q "SELECT Username FROM User WHERE Username LIKE '%salesmanagementagentuser%'" --target-org "$ORG_ALIAS" --json 2>/dev/null | jq -r '.result.records[0].Username // empty' 2>/dev/null || echo "")
|
|
97
|
+
printf " %-35s" "Agent User:"
|
|
98
|
+
if [[ -n "$AGENT_USER" ]]; then
|
|
99
|
+
echo "$AGENT_USER"
|
|
100
|
+
else
|
|
101
|
+
echo "NOT FOUND"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Flow — check by SourceTemplateId, then by naming convention, then by exact name
|
|
105
|
+
FLOW_QUERY=$(sf data query -q "SELECT ApiName, IsActive FROM FlowDefinitionView WHERE SourceTemplateId='sales_pipe_mgmt__OppSuggGenSchFlow' AND IsTemplate=false" --target-org "$ORG_ALIAS" --json 2>/dev/null)
|
|
106
|
+
FLOW_NAME=$(echo "$FLOW_QUERY" | jq -r '.result.records[0] | "\(.ApiName) (Active: \(.IsActive))"' 2>/dev/null | head -1 || echo "")
|
|
107
|
+
|
|
108
|
+
if [[ -z "$FLOW_NAME" || "$FLOW_NAME" == "null (Active: null)" ]]; then
|
|
109
|
+
FLOW_QUERY=$(sf data query -q "SELECT ApiName, IsActive FROM FlowDefinitionView WHERE ApiName = 'Process_Field_Update_Suggestions' AND IsTemplate=false" --target-org "$ORG_ALIAS" --json 2>/dev/null)
|
|
110
|
+
FLOW_NAME=$(echo "$FLOW_QUERY" | jq -r '.result.records[0] | "\(.ApiName) (Active: \(.IsActive))"' 2>/dev/null | head -1 || echo "")
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
printf " %-35s" "Schedule-Triggered Flow:"
|
|
114
|
+
if [[ -n "$FLOW_NAME" && "$FLOW_NAME" != "null (Active: null)" ]]; then
|
|
115
|
+
echo "$FLOW_NAME"
|
|
116
|
+
else
|
|
117
|
+
echo "NOT FOUND"
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Stage descriptions
|
|
121
|
+
DESC_RESULT=$(sf data query -q "SELECT Id FROM OpptStageDescription" --target-org "$ORG_ALIAS" --use-tooling-api --json 2>/dev/null || echo '{"status":1}')
|
|
122
|
+
printf " %-35s" "Stage Descriptions:"
|
|
123
|
+
if echo "$DESC_RESULT" | grep -qi "INVALID_TYPE\|NOT_FOUND\|sObject type.*not supported"; then
|
|
124
|
+
echo "N/A (PM not fully enabled)"
|
|
125
|
+
else
|
|
126
|
+
DESC_COUNT=$(echo "$DESC_RESULT" | jq -r '.result.totalSize // 0' 2>/dev/null | head -1 | tr -cd '0-9')
|
|
127
|
+
echo "${DESC_COUNT:-0}"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
echo ""
|
|
131
|
+
echo "Done."
|