@salesforce/afv-skills 1.55.0 → 1.57.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-generate/SKILL.md +8 -0
- package/skills/agentforce-generate/references/actions-reference.md +2 -2
- package/skills/agentforce-generate/references/voice-modality-reference.md +51 -15
- package/skills/agentforce-generate/references/voice-telephony-cli.md +193 -0
- package/skills/agentforce-observe/SKILL.md +13 -9
- package/skills/agentforce-observe/references/ahm-alerts.md +193 -14
- package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +24 -15
- package/skills/automation-sandbox-post-copy-config-generate/assets/config_template.json +11 -0
- package/skills/automation-sandbox-post-copy-config-generate/assets/json_schema.json +33 -1
- package/skills/automation-sandbox-post-copy-config-generate/references/configuration_catalog.md +32 -1
- package/skills/automation-sandbox-post-copy-configure/SKILL.md +75 -71
- package/skills/automation-sandbox-post-copy-configure/assets/scheduled_apex_template.apex +13 -0
- package/skills/automation-sandbox-post-copy-configure/examples/sample_scheduled_apex_config.json +13 -0
- package/skills/automation-sandbox-post-copy-configure/references/scheduled_apex_path.md +155 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/build-scheduled-apex.mjs +62 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/soql-escape-job-name.mjs +28 -0
- package/skills/commerce-b2b-open-code-components-integrate/SKILL.md +1 -1
- package/skills/commerce-b2b-open-code-components-replace/SKILL.md +16 -16
- package/skills/consumer-goods-accruals-datakit-deploy/SKILL.md +383 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/setup.js +324 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/00-check-prerequisites.js +63 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/01-download-static-resource.js +100 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/02-replace-org-id.js +46 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/03-deploy-metadata.js +46 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/04-deploy-engine.js +198 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/05-deploy-tpm-accruals.js +231 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/06-create-dataspace.js +82 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/07-deploy-accruals-reports.js +517 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/08-deploy-ui.js +416 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/09-completion.js +44 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/utils.js +514 -0
- package/skills/consumer-goods-sync-management-configure/SKILL.md +137 -0
- package/skills/consumer-goods-sync-management-configure/examples/scenarios.md +294 -0
- package/skills/consumer-goods-sync-management-configure/references/act1-setup-sync.md +333 -0
- package/skills/consumer-goods-sync-management-configure/references/act2-assign-users.md +324 -0
- package/skills/consumer-goods-sync-management-configure/references/act3-plan-verify.md +113 -0
- package/skills/consumer-goods-sync-management-configure/references/readiness-and-enablement.md +164 -0
- package/skills/consumer-goods-sync-management-configure/references/sync-management-app-install-backbone.md +159 -0
- package/skills/consumer-goods-sync-management-configure/references/transports-and-namespace.md +220 -0
- package/skills/consumer-goods-sync-management-configure/references/verify-and-smoke.md +175 -0
- package/skills/dx-devops-project-manage/SKILL.md +1 -1
- package/skills/dx-org-analyze/SKILL.md +0 -1
- package/skills/dx-org-analyze/scripts/collect_org_data.py +2 -2
- package/skills/dx-org-analyze/scripts/compute_diff.py +2 -4
- package/skills/dx-org-analyze/scripts/introspect_org.py +4 -40
- package/skills/dx-org-manage/SKILL.md +6 -50
- package/skills/dx-org-manage/examples/README.md +10 -16
- package/skills/dx-org-manage/references/scratch-org-create.md +1 -1
- package/skills/dx-org-manage/references/scratch-org-operations.md +1 -1
- package/skills/dx-org-shape-manage/SKILL.md +4 -3
- package/skills/education-cloud-domain-configure/references/gotchas-extended.md +1 -0
- package/skills/experience-accessibility-validate/SKILL.md +8 -5
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-1-1-non-text-content.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-i-lists.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-ii-tables.md +20 -85
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iii-form-labels.md +4 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iv-regions.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-v-groups.md +2 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-5-identify-input.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-4-3-contrast.md +4 -14
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-1-1-keyboard.md +9 -5
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-4-link-purpose.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-6-headings-labels.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-1-pointer-gestures.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-2-pointer-cancellation.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-3-label-in-name.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-7-dragging-movement.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-1-on-focus.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-2-on-input.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-1-error-identification.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-2-labels-instructions.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-3-error-suggestion.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-i-name.md +4 -5
- package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-ii-role.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-iii-value.md +0 -4
- package/skills/experience-cms-content-generate/SKILL.md +1 -1
- package/skills/experience-cms-content-render/SKILL.md +3 -3
- package/skills/experience-cms-content-render/assets/angular/MediaRenderer.component.ts +35 -7
- package/skills/experience-cms-content-render/assets/angular/cms-item.service.ts +13 -4
- package/skills/experience-cms-content-render/assets/react/MediaRenderer.tsx +30 -8
- package/skills/experience-cms-content-render/assets/react/useCmsItem.ts +14 -4
- package/skills/experience-cms-content-render/assets/shared/cmsCore.types.ts +11 -1
- package/skills/experience-cms-content-render/assets/shared/externalRefs.ts +1 -1
- package/skills/experience-cms-content-render/assets/shared/mediaLabels.ts +62 -0
- package/skills/experience-cms-content-render/references/init-scaffold.md +13 -6
- package/skills/experience-content-media-stock-image-search/SKILL.md +0 -1
- package/skills/experience-lwc-accessibility-jest-run/SKILL.md +104 -25
- package/skills/experience-lwc-accessibility-jest-run/assets/jest.config.js +4 -0
- package/skills/experience-lwc-accessibility-jest-run/assets/sa11y-jest-setup.js +5 -0
- package/skills/experience-lwc-design-generate/SKILL.md +1 -1
- package/skills/experience-lwc-legacy-migrate/SKILL.md +212 -0
- package/skills/experience-lwc-legacy-migrate/assets/lo20-host-page-template.html +192 -0
- package/skills/experience-lwc-legacy-migrate/references/aura-to-lwc-completeness-checklist.md +188 -0
- package/skills/experience-lwc-legacy-migrate/references/lightning-out-2-system-reference.md +495 -0
- package/skills/experience-lwc-legacy-migrate/references/lightning-out-beta-to-2-migration.md +824 -0
- package/skills/experience-lwc-legacy-migrate/scripts/convert-lo-names.py +94 -0
- package/skills/experience-lwc-legacy-migrate/scripts/validate-lo20-page.py +133 -0
- package/skills/experience-ui-bundle-app-coordinate/SKILL.md +5 -5
- package/skills/experience-ui-bundle-features-generate/SKILL.md +65 -36
- package/skills/experience-ui-bundle-features-generate/references/angular/features.md +74 -0
- package/skills/experience-ui-bundle-features-generate/references/react/features.md +59 -0
- package/skills/experience-ui-bundle-features-generate/scripts/detect-framework.sh +73 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +2 -2
- package/skills/experience-ui-bundle-metadata-generate/SKILL.md +26 -14
- package/skills/experience-ui-bundle-metadata-generate/references/angular-metadata-generate.md +37 -0
- package/skills/experience-ui-bundle-metadata-generate/references/react-metadata-generate.md +32 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.sh +73 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.sh +30 -8
- package/skills/experience-ui-bundle-project-generate/SKILL.md +1 -1
- package/skills/field-service-data-capture-migrate/SKILL.md +391 -0
- package/skills/field-service-data-capture-migrate/assets/sample-legacy-flow.flow-meta.xml +163 -0
- package/skills/field-service-data-capture-migrate/references/architecture-notes.md +40 -0
- package/skills/field-service-data-capture-migrate/references/component-mapping.md +278 -0
- package/skills/field-service-data-capture-migrate/references/converter-builder-contract.md +183 -0
- package/skills/field-service-data-capture-migrate/references/dc-platform-rules.md +130 -0
- package/skills/field-service-data-capture-migrate/references/fsm-dc-capability-catalog.md +215 -0
- package/skills/field-service-data-capture-migrate/references/known-deploy-errors.md +36 -0
- package/skills/field-service-data-capture-migrate/references/migration-checklist.md +121 -0
- package/skills/field-service-data-capture-migrate/references/transformer-rules.md +132 -0
- package/skills/field-service-data-capture-migrate/scripts/analyze_flow.py +277 -0
- package/skills/field-service-data-capture-migrate/scripts/convert_to_dc_spec.py +1311 -0
- package/skills/field-service-data-capture-migrate/scripts/cud_analysis.py +402 -0
- package/skills/field-service-data-capture-migrate/scripts/deploy_flow.sh +230 -0
- package/skills/field-service-data-capture-migrate/scripts/discover_subflow_tree.py +230 -0
- package/skills/field-service-data-capture-migrate/scripts/flow_input.py +186 -0
- package/skills/field-service-data-capture-migrate/scripts/flow_xml_utils.py +39 -0
- package/skills/field-service-data-capture-migrate/scripts/fsm_dc_catalog.py +413 -0
- package/skills/field-service-data-capture-migrate/scripts/generate_summary.py +199 -0
- package/skills/field-service-data-capture-migrate/scripts/json_to_flow_xml.py +146 -0
- package/skills/field-service-data-capture-migrate/scripts/manual_review_flags.py +42 -0
- package/skills/field-service-data-capture-migrate/scripts/retrieve_flow_rest.sh +155 -0
- package/skills/field-service-data-capture-migrate/scripts/subflow_names.py +49 -0
- package/skills/field-service-data-capture-migrate/scripts/transform_flow.py +1661 -0
- package/skills/field-service-data-capture-migrate/scripts/validate_flow.sh +147 -0
- package/skills/field-service-data-capture-migrate/scripts/vendor/build_flow.py +1258 -0
- package/skills/integration-connectivity-connected-app-configure/SKILL.md +5 -5
- package/skills/integration-connectivity-generate/SKILL.md +10 -10
- package/skills/integration-connectivity-generate/scripts/configure-named-credential.sh +2 -2
- package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +1 -1
- package/skills/life-sciences-fieldsalesrep-coordinate/references/orchestration-flow.md +1 -1
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +14 -1
- package/skills/mobile-apps-create/SKILL.md +1 -1
- package/skills/{platform-agentsetup-categories-fetch → platform-agenticsetup-categories-get}/SKILL.md +7 -7
- package/skills/platform-apex-test-generate/SKILL.md +1 -1
- package/skills/platform-apex-test-run/SKILL.md +1 -1
- package/skills/platform-custom-field-generate/SKILL.md +1 -1
- package/skills/platform-custom-lightning-type-generate/SKILL.md +1 -1
- package/skills/platform-custom-metadata-type-generate/SKILL.md +1 -1
- package/skills/platform-custom-object-generate/SKILL.md +1 -1
- package/skills/platform-custom-report-type-generate/SKILL.md +1 -1
- package/skills/platform-custom-setting-generate/SKILL.md +1 -1
- package/skills/platform-data-and-tooling-api-context-get/SKILL.md +1 -1
- package/skills/platform-data-manage/SKILL.md +10 -10
- package/skills/platform-flexipage-generate/SKILL.md +1 -1
- package/skills/platform-lightning-app-coordinate/SKILL.md +1 -1
- package/skills/platform-metadata-api-context-get/SKILL.md +1 -1
- package/skills/platform-metadata-retrieve/SKILL.md +1 -1
- package/skills/platform-permission-set-generate/SKILL.md +1 -1
- package/skills/platform-report-generate/SKILL.md +1 -1
- package/skills/platform-salesforce-connect-adapter-generate/SKILL.md +4 -4
- package/skills/platform-sandbox-configure/SKILL.md +108 -133
- package/skills/platform-sandbox-configure/references/api-response-shapes.md +39 -0
- package/skills/platform-sandbox-configure/references/definition-file-approach.md +73 -0
- package/skills/platform-sharing-owd-configure/SKILL.md +1 -1
- package/skills/platform-sharing-rules-generate/SKILL.md +1 -1
- package/skills/platform-soql-query/SKILL.md +1 -1
- package/skills/platform-value-set-generate/SKILL.md +1 -1
- package/skills/platform-widget-generate/SKILL.md +26 -18
- package/skills/platform-widget-generate/examples/formulas.json +191 -0
- package/skills/platform-widget-generate/references/widget-formulas.md +123 -0
- package/skills/platform-widget-generate/references/widget-meta-directives.md +4 -4
- package/skills/sales-call-scoring-configure/SKILL.md +318 -0
- package/skills/sales-call-scoring-configure/assets/best-practice-competencies.json +67 -0
- package/skills/sales-call-scoring-configure/assets/ootb-competencies.json +58 -0
- package/skills/sales-call-scoring-configure/references/admin-communication.md +79 -0
- package/skills/sales-call-scoring-configure/references/competency-crud.md +130 -0
- package/skills/sales-call-scoring-configure/scripts/create-competency.sh +166 -0
- package/skills/sales-call-scoring-configure/scripts/create-custom-competency.sh +166 -0
- package/skills/sales-call-scoring-configure/scripts/edit-competency.sh +185 -0
- package/skills/sales-call-scoring-configure/scripts/edit-custom-competency.sh +190 -0
- package/skills/sales-call-scoring-configure/scripts/enable-call-scoring.sh +436 -0
- package/skills/sales-call-scoring-configure/scripts/get-competency.sh +72 -0
- package/skills/sales-call-scoring-configure/scripts/get-custom-competency.sh +78 -0
- package/skills/sales-call-scoring-configure/scripts/install-best-practice-competencies.sh +223 -0
- package/skills/sales-call-scoring-configure/scripts/install-ootb-competencies.sh +237 -0
- package/skills/sales-call-scoring-configure/scripts/list-competencies.sh +99 -0
- package/skills/sales-call-scoring-configure/scripts/shared/auth.sh +116 -0
- package/skills/sales-call-scoring-configure/scripts/shared/cap.sh +86 -0
- package/skills/sales-call-scoring-configure/scripts/shared/soap.sh +267 -0
- package/skills/sales-call-scoring-configure/scripts/shared/soql.sh +25 -0
- package/skills/sales-call-scoring-configure/scripts/toggle-competency.sh +112 -0
- package/skills/sales-call-scoring-configure/scripts/toggle-custom-competency.sh +125 -0
- package/skills/sales-call-scoring-configure/scripts/verify-ootb-competencies.sh +116 -0
- package/skills/service-agentforce-human-escalation-configure/SKILL.md +4 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/tests/_bootstrap.py +26 -6
- package/skills/service-agentforce-human-escalation-configure/scripts/tests/test_escalation_contracts.py +5 -4
- package/skills/service-concierge-portal-generate/references/portal-deploy-runbook.md +1 -0
- package/skills/service-de-channel-activate/SKILL.md +6 -5
- package/skills/service-de-channel-create/SKILL.md +3 -3
- package/skills/service-de-channel-routing-configure/SKILL.md +3 -3
- package/skills/service-de-channel-settings-configure/SKILL.md +195 -0
- package/skills/service-de-channel-settings-configure/references/channel-settings-facets.md +152 -0
- package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/gotchas.md +3 -3
- package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/language-keywords.md +4 -4
- package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/worked-examples.md +14 -14
- package/skills/service-de-headless-channel-configure/SKILL.md +6 -6
- package/skills/service-de-headless-channel-configure/references/worked-examples.md +1 -1
- package/skills/service-de-waba-integrate/SKILL.md +2 -1
- package/skills/service-digital-engagement-deployment-configure/SKILL.md +2 -0
- package/skills/service-digital-engagement-deployment-configure/scripts/check-api-version.sh +29 -0
- package/skills/service-email-to-case-configure/SKILL.md +1 -1
- package/skills/service-helpagent-coordinate/SKILL.md +3 -2
- package/skills/service-helpagent-coordinate/references/channel-voice.md +15 -4
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +49 -31
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +71 -6
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +26 -4
- package/skills/service-itsm-agentic-setup-cmdb-access-assign/SKILL.md +35 -10
- package/skills/service-itsm-agentic-setup-cmdb-access-assign/references/mcp-invocation.md +25 -5
- package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/SKILL.md +1 -1
- package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +5 -5
- package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +1 -1
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +2 -2
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/examples/output-templates.md +1 -1
- package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/SKILL.md +25 -15
- package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +8 -5
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +4 -2
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +1 -1
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +29 -16
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +8 -5
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +4 -2
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +1 -1
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +29 -16
- package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +138 -68
- package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +31 -15
- package/skills/service-itsm-agentic-setup-incident-management/references/incident-persona-psg.md +156 -0
- package/skills/service-itsm-agentic-setup-incident-management/references/incident-preferences.md +148 -0
- package/skills/service-itsm-agentic-setup-incident-management/references/major-incident-management.md +162 -0
- package/skills/service-itsm-agentic-setup-incident-management/references/service-mgmt-privilege.md +149 -0
- package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +103 -89
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +2 -2
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +21 -39
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +3 -3
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +18 -1
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +63 -37
- package/skills/service-omni-attribute-routing-configure/SKILL.md +53 -0
- package/skills/service-omni-attribute-routing-configure/references/api-notes.md +7 -0
- package/skills/service-omni-attribute-routing-configure/scripts/configure-and-report.sh +224 -0
- package/skills/service-omni-attribute-routing-configure/scripts/tests/test_attribute_routing_contracts.py +137 -0
- package/skills/service-omni-channel-inventory-analyze/SKILL.md +96 -0
- package/skills/service-omni-channel-inventory-analyze/references/api-notes.md +52 -0
- package/skills/service-omni-channel-inventory-analyze/scripts/analyze.sh +185 -0
- package/skills/service-omni-channel-inventory-analyze/scripts/tests/_bootstrap.py +84 -0
- package/skills/service-omni-channel-inventory-analyze/scripts/tests/test_inventory_analyze_contracts.py +141 -0
- package/skills/service-omni-channel-limits-analyze/SKILL.md +70 -0
- package/skills/service-omni-channel-limits-analyze/references/api-notes.md +22 -0
- package/skills/service-omni-channel-limits-analyze/scripts/analyze.sh +159 -0
- package/skills/service-omni-channel-limits-analyze/scripts/tests/_bootstrap.py +87 -0
- package/skills/service-omni-channel-limits-analyze/scripts/tests/test_limits_analyze_contracts.py +99 -0
- package/skills/service-omni-channel-setup-coordinate/SKILL.md +12 -20
- package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +55 -5
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +38 -0
- package/skills/service-omni-command-center-analyze/SKILL.md +2 -2
- package/skills/service-omni-command-center-analyze/scripts/analyze.sh +3 -3
- package/skills/dx-org-manage/examples/snapshots/error_output.json +0 -9
- package/skills/dx-org-manage/examples/snapshots/success_output.json +0 -15
- package/skills/dx-org-manage/references/cli_flags.md +0 -67
- package/skills/dx-org-manage/references/creating-snapshot.md +0 -103
- package/skills/dx-org-manage/references/snapshot_usage.md +0 -74
- package/skills/experience-accessibility-validate/scripts/contrast-ratio.py +0 -153
- package/skills/experience-lwc-accessibility-jest-run/references/running-sa11y-jest-tests.md +0 -205
- package/skills/experience-ui-bundle-features-generate/scripts/verify-react-bundle.sh +0 -14
- /package/skills/experience-ui-bundle-features-generate/references/{conflict-resolution-schema.json → common/conflict-resolution-schema.json} +0 -0
- /package/skills/{platform-agentsetup-categories-fetch → platform-agenticsetup-categories-get}/references/api-response-schema.md +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# List existing Coaching Competencies on the org.
|
|
4
|
+
# Reads EnablementCompetencyDef (setup entity, keyPrefix 1nA) via Tooling API.
|
|
5
|
+
#
|
|
6
|
+
# Output modes (per SKILL.md rule #5 — admin-safe by default):
|
|
7
|
+
# default — MasterLabel + IsActive + Scope + Description only.
|
|
8
|
+
# No record Ids, DeveloperNames, or Template enum keys.
|
|
9
|
+
# --verbose — Everything the default shows, PLUS DeveloperName, Id, and
|
|
10
|
+
# SourceCompetencyTemplate. Use when the admin explicitly
|
|
11
|
+
# asks to debug or share with support.
|
|
12
|
+
# --json — Raw record JSON for the calling agent to parse. Never
|
|
13
|
+
# forward this to the admin directly.
|
|
14
|
+
#
|
|
15
|
+
# Usage:
|
|
16
|
+
# ./list-competencies.sh <org-alias>
|
|
17
|
+
# ./list-competencies.sh <org-alias> --verbose
|
|
18
|
+
# ./list-competencies.sh <org-alias> --json
|
|
19
|
+
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
export NO_COLOR=1
|
|
23
|
+
export FORCE_COLOR=0
|
|
24
|
+
|
|
25
|
+
ORG_ALIAS="${1:-}"
|
|
26
|
+
FORMAT="${2:-text}"
|
|
27
|
+
|
|
28
|
+
if [[ -z "$ORG_ALIAS" ]]; then
|
|
29
|
+
echo "Error: Missing org alias"
|
|
30
|
+
echo "Usage: $0 <org-alias> [--verbose|--json]"
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
case "$FORMAT" in
|
|
35
|
+
text|--verbose|--json) ;;
|
|
36
|
+
*) echo "Error: Unknown flag: $FORMAT (expected --verbose or --json)"; exit 1 ;;
|
|
37
|
+
esac
|
|
38
|
+
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# Auth
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
43
|
+
# shellcheck source=shared/auth.sh
|
|
44
|
+
source "$SCRIPT_DIR/shared/auth.sh"
|
|
45
|
+
|
|
46
|
+
resolve_org_auth "$ORG_ALIAS" || exit 1
|
|
47
|
+
|
|
48
|
+
QUERY="SELECT Id, DeveloperName, MasterLabel, Description, IsActive, EvaluationScope, SourceCompetencyTemplate FROM EnablementCompetencyDef ORDER BY MasterLabel"
|
|
49
|
+
|
|
50
|
+
RAW=$(sf data query --target-org "$ORG_ALIAS" --use-tooling-api \
|
|
51
|
+
--query "$QUERY" --json 2>/dev/null)
|
|
52
|
+
|
|
53
|
+
# sf can prepend update-available warnings to stdout — extract the JSON body.
|
|
54
|
+
RAW_JSON=$(echo "$RAW" | awk '/^{/,EOF')
|
|
55
|
+
|
|
56
|
+
if ! echo "$RAW_JSON" | jq -e '.status == 0' >/dev/null 2>&1; then
|
|
57
|
+
echo "Error: Tooling API query failed:"
|
|
58
|
+
echo "$RAW" | jq -r '.message // .' 2>/dev/null || echo "$RAW"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
RAW="$RAW_JSON"
|
|
62
|
+
|
|
63
|
+
if [[ "$FORMAT" == "--json" ]]; then
|
|
64
|
+
echo "$RAW" | jq '.result.records'
|
|
65
|
+
exit 0
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
TOTAL=$(echo "$RAW" | jq -r '.result.totalSize')
|
|
69
|
+
ACTIVE=$(echo "$RAW" | jq -r '[.result.records[] | select(.IsActive == true)] | length')
|
|
70
|
+
|
|
71
|
+
echo "Coaching Competencies on $ORG_ALIAS"
|
|
72
|
+
echo ""
|
|
73
|
+
echo " Total: $TOTAL Active: $ACTIVE / 8 (max)"
|
|
74
|
+
echo ""
|
|
75
|
+
|
|
76
|
+
if [[ "$TOTAL" == "0" ]]; then
|
|
77
|
+
echo " (none configured yet — run install-ootb-competencies.sh to seed the OOTB set)"
|
|
78
|
+
exit 0
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [[ "$FORMAT" == "--verbose" ]]; then
|
|
82
|
+
# Full technical detail — Ids, DeveloperNames, Template enum keys.
|
|
83
|
+
# Only show this when the admin explicitly asks to debug or share with support.
|
|
84
|
+
echo "$RAW" | jq -r '.result.records[] |
|
|
85
|
+
" \(if .IsActive then "" else "" end) \(.MasterLabel)
|
|
86
|
+
Scope: \(.EvaluationScope)
|
|
87
|
+
Description: \(.Description // "(none)")
|
|
88
|
+
DeveloperName: \(.DeveloperName)\(if .SourceCompetencyTemplate != null and .SourceCompetencyTemplate != "" then "
|
|
89
|
+
Template: \(.SourceCompetencyTemplate)" else "" end)
|
|
90
|
+
Id: \(.Id)
|
|
91
|
+
"'
|
|
92
|
+
else
|
|
93
|
+
# Default admin-safe view — no Ids, DeveloperNames, or Template enum keys.
|
|
94
|
+
echo "$RAW" | jq -r '.result.records[] |
|
|
95
|
+
" \(if .IsActive then "" else "" end) \(.MasterLabel)
|
|
96
|
+
Scope: \(.EvaluationScope)
|
|
97
|
+
Description: \(.Description // "(none)")
|
|
98
|
+
"'
|
|
99
|
+
fi
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Shared library for org authentication resolution.
|
|
3
|
+
#
|
|
4
|
+
# Two entry points, deliberately separate:
|
|
5
|
+
#
|
|
6
|
+
# resolve_org_auth <alias> → validate alias, confirm reachable,
|
|
7
|
+
# confirm HTTPS. Does NOT extract
|
|
8
|
+
# ACCESS_TOKEN. Use this if the caller
|
|
9
|
+
# only ever hits Salesforce through
|
|
10
|
+
# `sf api request rest --target-org`
|
|
11
|
+
# or `sf data query --target-org`,
|
|
12
|
+
# which authenticate via the CLI's own
|
|
13
|
+
# session and never need the raw token
|
|
14
|
+
# in shell scope.
|
|
15
|
+
#
|
|
16
|
+
# resolve_org_auth_with_token <alias> → does everything above, PLUS extracts
|
|
17
|
+
# and exports ACCESS_TOKEN. Use this
|
|
18
|
+
# ONLY when a caller must embed the
|
|
19
|
+
# token in a request body (e.g. SOAP
|
|
20
|
+
# Metadata API sessionId — see
|
|
21
|
+
# enable-call-scoring.sh).
|
|
22
|
+
#
|
|
23
|
+
# The split exists because passing ACCESS_TOKEN on a curl command line
|
|
24
|
+
# ("curl -H 'Authorization: Bearer $ACCESS_TOKEN' ...") exposes the token in
|
|
25
|
+
# the OS process table (ps / /proc/*/cmdline). Callers that don't strictly
|
|
26
|
+
# need the raw token should not extract it. See W-23934530.
|
|
27
|
+
#
|
|
28
|
+
# Both functions cache results on RESOLVED_ORG_ALIAS so back-to-back invocations
|
|
29
|
+
# in the same shell don't re-hit `sf org display`.
|
|
30
|
+
|
|
31
|
+
# Common gate — alias validation + reachability + HTTPS. Exports INSTANCE_URL
|
|
32
|
+
# (needed by SOAP callers to build the endpoint). Does NOT export a token.
|
|
33
|
+
resolve_org_auth() {
|
|
34
|
+
local org_alias="$1"
|
|
35
|
+
|
|
36
|
+
if [[ -z "$org_alias" ]]; then
|
|
37
|
+
echo "Error: Missing org alias"
|
|
38
|
+
return 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
if [[ ! "$org_alias" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then
|
|
42
|
+
echo "Invalid org alias: '$org_alias'"
|
|
43
|
+
return 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Cache hit — but re-check HTTPS in case the cached INSTANCE_URL was set by
|
|
47
|
+
# something other than a prior resolve_org_auth call.
|
|
48
|
+
if [[ -n "${INSTANCE_URL:-}" && "${RESOLVED_ORG_ALIAS:-}" == "$org_alias" ]]; then
|
|
49
|
+
if [[ ! "$INSTANCE_URL" =~ ^https:// ]]; then
|
|
50
|
+
echo "Cached instance URL is not HTTPS: $INSTANCE_URL"
|
|
51
|
+
echo " Refusing to authenticate over an insecure connection."
|
|
52
|
+
return 1
|
|
53
|
+
fi
|
|
54
|
+
return 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Capture stderr too — some CLI versions emit auth errors there — then strip
|
|
58
|
+
# any warning lines the sf CLI prepends to stdout before the JSON body.
|
|
59
|
+
local org_display org_json
|
|
60
|
+
org_display=$(sf org display --target-org "$org_alias" --json 2>&1)
|
|
61
|
+
org_json=$(echo "$org_display" | awk '/^{/,EOF')
|
|
62
|
+
|
|
63
|
+
INSTANCE_URL=$(echo "$org_json" | jq -r '.result.instanceUrl // empty' 2>/dev/null)
|
|
64
|
+
if [[ -z "$INSTANCE_URL" ]]; then
|
|
65
|
+
echo "Cannot connect to org '$org_alias'. Run: sf org login web --alias $org_alias"
|
|
66
|
+
return 1
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
if [[ ! "$INSTANCE_URL" =~ ^https:// ]]; then
|
|
70
|
+
echo "Instance URL is not HTTPS: $INSTANCE_URL"
|
|
71
|
+
echo " Refusing to authenticate over an insecure connection."
|
|
72
|
+
return 1
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
export INSTANCE_URL
|
|
76
|
+
RESOLVED_ORG_ALIAS="$org_alias"
|
|
77
|
+
export RESOLVED_ORG_ALIAS
|
|
78
|
+
return 0
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Superset — resolve_org_auth + extract ACCESS_TOKEN. Used ONLY by callers
|
|
82
|
+
# that must place the token inside a request body (SOAP sessionId). New code
|
|
83
|
+
# should not use this; prefer `sf api request rest --target-org` instead.
|
|
84
|
+
resolve_org_auth_with_token() {
|
|
85
|
+
local org_alias="$1"
|
|
86
|
+
|
|
87
|
+
resolve_org_auth "$org_alias" || return 1
|
|
88
|
+
|
|
89
|
+
# Cache hit on token too.
|
|
90
|
+
if [[ -n "${ACCESS_TOKEN:-}" && "${ACCESS_TOKEN}" != "null" \
|
|
91
|
+
&& "${RESOLVED_ORG_ALIAS:-}" == "$org_alias" \
|
|
92
|
+
&& "${ACCESS_TOKEN_RESOLVED:-}" == "1" ]]; then
|
|
93
|
+
return 0
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
local org_display org_json
|
|
97
|
+
org_display=$(sf org display --target-org "$org_alias" --json 2>&1)
|
|
98
|
+
org_json=$(echo "$org_display" | awk '/^{/,EOF')
|
|
99
|
+
|
|
100
|
+
ACCESS_TOKEN=$(echo "$org_json" | jq -r '.result.accessToken // empty' 2>/dev/null)
|
|
101
|
+
if [[ -z "$ACCESS_TOKEN" || "$ACCESS_TOKEN" == "null" || "$ACCESS_TOKEN" == *"REDACTED"* ]]; then
|
|
102
|
+
# CLI ~2.108+ redacts accessToken in `org display` — fall back to the
|
|
103
|
+
# dedicated command that always returns the real token.
|
|
104
|
+
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')
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
if [[ -z "$ACCESS_TOKEN" || "$ACCESS_TOKEN" == "null" ]]; then
|
|
108
|
+
echo "Cannot extract access token. Re-authenticate: sf org login web --alias $org_alias"
|
|
109
|
+
return 1
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
export ACCESS_TOKEN
|
|
113
|
+
ACCESS_TOKEN_RESOLVED="1"
|
|
114
|
+
export ACCESS_TOKEN_RESOLVED
|
|
115
|
+
return 0
|
|
116
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Shared cap-diagnosis helpers for the 8-active EnablementCompetencyDef limit.
|
|
3
|
+
#
|
|
4
|
+
# Server-side, EnablementCompetencyDef enforces a hard cap of 8 IsActive=true
|
|
5
|
+
# records per org (CoachingCompetenciesFeature.MAX_ACTIVE_COMPETENCIES). All
|
|
6
|
+
# five write scripts (create-competency, create-custom-competency,
|
|
7
|
+
# toggle-custom-competency, install-ootb-competencies,
|
|
8
|
+
# install-best-practice-competencies) call these helpers to keep the
|
|
9
|
+
# admin-facing cap message identical across the surface.
|
|
10
|
+
#
|
|
11
|
+
# Contract for callers: source this file, then use
|
|
12
|
+
# query_active_count <ORG_ALIAS>
|
|
13
|
+
# print_cap_report <ORG_ALIAS> <CONTEXT>
|
|
14
|
+
# print_cap_footer_activate_hint <NEW_ID_OR_NAME>
|
|
15
|
+
#
|
|
16
|
+
# CONTEXT is a short human phrase used in the header, e.g.
|
|
17
|
+
# "creating '$MASTER_LABEL'" (create paths)
|
|
18
|
+
# "activating '$REC_LABEL'" (toggle paths)
|
|
19
|
+
# "installing OOTB competencies" (installer paths)
|
|
20
|
+
#
|
|
21
|
+
# All queries run through `sf api request rest --target-org` so the org's
|
|
22
|
+
# access token is never passed as curl argv (visible in the process table).
|
|
23
|
+
# Nothing here writes to the org — read-only diagnosis only. The decision to
|
|
24
|
+
# fall back to inactive (custom / installer paths) or refuse outright (toggle
|
|
25
|
+
# path — you can't activate to inactive) is the caller's.
|
|
26
|
+
|
|
27
|
+
MAX_ACTIVE_COMPETENCIES=8
|
|
28
|
+
CAP_TOOLING_BASE="services/data/v68.0/tooling"
|
|
29
|
+
|
|
30
|
+
# Return the current active count (or "0" on any failure — callers should
|
|
31
|
+
# treat a query failure as "cannot verify cap" and continue optimistically;
|
|
32
|
+
# the server-side hard cap still protects them).
|
|
33
|
+
query_active_count() {
|
|
34
|
+
local org_alias="$1"
|
|
35
|
+
(sf api request rest \
|
|
36
|
+
"${CAP_TOOLING_BASE}/query/?q=SELECT+COUNT()+FROM+EnablementCompetencyDef+WHERE+IsActive=true" \
|
|
37
|
+
--target-org "$org_alias" 2>/dev/null || true) \
|
|
38
|
+
| jq -r '.totalSize // 0' 2>/dev/null || echo "0"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Print a rich, admin-actionable cap report to stderr. Lists the currently
|
|
42
|
+
# active competencies with their Ids (deactivate command is copy-pasteable)
|
|
43
|
+
# and explains next steps. Caller supplies the context string that goes at
|
|
44
|
+
# the top ("Cap reached while <context>").
|
|
45
|
+
print_cap_report() {
|
|
46
|
+
local org_alias="$1"
|
|
47
|
+
local context="$2"
|
|
48
|
+
|
|
49
|
+
local list_json
|
|
50
|
+
list_json=$(sf api request rest \
|
|
51
|
+
"${CAP_TOOLING_BASE}/query/?q=SELECT+Id,MasterLabel,DeveloperName,SourceCompetencyTemplate+FROM+EnablementCompetencyDef+WHERE+IsActive=true+ORDER+BY+MasterLabel" \
|
|
52
|
+
--target-org "$org_alias" 2>/dev/null || true)
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
echo ""
|
|
56
|
+
echo "Warning: Active Coaching Competency cap reached while ${context}."
|
|
57
|
+
echo ""
|
|
58
|
+
echo " Salesforce allows up to ${MAX_ACTIVE_COMPETENCIES} active competencies per org."
|
|
59
|
+
echo " This org currently has ${MAX_ACTIVE_COMPETENCIES} active — listed below."
|
|
60
|
+
echo ""
|
|
61
|
+
echo " Currently active:"
|
|
62
|
+
echo "$list_json" | jq -r '.records[]? | " • \(.MasterLabel) (\(.Id))"' 2>/dev/null || echo " (unable to list — the server-side cap check will still enforce this)"
|
|
63
|
+
echo ""
|
|
64
|
+
echo " To free a slot, deactivate one of the above:"
|
|
65
|
+
echo "$list_json" | jq -r '.records[0:1][]? | " ./skills/sales-call-scoring-configure/scripts/toggle-custom-competency.sh <alias> \(.Id) deactivate"' 2>/dev/null
|
|
66
|
+
echo ""
|
|
67
|
+
} >&2
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Print the second half of the fallback message (only used by paths that
|
|
71
|
+
# auto-create an inactive record). Explains what just happened and how to
|
|
72
|
+
# flip it on later.
|
|
73
|
+
#
|
|
74
|
+
# Args:
|
|
75
|
+
# $1 = record identifier the admin can copy-paste (Id preferred,
|
|
76
|
+
# MasterLabel acceptable)
|
|
77
|
+
print_cap_footer_activate_hint() {
|
|
78
|
+
local ident="$1"
|
|
79
|
+
{
|
|
80
|
+
echo " The new competency was created INACTIVE so your work isn't blocked."
|
|
81
|
+
echo " Once you deactivate an existing competency, activate the new one:"
|
|
82
|
+
echo ""
|
|
83
|
+
echo " ./skills/sales-call-scoring-configure/scripts/toggle-custom-competency.sh <alias> ${ident} activate"
|
|
84
|
+
echo ""
|
|
85
|
+
} >&2
|
|
86
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Shared library for SOAP Metadata API response parsing
|
|
3
|
+
#
|
|
4
|
+
# Functions:
|
|
5
|
+
# redact_token <input> - Redacts session IDs and Bearer tokens from error messages
|
|
6
|
+
# parse_soap_response <xml> <field> <http_status> - Classifies SOAP responses
|
|
7
|
+
#
|
|
8
|
+
# Returns:
|
|
9
|
+
# "true" - field is enabled
|
|
10
|
+
# "false" - field is explicitly disabled or omitted (setting is off)
|
|
11
|
+
# "AUTH_ERROR:<fault>" - authentication/authorization failure
|
|
12
|
+
# "TYPE_UNAVAILABLE:<fault>" - org lacks license/edition for this feature
|
|
13
|
+
# "WRITE_ERROR:<statusCode>[:<message>]" - updateMetadata returned a well-formed
|
|
14
|
+
# response with <success>false</success> and an <errors> block. The server
|
|
15
|
+
# accepted the request and reports a specific reason for refusal (e.g.
|
|
16
|
+
# INSUFFICIENT_ACCESS_OR_READONLY during a provisioning window). Callers
|
|
17
|
+
# decide whether the statusCode is transient (retryable) or terminal.
|
|
18
|
+
# "NETWORK_ERROR" - network/service error (empty response, 5xx, malformed XML)
|
|
19
|
+
|
|
20
|
+
# Redact session IDs and Bearer tokens from error messages
|
|
21
|
+
# Args: $1 = input string
|
|
22
|
+
# Returns: string with tokens replaced by [REDACTED]
|
|
23
|
+
#
|
|
24
|
+
# Salesforce session IDs start with the 15/18-char org id (00D...) followed by
|
|
25
|
+
# '!' and a signature segment that contains '.', '=', '-', '+' in addition to
|
|
26
|
+
# alphanumerics. Match greedily up to the next whitespace or XML tag boundary
|
|
27
|
+
# ('<') so the whole token tail is redacted, not just its leading run.
|
|
28
|
+
redact_token() {
|
|
29
|
+
local input="$1"
|
|
30
|
+
printf '%s' "$input" | sed 's/00D[^ <]*/[REDACTED]/g; s/Bearer [^ ]*/Bearer [REDACTED]/g'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Parse SOAP Metadata API response and classify the result
|
|
34
|
+
# Args:
|
|
35
|
+
# $1 = raw SOAP XML response
|
|
36
|
+
# $2 = field name to extract (e.g., "enableEinsteinGptPlatform")
|
|
37
|
+
# $3 = HTTP status code (e.g., "200", "503")
|
|
38
|
+
# Returns: classification string (see header comments)
|
|
39
|
+
parse_soap_response() {
|
|
40
|
+
local xml_response="$1"
|
|
41
|
+
local field_name="$2"
|
|
42
|
+
local http_status="$3"
|
|
43
|
+
|
|
44
|
+
# Validate field_name to prevent regex injection in grep patterns below
|
|
45
|
+
if [[ ! "$field_name" =~ ^[A-Za-z0-9_]+$ ]]; then
|
|
46
|
+
echo "NETWORK_ERROR"
|
|
47
|
+
return 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Disable pipefail locally to allow grep failures without aborting
|
|
51
|
+
local old_opts="$-"
|
|
52
|
+
set +e
|
|
53
|
+
|
|
54
|
+
# An empty response body is always a network error, regardless of status.
|
|
55
|
+
if [[ -z "$xml_response" ]]; then
|
|
56
|
+
# Restore pipefail before returning
|
|
57
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
58
|
+
echo "NETWORK_ERROR"
|
|
59
|
+
return 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Check for SOAP Fault (auth, permission, or type errors) *before* the
|
|
63
|
+
# generic non-2xx-status check below — Salesforce commonly returns real
|
|
64
|
+
# SOAP Faults (invalid session, insufficient access, unlicensed type) with
|
|
65
|
+
# an HTTP 500 status, so gating on status first would silently reclassify
|
|
66
|
+
# every such fault as a generic "network/timeout error" and hide the
|
|
67
|
+
# actual auth/licensing diagnosis from the admin.
|
|
68
|
+
# Handle both standard and namespace-prefixed faults
|
|
69
|
+
local fault_code=""
|
|
70
|
+
if echo "$xml_response" | grep -q "<soapenv:Fault>\\|<sf:Fault>\\|<Fault>"; then
|
|
71
|
+
# Extract faultcode - try multiple patterns for different namespace conventions
|
|
72
|
+
fault_code=$(echo "$xml_response" | grep -o "<faultcode>[^<]*</faultcode>" | sed 's/<[^>]*>//g' | head -1)
|
|
73
|
+
if [[ -z "$fault_code" ]]; then
|
|
74
|
+
fault_code=$(echo "$xml_response" | grep -o "<sf:faultcode>[^<]*</sf:faultcode>" | sed 's/<[^>]*>//g' | head -1)
|
|
75
|
+
fi
|
|
76
|
+
if [[ -z "$fault_code" ]]; then
|
|
77
|
+
# Handle fully-qualified fault codes like "sf:INVALID_SESSION_ID"
|
|
78
|
+
fault_code=$(echo "$xml_response" | grep -oE "faultcode>[^<]*</.*faultcode" | sed 's/<[^>]*>//g' | sed 's/.*://' | head -1)
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [[ -n "$fault_code" ]]; then
|
|
82
|
+
# Extract faultstring for context (will be redacted)
|
|
83
|
+
local fault_string=""
|
|
84
|
+
fault_string=$(echo "$xml_response" | grep -o "<faultstring>[^<]*</faultstring>" | sed 's/<[^>]*>//g' | head -1 || echo "")
|
|
85
|
+
if [[ -z "$fault_string" ]]; then
|
|
86
|
+
fault_string=$(echo "$xml_response" | grep -o "<sf:faultstring>[^<]*</sf:faultstring>" | sed 's/<[^>]*>//g' | head -1 || echo "")
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Redact tokens from fault string
|
|
90
|
+
if [[ -n "$fault_string" ]]; then
|
|
91
|
+
fault_string=$(redact_token "$fault_string")
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Classify by fault type
|
|
95
|
+
# INVALID_TYPE = org lacks license/edition - distinct from auth failures
|
|
96
|
+
if echo "$fault_code" | grep -qi "INVALID_TYPE"; then
|
|
97
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
98
|
+
echo "TYPE_UNAVAILABLE:${fault_code}${fault_string:+:$fault_string}"
|
|
99
|
+
return 0
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# All other faults are auth/permission errors
|
|
103
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
104
|
+
echo "AUTH_ERROR:${fault_code}${fault_string:+:$fault_string}"
|
|
105
|
+
return 0
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# No fault matched above — a non-2xx status at this point is a genuine
|
|
110
|
+
# network/service error (not a classifiable SOAP-level failure).
|
|
111
|
+
if [[ "$http_status" != "200" && "$http_status" != "201" ]]; then
|
|
112
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
113
|
+
echo "NETWORK_ERROR"
|
|
114
|
+
return 0
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
# Check if response is valid XML with the expected structure
|
|
118
|
+
# If it's HTML or malformed XML, treat as network error
|
|
119
|
+
if ! echo "$xml_response" | grep -q "<readMetadataResponse>\\|<updateMetadataResponse>"; then
|
|
120
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
121
|
+
echo "NETWORK_ERROR"
|
|
122
|
+
return 0
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Check for closing envelope tag - if missing, XML is truncated
|
|
126
|
+
if ! echo "$xml_response" | grep -q "</soapenv:Envelope>"; then
|
|
127
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
128
|
+
echo "NETWORK_ERROR"
|
|
129
|
+
return 0
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# Well-formed updateMetadataResponse with an <errors> block: the server
|
|
133
|
+
# accepted the request, reports success=false, and names the reason via
|
|
134
|
+
# <statusCode> (e.g. INSUFFICIENT_ACCESS_OR_READONLY when a dependent field
|
|
135
|
+
# is temporarily read-only during ECI's async provisioning window — see
|
|
136
|
+
# W-23968462). Without this branch, the fallback field-value grep below
|
|
137
|
+
# would find <success>false</success> and collapse to bare "false", losing
|
|
138
|
+
# the statusCode the admin needs to distinguish transient from terminal.
|
|
139
|
+
# Scoped to updateMetadataResponse to avoid a false positive on readMetadata
|
|
140
|
+
# responses that happen to contain an <errors> element in metadata content.
|
|
141
|
+
if echo "$xml_response" | grep -q "<updateMetadataResponse>" \
|
|
142
|
+
&& echo "$xml_response" | grep -q "<errors>"; then
|
|
143
|
+
local status_code=""
|
|
144
|
+
local err_message=""
|
|
145
|
+
status_code=$(echo "$xml_response" | grep -o "<statusCode>[^<]*</statusCode>" | sed 's/<[^>]*>//g' | head -1)
|
|
146
|
+
err_message=$(echo "$xml_response" | grep -o "<message>[^<]*</message>" | sed 's/<[^>]*>//g' | head -1)
|
|
147
|
+
if [[ -n "$err_message" ]]; then
|
|
148
|
+
err_message=$(redact_token "$err_message")
|
|
149
|
+
fi
|
|
150
|
+
if [[ -n "$status_code" ]]; then
|
|
151
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
152
|
+
echo "WRITE_ERROR:${status_code}${err_message:+:$err_message}"
|
|
153
|
+
return 0
|
|
154
|
+
fi
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# Extract field value - try to find <field>true/false</field>
|
|
158
|
+
# head -1 collapses multi-record responses to the first match so two records
|
|
159
|
+
# never produce a two-line value that fails the == comparisons below.
|
|
160
|
+
local field_value=""
|
|
161
|
+
field_value=$(echo "$xml_response" | grep -o "<${field_name}>[^<]*</${field_name}>" | grep -o "true\\|false" | head -1 || echo "")
|
|
162
|
+
|
|
163
|
+
if [[ "$field_value" == "true" ]]; then
|
|
164
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
165
|
+
echo "true"
|
|
166
|
+
return 0
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
# An update call reporting success=false has no SOAP fault, but the
|
|
170
|
+
# response still carries an <errors> block (statusCode + message) with the
|
|
171
|
+
# actual reason — e.g. INSUFFICIENT_ACCESS_OR_READONLY. Surface it instead
|
|
172
|
+
# of silently collapsing to a bare "false" the caller can't act on.
|
|
173
|
+
if [[ "$field_name" == "success" && "$field_value" == "false" ]]; then
|
|
174
|
+
local err_status_code="" err_message=""
|
|
175
|
+
err_status_code=$(echo "$xml_response" | grep -o "<statusCode>[^<]*</statusCode>" | sed 's/<[^>]*>//g' | head -1)
|
|
176
|
+
if [[ -z "$err_status_code" ]]; then
|
|
177
|
+
err_status_code=$(echo "$xml_response" | grep -o "<sf:statusCode>[^<]*</sf:statusCode>" | sed 's/<[^>]*>//g' | head -1)
|
|
178
|
+
fi
|
|
179
|
+
err_message=$(echo "$xml_response" | grep -o "<message>[^<]*</message>" | sed 's/<[^>]*>//g' | head -1)
|
|
180
|
+
if [[ -z "$err_message" ]]; then
|
|
181
|
+
err_message=$(echo "$xml_response" | grep -o "<sf:message>[^<]*</sf:message>" | sed 's/<[^>]*>//g' | head -1)
|
|
182
|
+
fi
|
|
183
|
+
if [[ -n "$err_message" ]]; then
|
|
184
|
+
err_message=$(redact_token "$err_message")
|
|
185
|
+
fi
|
|
186
|
+
if [[ -n "$err_status_code" || -n "$err_message" ]]; then
|
|
187
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
188
|
+
echo "UPDATE_REJECTED:${err_status_code:-UNKNOWN}${err_message:+:$err_message}"
|
|
189
|
+
return 0
|
|
190
|
+
fi
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
# If field is explicitly false OR field is omitted entirely, treat as disabled.
|
|
194
|
+
# Salesforce omits boolean settings fields when they're off rather than
|
|
195
|
+
# emitting <field>false</field>, so an absent field inside an otherwise valid
|
|
196
|
+
# readMetadataResponse is the disabled state, not an error.
|
|
197
|
+
if [[ "$field_value" == "false" ]] || [[ -z "$field_value" ]]; then
|
|
198
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
199
|
+
echo "false"
|
|
200
|
+
return 0
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
# Shouldn't reach here, but if we do, treat as network error (unexpected response format)
|
|
204
|
+
if [[ "$old_opts" =~ e ]]; then set -e; fi
|
|
205
|
+
echo "NETWORK_ERROR"
|
|
206
|
+
return 0
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
# Issues one SOAP Metadata API call. Requires $SOAP_ENDPOINT and
|
|
210
|
+
# $CURL_TIMEOUT to be set by the caller (see enable-call-scoring.sh /
|
|
211
|
+
# install-ootb-competencies.sh for the standard setup).
|
|
212
|
+
# Args: $1 = SOAPAction, $2 = request body
|
|
213
|
+
# Body is piped via stdin (-d @-) rather than argv so the SOAP sessionId
|
|
214
|
+
# — which embeds the raw ACCESS_TOKEN — is not visible in the OS process
|
|
215
|
+
# table (ps / /proc/*/cmdline). See W-23934530 / W-23974869.
|
|
216
|
+
soap_call() {
|
|
217
|
+
local action="$1"
|
|
218
|
+
local body="$2"
|
|
219
|
+
# `|| true` — a curl failure (timeout, DNS, refused connection) must not
|
|
220
|
+
# abort the script via set -e; empty output + empty status here falls
|
|
221
|
+
# through to parse_soap_response's NETWORK_ERROR classification below.
|
|
222
|
+
printf '%s' "$body" | curl -s -w '\nHTTPSTATUS:%{http_code}' --max-time "$CURL_TIMEOUT" -X POST "$SOAP_ENDPOINT" \
|
|
223
|
+
-H "Content-Type: text/xml; charset=utf-8" \
|
|
224
|
+
-H "SOAPAction: $action" \
|
|
225
|
+
--data-binary @- 2>/dev/null || true
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
# Splits a soap_call() response into HTTP status + body and classifies one
|
|
229
|
+
# field via parse_soap_response. Unlike a plain grep, this distinguishes
|
|
230
|
+
# *why* a read/update didn't come back "true": an explicit false/absent
|
|
231
|
+
# field, a SOAP fault (auth/permission), an org that isn't licensed for the
|
|
232
|
+
# type (INVALID_TYPE), or a network/timeout failure.
|
|
233
|
+
# Args: $1 = soap_call() response, $2 = field name
|
|
234
|
+
classify_field() {
|
|
235
|
+
local combined="$1"
|
|
236
|
+
local field="$2"
|
|
237
|
+
local http_status body
|
|
238
|
+
# `|| true` on the grep — an empty/malformed $combined (curl failure) has
|
|
239
|
+
# no HTTPSTATUS marker to match, and under pipefail that would otherwise
|
|
240
|
+
# abort the script instead of yielding an empty status for NETWORK_ERROR.
|
|
241
|
+
http_status=$( (echo "$combined" | grep -o 'HTTPSTATUS:[0-9]*$' || true) | cut -d: -f2)
|
|
242
|
+
body=$(echo "$combined" | sed 's/HTTPSTATUS:[0-9]*$//')
|
|
243
|
+
parse_soap_response "$body" "$field" "$http_status"
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
# Normalizes a classify_field() result to true/false, or "" for anything
|
|
247
|
+
# that isn't a clean field read (fault/error) — callers that need the fault
|
|
248
|
+
# detail should inspect the raw classification themselves.
|
|
249
|
+
normalize_class() {
|
|
250
|
+
case "$1" in
|
|
251
|
+
true|false) echo "$1" ;;
|
|
252
|
+
*) echo "" ;;
|
|
253
|
+
esac
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
# Turns a classify_field() classification into a one-line, token-redacted,
|
|
257
|
+
# admin-safe explanation of why a call failed.
|
|
258
|
+
describe_failure() {
|
|
259
|
+
case "$1" in
|
|
260
|
+
AUTH_ERROR:*) echo "authentication/permission error — ${1#AUTH_ERROR:}" ;;
|
|
261
|
+
TYPE_UNAVAILABLE:*) echo "org isn't licensed for this setting — ${1#TYPE_UNAVAILABLE:}" ;;
|
|
262
|
+
WRITE_ERROR:*) echo "server refused the change — ${1#WRITE_ERROR:}" ;;
|
|
263
|
+
NETWORK_ERROR*) echo "network/timeout error reaching Salesforce — try again" ;;
|
|
264
|
+
false) echo "call succeeded but reported failure (no SOAP fault returned)" ;;
|
|
265
|
+
*) echo "unexpected response: $1" ;;
|
|
266
|
+
esac
|
|
267
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# soql.sh — SOQL string-literal escaping.
|
|
3
|
+
#
|
|
4
|
+
# soql_escape RAW → SAFE
|
|
5
|
+
# Prints RAW with every character that has meaning inside a SOQL string
|
|
6
|
+
# literal escaped so the caller can wrap the result in single quotes:
|
|
7
|
+
#
|
|
8
|
+
# WHERE MasterLabel='$(soql_escape "$LABEL")'
|
|
9
|
+
#
|
|
10
|
+
# Escapes, in order:
|
|
11
|
+
# \ → \\ (must happen first)
|
|
12
|
+
# ' → \'
|
|
13
|
+
#
|
|
14
|
+
# Order matters. If the quote-pass ran first, the backslash-pass would
|
|
15
|
+
# double-escape the backslash inserted for quotes and re-open the string.
|
|
16
|
+
#
|
|
17
|
+
# Implemented with sed rather than bash parameter expansion. The natural
|
|
18
|
+
# "${var//\'/\\\'}" pattern silently emits TWO backslashes in the
|
|
19
|
+
# replacement because of how backslashes are consumed by both the shell
|
|
20
|
+
# scanner and the parameter-expansion replacement string. sed sidesteps
|
|
21
|
+
# that quirk and its escape rules match SOQL's directly.
|
|
22
|
+
|
|
23
|
+
soql_escape() {
|
|
24
|
+
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e "s/'/\\\\'/g"
|
|
25
|
+
}
|