@salesforce/afv-skills 1.42.0 → 1.44.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 +2 -6
- package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +3 -0
- package/skills/automation-sandbox-post-copy-configure/SKILL.md +4 -0
- package/skills/design-systems-slds-validate/SKILL.md +2 -2
- package/skills/dx-devops-conflict-resolve/SKILL.md +205 -0
- package/skills/dx-devops-conflict-resolve/examples/conflict-workflows.md +165 -0
- package/skills/dx-devops-conflict-resolve/references/deploy-failure-resolution.md +75 -0
- package/skills/dx-devops-conflict-resolve/references/git-conflict-resolution.md +124 -0
- package/skills/dx-devops-conflict-resolve/scripts/detect-conflicts.sh +91 -0
- package/skills/dx-devops-conflict-resolve/scripts/diagnose-deploy-failure.sh +156 -0
- package/skills/dx-devops-request-status/SKILL.md +160 -0
- package/skills/dx-devops-request-status/examples/polling-workflows.md +101 -0
- package/skills/dx-devops-request-status/references/cli-commands.md +176 -0
- package/skills/dx-devops-request-status/scripts/poll-status.sh +134 -0
- package/skills/dx-devops-test-failures-analyze/SKILL.md +6 -6
- package/skills/dx-devops-test-pipeline-configure/SKILL.md +7 -7
- package/skills/dx-devops-test-suite-assignments-configure/SKILL.md +6 -6
- package/skills/dx-devops-test-suite-run/SKILL.md +6 -6
- package/skills/dx-devops-work-item-manage/SKILL.md +2 -0
- package/skills/dx-org-manage/references/creating-scratch-org.md +5 -2
- package/skills/dx-org-manage/references/creating-snapshot.md +1 -0
- package/skills/dx-org-shape-manage/SKILL.md +152 -0
- package/skills/dx-org-shape-manage/examples/create_error_output.json +9 -0
- package/skills/dx-org-shape-manage/examples/create_success_output.json +9 -0
- package/skills/dx-org-shape-manage/examples/delete_output.json +11 -0
- package/skills/dx-org-shape-manage/examples/list_inactive_output.json +32 -0
- package/skills/dx-org-shape-manage/examples/list_output.json +24 -0
- package/skills/dx-org-shape-manage/references/cli_flags.md +135 -0
- package/skills/dx-org-switch/SKILL.md +2 -2
- package/skills/dx-org-trial-expiration-check/SKILL.md +2 -0
- package/skills/dx-pkg-post-install-configure/SKILL.md +3 -0
- package/skills/education-cloud-multi-campus-configure/SKILL.md +211 -0
- package/skills/education-cloud-multi-campus-configure/examples/hierarchy_visualization.md +174 -0
- package/skills/education-cloud-multi-campus-configure/examples/output_examples.md +54 -0
- package/skills/education-cloud-multi-campus-configure/examples/sample_hierarchy_input.csv +29 -0
- package/skills/education-cloud-multi-campus-configure/examples/sample_hierarchy_input_edgecases.csv +16 -0
- package/skills/education-cloud-multi-campus-configure/references/account_recordtype_prerequisite.md +44 -0
- package/skills/education-cloud-multi-campus-configure/references/delta_computation.md +33 -0
- package/skills/education-cloud-multi-campus-configure/references/error_handling.md +198 -0
- package/skills/education-cloud-multi-campus-configure/references/foundation_prerequisites.md +54 -0
- package/skills/education-cloud-multi-campus-configure/references/gotchas.md +16 -0
- package/skills/education-cloud-multi-campus-configure/references/hierarchy_parsing_rules.md +133 -0
- package/skills/education-cloud-multi-campus-configure/references/mcp-invocation.md +75 -0
- package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/SKILL.md +1 -1
- package/skills/experience-cms-brand-apply/SKILL.md +4 -1
- package/skills/experience-cms-brand-create/SKILL.md +197 -0
- package/skills/experience-cms-brand-create/assets/brand-template.json +329 -0
- package/skills/experience-cms-brand-create/references/brand-anatomy.md +120 -0
- package/skills/experience-cms-brand-create/references/disk-contract.md +84 -0
- package/skills/experience-cms-content-generate/SKILL.md +192 -0
- package/skills/experience-cms-content-generate/assets/display-formats.md +84 -0
- package/skills/experience-cms-content-generate/assets/payloads/create-content-bulk.json +11 -0
- package/skills/experience-cms-content-generate/assets/payloads/create-content-single.json +11 -0
- package/skills/experience-cms-content-generate/assets/payloads/publish-content.json +4 -0
- package/skills/experience-cms-content-generate/assets/payloads/update-content.json +9 -0
- package/skills/experience-cms-content-generate/assets/questions.md +241 -0
- package/skills/experience-cms-content-generate/examples/create-content-call.md +81 -0
- package/skills/experience-cms-content-generate/references/bulk-batching.md +56 -0
- package/skills/experience-cms-content-generate/references/content-type-classification.md +88 -0
- package/skills/experience-cms-content-generate/references/content-write-tool.md +95 -0
- package/skills/experience-cms-content-generate/references/delegation-protocol.md +37 -0
- package/skills/experience-cms-content-generate/references/edit-publish-workflow.md +63 -0
- package/skills/experience-cms-content-generate/references/error-recovery.md +72 -0
- package/skills/experience-cms-content-generate/references/identifier-resolution.md +26 -0
- package/skills/experience-cms-content-generate/references/intent-routing.md +45 -0
- package/skills/experience-cms-content-generate/references/principles.md +19 -0
- package/skills/experience-cms-content-generate/references/ux-rules.md +68 -0
- package/skills/experience-cms-content-generate/references/workspace-resolution.md +33 -0
- package/skills/experience-cms-content-type-generate/SKILL.md +449 -0
- package/skills/experience-cms-content-type-generate/assets/discovery-prompts.md +79 -0
- package/skills/experience-cms-content-type-generate/assets/schema-example.json +70 -0
- package/skills/experience-cms-content-type-generate/references/agent-checklist.md +50 -0
- package/skills/experience-cms-content-type-generate/references/anti-patterns.md +39 -0
- package/skills/experience-cms-content-type-generate/references/deployment-errors.md +27 -0
- package/skills/experience-cms-content-type-generate/references/discovery-details.md +106 -0
- package/skills/experience-cms-content-type-generate/references/discovery-query-rules.md +85 -0
- package/skills/experience-cms-content-type-generate/references/edit-fields-loop.md +48 -0
- package/skills/experience-cms-content-type-generate/references/pre-deploy-checklist.md +21 -0
- package/skills/experience-cms-content-type-generate/references/retrieve-and-reconcile.md +105 -0
- package/skills/experience-cms-content-type-generate/references/schema-rules.md +51 -0
- package/skills/experience-cms-content-type-generate/references/schema-summary-format.md +60 -0
- package/skills/experience-lds-graphql-generate/SKILL.md +4 -0
- package/skills/experience-lwc-accessibility-jest-run/SKILL.md +79 -0
- package/skills/experience-lwc-accessibility-jest-run/references/running-sa11y-jest-tests.md +205 -0
- package/skills/experience-lwc-design-generate/SKILL.md +5 -4
- package/skills/experience-lwc-generate/SKILL.md +10 -9
- package/skills/experience-ui-bundle-deploy/references/dev-preview.md +21 -0
- package/skills/experience-ui-bundle-deploy/references/social-login.md +1 -0
- package/skills/experience-ui-bundle-file-upload-generate/SKILL.md +6 -6
- package/skills/experience-ui-bundle-localize/SKILL.md +30 -37
- package/skills/experience-ui-bundle-localize/references/gotchas.md +23 -7
- package/skills/experience-ui-bundle-localize/references/i18n-setup.md +48 -4
- package/skills/experience-ui-bundle-localize/references/label-xml.md +22 -8
- package/skills/experience-ui-bundle-localize/references/verifying.md +39 -11
- package/skills/experience-ui-bundle-localize/scripts/detect-bundle-type.sh +118 -15
- package/skills/experience-ui-bundle-localize/scripts/tests/test-detect-bundle-type.sh +187 -0
- package/skills/experience-ui-bundle-mfa-configure/SKILL.md +13 -2
- package/skills/experience-ui-bundle-mfa-configure/references/social-login.md +1 -0
- package/skills/experience-ui-bundle-project-generate/SKILL.md +2 -2
- package/skills/integration-connectivity-generate/SKILL.md +11 -10
- package/skills/integration-eventing-cdc-configure/SKILL.md +6 -6
- package/skills/integration-eventing-subscription-configure/SKILL.md +6 -5
- package/skills/mobile-platform-native-capabilities-integrate/SKILL.md +2 -2
- package/skills/mobile-platform-offline-validate/scripts/package.json +1 -1
- package/skills/platform-agentexchange-partner-offers-configure/SKILL.md +8 -8
- package/skills/platform-custom-application-generate/SKILL.md +2 -0
- package/skills/platform-custom-field-generate/SKILL.md +8 -6
- package/skills/platform-custom-metadata-type-generate/SKILL.md +460 -0
- package/skills/platform-custom-metadata-type-generate/references/cmdt-records.md +251 -0
- package/skills/platform-custom-metadata-type-generate/scripts/sanitize-developer-name.sh +46 -0
- package/skills/platform-custom-setting-generate/SKILL.md +419 -0
- package/skills/platform-dataspace-access-configure/SKILL.md +2 -0
- package/skills/platform-sharing-owd-configure/SKILL.md +3 -0
- package/skills/platform-value-set-generate/SKILL.md +2 -0
- package/skills/service-agentforce-channel-configure/SKILL.md +29 -20
- package/skills/service-agentforce-channel-configure/assets/BotEmailDefinition.botEmailDefinition-meta.xml +36 -0
- package/skills/service-agentforce-channel-configure/assets/email/unfiled$public/AgentforceForServiceEmailTemplate.email +17 -0
- package/skills/service-agentforce-channel-configure/assets/email/unfiled$public/AgentforceForServiceEmailTemplate.email-meta.xml +29 -0
- package/skills/service-agentforce-channel-configure/assets/mdapi-package.xml +25 -0
- package/skills/service-agentforce-channel-configure/assets/settings-mdapi-package.xml +30 -0
- package/skills/service-agentforce-channel-configure/references/agent-wiring.md +20 -0
- package/skills/service-agentforce-channel-configure/references/botemaildefinition.md +107 -0
- package/skills/service-agentforce-channel-configure/references/channel-branch-email.md +203 -50
- package/skills/service-agentforce-channel-configure/references/channel-types.md +30 -3
- package/skills/service-agentforce-channel-configure/references/queue-resolution.md +17 -8
- package/skills/service-agentforce-channel-configure/references/routing-flow.md +14 -3
- package/skills/service-agentforce-channel-configure/scripts/validate-botemaildefinition.py +126 -0
- package/skills/service-agentforce-channel-configure/scripts/validate-emailtemplate.py +133 -0
- package/skills/service-de-channel-activate/SKILL.md +271 -0
- package/skills/service-de-channel-activate/references/gotchas.md +31 -0
- package/skills/service-de-channel-activate/references/phone-verification.md +96 -0
- package/skills/service-de-channel-activate/references/worked-examples.md +14 -0
- package/skills/service-de-channel-consent-configure/SKILL.md +230 -0
- package/skills/service-de-channel-consent-configure/references/gotchas.md +41 -0
- package/skills/service-de-channel-consent-configure/references/language-keywords.md +84 -0
- package/skills/service-de-channel-consent-configure/references/worked-examples.md +134 -0
- package/skills/service-de-channel-create/SKILL.md +369 -0
- package/skills/service-de-channel-create/references/apple.md +59 -0
- package/skills/service-de-channel-create/references/connect-insert.md +84 -0
- package/skills/service-de-channel-create/references/facebook.md +154 -0
- package/skills/service-de-channel-create/references/line.md +66 -0
- package/skills/service-de-channel-create/references/sms.md +98 -0
- package/skills/service-de-channel-create/references/whatsapp.md +98 -0
- package/skills/service-de-channel-create/references/worked-examples.md +70 -0
- package/skills/service-de-channel-routing-configure/SKILL.md +345 -0
- package/skills/service-de-channel-routing-configure/references/asa-routing.md +90 -0
- package/skills/service-de-channel-routing-configure/references/gotchas.md +27 -0
- package/skills/service-de-channel-routing-configure/references/queue-creation.md +123 -0
- package/skills/service-de-channel-routing-configure/references/target-locate.md +98 -0
- package/skills/service-de-channel-routing-configure/references/worked-examples.md +174 -0
- package/skills/service-de-headless-channel-configure/SKILL.md +305 -0
- package/skills/service-de-headless-channel-configure/references/gotchas.md +27 -0
- package/skills/service-de-headless-channel-configure/references/inputs.md +49 -0
- package/skills/service-de-headless-channel-configure/references/output-envelopes.md +53 -0
- package/skills/service-de-headless-channel-configure/references/partial-success.md +24 -0
- package/skills/service-de-headless-channel-configure/references/terms-and-conditions.md +54 -0
- package/skills/service-de-headless-channel-configure/references/worked-examples.md +108 -0
- package/skills/service-de-waba-integrate/SKILL.md +227 -0
- package/skills/service-digital-engagement-channel-configure/scripts/check-api-version.sh +29 -0
- package/skills/service-digital-engagement-messaging-site-integrate/SKILL.md +10 -9
- package/skills/service-digital-engagement-messaging-site-integrate/references/lwr_patch.md +39 -21
- package/skills/service-digital-engagement-messaging-site-integrate/scripts/patch_lwr_bundle.sh +157 -96
- package/skills/service-email-to-case-configure/SKILL.md +190 -0
- package/skills/service-email-to-case-configure/assets/CaseSettings.settings-meta.xml +45 -0
- package/skills/service-email-to-case-configure/examples/CaseSettings-two-addresses.settings-meta.xml +36 -0
- package/skills/service-email-to-case-configure/references/apply-mechanics.md +73 -0
- package/skills/service-email-to-case-configure/references/routing_address_reference.md +73 -0
- package/skills/service-email-to-case-configure/references/troubleshooting.md +25 -0
- package/skills/service-email-to-case-configure/scripts/apply-casesettings.py +1315 -0
- package/skills/service-email-to-case-configure/scripts/check-agent-email-capability.sh +26 -0
- package/skills/service-email-to-case-configure/scripts/tests/__init__.py +0 -0
- package/skills/service-email-to-case-configure/scripts/tests/_bootstrap.py +45 -0
- package/skills/service-email-to-case-configure/scripts/tests/_fakeorg.py +366 -0
- package/skills/service-email-to-case-configure/scripts/tests/_run.py +84 -0
- package/skills/service-email-to-case-configure/scripts/tests/test_apply_org_scenarios.py +655 -0
- package/skills/service-email-to-case-configure/scripts/tests/test_get_session.py +134 -0
- package/skills/service-email-to-case-configure/scripts/tests/test_new_capabilities.py +193 -0
- package/skills/service-email-to-case-configure/scripts/tests/test_validate_casesettings.py +170 -0
- package/skills/service-email-to-case-configure/scripts/validate-casesettings.py +229 -0
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +33 -15
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +63 -47
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/SKILL.md +17 -12
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/references/cli-invocation.md +5 -3
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-enable-plan.mjs +11 -3
- package/skills/service-itsm-agentic-setup-agentforce-studio-validate/SKILL.md +8 -6
- package/skills/service-itsm-agentic-setup-agentforce-studio-validate/references/cli-invocation.md +3 -3
- package/skills/service-itsm-agentic-setup-agentforce-studio-validate/scripts/classify-readiness.mjs +11 -3
- package/skills/service-itsm-agentic-setup-configure/SKILL.md +5 -5
- package/skills/service-itsm-agentic-setup-configure/examples/output-templates.md +5 -5
- package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +2 -2
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +11 -7
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +20 -7
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +10 -6
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/action-availability.md +7 -7
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +11 -7
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/build-create-body.mjs +24 -17
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-action-availability.mjs +98 -58
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +20 -7
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/strip-release-management.mjs +176 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/SKILL.md +19 -19
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/cli-invocation.md +3 -4
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/helper-contracts.md +6 -6
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/permset-topology.md +3 -10
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-permset-availability.mjs +7 -9
- package/skills/service-itsm-incident-mgmt-configure/SKILL.md +2 -0
- package/skills/service-itsm-incident-priority-configure/SKILL.md +15 -12
- package/skills/service-itsm-incident-priority-configure/examples/matrix-operations.md +27 -1
- package/skills/service-itsm-incident-priority-configure/references/sf-cli-invocation.md +37 -6
- package/skills/service-native-voice-recording-transcription-configure/SKILL.md +146 -0
- package/skills/service-native-voice-recording-transcription-configure/assets/confirmation-output.json +16 -0
- package/skills/service-native-voice-recording-transcription-configure/assets/package.xml +22 -0
- package/skills/service-native-voice-recording-transcription-configure/references/thunderbird-voice-settings.md +101 -0
- package/skills/service-native-voice-recording-transcription-configure/scripts/enable-recording-transcription.sh +181 -0
- package/skills/service-helpagent-coordinate/references/channel-help-portal.md +0 -22
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-1-1-non-text-content.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-i-lists.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-ii-tables.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-iii-form-labels.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-iv-regions.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-v-groups.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-5-identify-input.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-4-3-contrast.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-1-1-keyboard.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-4-4-link-purpose.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-4-6-headings-labels.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-5-1-pointer-gestures.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-5-2-pointer-cancellation.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-5-3-label-in-name.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-5-7-dragging-movement.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-2-1-on-focus.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-2-2-on-input.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-3-1-error-identification.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-3-2-labels-instructions.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-3-3-error-suggestion.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-4-1-2-i-name.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-4-1-2-ii-role.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-4-1-2-iii-value.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-1-1-non-text-content.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-4-1-use-of-color.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-4-10-resize-reflow.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-4-11-non-text-contrast.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-4-3-contrast.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/scripts/contrast-ratio.py +0 -0
|
@@ -12,16 +12,39 @@
|
|
|
12
12
|
// after the fact is expensive; this classifier flags the mismatch BEFORE the
|
|
13
13
|
// activate call.
|
|
14
14
|
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
15
|
+
// Availability model (A9 — no prose interpretation):
|
|
16
|
+
// Each action block in the Agent Script is a `source:` / `target:` pair:
|
|
17
|
+
// source: "svc_..._<AgentActionName>" # the planner-facing alias
|
|
18
|
+
// target: "<scheme>://<InvocationTargetName>" # the real invocation target
|
|
19
|
+
// The `source:` value is the agent-action alias; the `target:` URI names the
|
|
20
|
+
// thing actually invoked. These two names routinely DIFFER for the SAME action
|
|
21
|
+
// — e.g. source `CreateIncidentResolutionSummary` →
|
|
22
|
+
// target `generatePromptResponse://...IncidentResolutionSummarizationPrompt`,
|
|
23
|
+
// or source `CreateIncidentRootCauseSummary` → target `flow://...CreaIncRootCse`
|
|
24
|
+
// (an abbreviated flow API name). Treating the alias and the target as two
|
|
25
|
+
// separate required actions (the old behaviour) false-flagged the alias as
|
|
26
|
+
// "missing" and blocked a valid activation.
|
|
27
|
+
//
|
|
28
|
+
// Only `generatePromptResponse://` targets are surfaced by
|
|
29
|
+
// `/actions/custom/generatePromptResponse`; `flow://`, `apex://`, and
|
|
30
|
+
// `standardInvocableAction://` targets live in other action buckets the
|
|
31
|
+
// endpoint never lists (their names are often not even namespace-prefixed,
|
|
32
|
+
// e.g. `associateSvcMgmntRecords`). So this gate can only verify the
|
|
33
|
+
// `generatePromptResponse://` targets, keyed on the TARGET name — never the
|
|
34
|
+
// source alias, never a non-prompt target. Rules:
|
|
35
|
+
// 1. Parse every `target:` URI; split by scheme. The checkable set is the
|
|
36
|
+
// `generatePromptResponse://` target names. Non-gPR targets are recorded
|
|
37
|
+
// and SKIPPED (this endpoint has no jurisdiction over them).
|
|
18
38
|
// 2. Enumerate every action name exposed by
|
|
19
39
|
// `/actions/custom/generatePromptResponse` — accepts both response shapes:
|
|
20
40
|
// (a) legacy `{ actions: [ { name, ... }, ... ] }`
|
|
21
41
|
// (b) newer `{ actions: { <fullyQualifiedName>: {...}, ... } }`
|
|
22
|
-
// Emit `missing =
|
|
23
|
-
// NOT-READY
|
|
24
|
-
//
|
|
42
|
+
// Emit `missing = <generatePromptResponse targets> - present`. missing.length
|
|
43
|
+
// > 0 ⇒ NOT-READY (the ITSM Intelligence permset that surfaces these
|
|
44
|
+
// prompt-response actions is not assigned for the running user). Zero gPR
|
|
45
|
+
// targets referenced but other targets present ⇒ READY (nothing this gate
|
|
46
|
+
// governs). No target: lines at all / non-parseable inputs ⇒ CANNOT-CONFIRM
|
|
47
|
+
// (never block on unreadable state — surface it and let the workflow decide).
|
|
25
48
|
//
|
|
26
49
|
// Usage:
|
|
27
50
|
// node classify-action-availability.mjs \
|
|
@@ -30,7 +53,8 @@
|
|
|
30
53
|
// <agent-templates.json> — Phase-1 `agent-templates` capture; the matched
|
|
31
54
|
// template's `agentScript` is decoded exactly
|
|
32
55
|
// like build-create-body.mjs decodes it, then
|
|
33
|
-
//
|
|
56
|
+
// its `target:` invocation URIs are parsed and
|
|
57
|
+
// split by scheme.
|
|
34
58
|
// <masterLabel> — the display label of the target template
|
|
35
59
|
// (e.g. "IT Service Fulfiller").
|
|
36
60
|
// <generate-prompt-response.json> — GET
|
|
@@ -38,9 +62,10 @@
|
|
|
38
62
|
// response body.
|
|
39
63
|
//
|
|
40
64
|
// Emits a single JSON object to stdout:
|
|
41
|
-
// { referenced: [...],
|
|
42
|
-
// present: [...],
|
|
43
|
-
// missing: [...],
|
|
65
|
+
// { referenced: [...], // generatePromptResponse:// target names this gate verifies
|
|
66
|
+
// present: [...], // action names surfaced by generatePromptResponse
|
|
67
|
+
// missing: [...], // referenced - present
|
|
68
|
+
// skippedNonPromptTargets: [ { scheme, name }, ... ], // flow/apex/standard — not gate-checkable
|
|
44
69
|
// verdict: "READY" | "NOT-READY" | "CANNOT-CONFIRM",
|
|
45
70
|
// reasons: [...] }
|
|
46
71
|
// Exit is always 0 on parseable inputs; the verdict is carried in the payload.
|
|
@@ -49,6 +74,7 @@
|
|
|
49
74
|
// READY.
|
|
50
75
|
|
|
51
76
|
import { readFileSync } from 'node:fs';
|
|
77
|
+
import { stripReleaseManagement, decodeAgentScriptEntities } from './strip-release-management.mjs';
|
|
52
78
|
|
|
53
79
|
function readJson(path) {
|
|
54
80
|
try {
|
|
@@ -60,52 +86,46 @@ function readJson(path) {
|
|
|
60
86
|
}
|
|
61
87
|
}
|
|
62
88
|
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return s.replace(/&(#?\w+);/g, (m, ref) => {
|
|
68
|
-
if (ref.startsWith('#')) {
|
|
69
|
-
const n = ref[1] === 'x' || ref[1] === 'X' ? parseInt(ref.slice(2), 16) : parseInt(ref.slice(1), 10);
|
|
70
|
-
return Number.isFinite(n) ? String.fromCodePoint(n) : m;
|
|
71
|
-
}
|
|
72
|
-
return Object.prototype.hasOwnProperty.call(NAMED, ref) ? NAMED[ref] : m;
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
function decodeEntities(s) {
|
|
76
|
-
let prev = s, next = decodeEntitiesOnce(s);
|
|
77
|
-
while (next !== prev) { prev = next; next = decodeEntitiesOnce(next); }
|
|
78
|
-
return next;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function extractReferencedActions(scriptText) {
|
|
82
|
-
// Only lines whose YAML key is `source` or `target` are load-bearing — a
|
|
83
|
-
// namespace-prefixed action name mentioned inside a description, instruction,
|
|
84
|
-
// or comment is documentation, not a required invocation. Scanning globally
|
|
85
|
-
// would mis-flag such a mention as NOT-READY and block a valid activation.
|
|
89
|
+
function extractTargets(scriptText) {
|
|
90
|
+
// Each action block pairs a `source:` alias with a `target:` invocation URI:
|
|
91
|
+
// source: "svc_itsm_intelligence__CreateIncidentResolutionSummary"
|
|
92
|
+
// target: "generatePromptResponse://svc_itsm_intelligence__IncidentResolutionSummarizationPrompt"
|
|
86
93
|
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
94
|
+
// Only the `target:` names the thing actually invoked, and only a
|
|
95
|
+
// `generatePromptResponse://` target is surfaced (or withheld, per the ITSM
|
|
96
|
+
// Intelligence permset) by /actions/custom/generatePromptResponse. `flow://`,
|
|
97
|
+
// `apex://`, and `standardInvocableAction://` targets are surfaced through
|
|
98
|
+
// other mechanisms and never appear in that endpoint, so they are recorded and
|
|
99
|
+
// skipped rather than mis-flagged as missing. The `source:` alias is never
|
|
100
|
+
// itself a generatePromptResponse entry — it is not part of the checkable set;
|
|
101
|
+
// scanning it (the old behaviour) false-flagged aliases whose real target IS
|
|
102
|
+
// present, blocking a valid activation.
|
|
92
103
|
//
|
|
93
|
-
// The
|
|
94
|
-
//
|
|
95
|
-
// (
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
// The regex tolerates leading whitespace, an optional YAML list dash, and the
|
|
105
|
+
// scalar value in ANY of its YAML quote forms — unquoted, single-quoted, or
|
|
106
|
+
// double-quoted. The opening quote (if any) is captured in group 1 and the same
|
|
107
|
+
// character is re-checked as the optional closing quote via a backreference, so
|
|
108
|
+
// `target: 'generatePromptResponse://Name'` parses exactly like the double-quoted
|
|
109
|
+
// and unquoted forms (accepting only `"?` before was a regression: a
|
|
110
|
+
// single-quoted target silently fell through to CANNOT-CONFIRM, and the workflow
|
|
111
|
+
// then proceeded to create an agent whose activation fails). The name after `://`
|
|
112
|
+
// is captured up to the next quote (either style) or whitespace. A target with no
|
|
113
|
+
// `scheme://` shape simply does not match and contributes nothing.
|
|
114
|
+
const gpr = new Set();
|
|
115
|
+
const other = [];
|
|
116
|
+
const targetLineRe = /^[ \t]*-?[ \t]*target[ \t]*:[ \t]*(['"]?)([A-Za-z][A-Za-z0-9]*):\/\/([^'"\s]+)\1?/;
|
|
100
117
|
for (const rawLine of scriptText.split(/\r?\n/)) {
|
|
101
|
-
const
|
|
102
|
-
if (!
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
118
|
+
const m = targetLineRe.exec(rawLine);
|
|
119
|
+
if (!m) continue;
|
|
120
|
+
const scheme = m[2];
|
|
121
|
+
const name = m[3];
|
|
122
|
+
if (scheme === 'generatePromptResponse') {
|
|
123
|
+
gpr.add(name);
|
|
124
|
+
} else {
|
|
125
|
+
other.push({ scheme, name });
|
|
106
126
|
}
|
|
107
127
|
}
|
|
108
|
-
return [...
|
|
128
|
+
return { gprTargets: [...gpr].sort(), otherTargets: other };
|
|
109
129
|
}
|
|
110
130
|
|
|
111
131
|
function extractPresentActions(actionsData) {
|
|
@@ -136,7 +156,12 @@ function findTemplateScript(agentTemplatesData, masterLabel) {
|
|
|
136
156
|
const wanted = String(masterLabel).trim().toLowerCase();
|
|
137
157
|
const match = items.find((it) => String(it?.masterLabel ?? '').trim().toLowerCase() === wanted);
|
|
138
158
|
if (!match || typeof match.agentScript !== 'string' || !match.agentScript.trim()) return null;
|
|
139
|
-
|
|
159
|
+
// Scan the SAME script the create actually ships — with the Release
|
|
160
|
+
// Management subagent stripped. build-create-body.mjs removes it, so
|
|
161
|
+
// `svc_itsm_intelligence__SummarizeRelease` is never referenced by the created
|
|
162
|
+
// agent; leaving it in the scanned text here would false-flag it as "missing"
|
|
163
|
+
// and block the very flow the strip unblocks on an org without ReleaseManagementPref.
|
|
164
|
+
return stripReleaseManagement(decodeAgentScriptEntities(match.agentScript)).text;
|
|
140
165
|
}
|
|
141
166
|
|
|
142
167
|
const [templatesPath, rawLabel, actionsPath] = process.argv.slice(2);
|
|
@@ -175,27 +200,42 @@ if (!scriptText) {
|
|
|
175
200
|
process.exit(0);
|
|
176
201
|
}
|
|
177
202
|
|
|
178
|
-
const referenced =
|
|
203
|
+
const { gprTargets: referenced, otherTargets } = extractTargets(scriptText);
|
|
179
204
|
const present = extractPresentActions(actionsRead.data);
|
|
180
205
|
const presentSet = new Set(present);
|
|
181
206
|
const missing = referenced.filter((r) => !presentSet.has(r));
|
|
207
|
+
const skippedNonPromptTargets = otherTargets;
|
|
182
208
|
|
|
183
209
|
let verdict, reasons;
|
|
184
210
|
if (referenced.length === 0) {
|
|
185
|
-
|
|
186
|
-
|
|
211
|
+
if (otherTargets.length > 0) {
|
|
212
|
+
// The template references only flow/apex/standard-invocable targets — none of
|
|
213
|
+
// which /actions/custom/generatePromptResponse governs. There is nothing for
|
|
214
|
+
// this permset gate to verify, so it must not block.
|
|
215
|
+
verdict = 'READY';
|
|
216
|
+
reasons = [
|
|
217
|
+
`No generatePromptResponse-backed actions are referenced by the template; the ${otherTargets.length} non-prompt target(s) (flow/apex/standard-invocable) are surfaced through other mechanisms and are outside this gate.`,
|
|
218
|
+
];
|
|
219
|
+
} else {
|
|
220
|
+
verdict = 'CANNOT-CONFIRM';
|
|
221
|
+
reasons = ['No target: invocation URIs were found in the decoded Agent Script — either the script shape is unexpected or decoding failed. Surface and continue with caution.'];
|
|
222
|
+
}
|
|
187
223
|
} else if (missing.length === 0) {
|
|
188
224
|
verdict = 'READY';
|
|
189
|
-
reasons = [
|
|
225
|
+
reasons = [
|
|
226
|
+
`All ${referenced.length} generatePromptResponse-backed action(s) referenced by the template are surfaced by /actions/custom/generatePromptResponse for the running user${
|
|
227
|
+
otherTargets.length ? ` (${otherTargets.length} non-prompt flow/standard-invocable target(s) are outside this gate and were not checked)` : ''
|
|
228
|
+
}.`,
|
|
229
|
+
];
|
|
190
230
|
} else {
|
|
191
231
|
verdict = 'NOT-READY';
|
|
192
232
|
reasons = [
|
|
193
|
-
`${missing.length} of ${referenced.length}
|
|
233
|
+
`${missing.length} of ${referenced.length} generatePromptResponse-backed action(s) referenced by the template are NOT surfaced by /actions/custom/generatePromptResponse for the running user.`,
|
|
194
234
|
`Missing: ${missing.join(', ')}`,
|
|
195
235
|
'Activate will succeed at the HTTP level but return {success:false, messages:[...]} — the agent will not be usable. Offer to hand off to service-itsm-agentic-setup-itsm-agentforce-permset-assign, which handles both the permset-not-assigned case and the package-not-installed case.',
|
|
196
236
|
];
|
|
197
237
|
}
|
|
198
238
|
|
|
199
239
|
process.stdout.write(JSON.stringify({
|
|
200
|
-
referenced, present, missing, verdict, reasons,
|
|
240
|
+
referenced, present, missing, skippedNonPromptTargets, verdict, reasons,
|
|
201
241
|
}, null, 2) + '\n');
|
package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs
CHANGED
|
@@ -161,6 +161,15 @@ const NEXT_STEPS = {
|
|
|
161
161
|
: 'Review the observed error and remediate. Enablement of missing prerequisites is a Setup-UI/admin action outside this skill\'s scope — use `service-itsm-agentic-setup-agentforce-studio-validate` or `service-itsm-agentic-setup-agentforce-studio-configure` to check/enable readiness first. Re-run this skill once the blocker is resolved.',
|
|
162
162
|
};
|
|
163
163
|
|
|
164
|
+
// Escape a value for a Markdown table cell — a literal pipe or newline would
|
|
165
|
+
// break the row. The stage-detail values are enumerated/controlled, so this is
|
|
166
|
+
// belt-and-braces, but it keeps the table well-formed against any future field.
|
|
167
|
+
const cell = (v) => String(v).replace(/\|/g, '\\|').replace(/\r?\n/g, ' ');
|
|
168
|
+
const confirmDetail =
|
|
169
|
+
confirm === 'true' && (devName !== '<pending>' || label !== '<pending>')
|
|
170
|
+
? `; confirmed developerName=${devName}, label="${label}"`
|
|
171
|
+
: '';
|
|
172
|
+
|
|
164
173
|
const report = `# Fulfiller Agent — Create & Activate
|
|
165
174
|
|
|
166
175
|
IT Service Fulfiller Agent Creation (via service-itsm-agentic-setup-fulfiller-agent-configure)
|
|
@@ -168,13 +177,17 @@ IT Service Fulfiller Agent Creation (via service-itsm-agentic-setup-fulfiller-ag
|
|
|
168
177
|
Org: ${org} (API v67.0)
|
|
169
178
|
Agent: ${devName} ("${label}") — NGA-native bundle
|
|
170
179
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
180
|
+
Stage 2 — install & activate the agent from its template:
|
|
181
|
+
|
|
182
|
+
| Stage | Status |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| Preflight | ${cell(`Studio hasAccess=${preStudio}; template agentScript present=${preTmpl}; verdict=${preVerdict}`)} |
|
|
185
|
+
| Enumerate | ${cell(`target agent exists before write=${enumExists}; latest version status=${enumVer}; verdict=${enumVerdict}`)} |
|
|
186
|
+
| Confirm-to-write | ${cell(`user-confirmed=${confirm}${confirmDetail}`)} |
|
|
187
|
+
| Create bundle | ${cell(createBundle)} |
|
|
188
|
+
| Publish | ${cell(publish)} |
|
|
189
|
+
| Activate | ${cell(activate)} |
|
|
190
|
+
| Verify | ${cell(verify)} |
|
|
178
191
|
|
|
179
192
|
Verdict: ${verdict}
|
|
180
193
|
Reason: ${reason}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Strip the Release Management subagent from the decoded Fulfiller Agent Script.
|
|
3
|
+
//
|
|
4
|
+
// WHY: the shipped ITSM Fulfiller template ships a `topic
|
|
5
|
+
// ReleaseManagement:` subagent whose only action, `SummarizeRelease`, is sourced
|
|
6
|
+
// from the `svc_itsm_intelligence__SummarizeRelease` invocable. That invocable is
|
|
7
|
+
// gated behind Release Management (the `ReleaseManagementPref` org preference /
|
|
8
|
+
// `ReleaseManagerPermSet`) and is NOT surfaced by
|
|
9
|
+
// `/actions/custom/generatePromptResponse` on an org that has not enabled it. When
|
|
10
|
+
// the Agent Script references an unsurfaced action, `activate` returns HTTP 200
|
|
11
|
+
// with a `{success:false, "... does not exist"}` silent-failure body and the agent
|
|
12
|
+
// never comes up. Rather than force every Fulfiller install to also flip on
|
|
13
|
+
// Release Management, the approved workaround is to remove the Release Management
|
|
14
|
+
// subagent entirely from the script we create the agent from — the Fulfiller agent
|
|
15
|
+
// then activates cleanly on any Agentforce-for-IT-Service org without the pref.
|
|
16
|
+
//
|
|
17
|
+
// The removal is deliberately COMPLETE — leaving the `go_to_ReleaseManagement`
|
|
18
|
+
// transition behind would dangle a `@topic.ReleaseManagement` reference to a topic
|
|
19
|
+
// that no longer exists. Three surfaces are removed:
|
|
20
|
+
// 1. the top-level `topic ReleaseManagement:` block (carries the SummarizeRelease
|
|
21
|
+
// action's `source:`/`target:` — the actual dependency);
|
|
22
|
+
// 2. the `go_to_ReleaseManagement:` transition + its description inside
|
|
23
|
+
// `start_agent topic_selector:` (would otherwise dangle);
|
|
24
|
+
// 3. the "- Route to ReleaseManagement ..." routing bullet in the selector's
|
|
25
|
+
// reasoning instructions (cosmetic, but part of a complete removal).
|
|
26
|
+
//
|
|
27
|
+
// The function operates on the ALREADY-DECODED Agent Script text (post
|
|
28
|
+
// HTML-entity decode). It is a no-op — returns the input unchanged with
|
|
29
|
+
// `removed.topic === 0` — if no `topic ReleaseManagement:` block is present, so it
|
|
30
|
+
// is safe to call unconditionally and against future template revisions.
|
|
31
|
+
//
|
|
32
|
+
// This module is imported by both `build-create-body.mjs` (the create body must
|
|
33
|
+
// not reference the gated action) and `classify-action-availability.mjs` (the
|
|
34
|
+
// Phase-2c gate must scan the SAME post-strip script, otherwise it would still
|
|
35
|
+
// flag SummarizeRelease as "missing" and block the very flow this strip
|
|
36
|
+
// unblocks). The two callers MUST stay in lock-step; both the entity decode
|
|
37
|
+
// (`decodeAgentScriptEntities`) and the strip (`stripReleaseManagement`) live
|
|
38
|
+
// here and are imported by both callers, so the shipped script and the scanned
|
|
39
|
+
// script are byte-identical up to and including the transform.
|
|
40
|
+
|
|
41
|
+
// ── Shared HTML-entity decoder ──────────────────────────────────────────────
|
|
42
|
+
// The `agentScript` arrives HTML-entity-encoded (sometimes double-encoded).
|
|
43
|
+
// BOTH callers — build-create-body.mjs (ships the bundle) and
|
|
44
|
+
// classify-action-availability.mjs (scans it) — MUST decode it identically
|
|
45
|
+
// before the strip runs, or the scanned script and the shipped script can
|
|
46
|
+
// diverge on an entity one decoder handles and the other doesn't (e.g. hex
|
|
47
|
+
// `'`, `'`, ` `), reintroducing exactly the alias/target
|
|
48
|
+
// divergence the shared strip exists to prevent. Keeping ONE decoder here,
|
|
49
|
+
// alongside the strip, makes both callers byte-identical up to AND including
|
|
50
|
+
// the transform — not just for the strip step.
|
|
51
|
+
const NAMED_ENTITIES = { amp: '&', quot: '"', apos: "'", lt: '<', gt: '>', '#39': "'", nbsp: ' ' };
|
|
52
|
+
function decodeEntitiesOnce(s) {
|
|
53
|
+
return s.replace(/&(#?\w+);/g, (m, ref) => {
|
|
54
|
+
if (ref.startsWith('#')) {
|
|
55
|
+
const n = ref[1] === 'x' || ref[1] === 'X' ? parseInt(ref.slice(2), 16) : parseInt(ref.slice(1), 10);
|
|
56
|
+
return Number.isFinite(n) ? String.fromCodePoint(n) : m;
|
|
57
|
+
}
|
|
58
|
+
return Object.prototype.hasOwnProperty.call(NAMED_ENTITIES, ref) ? NAMED_ENTITIES[ref] : m;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Fully decode HTML entities in a template `agentScript`, unwinding multi-level
|
|
64
|
+
* encoding by re-running until the text stabilises. Shared by
|
|
65
|
+
* build-create-body.mjs and classify-action-availability.mjs so the shipped and
|
|
66
|
+
* scanned scripts are decoded identically.
|
|
67
|
+
* @param {string} text encoded agentScript
|
|
68
|
+
* @returns {string} decoded text
|
|
69
|
+
*/
|
|
70
|
+
export function decodeAgentScriptEntities(text) {
|
|
71
|
+
let prev = String(text);
|
|
72
|
+
let next = decodeEntitiesOnce(prev);
|
|
73
|
+
while (next !== prev) { prev = next; next = decodeEntitiesOnce(next); }
|
|
74
|
+
return next;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The `topic ReleaseManagement:` block ends at the next TOP-LEVEL section — a
|
|
78
|
+
// non-blank line beginning in column 0. Top-level Agent Script keys are never
|
|
79
|
+
// indented; a topic block's contents always are. Detecting the boundary by
|
|
80
|
+
// column-0 position rather than by enumerating known section keywords
|
|
81
|
+
// (`topic `/`start_agent `/`system:`/…) means a template revision that adds or
|
|
82
|
+
// reorders a top-level key — a global `actions:` manifest, a trailing
|
|
83
|
+
// `description:`, any new DSL key — still bounds the block correctly instead of
|
|
84
|
+
// letting the scan run to EOF and swallow that trailing content. Blank lines
|
|
85
|
+
// never bound the block (they read as block-internal).
|
|
86
|
+
const isTopLevelBoundary = (l) => /^\S/.test(l);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Remove the Release Management subagent from a decoded Fulfiller Agent Script.
|
|
90
|
+
* @param {string} scriptText decoded (post-HTML-entity) Agent Script YAML text
|
|
91
|
+
* @returns {{ text: string, removed: { topic: number, goto: number, bullet: number, residual: number } }}
|
|
92
|
+
* `removed.residual` is the count of ReleaseManagement/SummarizeRelease tokens
|
|
93
|
+
* that survive in the stripped text — a non-zero value means the template
|
|
94
|
+
* references the gated action outside the three stripped surfaces and the
|
|
95
|
+
* caller should warn (see completeness guard below).
|
|
96
|
+
*/
|
|
97
|
+
export function stripReleaseManagement(scriptText) {
|
|
98
|
+
const lines = String(scriptText).split(/\r?\n/);
|
|
99
|
+
const out = [];
|
|
100
|
+
const removed = { topic: 0, goto: 0, bullet: 0 };
|
|
101
|
+
|
|
102
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
103
|
+
const line = lines[i];
|
|
104
|
+
|
|
105
|
+
// 1) Top-level `topic ReleaseManagement:` block — runs until the next
|
|
106
|
+
// top-level section or EOF.
|
|
107
|
+
if (/^topic\s+ReleaseManagement\s*:/.test(line)) {
|
|
108
|
+
let j = i + 1;
|
|
109
|
+
while (j < lines.length && !isTopLevelBoundary(lines[j])) j += 1;
|
|
110
|
+
removed.topic += j - i;
|
|
111
|
+
i = j - 1; // resume at the next top-level section (or EOF)
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 2) Indented `go_to_ReleaseManagement:` transition block inside the topic
|
|
116
|
+
// selector — the header line plus every following line more-indented than
|
|
117
|
+
// it (its `description:` child). Stops at the first non-blank sibling
|
|
118
|
+
// (indent <= the header's indent).
|
|
119
|
+
const gotoMatch = /^(\s*)go_to_ReleaseManagement\s*:/.exec(line);
|
|
120
|
+
if (gotoMatch) {
|
|
121
|
+
const baseIndent = gotoMatch[1].length;
|
|
122
|
+
let j = i + 1;
|
|
123
|
+
while (j < lines.length) {
|
|
124
|
+
if (lines[j].trim() === '') {
|
|
125
|
+
// Blank line: only part of the block if the next non-blank line is
|
|
126
|
+
// deeper than the header; otherwise the block has ended.
|
|
127
|
+
let k = j;
|
|
128
|
+
while (k < lines.length && lines[k].trim() === '') k += 1;
|
|
129
|
+
if (k >= lines.length) { j = k; break; }
|
|
130
|
+
if (lines[k].match(/^\s*/)[0].length <= baseIndent) break;
|
|
131
|
+
j = k;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (lines[j].match(/^\s*/)[0].length <= baseIndent) break;
|
|
135
|
+
j += 1;
|
|
136
|
+
}
|
|
137
|
+
removed.goto += j - i;
|
|
138
|
+
i = j - 1;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 3) Routing bullet naming ReleaseManagement in the selector's reasoning
|
|
143
|
+
// instructions block scalar.
|
|
144
|
+
if (/^\s*-\s*Route to ReleaseManagement\b/.test(line)) {
|
|
145
|
+
removed.bullet += 1;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
out.push(line);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const text = out.join('\n');
|
|
153
|
+
// Completeness guard: the strip removes three KNOWN
|
|
154
|
+
// surfaces (topic block, go_to transition, routing bullet). If a future
|
|
155
|
+
// template references ReleaseManagement / SummarizeRelease from somewhere else
|
|
156
|
+
// — a global action registry, a variable, a start_agent action list — that
|
|
157
|
+
// reference dangles and reintroduces the {success:false} activate body the
|
|
158
|
+
// strip exists to prevent. Count any survivor so callers can warn rather than
|
|
159
|
+
// silently ship (or scan) a half-stripped script.
|
|
160
|
+
removed.residual = (text.match(/ReleaseManagement|SummarizeRelease/g) || []).length;
|
|
161
|
+
return { text, removed };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// CLI shim for debugging: `node strip-release-management.mjs <decoded-script.yaml>`
|
|
165
|
+
// prints the stripped script to stdout and the removal counts to stderr.
|
|
166
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
167
|
+
const { readFileSync } = await import('node:fs');
|
|
168
|
+
const path = process.argv[2];
|
|
169
|
+
if (!path) {
|
|
170
|
+
process.stderr.write('usage: node strip-release-management.mjs <decoded-script.yaml>\n');
|
|
171
|
+
process.exit(2);
|
|
172
|
+
}
|
|
173
|
+
const { text, removed } = stripReleaseManagement(readFileSync(path, 'utf8'));
|
|
174
|
+
process.stderr.write(`removed ${JSON.stringify(removed)}\n`);
|
|
175
|
+
process.stdout.write(text);
|
|
176
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: service-itsm-agentic-setup-itsm-agentforce-permset-assign
|
|
3
|
-
description: "Resolve missing ITSM Intelligence invocable actions so a Fulfiller NGA agent can activate. Reads which of the
|
|
3
|
+
description: "Resolve missing ITSM Intelligence invocable actions so a Fulfiller NGA agent can activate. Reads which of the three Core Fulfiller persona permsets (IncidentFulfiller, ProblemFulfillerPermSet, ChangeRequestFulfillerPermSet) are provisioned, then assigns the running user the selected persona (plus backing PSL when license-gated) so svc_itsm_intelligence__* actions surface; hands off to service-itsm-agentic-setup-agentforce-studio-validate if none are provisioned. Use when the Fulfiller agent-configure skill reports missing actions on activate, when 'Invocable action svc_itsm_intelligence__X does not exist' surfaces, when a user asks to grant themselves Fulfiller prompt-template access, when asked to assign the Incident, Problem, or Change Fulfiller persona permission set, or when resolving missing ITSM Intelligence action access for the Fulfiller agent. DO NOT TRIGGER for Employee-agent access, Agentforce for IT Service toggles, agent creation, CMDB access, or generic permset assignment."
|
|
4
4
|
metadata:
|
|
5
|
-
version: "1.
|
|
5
|
+
version: "1.1"
|
|
6
6
|
domains: ["Service", "Agentforce"]
|
|
7
7
|
minApiVersion: "67.0"
|
|
8
8
|
relatedSkills:
|
|
@@ -28,9 +28,9 @@ allowed-tools: |
|
|
|
28
28
|
|
|
29
29
|
Grants the **running user** one of the Core-shipped **Fulfiller persona permission sets** that expose the `svc_itsm_intelligence__*` prompt-template **invocable actions** on the target org — the actions the Fulfiller NGA agent scripts reference via `source:` / `target: generatePromptResponse://...`. When those invocables are not surfaced by `/services/data/v67.0/actions/custom/generatePromptResponse` for the running user, the Fulfiller agent-configure skill's Phase 6 `activate` call returns **HTTP 200** with a silent `{success:false, messages:[{... "does not exist"}]}` body and the agent never becomes usable. This skill fixes that gap by assigning the correct Fulfiller persona permset (and its backing license when one exists) — **or**, when no Fulfiller persona permset is provisioned on the org at all, hands off to the Agentforce Studio configure/validate skill so the ITSM AddOn(s) can be enabled first.
|
|
30
30
|
|
|
31
|
-
The
|
|
31
|
+
The three Fulfiller persona permsets, their AddOns, PSLs, and the userPerms they grant are documented in `references/permset-topology.md`. All are Core-shipped in namespace `force` — there is no managed-package namespaced permset for this feature.
|
|
32
32
|
|
|
33
|
-
**Employee agent is out of scope.** The Employee NGA agent's access model is separate (org-preferences + a different persona layer) and does not map onto these
|
|
33
|
+
**Employee agent is out of scope.** The Employee NGA agent's access model is separate (org-preferences + a different persona layer) and does not map onto these three persona permsets.
|
|
34
34
|
|
|
35
35
|
Every call runs through the **Salesforce CLI (`sf`)**:
|
|
36
36
|
- `sf api request rest` — authenticated Connect API GET (identity, verify read).
|
|
@@ -40,7 +40,7 @@ Every call runs through the **Salesforce CLI (`sf`)**:
|
|
|
40
40
|
|
|
41
41
|
## Scope
|
|
42
42
|
|
|
43
|
-
- **In scope**: detecting which of the
|
|
43
|
+
- **In scope**: detecting which of the three Fulfiller persona permsets (`IncidentFulfiller`, `ProblemFulfillerPermSet`, `ChangeRequestFulfillerPermSet`) are provisioned on the org, letting the user pick which persona to assign, checking existing assignments, assigning the permission-set license (when the persona is license-gated) and permission set to the running user (or a named user), verifying the target `svc_itsm_intelligence__*` invocable actions surface via a follow-up `/actions/custom/generatePromptResponse` read.
|
|
44
44
|
- **Out of scope**: Employee-agent access (different access model, different skill), installing/enabling the ITSM AddOn(s) or content bundle (hand off to `service-itsm-agentic-setup-agentforce-studio-validate`), enabling org-level Agentforce feature toggles, creating a permission set, creating or activating the Fulfiller agent (that's `service-itsm-agentic-setup-fulfiller-agent-configure`), CMDB access (`service-itsm-agentic-setup-cmdb-access-assign`), generic non-ITSM permission-set assignment (`dx-org-permission-set-assign`).
|
|
45
45
|
|
|
46
46
|
## Mechanism
|
|
@@ -48,9 +48,9 @@ Every call runs through the **Salesforce CLI (`sf`)**:
|
|
|
48
48
|
Two branches, decided by a read-only detection step first:
|
|
49
49
|
|
|
50
50
|
- **Branch A — one or more Fulfiller persona permsets exist on the org.** Ask the user which persona to assign (do not auto-select — a Fulfiller commonly needs only one). Idempotent assign: PSL first when the persona is license-gated, then permission set, verified by read-back and by a follow-up `/actions/custom/generatePromptResponse` read.
|
|
51
|
-
- **Branch B — none of the
|
|
51
|
+
- **Branch B — none of the three Fulfiller persona permsets exist on the org.** The ITSM AddOn(s) are not provisioned; permset-assign is a no-op. STOP and hand off to `service-itsm-agentic-setup-agentforce-studio-validate` so the AddOn(s) can be enabled first.
|
|
52
52
|
|
|
53
|
-
The two-branch shape is deliberate — the failure signature ("`svc_itsm_intelligence__X` does not exist" on activate) looks identical whether a persona is present-and-unassigned or the AddOn is absent entirely, and there is no way to tell from the activate response alone. The pre-check on the
|
|
53
|
+
The two-branch shape is deliberate — the failure signature ("`svc_itsm_intelligence__X` does not exist" on activate) looks identical whether a persona is present-and-unassigned or the AddOn is absent entirely, and there is no way to tell from the activate response alone. The pre-check on the three persona `PermissionSet` names is what disambiguates them.
|
|
54
54
|
|
|
55
55
|
## Four helper scripts (all invoked via `Bash`) hold every deterministic decision (A9). Full I/O contracts in `references/helper-contracts.md`; workflow-level usage summarized below:
|
|
56
56
|
|
|
@@ -77,7 +77,7 @@ Ask only what cannot be inferred from conversation:
|
|
|
77
77
|
|
|
78
78
|
- **Target org** — the `sf` alias. Default to `sf config get target-org` if unset.
|
|
79
79
|
- **Target user** — default to the **running user** (resolved via `scripts/resolve-target-user.mjs`). If the user asks to assign on behalf of a named user, resolve them by `Username` first.
|
|
80
|
-
- **Which Fulfiller persona?** Incident / Problem / Change
|
|
80
|
+
- **Which Fulfiller persona?** Incident / Problem / Change. Only ask about personas that are actually provisioned on the org (from `candidates[]`). Do not auto-select — a Fulfiller commonly needs only one persona (e.g. Incident) even when others are provisioned.
|
|
81
81
|
- **Confirm the write** — assigning a permission-set license consumes a seat and takes effect for a live user session. Present the target user + org + persona permset name, and require an explicit "yes" via `AskUserQuestion` before writing.
|
|
82
82
|
|
|
83
83
|
---
|
|
@@ -88,15 +88,15 @@ All calls go through `sf`; substitute `<alias>` with the target org.
|
|
|
88
88
|
|
|
89
89
|
### Phase 1 — Read: which Fulfiller persona permsets are provisioned on this org?
|
|
90
90
|
|
|
91
|
-
1. Query `PermissionSet` for the
|
|
91
|
+
1. Query `PermissionSet` for the three known Fulfiller persona DeveloperNames:
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
94
|
sf data query \
|
|
95
|
-
-q "SELECT Id, Name, Label, LicenseId FROM PermissionSet WHERE Name IN ('IncidentFulfiller','ProblemFulfillerPermSet','ChangeRequestFulfillerPermSet'
|
|
95
|
+
-q "SELECT Id, Name, Label, LicenseId FROM PermissionSet WHERE Name IN ('IncidentFulfiller','ProblemFulfillerPermSet','ChangeRequestFulfillerPermSet')" \
|
|
96
96
|
--target-org <alias> --json > /tmp/itsm-personas.json 2>/tmp/itsm-personas.err || true
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
(The `PermissionSet` namespace on all
|
|
99
|
+
(The `PermissionSet` namespace on all three is `force` — do NOT filter by `NamespacePrefix`.)
|
|
100
100
|
|
|
101
101
|
2. Classify:
|
|
102
102
|
|
|
@@ -106,7 +106,7 @@ All calls go through `sf`; substitute `<alias>` with the target org.
|
|
|
106
106
|
|
|
107
107
|
The classifier prints `{ personasFound, personasMissing, candidates, verdict, reasons }`, where each `candidates[]` row is `{Id, Name, Label, LicenseId, needsPsl}`:
|
|
108
108
|
- `verdict:"ASSIGN"` (≥1 persona present) ⇒ continue to Phase 2. Present the `personasFound` list to the user via `AskUserQuestion` and get the selected persona; record its `Id`, `LicenseId`, and `needsPsl` — they drive whether Phase 2b/2d touch the PSL at all.
|
|
109
|
-
- `verdict:"HAND-OFF"` (none of the
|
|
109
|
+
- `verdict:"HAND-OFF"` (none of the three personas present) ⇒ Phase 2 is impossible on this org; go to Phase 3 (Branch B hand-off).
|
|
110
110
|
- `verdict:"CANNOT-CONFIRM"` (query failed) ⇒ surface the raw CLI error verbatim; stop.
|
|
111
111
|
|
|
112
112
|
### Phase 2 — Assign path (Branch A)
|
|
@@ -149,7 +149,7 @@ All calls go through `sf`; substitute `<alias>` with the target org.
|
|
|
149
149
|
2d. **Assign** — order depends on the selected persona's `needsPsl`:
|
|
150
150
|
|
|
151
151
|
- **`needsPsl:true`** — POST the PSL to `/sobjects/PermissionSetLicenseAssign` FIRST, then run `sf org assign permset --name <permsetName> --on-behalf-of <userId>`. Assigning the permission set without the PSL sticks the assignment but the license backing it never activates. Exact call shapes: `references/cli-invocation.md`.
|
|
152
|
-
- **`needsPsl:false`** — SKIP the PSL POST entirely; run `sf org assign permset` only. (
|
|
152
|
+
- **`needsPsl:false`** — SKIP the PSL POST entirely; run `sf org assign permset` only. (A persona whose `PermissionSet` has no backing `LicenseId` is not license-gated — there is no PSL seat to hold, so assigning the permset alone is the correct and complete write.) _Retained defensively:_ every shipped persona is now PSL-backed (`needsPsl` is derived per-row from `LicenseId`), so this `false` branch and its `NO-PSL` wiring are currently unexercised by shipped data — kept for correctness against a future persona whose `PermissionSet` carries no backing `LicenseId`.
|
|
153
153
|
|
|
154
154
|
Response handling:
|
|
155
155
|
- `201` on POST / `success:true` on `sf org assign permset` ⇒ assigned.
|
|
@@ -158,9 +158,9 @@ All calls go through `sf`; substitute `<alias>` with the target org.
|
|
|
158
158
|
|
|
159
159
|
### Phase 3 — Hand-off path (Branch B: no Fulfiller persona provisioned)
|
|
160
160
|
|
|
161
|
-
3. When Phase 1 returns `verdict:"HAND-OFF"`, none of the
|
|
161
|
+
3. When Phase 1 returns `verdict:"HAND-OFF"`, none of the three Fulfiller persona permsets exist on this org — the ITSM AddOn(s) are not provisioned. Permset-assign is a no-op in this state. Present the discovery via `AskUserQuestion`:
|
|
162
162
|
|
|
163
|
-
_"None of the Fulfiller persona permission sets (Incident, Problem, Change
|
|
163
|
+
_"None of the Fulfiller persona permission sets (Incident, Problem, Change) is provisioned on this org — no permset can grant access to actions that don't exist yet. Run `service-itsm-agentic-setup-agentforce-studio-validate` to diagnose which AddOn needs enabling?"_ (options: **Yes, run the readiness check** / **No, stop here**).
|
|
164
164
|
|
|
165
165
|
- On **Yes**: delegate to `service-itsm-agentic-setup-agentforce-studio-validate` and let it recommend the configure/bundle-deploy skill.
|
|
166
166
|
- On **No**: stop and report the current state (no persona provisioned, cannot assign) — no writes.
|
|
@@ -192,7 +192,7 @@ All calls go through `sf`; substitute `<alias>` with the target org.
|
|
|
192
192
|
|
|
193
193
|
| Constraint | Rationale |
|
|
194
194
|
|-----------|-----------|
|
|
195
|
-
| Detect Fulfiller persona presence via the
|
|
195
|
+
| Detect Fulfiller persona presence via the three fixed `PermissionSet.Name` values BEFORE any permset write | The failure signature ("action does not exist" on activate) is identical for AddOn-absent and permset-not-assigned; only the pre-check disambiguates them. The three personas are Core-shipped in namespace `force` — a `NamespacePrefix` filter never returns them |
|
|
196
196
|
| Ask the user which persona to assign — never auto-select | A Fulfiller commonly needs only one persona (e.g. Incident). Auto-assigning the first row returned would over-grant |
|
|
197
197
|
| All decisions are made by helper scripts, never by prose | Assignment/idempotency logic is deterministic; prose interpretation is not (A9) |
|
|
198
198
|
| Assign the PSL before the permission set — ONLY when the selected persona's `needsPsl:true` | The permission set is license-backed; the license seat must be held before the assignment sticks. When the selected persona has no `LicenseId`, `needsPsl:false` and the PSL POST is skipped entirely |
|
|
@@ -211,7 +211,7 @@ All calls go through `sf`; substitute `<alias>` with the target org.
|
|
|
211
211
|
|
|
212
212
|
## Verification Checklist
|
|
213
213
|
|
|
214
|
-
- [ ] Persona availability classified by `scripts/classify-permset-availability.mjs` against the
|
|
214
|
+
- [ ] Persona availability classified by `scripts/classify-permset-availability.mjs` against the three fixed persona Names — never by prose scanning the query output.
|
|
215
215
|
- [ ] User was asked to pick a persona from `personasFound[]` — no auto-selection.
|
|
216
216
|
- [ ] Target user Id resolved by `scripts/resolve-target-user.mjs` — never by prose splitting the identity URL.
|
|
217
217
|
- [ ] The SELECTED persona's `needsPsl` drove Phase 2b/2d: PSL SOQL + POST were performed when `true` and skipped when `false`.
|
|
@@ -233,7 +233,7 @@ ITSM Fulfiller Persona Permset Assignment (via service-itsm-agentic-setup-itsm-a
|
|
|
233
233
|
|
|
234
234
|
Org: <org-alias> (API v67.0)
|
|
235
235
|
Target user: <username> (<userId>)
|
|
236
|
-
Persona: <Incident | Problem | Change
|
|
236
|
+
Persona: <Incident | Problem | Change>
|
|
237
237
|
PermSet: <DeveloperName>
|
|
238
238
|
|
|
239
239
|
Personas provisioned on org ...... <comma-separated list | none>
|
|
@@ -261,6 +261,6 @@ Keep internal jargon (record Ids, HTTP status codes, `FUNCTIONALITY_NOT_ENABLED`
|
|
|
261
261
|
|
|
262
262
|
| File | When to read |
|
|
263
263
|
|------|--------------|
|
|
264
|
-
| `references/permset-topology.md` | Any change to the persona list — the
|
|
264
|
+
| `references/permset-topology.md` | Any change to the persona list — the three Core-shipped Fulfiller permsets, their AddOns/PSLs/userPerms, and the fixed-lookup discovery query |
|
|
265
265
|
| `references/cli-invocation.md` | Every phase — exact `sf api request rest` / `sf data query` / `sf org assign permset` call shapes, the never-extract-token rule, response envelopes |
|
|
266
266
|
| `references/helper-contracts.md` | The input/output shapes of all four helper scripts (`classify-permset-availability.mjs`, `resolve-target-user.mjs`, `classify-assignment-state.mjs`, `classify-action-surface.mjs`) and how to interpret each verdict |
|
|
@@ -10,7 +10,7 @@ Every read and write in this skill uses the **Salesforce CLI (`sf`)** against th
|
|
|
10
10
|
|
|
11
11
|
## Discovery read (Phase 1)
|
|
12
12
|
|
|
13
|
-
Fixed-lookup query over the
|
|
13
|
+
Fixed-lookup query over the three Core-shipped Fulfiller persona `PermissionSet.Name` values (see `permset-topology.md`). The namespace on all three is `force` — do NOT filter by `NamespacePrefix`.
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
sf data query \
|
|
@@ -19,8 +19,7 @@ sf data query \
|
|
|
19
19
|
WHERE Name IN ( \
|
|
20
20
|
'IncidentFulfiller', \
|
|
21
21
|
'ProblemFulfillerPermSet', \
|
|
22
|
-
'ChangeRequestFulfillerPermSet'
|
|
23
|
-
'ReleaseManagerPermSet' \
|
|
22
|
+
'ChangeRequestFulfillerPermSet' \
|
|
24
23
|
)" \
|
|
25
24
|
--target-org <alias> --json
|
|
26
25
|
```
|
|
@@ -60,7 +59,7 @@ sf data query -q "SELECT Id FROM PermissionSetLicenseAssign WHERE AssigneeId = '
|
|
|
60
59
|
--target-org <alias> --json > /tmp/psla-existing.json
|
|
61
60
|
```
|
|
62
61
|
|
|
63
|
-
When the selected persona's `needsPsl:false` (
|
|
62
|
+
When the selected persona's `needsPsl:false` (its `PermissionSet` has no backing `LicenseId`), SKIP the PSLA query — pass the sentinel `NO-PSL` to `classify-assignment-state.mjs`.
|
|
64
63
|
|
|
65
64
|
## Writes (Phase 2d)
|
|
66
65
|
|