@salesforce/afv-skills 1.47.0 → 1.49.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/education-cloud-domain-configure/SKILL.md +234 -0
- package/skills/education-cloud-domain-configure/references/dependent-features.md +198 -0
- package/skills/education-cloud-domain-configure/references/domain-features/academic-operations.md +386 -0
- package/skills/education-cloud-domain-configure/references/domain-features/alumni-relations.md +155 -0
- package/skills/education-cloud-domain-configure/references/domain-features/cross-domain-dependencies.md +18 -0
- package/skills/education-cloud-domain-configure/references/domain-features/industriessettings-toggle-reference.md +43 -0
- package/skills/education-cloud-domain-configure/references/domain-features/mentoring.md +198 -0
- package/skills/education-cloud-domain-configure/references/domain-features/recruitment-admissions.md +315 -0
- package/skills/education-cloud-domain-configure/references/domain-features/student-management.md +155 -0
- package/skills/education-cloud-domain-configure/references/domain-features/student-success.md +249 -0
- package/skills/education-cloud-domain-configure/references/domain-features.md +27 -0
- package/skills/education-cloud-domain-configure/references/gotchas-extended.md +23 -0
- package/skills/education-cloud-domain-configure/references/toggle-write-path.md +67 -0
- package/skills/education-cloud-domain-configure/scripts/check_license_provisioned.py +62 -0
- package/skills/education-cloud-domain-configure/scripts/check_org_edition.py +44 -0
- package/skills/education-cloud-domain-configure/scripts/check_permission_assigned.py +39 -0
- package/skills/education-cloud-multi-campus-configure/SKILL.md +2 -0
- package/skills/education-cloud-multi-campus-configure/references/foundation_prerequisites.md +4 -3
- package/skills/service-agentforce-channel-configure/SKILL.md +33 -28
- package/skills/service-agentforce-human-escalation-configure/SKILL.md +205 -0
- package/skills/service-agentforce-human-escalation-configure/assets/escalation-thresholds.instructions.md +37 -0
- package/skills/service-agentforce-human-escalation-configure/assets/force-app/main/default/flows/Human_Escalation_Outbound_Flow.flow-meta.xml +173 -0
- package/skills/service-agentforce-human-escalation-configure/assets/package.xml +8 -0
- package/skills/service-agentforce-human-escalation-configure/assets/sfdx-project.json +5 -0
- package/skills/service-agentforce-human-escalation-configure/references/classifier-contracts.md +103 -0
- package/skills/service-agentforce-human-escalation-configure/references/escalation-mechanism.md +63 -0
- package/skills/service-agentforce-human-escalation-configure/references/failure-policy.md +44 -0
- package/skills/service-agentforce-human-escalation-configure/references/nga-escalation.md +57 -0
- package/skills/service-agentforce-human-escalation-configure/references/runtime-verification.md +72 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/classify-agent-active.mjs +49 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/classify-nga-escalation.mjs +166 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/extract-outbound-route.mjs +67 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/patch-escalation-surfaces.mjs +131 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/tests/__init__.py +0 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/tests/_bootstrap.py +249 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/tests/test_escalation_contracts.py +899 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/verify-and-configure.sh +705 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/verify-escalation-config.mjs +89 -0
- package/skills/service-de-channel-routing-configure/SKILL.md +13 -5
- package/skills/service-de-channel-routing-configure/scripts/tests/test_skill_contract.py +25 -0
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +23 -10
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +63 -48
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +6 -2
- package/skills/service-omni-agent-users-create/SKILL.md +96 -0
- package/skills/service-omni-agent-users-create/assets/create-users.apex.template +80 -0
- package/skills/service-omni-agent-users-create/references/apex-patterns.md +135 -0
- package/skills/service-omni-agent-users-create/references/apex-template-notes.md +40 -0
- package/skills/service-omni-agent-users-create/scripts/detect-and-create.sh +206 -0
- package/skills/service-omni-agent-users-create/scripts/detect-existing.sh +122 -0
- package/skills/service-omni-agent-users-create/scripts/run-create.sh +298 -0
- package/skills/service-omni-agent-users-create/scripts/tests/test_user_create_security.py +171 -0
- package/skills/service-omni-agent-work-sharing-configure/SKILL.md +78 -0
- package/skills/service-omni-agent-work-sharing-configure/references/api-notes.md +31 -0
- package/skills/service-omni-agent-work-sharing-configure/scripts/configure-and-report.sh +186 -0
- package/skills/service-omni-agent-work-sharing-configure/scripts/tests/_bootstrap.py +120 -0
- package/skills/service-omni-agent-work-sharing-configure/scripts/tests/test_agent_work_sharing_contracts.py +93 -0
- package/skills/service-omni-base-settings-configure/SKILL.md +77 -0
- package/skills/service-omni-base-settings-configure/assets/force-app/main/default/settings/OmniChannel.settings-meta.xml +8 -0
- package/skills/service-omni-base-settings-configure/assets/package.xml +8 -0
- package/skills/service-omni-base-settings-configure/assets/sfdx-project.json +12 -0
- package/skills/service-omni-base-settings-configure/references/api-notes.md +121 -0
- package/skills/service-omni-base-settings-configure/scripts/configure-and-report.sh +164 -0
- package/skills/service-omni-base-settings-configure/scripts/detect-existing.sh +69 -0
- package/skills/service-omni-channel-setup-coordinate/SKILL.md +168 -0
- package/skills/service-omni-channel-setup-coordinate/examples/output-templates.md +161 -0
- package/skills/service-omni-channel-setup-coordinate/references/gap-catalog.md +99 -0
- package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +1542 -0
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/__init__.py +0 -0
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/_bootstrap.py +223 -0
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +804 -0
- package/skills/service-omni-command-center-analyze/SKILL.md +84 -0
- package/skills/service-omni-command-center-analyze/references/api-notes.md +54 -0
- package/skills/service-omni-command-center-analyze/scripts/analyze.sh +198 -0
- package/skills/service-omni-command-center-analyze/scripts/tests/_bootstrap.py +115 -0
- package/skills/service-omni-command-center-analyze/scripts/tests/test_command_center_analyze_contracts.py +165 -0
- package/skills/service-omni-permission-set-assign/SKILL.md +88 -0
- package/skills/service-omni-permission-set-assign/assets/package.xml +8 -0
- package/skills/service-omni-permission-set-assign/references/api-notes.md +143 -0
- package/skills/service-omni-permission-set-assign/scripts/verify-and-assign.sh +397 -0
- package/skills/service-omni-presence-status-deploy/SKILL.md +87 -0
- package/skills/service-omni-presence-status-deploy/assets/package.xml +12 -0
- package/skills/service-omni-presence-status-deploy/references/api-notes.md +115 -0
- package/skills/service-omni-presence-status-deploy/scripts/deploy-and-report.sh +422 -0
- package/skills/service-omni-presence-user-config-deploy/SKILL.md +80 -0
- package/skills/service-omni-presence-user-config-deploy/references/api-notes.md +60 -0
- package/skills/service-omni-presence-user-config-deploy/scripts/deploy-and-report.sh +261 -0
- package/skills/service-omni-presence-user-config-deploy/scripts/tests/_bootstrap.py +106 -0
- package/skills/service-omni-presence-user-config-deploy/scripts/tests/test_presence_user_config_contracts.py +142 -0
- package/skills/service-omni-queue-deploy/SKILL.md +91 -0
- package/skills/service-omni-queue-deploy/references/api-notes.md +140 -0
- package/skills/service-omni-queue-deploy/scripts/verify-and-align.sh +470 -0
- package/skills/service-omni-queue-members-assign/SKILL.md +93 -0
- package/skills/service-omni-queue-members-assign/references/api-notes.md +144 -0
- package/skills/service-omni-queue-members-assign/scripts/tests/_bootstrap.py +67 -0
- package/skills/service-omni-queue-members-assign/scripts/tests/test_queue_members_contracts.py +73 -0
- package/skills/service-omni-queue-members-assign/scripts/verify-and-bind.sh +362 -0
- package/skills/service-omni-queue-routing-config-deploy/SKILL.md +101 -0
- package/skills/service-omni-queue-routing-config-deploy/references/api-notes.md +127 -0
- package/skills/service-omni-queue-routing-config-deploy/scripts/tests/_bootstrap.py +90 -0
- package/skills/service-omni-queue-routing-config-deploy/scripts/tests/test_queue_routing_config_contracts.py +70 -0
- package/skills/service-omni-queue-routing-config-deploy/scripts/upsert-and-report.sh +538 -0
- package/skills/service-omni-routing-flow-deploy/SKILL.md +111 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Case_Trigger.SkillsBased.flow-meta.xml +94 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Case_Trigger.flow-meta.xml +88 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Cases.flow-meta.xml +144 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCall_Trigger.SkillsBased.flow-meta.xml +94 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCall_Trigger.flow-meta.xml +88 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCalls.flow-meta.xml +144 -0
- package/skills/service-omni-routing-flow-deploy/assets/package.xml +11 -0
- package/skills/service-omni-routing-flow-deploy/assets/sfdx-project.json +11 -0
- package/skills/service-omni-routing-flow-deploy/references/api-notes.md +265 -0
- package/skills/service-omni-routing-flow-deploy/scripts/deploy-and-report.sh +684 -0
- package/skills/service-omni-service-channel-configure/SKILL.md +83 -0
- package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/Cases.serviceChannel-meta.xml +9 -0
- package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/Incidents.serviceChannel-meta.xml +9 -0
- package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/MessagingSessions.serviceChannel-meta.xml +9 -0
- package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/VoiceCalls.serviceChannel-meta.xml +9 -0
- package/skills/service-omni-service-channel-configure/assets/package.xml +11 -0
- package/skills/service-omni-service-channel-configure/assets/sfdx-project.json +12 -0
- package/skills/service-omni-service-channel-configure/references/api-notes.md +84 -0
- package/skills/service-omni-service-channel-configure/scripts/deploy-and-report.sh +383 -0
- package/skills/service-omni-sidebar-configure/SKILL.md +77 -0
- package/skills/service-omni-sidebar-configure/references/api-notes.md +51 -0
- package/skills/service-omni-sidebar-configure/scripts/enable-and-report.sh +315 -0
- package/skills/service-omni-sidebar-configure/scripts/tests/_bootstrap.py +142 -0
- package/skills/service-omni-sidebar-configure/scripts/tests/test_sidebar_contracts.py +139 -0
- package/skills/service-omni-skills-based-routing-configure/SKILL.md +81 -0
- package/skills/service-omni-skills-based-routing-configure/references/api-notes.md +50 -0
- package/skills/service-omni-skills-based-routing-configure/scripts/configure-and-report.sh +270 -0
- package/skills/service-omni-skills-based-routing-configure/scripts/tests/_bootstrap.py +120 -0
- package/skills/service-omni-skills-based-routing-configure/scripts/tests/test_sbr_contracts.py +129 -0
- package/skills/service-omni-supervisor-config-deploy/SKILL.md +97 -0
- package/skills/service-omni-supervisor-config-deploy/assets/force-app/main/default/omniSupervisorConfigs/Omni_Supervisor.omniSupervisorConfig-meta.xml +9 -0
- package/skills/service-omni-supervisor-config-deploy/assets/package.xml +8 -0
- package/skills/service-omni-supervisor-config-deploy/assets/sfdx-project.json +12 -0
- package/skills/service-omni-supervisor-config-deploy/references/api-notes.md +205 -0
- package/skills/service-omni-supervisor-config-deploy/scripts/deploy-and-report.sh +586 -0
- package/skills/service-omni-supervisor-config-deploy/scripts/tests/_bootstrap.py +153 -0
- package/skills/service-omni-supervisor-config-deploy/scripts/tests/test_supervisor_config_contracts.py +116 -0
- package/skills/service-omni-supervisor-permset-assign/SKILL.md +88 -0
- package/skills/service-omni-supervisor-permset-assign/references/api-notes.md +48 -0
- package/skills/service-omni-supervisor-permset-assign/scripts/verify-and-assign.sh +316 -0
- package/skills/service-omni-supervisor-surface-deploy/SKILL.md +85 -0
- package/skills/service-omni-supervisor-surface-deploy/references/api-notes.md +47 -0
- package/skills/service-omni-supervisor-surface-deploy/scripts/deploy-and-report.sh +216 -0
- package/skills/service-omni-supervisor-surface-deploy/scripts/tests/_bootstrap.py +95 -0
- package/skills/service-omni-supervisor-surface-deploy/scripts/tests/test_supervisor_surface_contracts.py +154 -0
- package/skills/service-omni-supervisor-users-create/SKILL.md +92 -0
- package/skills/service-omni-supervisor-users-create/assets/create-supervisors.apex.template +72 -0
- package/skills/service-omni-supervisor-users-create/references/apex-patterns.md +73 -0
- package/skills/service-omni-supervisor-users-create/references/apex-template-notes.md +41 -0
- package/skills/service-omni-supervisor-users-create/scripts/detect-and-create.sh +197 -0
- package/skills/service-omni-supervisor-users-create/scripts/detect-existing.sh +112 -0
- package/skills/service-omni-supervisor-users-create/scripts/run-create.sh +296 -0
- package/skills/service-omni-work-skill-routing-configure/SKILL.md +80 -0
- package/skills/service-omni-work-skill-routing-configure/references/api-notes.md +67 -0
- package/skills/service-omni-work-skill-routing-configure/scripts/configure-and-report.sh +262 -0
- package/skills/service-omni-work-skill-routing-configure/scripts/tests/_bootstrap.py +121 -0
- package/skills/service-omni-work-skill-routing-configure/scripts/tests/test_work_skill_routing_contracts.py +161 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
ORG="${1:-}"
|
|
6
|
+
MODE="run"
|
|
7
|
+
CONFIRMED="false"
|
|
8
|
+
|
|
9
|
+
if [ "$#" -gt 0 ]; then
|
|
10
|
+
shift
|
|
11
|
+
fi
|
|
12
|
+
while [ "$#" -gt 0 ]; do
|
|
13
|
+
case "$1" in
|
|
14
|
+
--plan) MODE="plan" ;;
|
|
15
|
+
--confirm-org-wide-visibility) CONFIRMED="true" ;;
|
|
16
|
+
*)
|
|
17
|
+
echo '{"status":"blocked","blocking_issue":"Usage: configure-and-report.sh <org-alias> [--plan] [--confirm-org-wide-visibility]"}'
|
|
18
|
+
exit 1
|
|
19
|
+
;;
|
|
20
|
+
esac
|
|
21
|
+
shift
|
|
22
|
+
done
|
|
23
|
+
|
|
24
|
+
if [ -z "$ORG" ]; then
|
|
25
|
+
echo '{"status":"blocked","blocking_issue":"An authenticated org alias is required."}'
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
WORK_DIR=$(mktemp -d "${TMPDIR:-/tmp}/agentwork-sharing.XXXXXX")
|
|
30
|
+
trap 'rm -rf "$WORK_DIR"' EXIT
|
|
31
|
+
|
|
32
|
+
emit_result() {
|
|
33
|
+
local status="$1" previous_model="$2" current_model="$3" external_model="$4"
|
|
34
|
+
local changed="$5" dry_run="$6" deploy_id="$7" blocking_issue="$8"
|
|
35
|
+
jq -n \
|
|
36
|
+
--arg status "$status" \
|
|
37
|
+
--arg previous "$previous_model" \
|
|
38
|
+
--arg current "$current_model" \
|
|
39
|
+
--arg external "$external_model" \
|
|
40
|
+
--arg changed "$changed" \
|
|
41
|
+
--arg dry_run "$dry_run" \
|
|
42
|
+
--arg deploy_id "$deploy_id" \
|
|
43
|
+
--arg blocking_issue "$blocking_issue" \
|
|
44
|
+
'{
|
|
45
|
+
skill: "service-omni-agent-work-sharing-configure",
|
|
46
|
+
status: $status,
|
|
47
|
+
previous_sharing_model: (if $previous == "" then null else $previous end),
|
|
48
|
+
sharing_model: (if $current == "" then null else $current end),
|
|
49
|
+
external_sharing_model: (if $external == "" then null else $external end),
|
|
50
|
+
changed: ($changed == "true"),
|
|
51
|
+
dry_run: ($dry_run == "true"),
|
|
52
|
+
deploy_id: (if $deploy_id == "" then null else $deploy_id end),
|
|
53
|
+
blocking_issue: (if $blocking_issue == "" then null else $blocking_issue end)
|
|
54
|
+
}'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
xml_value() {
|
|
58
|
+
local tag="$1" file="$2"
|
|
59
|
+
tr -d '\n\r' < "$file" | sed -n "s:.*<$tag>\([^<]*\)</$tag>.*:\1:p"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
retrieve_agent_work() {
|
|
63
|
+
local destination="$1" result object_file
|
|
64
|
+
mkdir -p "$destination"
|
|
65
|
+
if ! result=$(sf project retrieve start \
|
|
66
|
+
--metadata "CustomObject:AgentWork" \
|
|
67
|
+
--target-org "$ORG" \
|
|
68
|
+
--target-metadata-dir "$destination" \
|
|
69
|
+
--unzip \
|
|
70
|
+
--json 2>&1); then
|
|
71
|
+
return 1
|
|
72
|
+
fi
|
|
73
|
+
if [ "$(jq -r '.status // 1' <<<"$result" 2>/dev/null)" != "0" ]; then
|
|
74
|
+
return 1
|
|
75
|
+
fi
|
|
76
|
+
object_file=$(find "$destination" -type f -name 'AgentWork.object' -print -quit)
|
|
77
|
+
if [ -z "$object_file" ]; then
|
|
78
|
+
return 1
|
|
79
|
+
fi
|
|
80
|
+
printf '%s' "$object_file"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
dry_run="false"
|
|
84
|
+
if [ "$MODE" = "plan" ]; then
|
|
85
|
+
dry_run="true"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
org_result=$(sf data query \
|
|
89
|
+
--query "SELECT IsSandbox, TrialExpirationDate, OrganizationType FROM Organization LIMIT 1" \
|
|
90
|
+
--target-org "$ORG" \
|
|
91
|
+
--json 2>&1) || {
|
|
92
|
+
emit_result "blocked" "" "" "" false "$dry_run" "" \
|
|
93
|
+
"Unable to classify the target org; refusing an org-wide sharing change."
|
|
94
|
+
exit 1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
is_sandbox=$(jq -r '.result.records[0].IsSandbox // false' <<<"$org_result" 2>/dev/null)
|
|
98
|
+
trial_expiration=$(jq -r '.result.records[0].TrialExpirationDate // empty' <<<"$org_result" 2>/dev/null)
|
|
99
|
+
organization_type=$(jq -r '.result.records[0].OrganizationType // empty' <<<"$org_result" 2>/dev/null)
|
|
100
|
+
if [ "$MODE" = "run" ] \
|
|
101
|
+
&& [ "$is_sandbox" != "true" ] \
|
|
102
|
+
&& [ -z "$trial_expiration" ] \
|
|
103
|
+
&& [ "$organization_type" != "Developer Edition" ] \
|
|
104
|
+
&& [ "$organization_type" != "Base Edition" ]; then
|
|
105
|
+
emit_result "blocked" "" "" "" false false "" \
|
|
106
|
+
"Production customer org detected; org-wide AgentWork sharing changes are refused."
|
|
107
|
+
exit 1
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
if ! object_file=$(retrieve_agent_work "$WORK_DIR/before"); then
|
|
111
|
+
emit_result "blocked" "" "" "" false "$dry_run" "" \
|
|
112
|
+
"Unable to retrieve CustomObject:AgentWork through the Metadata API."
|
|
113
|
+
exit 1
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
previous_model=$(xml_value sharingModel "$object_file")
|
|
117
|
+
external_model=$(xml_value externalSharingModel "$object_file")
|
|
118
|
+
if [[ ! "$previous_model" =~ ^(Private|Read|ReadWrite)$ ]] || [[ ! "$external_model" =~ ^(Private|Read|ReadWrite)$ ]]; then
|
|
119
|
+
emit_result "blocked" "$previous_model" "$previous_model" "$external_model" false "$dry_run" "" \
|
|
120
|
+
"AgentWork sharing metadata was incomplete or used an unsupported sharing model."
|
|
121
|
+
exit 1
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
if [ "$previous_model" = "Read" ] || [ "$previous_model" = "ReadWrite" ]; then
|
|
125
|
+
emit_result "reused" "$previous_model" "$previous_model" "$external_model" false "$dry_run" "" ""
|
|
126
|
+
exit 0
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
if [ "$MODE" = "plan" ]; then
|
|
130
|
+
emit_result "action_needed" "$previous_model" "Read" "$external_model" false true "" ""
|
|
131
|
+
exit 2
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
if [ "$CONFIRMED" != "true" ]; then
|
|
135
|
+
emit_result "blocked" "$previous_model" "$previous_model" "$external_model" false false "" \
|
|
136
|
+
"Changing AgentWork from Private to Read expands org-wide internal visibility. Re-run with --confirm-org-wide-visibility after reviewing the blast radius."
|
|
137
|
+
exit 1
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
source_root="$WORK_DIR/source"
|
|
141
|
+
mkdir -p "$source_root/force-app/main/default/objects/AgentWork"
|
|
142
|
+
cat > "$source_root/sfdx-project.json" <<'JSON'
|
|
143
|
+
{"packageDirectories":[{"path":"force-app","default":true}],"namespace":"","sourceApiVersion":"66.0"}
|
|
144
|
+
JSON
|
|
145
|
+
cat > "$source_root/force-app/main/default/objects/AgentWork/AgentWork.object-meta.xml" <<XML
|
|
146
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
147
|
+
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
148
|
+
<externalSharingModel>${external_model}</externalSharingModel>
|
|
149
|
+
<sharingModel>Read</sharingModel>
|
|
150
|
+
</CustomObject>
|
|
151
|
+
XML
|
|
152
|
+
|
|
153
|
+
if ! deploy_result=$(cd "$source_root" && sf project deploy start \
|
|
154
|
+
--source-dir force-app/main/default/objects/AgentWork/AgentWork.object-meta.xml \
|
|
155
|
+
--target-org "$ORG" \
|
|
156
|
+
--wait 20 \
|
|
157
|
+
--json 2>&1); then
|
|
158
|
+
emit_result "blocked" "$previous_model" "$previous_model" "$external_model" false false "" \
|
|
159
|
+
"The AgentWork sharing metadata deploy failed."
|
|
160
|
+
exit 1
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
deploy_status=$(jq -r '.result.status // empty' <<<"$deploy_result" 2>/dev/null)
|
|
164
|
+
deploy_success=$(jq -r '.result.success // false' <<<"$deploy_result" 2>/dev/null)
|
|
165
|
+
deploy_id=$(jq -r '.result.id // empty' <<<"$deploy_result" 2>/dev/null)
|
|
166
|
+
if [ "$deploy_status" != "Succeeded" ] && [ "$deploy_success" != "true" ]; then
|
|
167
|
+
emit_result "blocked" "$previous_model" "$previous_model" "$external_model" false false "$deploy_id" \
|
|
168
|
+
"The AgentWork sharing metadata deploy did not succeed."
|
|
169
|
+
exit 1
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
if ! readback_file=$(retrieve_agent_work "$WORK_DIR/readback"); then
|
|
173
|
+
emit_result "blocked" "$previous_model" "" "$external_model" true false "$deploy_id" \
|
|
174
|
+
"The AgentWork sharing read-back could not be retrieved after deployment."
|
|
175
|
+
exit 1
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
readback_model=$(xml_value sharingModel "$readback_file")
|
|
179
|
+
readback_external=$(xml_value externalSharingModel "$readback_file")
|
|
180
|
+
if [ "$readback_model" != "Read" ] || [ "$readback_external" != "$external_model" ]; then
|
|
181
|
+
emit_result "blocked" "$previous_model" "$readback_model" "$readback_external" true false "$deploy_id" \
|
|
182
|
+
"The AgentWork sharing read-back did not match the requested internal model or preserved external model."
|
|
183
|
+
exit 1
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
emit_result "configured" "$previous_model" "$readback_model" "$readback_external" true false "$deploy_id" ""
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import subprocess
|
|
6
|
+
import tempfile
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
SKILLS_ROOT = Path(__file__).resolve().parents[3]
|
|
11
|
+
SCRIPT = "service-omni-agent-work-sharing-configure/scripts/configure-and-report.sh"
|
|
12
|
+
|
|
13
|
+
_FAKE_SF = r'''#!/usr/bin/env bash
|
|
14
|
+
sub="${1:-} ${2:-}"; args="$*"
|
|
15
|
+
state_dir="${FAKE_STATE_DIR:?}"
|
|
16
|
+
trace="$state_dir/trace"
|
|
17
|
+
deployed="$state_dir/deployed"
|
|
18
|
+
printf '%s\n' "$args" >> "$trace"
|
|
19
|
+
|
|
20
|
+
arg_after() {
|
|
21
|
+
local wanted="$1" previous=""
|
|
22
|
+
shift
|
|
23
|
+
for value in "$@"; do
|
|
24
|
+
if [ "$previous" = "$wanted" ]; then printf '%s' "$value"; return; fi
|
|
25
|
+
previous="$value"
|
|
26
|
+
done
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
case "$sub" in
|
|
30
|
+
"data query")
|
|
31
|
+
if printf '%s' "$args" | grep -q "FROM Organization"; then
|
|
32
|
+
if [ "${FAKE_PRODUCTION:-0}" = "1" ]; then
|
|
33
|
+
echo '{"status":0,"result":{"records":[{"Id":"00Dxx0000000000EAA","IsSandbox":false,"TrialExpirationDate":null,"OrganizationType":"Enterprise Edition"}]}}'
|
|
34
|
+
elif [ "${FAKE_DEVELOPER_EDITION:-0}" = "1" ]; then
|
|
35
|
+
echo '{"status":0,"result":{"records":[{"Id":"00Dxx0000000000EAA","IsSandbox":false,"TrialExpirationDate":null,"OrganizationType":"Developer Edition"}]}}'
|
|
36
|
+
else
|
|
37
|
+
echo '{"status":0,"result":{"records":[{"Id":"00Dxx0000000000EAA","IsSandbox":true,"TrialExpirationDate":null,"OrganizationType":"Developer Edition"}]}}'
|
|
38
|
+
fi
|
|
39
|
+
fi;;
|
|
40
|
+
"project retrieve")
|
|
41
|
+
target_dir=$(arg_after --target-metadata-dir "$@")
|
|
42
|
+
mkdir -p "$target_dir/unpackaged/unpackaged/objects"
|
|
43
|
+
model="${FAKE_CURRENT_MODEL:-Private}"
|
|
44
|
+
if [ -f "$deployed" ]; then model="${FAKE_READBACK_MODEL:-Read}"; fi
|
|
45
|
+
cat > "$target_dir/unpackaged/unpackaged/objects/AgentWork.object" <<XML
|
|
46
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
47
|
+
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
48
|
+
<externalSharingModel>${FAKE_EXTERNAL_MODEL:-Private}</externalSharingModel>
|
|
49
|
+
<sharingModel>${model}</sharingModel>
|
|
50
|
+
</CustomObject>
|
|
51
|
+
XML
|
|
52
|
+
echo '{"status":0,"result":{"status":"Succeeded","success":true}}';;
|
|
53
|
+
"project deploy")
|
|
54
|
+
: > "$deployed"
|
|
55
|
+
echo '{"status":0,"result":{"id":"0Afxx0000000001AAA","status":"Succeeded","success":true,"details":{"componentFailures":[]}}}';;
|
|
56
|
+
*) echo '{"status":0,"result":{}}';;
|
|
57
|
+
esac
|
|
58
|
+
'''
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def last_json(output: str) -> dict:
|
|
62
|
+
decoder = json.JSONDecoder()
|
|
63
|
+
result, index = None, 0
|
|
64
|
+
while index < len(output):
|
|
65
|
+
if output[index] not in "{[":
|
|
66
|
+
index += 1
|
|
67
|
+
continue
|
|
68
|
+
try:
|
|
69
|
+
candidate, end = decoder.raw_decode(output, index)
|
|
70
|
+
if isinstance(candidate, dict):
|
|
71
|
+
result = candidate
|
|
72
|
+
index = end
|
|
73
|
+
except json.JSONDecodeError:
|
|
74
|
+
index += 1
|
|
75
|
+
assert result is not None, output
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class FakeSf:
|
|
80
|
+
def __init__(self):
|
|
81
|
+
self.root: Path | None = None
|
|
82
|
+
self.bin_dir: Path | None = None
|
|
83
|
+
self.state_dir: Path | None = None
|
|
84
|
+
|
|
85
|
+
def __enter__(self):
|
|
86
|
+
self.root = Path(tempfile.mkdtemp(prefix="agentwork-sharing-fake-sf-"))
|
|
87
|
+
self.bin_dir = self.root / "bin"
|
|
88
|
+
self.state_dir = self.root / "state"
|
|
89
|
+
self.bin_dir.mkdir()
|
|
90
|
+
self.state_dir.mkdir()
|
|
91
|
+
executable = self.bin_dir / "sf"
|
|
92
|
+
executable.write_text(_FAKE_SF)
|
|
93
|
+
executable.chmod(0o755)
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
def run(self, args, extra_env=None):
|
|
97
|
+
assert self.bin_dir is not None and self.state_dir is not None
|
|
98
|
+
env = dict(os.environ)
|
|
99
|
+
env["PATH"] = str(self.bin_dir) + os.pathsep + env.get("PATH", "")
|
|
100
|
+
env["FAKE_STATE_DIR"] = str(self.state_dir)
|
|
101
|
+
if extra_env:
|
|
102
|
+
env.update({key: str(value) for key, value in extra_env.items()})
|
|
103
|
+
proc = subprocess.run(
|
|
104
|
+
["bash", str(SKILLS_ROOT / SCRIPT), *args],
|
|
105
|
+
capture_output=True,
|
|
106
|
+
text=True,
|
|
107
|
+
env=env,
|
|
108
|
+
cwd=str(SKILLS_ROOT),
|
|
109
|
+
)
|
|
110
|
+
return proc.returncode, (proc.stdout or "") + (proc.stderr or "")
|
|
111
|
+
|
|
112
|
+
def read_state(self, name: str) -> str:
|
|
113
|
+
assert self.state_dir is not None
|
|
114
|
+
path = self.state_dir / name
|
|
115
|
+
return path.read_text() if path.exists() else ""
|
|
116
|
+
|
|
117
|
+
def __exit__(self, *_):
|
|
118
|
+
import shutil
|
|
119
|
+
if self.root:
|
|
120
|
+
shutil.rmtree(self.root, ignore_errors=True)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import sys
|
|
3
|
+
import unittest
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
7
|
+
from _bootstrap import FakeSf, last_json # noqa: E402
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AgentWorkSharingContractTests(unittest.TestCase):
|
|
11
|
+
def test_private_model_deploys_read_and_verifies(self):
|
|
12
|
+
with FakeSf() as fake:
|
|
13
|
+
rc, output = fake.run(["org", "--confirm-org-wide-visibility"])
|
|
14
|
+
trace = fake.read_state("trace")
|
|
15
|
+
|
|
16
|
+
self.assertEqual(rc, 0, output)
|
|
17
|
+
self.assertIn("project deploy start", trace)
|
|
18
|
+
self.assertIn("CustomObject:AgentWork", trace)
|
|
19
|
+
result = last_json(output)
|
|
20
|
+
self.assertEqual(result["status"], "configured")
|
|
21
|
+
self.assertEqual(result["previous_sharing_model"], "Private")
|
|
22
|
+
self.assertEqual(result["sharing_model"], "Read")
|
|
23
|
+
self.assertEqual(result["external_sharing_model"], "Private")
|
|
24
|
+
self.assertTrue(result["changed"])
|
|
25
|
+
|
|
26
|
+
def test_read_model_is_reused_without_deploy(self):
|
|
27
|
+
with FakeSf() as fake:
|
|
28
|
+
rc, output = fake.run(["org"], {"FAKE_CURRENT_MODEL": "Read"})
|
|
29
|
+
trace = fake.read_state("trace")
|
|
30
|
+
|
|
31
|
+
self.assertEqual(rc, 0, output)
|
|
32
|
+
self.assertNotIn("project deploy start", trace)
|
|
33
|
+
result = last_json(output)
|
|
34
|
+
self.assertEqual(result["status"], "reused")
|
|
35
|
+
self.assertFalse(result["changed"])
|
|
36
|
+
|
|
37
|
+
def test_plan_reports_action_without_deploy(self):
|
|
38
|
+
with FakeSf() as fake:
|
|
39
|
+
rc, output = fake.run(["org", "--plan"])
|
|
40
|
+
trace = fake.read_state("trace")
|
|
41
|
+
|
|
42
|
+
self.assertEqual(rc, 2, output)
|
|
43
|
+
self.assertNotIn("project deploy start", trace)
|
|
44
|
+
result = last_json(output)
|
|
45
|
+
self.assertEqual(result["status"], "action_needed")
|
|
46
|
+
self.assertTrue(result["dry_run"])
|
|
47
|
+
|
|
48
|
+
def test_production_blocks_before_deploy(self):
|
|
49
|
+
with FakeSf() as fake:
|
|
50
|
+
rc, output = fake.run(
|
|
51
|
+
["org", "--confirm-org-wide-visibility"],
|
|
52
|
+
{"FAKE_PRODUCTION": "1"},
|
|
53
|
+
)
|
|
54
|
+
trace = fake.read_state("trace")
|
|
55
|
+
|
|
56
|
+
self.assertEqual(rc, 1, output)
|
|
57
|
+
self.assertNotIn("project deploy start", trace)
|
|
58
|
+
self.assertIn("production", last_json(output)["blocking_issue"].lower())
|
|
59
|
+
|
|
60
|
+
def test_developer_edition_is_safe_for_confirmed_change(self):
|
|
61
|
+
with FakeSf() as fake:
|
|
62
|
+
rc, output = fake.run(
|
|
63
|
+
["org", "--confirm-org-wide-visibility"],
|
|
64
|
+
{"FAKE_DEVELOPER_EDITION": "1"},
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
self.assertEqual(rc, 0, output)
|
|
68
|
+
self.assertEqual(last_json(output)["status"], "configured")
|
|
69
|
+
|
|
70
|
+
def test_failed_readback_blocks(self):
|
|
71
|
+
with FakeSf() as fake:
|
|
72
|
+
rc, output = fake.run(
|
|
73
|
+
["org", "--confirm-org-wide-visibility"],
|
|
74
|
+
{"FAKE_READBACK_MODEL": "Private"},
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
self.assertEqual(rc, 1, output)
|
|
78
|
+
result = last_json(output)
|
|
79
|
+
self.assertEqual(result["status"], "blocked")
|
|
80
|
+
self.assertIn("read-back", result["blocking_issue"])
|
|
81
|
+
|
|
82
|
+
def test_change_requires_explicit_org_wide_confirmation(self):
|
|
83
|
+
with FakeSf() as fake:
|
|
84
|
+
rc, output = fake.run(["org"])
|
|
85
|
+
trace = fake.read_state("trace")
|
|
86
|
+
|
|
87
|
+
self.assertEqual(rc, 1, output)
|
|
88
|
+
self.assertNotIn("project deploy start", trace)
|
|
89
|
+
self.assertIn("confirm-org-wide-visibility", last_json(output)["blocking_issue"])
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
unittest.main(verbosity=2)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: service-omni-base-settings-configure
|
|
3
|
+
description: "Use to enable the five Omni-Channel base settings on a Salesforce org via the Metadata API. The canonical writer scripts/configure-and-report.sh detects, deploys, and re-verifies in one call (run mode) or detects only (plan mode); it is idempotent (deploys only when a toggle is false or missing) and guards writes with a sandbox/CDO/trial/DE safe_to_write check. It always surfaces the UI-only login-behavior gap in its report. Triggers: enable Omni-Channel, turn on Omni base settings, configure OmniChannelSettings, deploy Settings:OmniChannel. Do not use to configure downstream Omni entities (queues, presence, permissions — use the entity-specific skill) or to deploy other Settings types (use platform-metadata-deploy)."
|
|
4
|
+
allowed-tools: Bash Read Write Edit Glob Grep
|
|
5
|
+
metadata:
|
|
6
|
+
version: "1.0"
|
|
7
|
+
domains: ["Service"]
|
|
8
|
+
minApiVersion: "66.0"
|
|
9
|
+
relatedSkills:
|
|
10
|
+
- "platform-metadata-deploy"
|
|
11
|
+
- "service-omni-channel-setup-coordinate"
|
|
12
|
+
accessCheck:
|
|
13
|
+
- type: license
|
|
14
|
+
value: ServiceCloud
|
|
15
|
+
cliTools:
|
|
16
|
+
- tool: ["jq"]
|
|
17
|
+
semver: ">=1.6"
|
|
18
|
+
- tool: ["sf"]
|
|
19
|
+
semver: ">=2.139.6"
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# service-omni-base-settings-configure
|
|
23
|
+
|
|
24
|
+
Enable the five `OmniChannelSettings` booleans (`enableOmniChannel`, `enableOmniAutoLoginPrompt`, `enableOmniSecondaryRoutingPriority`, `enableOmniSkillsRouting`, `enableOmniStatusCapModel`) via a single Metadata API deploy. Nothing downstream — queues, presence statuses, routing flows — works without `enableOmniChannel=true`, so this must be the first write in an Omni setup sequence. The skill probes first and deploys only when a toggle is false or missing.
|
|
25
|
+
|
|
26
|
+
## Inputs
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
bash scripts/configure-and-report.sh run <org-alias> # detect; deploy if needed; re-verify
|
|
30
|
+
bash scripts/configure-and-report.sh plan <org-alias> # read-only: detect only, never deploys
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`org-alias` is the only input. All five toggles are always set to `true` — the skill takes no per-toggle overrides; a caller who wants a subset should use `platform-metadata-deploy` with their own `OmniChannel.settings-meta.xml`.
|
|
34
|
+
|
|
35
|
+
## Preconditions and safety
|
|
36
|
+
|
|
37
|
+
- Target org authenticated via `sf` CLI (My Domain URL, not `.lightning.force.com`), Service Cloud license present, `sf` CLI ≥ 2.139.6.
|
|
38
|
+
- **Production guardrail:** the writer computes `safe_to_write` as `IsSandbox` OR `TrialExpirationDate != null` OR `OrganizationType` in {Developer Edition, Base Edition}, and blocks with no override when it is false. This permits CDOs (`IsSandbox=false` with a non-null `TrialExpirationDate`); do not weaken it to a bare `IsSandbox` check.
|
|
39
|
+
|
|
40
|
+
## Run
|
|
41
|
+
|
|
42
|
+
`configure-and-report.sh` is the canonical entry point:
|
|
43
|
+
|
|
44
|
+
- **run** — probe; if all five are already enabled, emit `reused` (no deploy); otherwise run the `safe_to_write` guard, deploy the explicit `assets/force-app/main/default/settings/OmniChannel.settings-meta.xml` source file with all five `true` (a `SucceededPartial` is treated as failure), re-probe, and emit `configured` iff all five are now true, else `blocked`. The explicit source path bypasses source-tracking no-op decisions when the org value has drifted.
|
|
45
|
+
- **plan** — probe only; emit `reused` if all enabled, else `action_needed`. Never deploys.
|
|
46
|
+
|
|
47
|
+
The probe retrieves `Settings:OmniChannel` and takes 1–2 minutes (Metadata retrieve is slow); this is expected. The deploy runs from `assets/` (a valid DX project) and names the settings file with `--source-dir`; its template is never mutated at runtime, so the skill stays reproducible and does not report "No local changes to deploy" solely because local source tracking is clean.
|
|
48
|
+
|
|
49
|
+
## Behavior
|
|
50
|
+
|
|
51
|
+
**Whole-document writes.** `Settings` is a whole-document metadata type — the Metadata API does not accept partial updates, so the skill always deploys the full file rather than PATCHing individual toggles.
|
|
52
|
+
|
|
53
|
+
**Login-behavior gap.** The Omni login-behavior radio (Setup → Omni-Channel Settings → "Define login behavior when an agent opens a new window/tab") has no public API on v66. The report always surfaces its click-path — even on a no-op `reused` run — so a "nothing to do" result never hides the one manual action. `enableOmniAutoLoginPrompt` still deploys cleanly (other Omni features may depend on it internally) but does not drive that radio.
|
|
54
|
+
|
|
55
|
+
**Fail-closed verify.** After a deploy the skill re-probes and requires all five toggles true; a deploy that reports success but does not stick (an uncommon org-level restriction) blocks rather than reporting success.
|
|
56
|
+
|
|
57
|
+
## Output contract
|
|
58
|
+
|
|
59
|
+
`configure-and-report.sh` emits a single JSON object with `status` ∈ `configured` | `reused` | `action_needed` | `blocked`, a top-level `all_enabled` boolean the coordinator reads to gate downstream skills, full `before`/`after` toggle objects, `deploy_id`, `safe_to_write`, `manual_actions`, and `blocking_issue`.
|
|
60
|
+
|
|
61
|
+
- `configured` — a toggle was false, the deploy ran, and the re-probe shows all true (run mode).
|
|
62
|
+
- `reused` — all five were already true; no deploy.
|
|
63
|
+
- `action_needed` — plan mode saw a disabled toggle; nothing deployed.
|
|
64
|
+
- `blocked` — `safe_to_write=false`, the deploy failed or was `SucceededPartial`, or the re-probe still shows a false toggle.
|
|
65
|
+
|
|
66
|
+
`manual_actions` always includes the login-behavior gap entry on non-blocked reports; `deploy_id` is `null` for `reused`/`action_needed`; `blocking_issue` names the failure only when `status: blocked`.
|
|
67
|
+
|
|
68
|
+
## Limitations
|
|
69
|
+
|
|
70
|
+
- Configures only `OmniChannelSettings`, always with all five toggles true — other `Settings` types belong to `platform-metadata-deploy`.
|
|
71
|
+
- Cannot turn the login-behavior radio (no public API on v66) — it only surfaces the click-path.
|
|
72
|
+
|
|
73
|
+
## References
|
|
74
|
+
|
|
75
|
+
| File | When to read |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `references/api-notes.md` | Before a deploy — the five toggles' semantics, dependencies, and the login-behavior caveat |
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<OmniChannelSettings xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
3
|
+
<enableOmniAutoLoginPrompt>true</enableOmniAutoLoginPrompt>
|
|
4
|
+
<enableOmniChannel>true</enableOmniChannel>
|
|
5
|
+
<enableOmniSecondaryRoutingPriority>true</enableOmniSecondaryRoutingPriority>
|
|
6
|
+
<enableOmniSkillsRouting>true</enableOmniSkillsRouting>
|
|
7
|
+
<enableOmniStatusCapModel>true</enableOmniStatusCapModel>
|
|
8
|
+
</OmniChannelSettings>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# OmniChannelSettings — API notes
|
|
2
|
+
|
|
3
|
+
Load this reference **only when a deploy is actually needed** (i.e., after `detect-existing.sh` returned `all_enabled: false`). It covers the five toggles' semantics, cross-field validators, and the login-behavior UI-only caveat.
|
|
4
|
+
|
|
5
|
+
**Metadata type:** `Settings` with name `OmniChannel` (deployed as `Settings:OmniChannel`).
|
|
6
|
+
**API version verified:** v66 (Summer '26 baseline).
|
|
7
|
+
**Whole-document type:** always deploy the full XML, never PATCH individual toggles.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## The five toggles
|
|
12
|
+
|
|
13
|
+
All five ship as `true` in this skill's `assets/force-app/main/default/settings/OmniChannel.settings-meta.xml`. This skill does not accept per-toggle overrides — a user who wants a subset should invoke `platform-metadata-deploy` directly with their own XML.
|
|
14
|
+
|
|
15
|
+
### 1. `enableOmniChannel` (master switch)
|
|
16
|
+
|
|
17
|
+
**Effect:** Enables the Omni-Channel feature on the org. When `false`, no downstream Omni entity can be created (`ServicePresenceStatus`, `PresenceUserConfig`, `QueueRoutingConfig`, `WorkSkillRouting`, etc. all reject with `INVALID_TYPE`).
|
|
18
|
+
|
|
19
|
+
**Values:** `true` | `false`.
|
|
20
|
+
|
|
21
|
+
**Dependencies:** Must be `true` for any of the other four toggles to have meaningful effect.
|
|
22
|
+
|
|
23
|
+
**Reversibility:** Setting to `false` after enablement is not blocked, but is destructive — existing Omni entities remain but stop routing work. Do not disable in a production-like environment without explicit user acknowledgement.
|
|
24
|
+
|
|
25
|
+
### 2. `enableOmniSkillsRouting`
|
|
26
|
+
|
|
27
|
+
**Effect:** Enables skills-based routing. Required for:
|
|
28
|
+
- `WorkSkillRouting` rules to fire
|
|
29
|
+
- `routeWork` action in Flow with `routingType=SkillsBased`
|
|
30
|
+
- `Skill` records to influence work-item assignment
|
|
31
|
+
|
|
32
|
+
**Values:** `true` | `false`.
|
|
33
|
+
|
|
34
|
+
**Dependencies:** Requires `enableOmniChannel=true`.
|
|
35
|
+
|
|
36
|
+
### 3. `enableOmniSecondaryRoutingPriority`
|
|
37
|
+
|
|
38
|
+
**Effect:** Enables the secondary routing priority field on queue routing configurations. Allows two-level priority sorting when multiple work items match the same queue.
|
|
39
|
+
|
|
40
|
+
**Values:** `true` | `false`.
|
|
41
|
+
|
|
42
|
+
**Dependencies:** Requires `enableOmniChannel=true`.
|
|
43
|
+
|
|
44
|
+
### 4. `enableOmniStatusCapModel`
|
|
45
|
+
|
|
46
|
+
**Effect:** Enables the status-based capacity model on `ServiceChannel`. When true, agents can have different capacity ceilings based on which presence status they are in.
|
|
47
|
+
|
|
48
|
+
**Values:** `true` | `false`.
|
|
49
|
+
|
|
50
|
+
**Dependencies:** Requires `enableOmniChannel=true`.
|
|
51
|
+
|
|
52
|
+
### 5. `enableOmniAutoLoginPrompt` (⚠ caveat — see below)
|
|
53
|
+
|
|
54
|
+
**Effect (documented):** Should control the Omni-Channel login-prompt behavior when an agent opens a new window/tab.
|
|
55
|
+
|
|
56
|
+
**Effect (observed):** Deploys cleanly and round-trips through retrieve — but does **not** drive the UI radio at *Setup → Omni-Channel Settings → "Define login behavior when an agent using Omni-Channel opens a new window or tab"*. Flipping the value `true`/`false` re-retrieves the same value while the UI radio stays unchanged. The login-behavior radio is not reachable through this metadata field.
|
|
57
|
+
|
|
58
|
+
**Values:** `true` | `false`.
|
|
59
|
+
|
|
60
|
+
**Dependencies:** Requires `enableOmniChannel=true`.
|
|
61
|
+
|
|
62
|
+
**This skill still deploys the toggle as `true`.** The XML deploys cleanly and other Omni features may depend on it internally; not shipping it would be an incomplete base-settings deploy.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Cross-field validators
|
|
67
|
+
|
|
68
|
+
The Metadata API does **not** enforce cross-field validators on `OmniChannelSettings` — every combination of the five booleans is accepted by the deploy. However, functional dependencies exist at runtime:
|
|
69
|
+
|
|
70
|
+
| If this is `true` | Then this must also be `true` (for the feature to actually work) |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `enableOmniSkillsRouting` | `enableOmniChannel` |
|
|
73
|
+
| `enableOmniSecondaryRoutingPriority` | `enableOmniChannel` |
|
|
74
|
+
| `enableOmniStatusCapModel` | `enableOmniChannel` |
|
|
75
|
+
| `enableOmniAutoLoginPrompt` | `enableOmniChannel` |
|
|
76
|
+
|
|
77
|
+
Since this skill sets all five to `true`, the dependencies are automatically satisfied.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Deploy metadata name
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
Settings:OmniChannel
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Command:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
cd assets
|
|
91
|
+
sf project deploy start --target-org <org-alias> --metadata "Settings:OmniChannel" --json
|
|
92
|
+
```text
|
|
93
|
+
|
|
94
|
+
Expected response:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"status": 0,
|
|
99
|
+
"result": {
|
|
100
|
+
"id": "0AfRZ000001Yhef0AC",
|
|
101
|
+
"status": "Succeeded",
|
|
102
|
+
"success": true,
|
|
103
|
+
"numberComponentsDeployed": 1,
|
|
104
|
+
"numberComponentsTotal": 1
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Failure modes:**
|
|
110
|
+
|
|
111
|
+
- `status: Failed` + `componentFailures[0].problem: "Namespace: unable to deploy ..."` — org does not have Omni-Channel provisioned at all. Rare on Service Cloud orgs; possible on stripped-down trial orgs. Fail the skill; the user must contact Salesforce for org-shape correction.
|
|
112
|
+
- `UNKNOWN_EXCEPTION` during retrieve or deploy — transient server-side error. Retry once before failing.
|
|
113
|
+
- `LightningDomain` error on retrieve/deploy — org was authenticated with the `.lightning.force.com` URL instead of the My Domain URL. Re-authenticate with the My Domain URL. This is an auth bug, not an API issue.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Login-behavior UI-only gap (surface always)
|
|
118
|
+
|
|
119
|
+
The `enableOmniAutoLoginPrompt` toggle does not drive the *Setup → Omni-Channel Settings → "Define login behavior when an agent opens a new window/tab"* three-way radio. The full write-up (root cause, coordinator behavior) lives in the `service-omni-channel-setup-coordinate` skill's gap catalog reference.
|
|
120
|
+
|
|
121
|
+
**Skill behavior:** always include the login-behavior click-path in the report's `manual_actions` array, even for `reused` (no-op) runs. The operator may still need to click the radio manually to select their preferred behavior.
|