@salesforce/afv-skills 1.46.0 → 1.48.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.
Files changed (317) hide show
  1. package/package.json +1 -1
  2. package/skills/agentforce-observe/SKILL.md +32 -4
  3. package/skills/agentforce-observe/references/ahm-alerts.md +719 -0
  4. package/skills/consumer-goods-promotion-bo-api-deploy/SKILL.md +275 -0
  5. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/README.md +32 -0
  6. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/SetCommentValue.cls +75 -0
  7. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/SetCommentValue.cls-meta.xml +5 -0
  8. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/interview-answers.json +13 -0
  9. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/copy.json +10 -0
  10. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/create.json +20 -0
  11. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/update.json +16 -0
  12. package/skills/consumer-goods-promotion-bo-api-deploy/references/conventions-and-payload-rules.md +273 -0
  13. package/skills/consumer-goods-promotion-bo-api-deploy/references/generate-and-wire.md +236 -0
  14. package/skills/consumer-goods-promotion-bo-api-deploy/references/reference-example-set-comment-value.md +132 -0
  15. package/skills/consumer-goods-promotion-bo-api-deploy/references/smoke-and-verify.md +211 -0
  16. package/skills/dx-devops-project-manage/SKILL.md +197 -0
  17. package/skills/dx-devops-project-manage/examples/common-workflows.md +197 -0
  18. package/skills/dx-devops-project-manage/references/cli-commands.md +295 -0
  19. package/skills/dx-devops-project-manage/scripts/create-project.sh +48 -0
  20. package/skills/dx-devops-project-manage/scripts/list-projects.sh +51 -0
  21. package/skills/dx-devops-project-manage/scripts/update-project.sh +96 -0
  22. package/skills/education-cloud-academic-calendar-generate/SKILL.md +225 -0
  23. package/skills/education-cloud-academic-calendar-generate/examples/quarter-calendar.json +47 -0
  24. package/skills/education-cloud-academic-calendar-generate/examples/sample-output.md +57 -0
  25. package/skills/education-cloud-academic-calendar-generate/examples/semester-calendar.json +54 -0
  26. package/skills/education-cloud-academic-calendar-generate/references/calendar-systems.md +127 -0
  27. package/skills/education-cloud-academic-calendar-generate/references/date-validation.md +222 -0
  28. package/skills/education-cloud-academic-calendar-generate/references/foundation_prerequisites.md +40 -0
  29. package/skills/education-cloud-academic-calendar-generate/scripts/validate_calendar_dates.py +143 -0
  30. package/skills/education-cloud-course-catalog-migrate/SKILL.md +321 -0
  31. package/skills/education-cloud-course-catalog-migrate/references/gotchas-detail.md +16 -0
  32. package/skills/education-cloud-course-catalog-migrate/references/gotchas.md +16 -0
  33. package/skills/education-cloud-course-catalog-migrate/references/large-catalog-handling.md +42 -0
  34. package/skills/education-cloud-course-catalog-migrate/scripts/batch_courses.py +36 -0
  35. package/skills/education-cloud-course-catalog-migrate/scripts/detect_linked_courses.py +51 -0
  36. package/skills/education-cloud-course-catalog-migrate/scripts/detect_modality_variants.py +48 -0
  37. package/skills/education-cloud-course-catalog-migrate/scripts/resolve_api_version.py +43 -0
  38. package/skills/education-cloud-course-catalog-migrate/scripts/split_course_code.py +39 -0
  39. package/skills/education-cloud-course-catalog-migrate/scripts/validate_completeness.py +54 -0
  40. package/skills/education-cloud-domain-configure/SKILL.md +234 -0
  41. package/skills/education-cloud-domain-configure/references/dependent-features.md +198 -0
  42. package/skills/education-cloud-domain-configure/references/domain-features/academic-operations.md +386 -0
  43. package/skills/education-cloud-domain-configure/references/domain-features/alumni-relations.md +155 -0
  44. package/skills/education-cloud-domain-configure/references/domain-features/cross-domain-dependencies.md +18 -0
  45. package/skills/education-cloud-domain-configure/references/domain-features/industriessettings-toggle-reference.md +43 -0
  46. package/skills/education-cloud-domain-configure/references/domain-features/mentoring.md +198 -0
  47. package/skills/education-cloud-domain-configure/references/domain-features/recruitment-admissions.md +315 -0
  48. package/skills/education-cloud-domain-configure/references/domain-features/student-management.md +155 -0
  49. package/skills/education-cloud-domain-configure/references/domain-features/student-success.md +249 -0
  50. package/skills/education-cloud-domain-configure/references/domain-features.md +27 -0
  51. package/skills/education-cloud-domain-configure/references/gotchas-extended.md +23 -0
  52. package/skills/education-cloud-domain-configure/references/toggle-write-path.md +67 -0
  53. package/skills/education-cloud-domain-configure/scripts/check_license_provisioned.py +62 -0
  54. package/skills/education-cloud-domain-configure/scripts/check_org_edition.py +44 -0
  55. package/skills/education-cloud-domain-configure/scripts/check_permission_assigned.py +39 -0
  56. package/skills/education-cloud-multi-campus-configure/SKILL.md +7 -0
  57. package/skills/education-cloud-multi-campus-configure/references/foundation_prerequisites.md +1 -2
  58. package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +177 -0
  59. package/skills/education-cloud-student-recruitment-agent-configure/references/agent-and-subagents.md +151 -0
  60. package/skills/education-cloud-student-recruitment-agent-configure/references/customer-narration.md +34 -0
  61. package/skills/education-cloud-student-recruitment-agent-configure/references/execution-model.md +54 -0
  62. package/skills/education-cloud-student-recruitment-agent-configure/references/flows.md +82 -0
  63. package/skills/education-cloud-student-recruitment-agent-configure/references/grounding.md +199 -0
  64. package/skills/education-cloud-student-recruitment-agent-configure/references/permissions.md +183 -0
  65. package/skills/education-cloud-student-recruitment-agent-configure/references/platform-enablement.md +82 -0
  66. package/skills/education-cloud-student-recruitment-agent-configure/references/prerequisites.md +158 -0
  67. package/skills/education-cloud-student-recruitment-agent-configure/references/routing.md +141 -0
  68. package/skills/experience-cms-brand-apply/SKILL.md +5 -5
  69. package/skills/experience-cms-brand-create/SKILL.md +2 -2
  70. package/skills/experience-cms-content-generate/SKILL.md +1 -0
  71. package/skills/experience-cms-content-render/SKILL.md +173 -0
  72. package/skills/experience-cms-content-render/assets/angular/DetailPage.component.ts +25 -0
  73. package/skills/experience-cms-content-render/assets/angular/MediaRenderer.component.ts +133 -0
  74. package/skills/experience-cms-content-render/assets/angular/TypeList.component.ts +38 -0
  75. package/skills/experience-cms-content-render/assets/angular/TypeRenderer.component.ts +90 -0
  76. package/skills/experience-cms-content-render/assets/angular/cms-content.component.ts +248 -0
  77. package/skills/experience-cms-content-render/assets/angular/cms-item.service.ts +100 -0
  78. package/skills/experience-cms-content-render/assets/react/DetailPage.tsx +20 -0
  79. package/skills/experience-cms-content-render/assets/react/MediaRenderer.tsx +129 -0
  80. package/skills/experience-cms-content-render/assets/react/TypeList.tsx +40 -0
  81. package/skills/experience-cms-content-render/assets/react/TypeRenderer.tsx +64 -0
  82. package/skills/experience-cms-content-render/assets/react/heuristicRenderer.tsx +310 -0
  83. package/skills/experience-cms-content-render/assets/react/useCmsItem.ts +129 -0
  84. package/skills/experience-cms-content-render/assets/shared/cmsContentType.ts +49 -0
  85. package/skills/experience-cms-content-render/assets/shared/cmsCore.types.ts +96 -0
  86. package/skills/experience-cms-content-render/assets/shared/externalRefs.ts +55 -0
  87. package/skills/experience-cms-content-render/references/bulk-loading.md +60 -0
  88. package/skills/experience-cms-content-render/references/codegen-guardrails.md +111 -0
  89. package/skills/experience-cms-content-render/references/detail-pages.md +87 -0
  90. package/skills/experience-cms-content-render/references/embed-recipes.md +127 -0
  91. package/skills/experience-cms-content-render/references/failure-modes.md +96 -0
  92. package/skills/experience-cms-content-render/references/heuristic-render-rules.md +131 -0
  93. package/skills/experience-cms-content-render/references/init-scaffold.md +122 -0
  94. package/skills/experience-cms-content-render/references/interaction-model.md +173 -0
  95. package/skills/experience-cms-content-render/references/package-api.md +106 -0
  96. package/skills/experience-cms-content-render/references/schema-sync.md +114 -0
  97. package/skills/experience-cms-content-render/references/styling-scopes.md +65 -0
  98. package/skills/experience-cms-content-render/references/verify.md +49 -0
  99. package/skills/experience-cms-content-type-generate/SKILL.md +2 -2
  100. package/skills/experience-content-media-stock-image-search/SKILL.md +5 -4
  101. package/skills/experience-search-coordinate/SKILL.md +198 -0
  102. package/skills/experience-search-coordinate/assets/search-payload-template.json +25 -0
  103. package/skills/experience-search-coordinate/references/content-route.md +313 -0
  104. package/skills/experience-search-coordinate/references/content-type-discovery.md +57 -0
  105. package/skills/experience-search-coordinate/references/media-route.md +172 -0
  106. package/skills/experience-search-coordinate/references/scope-resolution.md +14 -0
  107. package/skills/experience-ui-bundle-localize/SKILL.md +1 -1
  108. package/skills/experience-ui-bundle-localize/references/i18n-setup.md +5 -3
  109. package/skills/experience-ui-bundle-project-generate/SKILL.md +18 -14
  110. package/skills/experience-ui-bundle-project-generate/references/angular-project-generate.md +22 -0
  111. package/skills/experience-ui-bundle-project-generate/references/react-project-generate.md +20 -0
  112. package/skills/experience-ui-bundle-salesforce-data-access/SKILL.md +58 -54
  113. package/skills/experience-ui-bundle-salesforce-data-access/references/caching.md +6 -0
  114. package/skills/experience-ui-bundle-salesforce-data-access/references/graphiti-cli.md +2 -2
  115. package/skills/experience-ui-bundle-salesforce-data-access/references/migration.md +6 -0
  116. package/skills/experience-ui-bundle-salesforce-data-access/references/rest-and-integration.md +2 -1
  117. package/skills/experience-ui-bundle-salesforce-data-access/references/sdk-api.md +6 -0
  118. package/skills/experience-ui-bundle-site-generate/SKILL.md +59 -8
  119. package/skills/experience-ui-bundle-site-generate/references/configure-metadata-digital-experience.md +8 -3
  120. package/skills/experience-ui-bundle-site-generate/references/configure-metadata-language-settings.md +120 -0
  121. package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +336 -0
  122. package/skills/life-sciences-fieldsalesrep-coordinate/references/orchestration-flow.md +143 -0
  123. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-application-flexipage-mapping.md +127 -0
  124. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-deploy-commands.md +116 -0
  125. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-lifesci-metadata-deploy.md +111 -0
  126. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-overview.md +312 -0
  127. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-profile-layout-assignments.md +171 -0
  128. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-state-tracking.md +64 -0
  129. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-trigger-handlers.md +122 -0
  130. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-4-user-provisioning-overview.md +335 -0
  131. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-4-user-provisioning-user-provisioning-details.md +140 -0
  132. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-execution-state-and-recovery.md +196 -0
  133. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-metadata-cache-generation.md +155 -0
  134. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-overview.md +307 -0
  135. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-visit-creation-data.md +211 -0
  136. package/skills/life-sciences-fieldsalesrep-coordinate/references/state-machine-and-changes.md +108 -0
  137. package/skills/life-sciences-kam-coordinate/SKILL.md +241 -0
  138. package/skills/life-sciences-kam-coordinate/references/orchestration-flow.md +152 -0
  139. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-application-flexipage-mapping.md +79 -0
  140. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-deploy-commands.md +131 -0
  141. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-kam-config-records.md +85 -0
  142. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-lifesci-metadata-deploy.md +112 -0
  143. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-overview.md +202 -0
  144. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-profile-layout-assignments.md +67 -0
  145. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-state-tracking.md +65 -0
  146. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-trigger-handlers.md +123 -0
  147. package/skills/life-sciences-kam-coordinate/references/stage-4-participant-role-and-sprint.md +89 -0
  148. package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +337 -0
  149. package/skills/life-sciences-kam-coordinate/references/stage-5-data-creation-data.md +248 -0
  150. package/skills/life-sciences-kam-coordinate/references/stage-6-ipad-validation-script.md +35 -0
  151. package/skills/life-sciences-kam-coordinate/references/stage-6-metadata-cache-generation.md +155 -0
  152. package/skills/life-sciences-kam-coordinate/references/stage-6-user-provisioning-details.md +146 -0
  153. package/skills/life-sciences-kam-coordinate/references/stage-6-user-provisioning-overview.md +89 -0
  154. package/skills/life-sciences-kam-coordinate/references/state-machine-and-changes.md +114 -0
  155. package/skills/life-sciences-prerequisites-validate/SKILL.md +138 -0
  156. package/skills/life-sciences-prerequisites-validate/references/checks-org-settings.md +190 -0
  157. package/skills/life-sciences-prerequisites-validate/references/checks-user-and-package.md +211 -0
  158. package/skills/life-sciences-territory-configure/SKILL.md +217 -0
  159. package/skills/life-sciences-territory-configure/references/territory-metadata.md +262 -0
  160. package/skills/platform-dsar-policy-manage/SKILL.md +272 -0
  161. package/skills/platform-dsar-policy-manage/references/configure.md +106 -0
  162. package/skills/platform-dsar-policy-manage/references/export-and-history.md +123 -0
  163. package/skills/platform-dsar-policy-manage/references/gap-analysis-guide.md +150 -0
  164. package/skills/platform-dsar-policy-manage/references/gap-scan.md +129 -0
  165. package/skills/platform-dsar-policy-manage/references/headless-sor.md +59 -0
  166. package/skills/platform-dsar-policy-manage/references/report-format.md +59 -0
  167. package/skills/platform-dsar-policy-manage/scripts/tests/__init__.py +0 -0
  168. package/skills/platform-dsar-policy-manage/scripts/tests/test_validate_policy_tree.py +76 -0
  169. package/skills/platform-dsar-policy-manage/scripts/validate-policy-tree.py +130 -0
  170. package/skills/platform-salesforce-connect-adapter-generate/SKILL.md +359 -0
  171. package/skills/platform-salesforce-connect-adapter-generate/references/official-examples.md +69 -0
  172. package/skills/platform-salesforce-connect-adapter-generate/references/scenarios.md +187 -0
  173. package/skills/service-agentforce-channel-configure/SKILL.md +33 -28
  174. package/skills/service-agentforce-human-escalation-configure/SKILL.md +205 -0
  175. package/skills/service-agentforce-human-escalation-configure/assets/escalation-thresholds.instructions.md +37 -0
  176. package/skills/service-agentforce-human-escalation-configure/assets/force-app/main/default/flows/Human_Escalation_Outbound_Flow.flow-meta.xml +173 -0
  177. package/skills/service-agentforce-human-escalation-configure/assets/package.xml +8 -0
  178. package/skills/service-agentforce-human-escalation-configure/assets/sfdx-project.json +5 -0
  179. package/skills/service-agentforce-human-escalation-configure/references/classifier-contracts.md +103 -0
  180. package/skills/service-agentforce-human-escalation-configure/references/escalation-mechanism.md +63 -0
  181. package/skills/service-agentforce-human-escalation-configure/references/failure-policy.md +44 -0
  182. package/skills/service-agentforce-human-escalation-configure/references/nga-escalation.md +57 -0
  183. package/skills/service-agentforce-human-escalation-configure/references/runtime-verification.md +72 -0
  184. package/skills/service-agentforce-human-escalation-configure/scripts/classify-agent-active.mjs +49 -0
  185. package/skills/service-agentforce-human-escalation-configure/scripts/classify-nga-escalation.mjs +166 -0
  186. package/skills/service-agentforce-human-escalation-configure/scripts/extract-outbound-route.mjs +67 -0
  187. package/skills/service-agentforce-human-escalation-configure/scripts/patch-escalation-surfaces.mjs +131 -0
  188. package/skills/service-agentforce-human-escalation-configure/scripts/tests/__init__.py +0 -0
  189. package/skills/service-agentforce-human-escalation-configure/scripts/tests/_bootstrap.py +249 -0
  190. package/skills/service-agentforce-human-escalation-configure/scripts/tests/test_escalation_contracts.py +899 -0
  191. package/skills/service-agentforce-human-escalation-configure/scripts/verify-and-configure.sh +705 -0
  192. package/skills/service-agentforce-human-escalation-configure/scripts/verify-escalation-config.mjs +89 -0
  193. package/skills/service-de-channel-routing-configure/SKILL.md +13 -5
  194. package/skills/service-de-channel-routing-configure/scripts/tests/test_skill_contract.py +25 -0
  195. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +23 -10
  196. package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +63 -48
  197. package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +6 -2
  198. package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +20 -27
  199. package/skills/service-native-voice-recording-transcription-configure/SKILL.md +47 -27
  200. package/skills/service-native-voice-recording-transcription-configure/references/thunderbird-voice-settings.md +13 -9
  201. package/skills/service-native-voice-recording-transcription-configure/scripts/enable-recording-transcription.sh +104 -45
  202. package/skills/service-omni-agent-users-create/SKILL.md +96 -0
  203. package/skills/service-omni-agent-users-create/assets/create-users.apex.template +80 -0
  204. package/skills/service-omni-agent-users-create/references/apex-patterns.md +135 -0
  205. package/skills/service-omni-agent-users-create/references/apex-template-notes.md +40 -0
  206. package/skills/service-omni-agent-users-create/scripts/detect-and-create.sh +206 -0
  207. package/skills/service-omni-agent-users-create/scripts/detect-existing.sh +122 -0
  208. package/skills/service-omni-agent-users-create/scripts/run-create.sh +298 -0
  209. package/skills/service-omni-agent-users-create/scripts/tests/test_user_create_security.py +171 -0
  210. package/skills/service-omni-agent-work-sharing-configure/SKILL.md +78 -0
  211. package/skills/service-omni-agent-work-sharing-configure/references/api-notes.md +31 -0
  212. package/skills/service-omni-agent-work-sharing-configure/scripts/configure-and-report.sh +186 -0
  213. package/skills/service-omni-agent-work-sharing-configure/scripts/tests/_bootstrap.py +120 -0
  214. package/skills/service-omni-agent-work-sharing-configure/scripts/tests/test_agent_work_sharing_contracts.py +93 -0
  215. package/skills/service-omni-base-settings-configure/SKILL.md +77 -0
  216. package/skills/service-omni-base-settings-configure/assets/force-app/main/default/settings/OmniChannel.settings-meta.xml +8 -0
  217. package/skills/service-omni-base-settings-configure/assets/package.xml +8 -0
  218. package/skills/service-omni-base-settings-configure/assets/sfdx-project.json +12 -0
  219. package/skills/service-omni-base-settings-configure/references/api-notes.md +121 -0
  220. package/skills/service-omni-base-settings-configure/scripts/configure-and-report.sh +164 -0
  221. package/skills/service-omni-base-settings-configure/scripts/detect-existing.sh +69 -0
  222. package/skills/service-omni-channel-setup-coordinate/SKILL.md +168 -0
  223. package/skills/service-omni-channel-setup-coordinate/examples/output-templates.md +161 -0
  224. package/skills/service-omni-channel-setup-coordinate/references/gap-catalog.md +99 -0
  225. package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +1542 -0
  226. package/skills/service-omni-channel-setup-coordinate/scripts/tests/__init__.py +0 -0
  227. package/skills/service-omni-channel-setup-coordinate/scripts/tests/_bootstrap.py +223 -0
  228. package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +804 -0
  229. package/skills/service-omni-command-center-analyze/SKILL.md +84 -0
  230. package/skills/service-omni-command-center-analyze/references/api-notes.md +54 -0
  231. package/skills/service-omni-command-center-analyze/scripts/analyze.sh +198 -0
  232. package/skills/service-omni-command-center-analyze/scripts/tests/_bootstrap.py +115 -0
  233. package/skills/service-omni-command-center-analyze/scripts/tests/test_command_center_analyze_contracts.py +165 -0
  234. package/skills/service-omni-permission-set-assign/SKILL.md +88 -0
  235. package/skills/service-omni-permission-set-assign/assets/package.xml +8 -0
  236. package/skills/service-omni-permission-set-assign/references/api-notes.md +143 -0
  237. package/skills/service-omni-permission-set-assign/scripts/verify-and-assign.sh +397 -0
  238. package/skills/service-omni-presence-status-deploy/SKILL.md +87 -0
  239. package/skills/service-omni-presence-status-deploy/assets/package.xml +12 -0
  240. package/skills/service-omni-presence-status-deploy/references/api-notes.md +115 -0
  241. package/skills/service-omni-presence-status-deploy/scripts/deploy-and-report.sh +422 -0
  242. package/skills/service-omni-presence-user-config-deploy/SKILL.md +80 -0
  243. package/skills/service-omni-presence-user-config-deploy/references/api-notes.md +60 -0
  244. package/skills/service-omni-presence-user-config-deploy/scripts/deploy-and-report.sh +261 -0
  245. package/skills/service-omni-presence-user-config-deploy/scripts/tests/_bootstrap.py +106 -0
  246. package/skills/service-omni-presence-user-config-deploy/scripts/tests/test_presence_user_config_contracts.py +142 -0
  247. package/skills/service-omni-queue-deploy/SKILL.md +91 -0
  248. package/skills/service-omni-queue-deploy/references/api-notes.md +140 -0
  249. package/skills/service-omni-queue-deploy/scripts/verify-and-align.sh +470 -0
  250. package/skills/service-omni-queue-members-assign/SKILL.md +93 -0
  251. package/skills/service-omni-queue-members-assign/references/api-notes.md +144 -0
  252. package/skills/service-omni-queue-members-assign/scripts/tests/_bootstrap.py +67 -0
  253. package/skills/service-omni-queue-members-assign/scripts/tests/test_queue_members_contracts.py +73 -0
  254. package/skills/service-omni-queue-members-assign/scripts/verify-and-bind.sh +362 -0
  255. package/skills/service-omni-queue-routing-config-deploy/SKILL.md +101 -0
  256. package/skills/service-omni-queue-routing-config-deploy/references/api-notes.md +127 -0
  257. package/skills/service-omni-queue-routing-config-deploy/scripts/tests/_bootstrap.py +90 -0
  258. package/skills/service-omni-queue-routing-config-deploy/scripts/tests/test_queue_routing_config_contracts.py +70 -0
  259. package/skills/service-omni-queue-routing-config-deploy/scripts/upsert-and-report.sh +538 -0
  260. package/skills/service-omni-routing-flow-deploy/SKILL.md +111 -0
  261. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Case_Trigger.SkillsBased.flow-meta.xml +94 -0
  262. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Case_Trigger.flow-meta.xml +88 -0
  263. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Cases.flow-meta.xml +144 -0
  264. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCall_Trigger.SkillsBased.flow-meta.xml +94 -0
  265. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCall_Trigger.flow-meta.xml +88 -0
  266. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCalls.flow-meta.xml +144 -0
  267. package/skills/service-omni-routing-flow-deploy/assets/package.xml +11 -0
  268. package/skills/service-omni-routing-flow-deploy/assets/sfdx-project.json +11 -0
  269. package/skills/service-omni-routing-flow-deploy/references/api-notes.md +265 -0
  270. package/skills/service-omni-routing-flow-deploy/scripts/deploy-and-report.sh +684 -0
  271. package/skills/service-omni-service-channel-configure/SKILL.md +83 -0
  272. package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/Cases.serviceChannel-meta.xml +9 -0
  273. package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/Incidents.serviceChannel-meta.xml +9 -0
  274. package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/MessagingSessions.serviceChannel-meta.xml +9 -0
  275. package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/VoiceCalls.serviceChannel-meta.xml +9 -0
  276. package/skills/service-omni-service-channel-configure/assets/package.xml +11 -0
  277. package/skills/service-omni-service-channel-configure/assets/sfdx-project.json +12 -0
  278. package/skills/service-omni-service-channel-configure/references/api-notes.md +84 -0
  279. package/skills/service-omni-service-channel-configure/scripts/deploy-and-report.sh +383 -0
  280. package/skills/service-omni-sidebar-configure/SKILL.md +77 -0
  281. package/skills/service-omni-sidebar-configure/references/api-notes.md +51 -0
  282. package/skills/service-omni-sidebar-configure/scripts/enable-and-report.sh +315 -0
  283. package/skills/service-omni-sidebar-configure/scripts/tests/_bootstrap.py +142 -0
  284. package/skills/service-omni-sidebar-configure/scripts/tests/test_sidebar_contracts.py +139 -0
  285. package/skills/service-omni-skills-based-routing-configure/SKILL.md +81 -0
  286. package/skills/service-omni-skills-based-routing-configure/references/api-notes.md +50 -0
  287. package/skills/service-omni-skills-based-routing-configure/scripts/configure-and-report.sh +270 -0
  288. package/skills/service-omni-skills-based-routing-configure/scripts/tests/_bootstrap.py +120 -0
  289. package/skills/service-omni-skills-based-routing-configure/scripts/tests/test_sbr_contracts.py +129 -0
  290. package/skills/service-omni-supervisor-config-deploy/SKILL.md +97 -0
  291. package/skills/service-omni-supervisor-config-deploy/assets/force-app/main/default/omniSupervisorConfigs/Omni_Supervisor.omniSupervisorConfig-meta.xml +9 -0
  292. package/skills/service-omni-supervisor-config-deploy/assets/package.xml +8 -0
  293. package/skills/service-omni-supervisor-config-deploy/assets/sfdx-project.json +12 -0
  294. package/skills/service-omni-supervisor-config-deploy/references/api-notes.md +205 -0
  295. package/skills/service-omni-supervisor-config-deploy/scripts/deploy-and-report.sh +586 -0
  296. package/skills/service-omni-supervisor-config-deploy/scripts/tests/_bootstrap.py +153 -0
  297. package/skills/service-omni-supervisor-config-deploy/scripts/tests/test_supervisor_config_contracts.py +116 -0
  298. package/skills/service-omni-supervisor-permset-assign/SKILL.md +88 -0
  299. package/skills/service-omni-supervisor-permset-assign/references/api-notes.md +48 -0
  300. package/skills/service-omni-supervisor-permset-assign/scripts/verify-and-assign.sh +316 -0
  301. package/skills/service-omni-supervisor-surface-deploy/SKILL.md +85 -0
  302. package/skills/service-omni-supervisor-surface-deploy/references/api-notes.md +47 -0
  303. package/skills/service-omni-supervisor-surface-deploy/scripts/deploy-and-report.sh +216 -0
  304. package/skills/service-omni-supervisor-surface-deploy/scripts/tests/_bootstrap.py +95 -0
  305. package/skills/service-omni-supervisor-surface-deploy/scripts/tests/test_supervisor_surface_contracts.py +154 -0
  306. package/skills/service-omni-supervisor-users-create/SKILL.md +92 -0
  307. package/skills/service-omni-supervisor-users-create/assets/create-supervisors.apex.template +72 -0
  308. package/skills/service-omni-supervisor-users-create/references/apex-patterns.md +73 -0
  309. package/skills/service-omni-supervisor-users-create/references/apex-template-notes.md +41 -0
  310. package/skills/service-omni-supervisor-users-create/scripts/detect-and-create.sh +197 -0
  311. package/skills/service-omni-supervisor-users-create/scripts/detect-existing.sh +112 -0
  312. package/skills/service-omni-supervisor-users-create/scripts/run-create.sh +296 -0
  313. package/skills/service-omni-work-skill-routing-configure/SKILL.md +80 -0
  314. package/skills/service-omni-work-skill-routing-configure/references/api-notes.md +67 -0
  315. package/skills/service-omni-work-skill-routing-configure/scripts/configure-and-report.sh +262 -0
  316. package/skills/service-omni-work-skill-routing-configure/scripts/tests/_bootstrap.py +121 -0
  317. package/skills/service-omni-work-skill-routing-configure/scripts/tests/test_work_skill_routing_contracts.py +161 -0
@@ -0,0 +1,135 @@
1
+ # Apex patterns for agent user creation
2
+
3
+ Load this reference **only when the Apex block is actually going to run** (i.e., after `detect-existing.sh` returned `missing_count > 0`). It covers the Apex structure, `User` sObject required fields, password policy, profile-localization gotcha, and the emitted-log contract.
4
+
5
+ **Apex version verified:** v66 (Summer '26 baseline).
6
+ **Runtime:** Anonymous Apex via `sf apex run --target-org <alias> --file <resolved>.apex`.
7
+
8
+ ---
9
+
10
+ ## The Apex template shape
11
+
12
+ The template at `assets/create-users.apex.template` uses three tokens:
13
+
14
+ | Token | Type | Resolved by |
15
+ |---|---|---|
16
+ | `__COUNT__` | integer 1..10 | `run-create.sh` argument 2 (from operator input, default 3) |
17
+ | `__PROFILE_ID__` | 18-char Profile Id | `detect-existing.sh` from `SELECT Id FROM Profile WHERE Name = ?` |
18
+ | `__SUFFIX__` | 8-char lowercase hex | `detect-existing.sh` from `Organization.Id.substring(10, 18).toLowerCase()` |
19
+
20
+ Token substitution uses `sed` with **pipe (`|`) as the delimiter**, not `/`. This is not because Ids or names contain `/` (they do not) but because pipe is universally not-a-metacharacter in `sed`, avoiding future foot-guns if a token value ever contains a `/`.
21
+
22
+ ---
23
+
24
+ ## `User` sObject required fields
25
+
26
+ Salesforce enforces the following as required (non-nullable) when inserting a `User`:
27
+
28
+ | Field | Value used | Notes |
29
+ |---|---|---|
30
+ | `Username` | `agent{i}.{suffix}@example.com` | Must be globally unique across all Salesforce orgs. Our suffix strategy makes this per-org-unique; `@example.com` domain avoids sending real email |
31
+ | `Email` | same as `Username` | Salesforce enforces per-org email uniqueness (not global) — same suffix works |
32
+ | `LastName` | `Agent{i}` | Required, no default |
33
+ | `Alias` | `omag{i}{last-3-of-suffix}` (or `last-2` for i≥10) | Max 8 chars. Cross-org uniqueness NOT required |
34
+ | `ProfileId` | resolved from `Profile.Name` | See profile-localization note below |
35
+ | `TimeZoneSidKey` | `America/Los_Angeles` | Safe default for CDOs |
36
+ | `LocaleSidKey` | `en_US` | Safe default |
37
+ | `EmailEncodingKey` | `UTF-8` | Safe default |
38
+ | `LanguageLocaleKey` | `en_US` | Safe default; not all orgs enable all languages, but `en_US` is always available |
39
+
40
+ Optional but set for clarity: `FirstName = 'Omni'`, `IsActive = true`.
41
+
42
+ ---
43
+
44
+ ## Password policy & `System.setPassword`
45
+
46
+ Default org password policy on Enterprise Edition CDOs: min 8 chars, must contain at least 1 letter and 1 number. Our password format `AgntV1<10-hex>` satisfies this (contains `A`, `V` (upper), `g`, `n`, `t` (lower), `1` (digit), plus hex chars which contribute more letters+digits).
47
+
48
+ **`System.setPassword(Id, String)` requirements:**
49
+ - Executing user must have `PermissionsManagePasswordPolicies=true` (standard on System Administrator)
50
+ - Password must satisfy the org's password policy (`Setup → Password Policies`)
51
+ - On success, the user's password is set immediately; the user does NOT receive a verification email and is immediately usable
52
+ - On failure (policy violation), throws `System.NoAccessException` or a `System.InvalidPasswordException` — the skill's Apex catches these per-user and emits a `AGENT_USERS_PASSWORD_ERRORS` line without failing the whole run
53
+
54
+ **Note:** the skill's Apex sets passwords AFTER inserting users, not as a single atomic transaction. If a password-set fails for user N, the user still exists but has no password (Salesforce assigns a random one internally). The operator can then use "Reset Password" in Setup.
55
+
56
+ ---
57
+
58
+ ## Idempotency (belt + suspenders)
59
+
60
+ Two independent guards:
61
+
62
+ 1. **Pre-check (in `detect-existing.sh`):** query `User` by username pattern → return `missing_indexes` array. If empty, skip Apex entirely.
63
+ 2. **In-Apex re-check:** the Apex block queries `User WHERE Username IN :expectedByUsername.keySet()` inside its transaction, then builds `toInsert` from only the truly missing indexes. This handles two edge cases:
64
+ - Concurrent skill runs (rare): two agents run this skill against the same org at nearly the same time
65
+ - State drift between pre-check and Apex execution (very rare): another skill or manual UI action creates a matching user between the two SOQL queries
66
+
67
+ The in-Apex re-check makes the skill safe even if the pre-check is stale. In the concurrent-race case, the second run will find all users existing and emit `AGENT_USERS_ALL_EXIST` with no inserts.
68
+
69
+ ---
70
+
71
+ ## Profile-localization gotcha
72
+
73
+ `Profile.Name` is **not localized** for standard profiles (`Standard User`, `System Administrator`, `Marketing User`, etc.) as of v66 — verified on EPIC CDOs (English). But other Salesforce edition variants may localize these names (`Utilisateur standard` on French orgs?). Empirically we have not seen this, but the skill accepts the risk with a hardcoded default of `Standard User`.
74
+
75
+ **If a user overrides `--profile` to a custom profile**, they own the risk that the profile name is spelled correctly and matches exactly (case-sensitive). Custom profiles have a `DeveloperName` field (API-stable) but standard profiles do not — so this skill uses `Name` as the only universal lookup key.
76
+
77
+ A fallback query that also matches `DeveloperName` is possible:
78
+ ```sql
79
+ SELECT Id FROM Profile WHERE Name = :profileName OR DeveloperName = :profileName LIMIT 1
80
+ ```
81
+ The skill uses `Name` only, to keep the query simple and the error message clear.
82
+
83
+ ---
84
+
85
+ ## The emitted-log contract (parsed by `run-create.sh`)
86
+
87
+ The Apex block emits three kinds of `System.debug` lines that the shell script parses:
88
+
89
+ | Line prefix | When | Format |
90
+ |---|---|---|
91
+ | `AGENT_USER_CREATED` | One per newly-created user (never for reused users) | `AGENT_USER_CREATED\|<userId>\|<username>\|<password>\|<email>` |
92
+ | `AGENT_USERS_ALL_EXIST` | When `toInsert` is empty (all N users already existed at Apex transaction time) | Exactly the string `AGENT_USERS_ALL_EXIST — no inserts required` |
93
+ | `AGENT_USERS_PASSWORD_ERRORS` | When one or more `System.setPassword` calls failed | `AGENT_USERS_PASSWORD_ERRORS: <JSON-array of "username: error-message">` |
94
+
95
+ `run-create.sh` greps for these lines (they are the only lines starting with `AGENT_`), parses them, and constructs the return JSON.
96
+
97
+ ---
98
+
99
+ ## Failure modes
100
+
101
+ | Symptom in Apex output | Root cause | Skill behavior |
102
+ |---|---|---|
103
+ | `DUPLICATE_USERNAME` | Global-uniqueness violation — another org somewhere in Salesforce owns this username | Should not happen with the org-id suffix strategy. If it does, run detect again — likely a race with a concurrent run. Fail if it persists |
104
+ | `INVALID_EMAIL_ADDRESS` | Should not happen with `@example.com`. Would indicate a bug in username construction | Fail and escalate — skill logic error |
105
+ | `LICENSE_LIMIT_EXCEEDED` | Org's Salesforce license count is at max | Fail with an operator-friendly message: "Org has reached its user license limit — free up a license slot or ask Salesforce for more" |
106
+ | `System.NoAccessException` on `System.setPassword` | Executing user lacks `ManagePasswordPolicies` perm | Skill continues (per-user catch), emits `AGENT_USERS_PASSWORD_ERRORS`, operator uses Setup → Reset Password |
107
+ | `System.InvalidPasswordException` on `System.setPassword` | Org has a stricter password policy than our `AgntV1<10-hex>` satisfies | Should not happen with default policies. Skill continues, emits `AGENT_USERS_PASSWORD_ERRORS`, escalate to update the password generator |
108
+ | `UNABLE_TO_LOCK_ROW` | Concurrent transaction locked the `User` table | Retry the skill once. Rare on CDOs |
109
+
110
+ ---
111
+
112
+ ## Production-safety signal (three-way check)
113
+
114
+ **Discovery during on-org testing:** `IsSandbox` alone is insufficient to distinguish "safe to write demo data" from "real customer production". CDOs (Customer Demo Orgs, our primary target shape) have `IsSandbox=false` because they are not derived from a production org — they are standalone Enterprise Edition orgs with a trial expiration.
115
+
116
+ The correct three-way check:
117
+
118
+ ```sql
119
+ SELECT IsSandbox, TrialExpirationDate, OrganizationType FROM Organization LIMIT 1
120
+ ```
121
+
122
+ `safe_to_write = true` if **any** of the following is true:
123
+
124
+ | Signal | Meaning |
125
+ |---|---|
126
+ | `IsSandbox = true` | Real sandbox — safe by construction |
127
+ | `TrialExpirationDate != null` | Trial org, CDO, or similar time-limited org — safe |
128
+ | `OrganizationType = 'Developer Edition'` | Dev org — safe |
129
+ | `OrganizationType = 'Base Edition'` | Scratch org — safe |
130
+
131
+ `safe_to_write = false` only when **all four** signals fail — i.e., `IsSandbox=false` AND `TrialExpirationDate=null` AND `OrganizationType NOT IN ('Developer Edition', 'Base Edition')`. That combination is definitionally a real customer production org.
132
+
133
+ **Example:** a CDO reporting `IsSandbox=false`, a non-null `TrialExpirationDate`, and `OrganizationType=Enterprise Edition` resolves to `safe_to_write=true` — the correct behavior for a demo/trial org.
134
+
135
+ **Other write-capable skills reuse this same three-way check.** A naive `IsSandbox=true` check would incorrectly block all CDOs, which are the primary target shape for these skills.
@@ -0,0 +1,40 @@
1
+ # `create-users.apex.template` notes
2
+
3
+ Anonymous Apex template for creating agent demo users. `run-create.sh` resolves the tokens
4
+ before execution and submits the rendered Apex.
5
+
6
+ ## Tokens
7
+
8
+ | token | meaning |
9
+ | --- | --- |
10
+ | `__COUNT__` | integer 1..10 — number of user slots |
11
+ | `__PROFILE_ID__` | 18-char Profile Id (e.g. `00eRZ00000012tKYAQ`) |
12
+ | `__SUFFIX__` | 8-char lowercase hex string derived from `Organization.Id` |
13
+
14
+ ## Idempotency
15
+
16
+ The block re-queries existing users inside the transaction and inserts only the truly
17
+ missing indexes. Two concurrent runs can both pass the pre-query before either commits;
18
+ Salesforce's `DUPLICATE_USERNAME` constraint is the authoritative deduplicator, and
19
+ `run-create.sh` treats `DUPLICATE_USERNAME` as "another agent won the race" and retries a
20
+ re-detect.
21
+
22
+ ## Security note (password / TraceFlag)
23
+
24
+ This block only creates the `User` rows and never emits a password via `System.debug`. The
25
+ caller (`run-create.sh`) sets each password with a SEPARATE Anonymous Apex
26
+ `System.setPassword(id, pw)` submission per newly-created user. That plaintext lives in the
27
+ submitted Apex source, which appears in the inline `executeAnonymous` debug log and — ONLY
28
+ when a debug-log TraceFlag is active for the running user — in a queryable `ApexLog` row.
29
+ `run-create.sh` proves no active TraceFlag exists before calling `System.setPassword` and
30
+ otherwise fails closed (no password set), so plaintext never reaches a queryable log.
31
+
32
+ ## Output contract
33
+
34
+ For every user created this run, `System.debug` emits one line:
35
+
36
+ ```text
37
+ AGENT_USER_CREATED|<userId>|<username>|<email>
38
+ ```
39
+
40
+ which `run-create.sh` greps from the log to build the skill's JSON return value.
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env bash
2
+ # detect-and-create.sh - canonical entry point: chains detect-existing.sh → run-create.sh (plan|run), idempotent, production-guarded. Args, JSON status contract, exit codes: SKILL.md.
3
+
4
+ set -euo pipefail
5
+
6
+ if [ $# -lt 2 ]; then
7
+ echo '{"status":"blocked","blocking_issue":"Missing required args","usage":"bash detect-and-create.sh <plan|run> <org-alias> [count=3] [profile-name=\"Standard User\"]"}' >&2
8
+ exit 1
9
+ fi
10
+
11
+ MODE="$1"
12
+ ORG="$2"
13
+ COUNT="${3:-3}"
14
+ PROFILE_NAME="${4:-Standard User}"
15
+
16
+ case "$MODE" in
17
+ plan|run) ;;
18
+ *)
19
+ echo "{\"status\":\"blocked\",\"blocking_issue\":\"Invalid mode '$MODE'. Expected 'plan' or 'run'.\"}" >&2
20
+ exit 1
21
+ ;;
22
+ esac
23
+
24
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
25
+ DETECT_SCRIPT="$SCRIPT_DIR/detect-existing.sh"
26
+ CREATE_SCRIPT="$SCRIPT_DIR/run-create.sh"
27
+
28
+ if [ ! -f "$DETECT_SCRIPT" ]; then
29
+ echo "{\"status\":\"blocked\",\"blocking_issue\":\"Sibling script not found: $DETECT_SCRIPT\"}" >&2
30
+ exit 1
31
+ fi
32
+ if [ "$MODE" = "run" ] && [ ! -f "$CREATE_SCRIPT" ]; then
33
+ echo "{\"status\":\"blocked\",\"blocking_issue\":\"Sibling script not found: $CREATE_SCRIPT\"}" >&2
34
+ exit 1
35
+ fi
36
+
37
+ # Step 1: detect
38
+ DETECT_EXIT=0
39
+ DETECT_JSON=$(bash "$DETECT_SCRIPT" "$ORG" "$COUNT" "$PROFILE_NAME" 2>&1) || DETECT_EXIT=$?
40
+
41
+ if [ "$DETECT_EXIT" -ne 0 ]; then
42
+ jq -n --arg raw "$DETECT_JSON" --argjson exit "$DETECT_EXIT" \
43
+ '{status:"blocked",blocking_issue:("detect-existing.sh exited " + ($exit|tostring)),detect_raw:$raw,create:null}'
44
+ exit 1
45
+ fi
46
+
47
+ if ! echo "$DETECT_JSON" | jq -e . >/dev/null 2>&1; then
48
+ jq -n --arg raw "$DETECT_JSON" \
49
+ '{status:"blocked",blocking_issue:"detect-existing.sh produced non-JSON output",detect_raw:$raw,create:null}'
50
+ exit 1
51
+ fi
52
+
53
+ MISSING_COUNT=$(echo "$DETECT_JSON" | jq -r '.missing_count // 0')
54
+ SAFE_TO_WRITE=$(echo "$DETECT_JSON" | jq -r '.safe_to_write // false')
55
+ PROFILE_ID=$(echo "$DETECT_JSON" | jq -r '.profile_id // ""')
56
+ ORG_SUFFIX=$(echo "$DETECT_JSON" | jq -r '.org_suffix // ""')
57
+ EXISTING_COUNT=$(echo "$DETECT_JSON" | jq -r '.existing_users | length')
58
+ REUSED_USERS=$(echo "$DETECT_JSON" | jq -c '.existing_users // []')
59
+ # A deactivated user in a slot is neither reusable nor recreatable (globally-unique username);
60
+ # surface it as a manual action so a dead slot never passes as clean.
61
+ INACTIVE_COUNT=$(echo "$DETECT_JSON" | jq -r '.inactive_count // 0')
62
+ INACTIVE_ACTION=""
63
+ if [ "$INACTIVE_COUNT" -gt 0 ]; then
64
+ INACTIVE_ACTION="$INACTIVE_COUNT agent slot(s) are occupied by DEACTIVATED users (see inactive_users). Their usernames are globally unique so they cannot be recreated - reactivate them in Setup → Users, or free the usernames, before those slots can be used."
65
+ fi
66
+
67
+ # Step 2: early returns. Nothing missing => "reused" (or action_needed if a dead slot is present).
68
+ if [ "$MISSING_COUNT" = "0" ]; then
69
+ if [ "$INACTIVE_COUNT" -gt 0 ]; then
70
+ jq -n \
71
+ --argjson detect "$DETECT_JSON" \
72
+ --argjson reused_users "$REUSED_USERS" \
73
+ --argjson reused_count "$EXISTING_COUNT" \
74
+ --arg action "$INACTIVE_ACTION" \
75
+ '{
76
+ status: "action_needed",
77
+ action_required: $action,
78
+ detect: $detect,
79
+ reused_users: $reused_users,
80
+ create: null,
81
+ created_count: 0,
82
+ reused_count: $reused_count,
83
+ total_present_after: $reused_count,
84
+ safe_to_write: $detect.safe_to_write
85
+ }'
86
+ exit 0
87
+ fi
88
+ jq -n \
89
+ --argjson detect "$DETECT_JSON" \
90
+ --argjson reused_users "$REUSED_USERS" \
91
+ --argjson reused_count "$EXISTING_COUNT" \
92
+ '{
93
+ status: "reused",
94
+ detect: $detect,
95
+ reused_users: $reused_users,
96
+ create: null,
97
+ created_count: 0,
98
+ reused_count: $reused_count,
99
+ total_present_after: $reused_count,
100
+ safe_to_write: $detect.safe_to_write
101
+ }'
102
+ exit 0
103
+ fi
104
+
105
+ # --plan mode: never create. Report action_needed with the missing indexes (and any dead slots).
106
+ if [ "$MODE" = "plan" ]; then
107
+ jq -n \
108
+ --argjson detect "$DETECT_JSON" \
109
+ --argjson reused_users "$REUSED_USERS" \
110
+ --argjson reused_count "$EXISTING_COUNT" \
111
+ --argjson missing_count "$MISSING_COUNT" \
112
+ --arg inactive_action "$INACTIVE_ACTION" \
113
+ '{
114
+ status: "action_needed",
115
+ action_required: (
116
+ "Missing " + ($missing_count|tostring) + " user(s) at indexes " + ($detect.missing_indexes | map(tostring) | join(",")) + ". Re-run in --run mode to create."
117
+ + (if $inactive_action == "" then "" else " ALSO: " + $inactive_action end)
118
+ ),
119
+ detect: $detect,
120
+ reused_users: $reused_users,
121
+ create: null,
122
+ created_count: 0,
123
+ reused_count: $reused_count,
124
+ total_present_after: $reused_count,
125
+ safe_to_write: $detect.safe_to_write
126
+ }'
127
+ exit 0
128
+ fi
129
+
130
+ # Step 3: --run mode with missing users - safe_to_write guard, then create.
131
+ if [ "$SAFE_TO_WRITE" != "true" ]; then
132
+ jq -n --argjson detect "$DETECT_JSON" \
133
+ '{status:"blocked",blocking_issue:"safe_to_write=false - refusing to create users on a production customer org.",detect:$detect,create:null,created_count:0,reused_count:0,total_present_after:0,safe_to_write:false}'
134
+ exit 1
135
+ fi
136
+
137
+ if [ -z "$PROFILE_ID" ] || [ -z "$ORG_SUFFIX" ]; then
138
+ jq -n --argjson detect "$DETECT_JSON" \
139
+ '{status:"blocked",blocking_issue:"detect-existing.sh did not resolve profile_id or org_suffix - cannot invoke create.",detect:$detect,create:null,created_count:0,reused_count:0,total_present_after:0,safe_to_write:$detect.safe_to_write}'
140
+ exit 1
141
+ fi
142
+
143
+ CREATE_EXIT=0
144
+ CREATE_JSON=$(bash "$CREATE_SCRIPT" "$ORG" "$COUNT" "$PROFILE_ID" "$ORG_SUFFIX" 2>&1) || CREATE_EXIT=$?
145
+
146
+ if [ "$CREATE_EXIT" -ne 0 ]; then
147
+ jq -n --argjson detect "$DETECT_JSON" --arg raw "$CREATE_JSON" --argjson exit "$CREATE_EXIT" \
148
+ '{status:"blocked",blocking_issue:("run-create.sh exited " + ($exit|tostring)),detect:$detect,create:null,create_raw:$raw,created_count:0,reused_count:0,total_present_after:0,safe_to_write:$detect.safe_to_write}'
149
+ exit 1
150
+ fi
151
+
152
+ if ! echo "$CREATE_JSON" | jq -e . >/dev/null 2>&1; then
153
+ jq -n --argjson detect "$DETECT_JSON" --arg raw "$CREATE_JSON" \
154
+ '{status:"blocked",blocking_issue:"run-create.sh produced non-JSON output",detect:$detect,create:null,create_raw:$raw,created_count:0,reused_count:0,total_present_after:0,safe_to_write:$detect.safe_to_write}'
155
+ exit 1
156
+ fi
157
+
158
+ CREATED_COUNT=$(echo "$CREATE_JSON" | jq -r '.created_count // 0')
159
+ ROLLED_BACK_COUNT=$(echo "$CREATE_JSON" | jq -r '.rolled_back_users | length')
160
+ # A created user without a working password (setPassword failed, non-destructive: stays active +
161
+ # reset_required) is not login-ready; any pending reset forces "partial" with a manual action.
162
+ PW_RESET_COUNT=$(echo "$CREATE_JSON" | jq -r '(.users_needing_password_reset // []) | length')
163
+
164
+ # Classify: created (all landed with a password) / partial (some landed, rollbacks, or pending
165
+ # password resets) / blocked (nothing landed).
166
+ if [ "$CREATED_COUNT" = "0" ]; then
167
+ STATUS="blocked"
168
+ elif [ "$ROLLED_BACK_COUNT" -gt 0 ] || [ "$CREATED_COUNT" -lt "$MISSING_COUNT" ] || [ "$PW_RESET_COUNT" -gt 0 ] || [ "$INACTIVE_COUNT" -gt 0 ]; then
169
+ STATUS="partial"
170
+ else
171
+ STATUS="created"
172
+ fi
173
+
174
+ jq -n \
175
+ --argjson detect "$DETECT_JSON" \
176
+ --argjson create "$CREATE_JSON" \
177
+ --argjson reused_users "$REUSED_USERS" \
178
+ --argjson created_count "$CREATED_COUNT" \
179
+ --argjson reused_count "$EXISTING_COUNT" \
180
+ --argjson pw_reset_count "$PW_RESET_COUNT" \
181
+ --arg inactive_action "$INACTIVE_ACTION" \
182
+ --arg status "$STATUS" \
183
+ '{
184
+ status: $status,
185
+ detect: $detect,
186
+ create: $create,
187
+ reused_users: $reused_users,
188
+ created_count: $created_count,
189
+ reused_count: $reused_count,
190
+ total_present_after: ($created_count + $reused_count),
191
+ users_needing_password_reset: ($create.users_needing_password_reset // []),
192
+ action_required: (
193
+ [
194
+ (if $pw_reset_count > 0 then
195
+ ($pw_reset_count | tostring) + " user(s) were created but could NOT have a password set automatically and cannot log in yet. Manually reset their passwords (Setup → Users → Reset Password, or `sf org open` → user record) before use. See users_needing_password_reset and CREDENTIALS.json."
196
+ else empty end),
197
+ (if $inactive_action == "" then empty else $inactive_action end)
198
+ ] | if length == 0 then null else join(" ") end
199
+ ),
200
+ safe_to_write: $detect.safe_to_write
201
+ }'
202
+
203
+ case "$STATUS" in
204
+ created|partial) exit 0 ;;
205
+ blocked) exit 1 ;;
206
+ esac
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env bash
2
+ # detect-existing.sh - read-only probe for existing agent users (org/profile/existing/missing indexes); deterministic, no side effects. Args + JSON output: SKILL.md.
3
+
4
+ set -euo pipefail
5
+
6
+ if [ $# -lt 1 ]; then
7
+ echo '{"error":"Missing required argument: org-alias","usage":"bash detect-existing.sh <org-alias> [count=3] [profile-name=\"Standard User\"]"}' >&2
8
+ exit 1
9
+ fi
10
+
11
+ ORG="$1"
12
+ COUNT="${2:-3}"
13
+ PROFILE_NAME="${3:-Standard User}"
14
+
15
+ if ! [[ "$COUNT" =~ ^[1-9]$|^10$ ]]; then
16
+ echo "{\"error\":\"Count must be an integer in range 1..10, got: $COUNT\"}" >&2
17
+ exit 1
18
+ fi
19
+
20
+ if ! sf org display --target-org "$ORG" --json >/dev/null 2>&1; then
21
+ echo "{\"error\":\"Org alias '$ORG' is not authenticated. Run: sf org login web -a $ORG -r <my-domain-url>\"}" >&2
22
+ exit 1
23
+ fi
24
+
25
+ # 1. Query Organization: a production org fails all of IsSandbox / TrialExpirationDate!=null /
26
+ # OrganizationType in (Developer Edition, Base Edition).
27
+ ORG_JSON=$(sf data query --target-org "$ORG" --query "SELECT Id, IsSandbox, TrialExpirationDate, OrganizationType FROM Organization LIMIT 1" --json 2>/dev/null || true)
28
+ ORG_ID=$(echo "$ORG_JSON" | jq -r '.result.records[0].Id // empty')
29
+ IS_SANDBOX=$(echo "$ORG_JSON" | jq -r '.result.records[0].IsSandbox // false')
30
+ TRIAL_EXP=$(echo "$ORG_JSON" | jq -r '.result.records[0].TrialExpirationDate // "null"')
31
+ ORG_TYPE=$(echo "$ORG_JSON" | jq -r '.result.records[0].OrganizationType // "Unknown"')
32
+
33
+ if [ -z "$ORG_ID" ]; then
34
+ echo '{"error":"Failed to query Organization.Id - check org auth and API permissions."}' >&2
35
+ exit 1
36
+ fi
37
+
38
+ # Compute safe-to-write flag: true if the org is definitively NOT a production customer org.
39
+ SAFE_TO_WRITE=false
40
+ if [ "$IS_SANDBOX" = "true" ] || [ "$TRIAL_EXP" != "null" ] || [ "$ORG_TYPE" = "Developer Edition" ] || [ "$ORG_TYPE" = "Base Edition" ]; then
41
+ SAFE_TO_WRITE=true
42
+ fi
43
+
44
+ # Derive suffix: last 8 chars of Organization.Id, lowercased. Deterministic per org.
45
+ SUFFIX=$(echo -n "${ORG_ID:10:8}" | tr '[:upper:]' '[:lower:]')
46
+
47
+ # 2. Query Profile. Profile.Name is a display name; escape ' for the SOQL literal (apostrophe safety + no injection).
48
+ PROFILE_NAME_SOQL=${PROFILE_NAME//\'/\\\'}
49
+ PROFILE_JSON=$(sf data query --target-org "$ORG" --query "SELECT Id, Name FROM Profile WHERE Name = '$PROFILE_NAME_SOQL' LIMIT 1" --json 2>/dev/null || true)
50
+ PROFILE_ID=$(echo "$PROFILE_JSON" | jq -r '.result.records[0].Id // empty')
51
+
52
+ if [ -z "$PROFILE_ID" ]; then
53
+ echo "{\"error\":\"Profile '$PROFILE_NAME' not found on org '$ORG'. Check spelling - profile names are case-sensitive on some orgs and may be localized.\"}" >&2
54
+ exit 1
55
+ fi
56
+
57
+ # 3. Query existing agent users matching the pattern
58
+ USER_JSON=$(sf data query --target-org "$ORG" \
59
+ --query "SELECT Id, Username, IsActive FROM User WHERE Username LIKE 'agent%.${SUFFIX}@example.com'" \
60
+ --json 2>/dev/null || true)
61
+
62
+ # Build existing_users array + missing_indexes array via jq
63
+ # For each i in 1..COUNT, check if agent{i}.<suffix>@example.com exists.
64
+ EXPECTED_USERNAMES=$(seq 1 "$COUNT" | awk -v s="$SUFFIX" '{ printf "\"agent%s.%s@example.com\"\n", $1, s }' | jq -s '.')
65
+
66
+ FULL_JSON=$(jq -n \
67
+ --arg org_id "$ORG_ID" \
68
+ --arg org_suffix "$SUFFIX" \
69
+ --argjson is_sandbox "$IS_SANDBOX" \
70
+ --arg trial_expiration_date "$TRIAL_EXP" \
71
+ --arg organization_type "$ORG_TYPE" \
72
+ --argjson safe_to_write "$SAFE_TO_WRITE" \
73
+ --arg profile_id "$PROFILE_ID" \
74
+ --arg profile_name "$PROFILE_NAME" \
75
+ --argjson count "$COUNT" \
76
+ --argjson expected "$EXPECTED_USERNAMES" \
77
+ --argjson user_records "$(echo "$USER_JSON" | jq '.result.records // []')" \
78
+ '
79
+ # Build a map: username -> {id, is_active}
80
+ ($user_records | map({ (.Username | ascii_downcase): {id: .Id, is_active: .IsActive} }) | add // {}) as $by_uname
81
+ |
82
+ # For each expected index, determine if user exists
83
+ [range(1; $count + 1) as $i
84
+ | ($expected[$i - 1] | ascii_downcase) as $uname
85
+ | if $by_uname[$uname] then
86
+ {index: $i, id: $by_uname[$uname].id, username: $uname, is_active: $by_uname[$uname].is_active}
87
+ else
88
+ null
89
+ end
90
+ ] as $slots
91
+ |
92
+ # occupied slots (any user present, active or not)
93
+ ($slots | map(select(. != null))) as $occupied
94
+ |
95
+ # existing_users: only active occupants are reusable; inactive users are surfaced separately
96
+ # (globally-unique username, not recreatable).
97
+ ($occupied | map(select(.is_active == true))) as $existing
98
+ |
99
+ ($occupied | map(select(.is_active != true))) as $inactive
100
+ |
101
+ # missing_indexes: indexes where the slot is empty (no user at all - safe to create)
102
+ ([range(1; $count + 1) as $i | if $slots[$i - 1] == null then $i else null end] | map(select(. != null))) as $missing
103
+ |
104
+ {
105
+ org_id: $org_id,
106
+ org_suffix: $org_suffix,
107
+ is_sandbox: $is_sandbox,
108
+ trial_expiration_date: (if $trial_expiration_date == "null" then null else $trial_expiration_date end),
109
+ organization_type: $organization_type,
110
+ safe_to_write: $safe_to_write,
111
+ profile_id: $profile_id,
112
+ profile_name: $profile_name,
113
+ requested_count: $count,
114
+ existing_users: $existing,
115
+ inactive_users: $inactive,
116
+ inactive_count: ($inactive | length),
117
+ missing_indexes: $missing,
118
+ missing_count: ($missing | length)
119
+ }
120
+ ')
121
+
122
+ echo "$FULL_JSON"