@salesforce/afv-skills 1.54.0 → 1.56.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 (244) hide show
  1. package/package.json +1 -1
  2. package/skills/agentforce-generate/SKILL.md +8 -0
  3. package/skills/agentforce-generate/references/actions-reference.md +2 -2
  4. package/skills/agentforce-generate/references/voice-modality-reference.md +51 -15
  5. package/skills/agentforce-generate/references/voice-telephony-cli.md +193 -0
  6. package/skills/agentforce-observe/SKILL.md +13 -9
  7. package/skills/agentforce-observe/references/ahm-alerts.md +193 -14
  8. package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +24 -15
  9. package/skills/automation-sandbox-post-copy-config-generate/assets/config_template.json +11 -0
  10. package/skills/automation-sandbox-post-copy-config-generate/assets/json_schema.json +33 -1
  11. package/skills/automation-sandbox-post-copy-config-generate/references/configuration_catalog.md +32 -1
  12. package/skills/automation-sandbox-post-copy-configure/SKILL.md +75 -71
  13. package/skills/automation-sandbox-post-copy-configure/assets/scheduled_apex_template.apex +13 -0
  14. package/skills/automation-sandbox-post-copy-configure/examples/sample_scheduled_apex_config.json +13 -0
  15. package/skills/automation-sandbox-post-copy-configure/references/scheduled_apex_path.md +155 -0
  16. package/skills/automation-sandbox-post-copy-configure/scripts/build-scheduled-apex.mjs +62 -0
  17. package/skills/automation-sandbox-post-copy-configure/scripts/soql-escape-job-name.mjs +28 -0
  18. package/skills/consumer-goods-accruals-datakit-deploy/SKILL.md +383 -0
  19. package/skills/consumer-goods-accruals-datakit-deploy/scripts/setup.js +324 -0
  20. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/00-check-prerequisites.js +63 -0
  21. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/01-download-static-resource.js +100 -0
  22. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/02-replace-org-id.js +46 -0
  23. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/03-deploy-metadata.js +46 -0
  24. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/04-deploy-engine.js +198 -0
  25. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/05-deploy-tpm-accruals.js +231 -0
  26. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/06-create-dataspace.js +82 -0
  27. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/07-deploy-accruals-reports.js +517 -0
  28. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/08-deploy-ui.js +416 -0
  29. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/09-completion.js +44 -0
  30. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/utils.js +514 -0
  31. package/skills/consumer-goods-sync-management-configure/SKILL.md +137 -0
  32. package/skills/consumer-goods-sync-management-configure/examples/scenarios.md +294 -0
  33. package/skills/consumer-goods-sync-management-configure/references/act1-setup-sync.md +333 -0
  34. package/skills/consumer-goods-sync-management-configure/references/act2-assign-users.md +324 -0
  35. package/skills/consumer-goods-sync-management-configure/references/act3-plan-verify.md +113 -0
  36. package/skills/consumer-goods-sync-management-configure/references/readiness-and-enablement.md +164 -0
  37. package/skills/consumer-goods-sync-management-configure/references/sync-management-app-install-backbone.md +159 -0
  38. package/skills/consumer-goods-sync-management-configure/references/transports-and-namespace.md +220 -0
  39. package/skills/consumer-goods-sync-management-configure/references/verify-and-smoke.md +175 -0
  40. package/skills/dx-org-analyze/README.md +310 -0
  41. package/skills/dx-org-analyze/SKILL.md +260 -0
  42. package/skills/dx-org-analyze/references/collection-details.md +88 -0
  43. package/skills/dx-org-analyze/references/report-format.md +67 -0
  44. package/skills/dx-org-analyze/scripts/collect_org_data.py +823 -0
  45. package/skills/dx-org-analyze/scripts/compute_diff.py +1101 -0
  46. package/skills/dx-org-analyze/scripts/introspect_org.py +400 -0
  47. package/skills/dx-org-analyze/tests/README.md +46 -0
  48. package/skills/dx-org-analyze/tests/fixtures/org_a.json +76 -0
  49. package/skills/dx-org-analyze/tests/fixtures/org_b.json +70 -0
  50. package/skills/dx-org-analyze/tests/test_compute_diff.sh +284 -0
  51. package/skills/dx-org-analyze/tests/test_consistency.sh +428 -0
  52. package/skills/dx-org-manage/SKILL.md +6 -50
  53. package/skills/dx-org-manage/examples/README.md +10 -16
  54. package/skills/dx-org-manage/references/scratch-org-create.md +1 -1
  55. package/skills/dx-org-manage/references/scratch-org-operations.md +1 -1
  56. package/skills/dx-org-shape-manage/SKILL.md +4 -3
  57. package/skills/education-cloud-domain-configure/references/gotchas-extended.md +1 -0
  58. package/skills/experience-accessibility-validate/SKILL.md +8 -5
  59. package/skills/experience-accessibility-validate/references/reviewers/sc-1-1-1-non-text-content.md +1 -4
  60. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-i-lists.md +0 -4
  61. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-ii-tables.md +20 -85
  62. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iii-form-labels.md +4 -4
  63. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iv-regions.md +0 -4
  64. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-v-groups.md +2 -4
  65. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-5-identify-input.md +0 -4
  66. package/skills/experience-accessibility-validate/references/reviewers/sc-1-4-3-contrast.md +4 -14
  67. package/skills/experience-accessibility-validate/references/reviewers/sc-2-1-1-keyboard.md +9 -5
  68. package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-4-link-purpose.md +1 -4
  69. package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-6-headings-labels.md +0 -4
  70. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-1-pointer-gestures.md +0 -4
  71. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-2-pointer-cancellation.md +0 -4
  72. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-3-label-in-name.md +0 -4
  73. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-7-dragging-movement.md +0 -4
  74. package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-1-on-focus.md +0 -4
  75. package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-2-on-input.md +1 -4
  76. package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-1-error-identification.md +1 -4
  77. package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-2-labels-instructions.md +1 -4
  78. package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-3-error-suggestion.md +1 -4
  79. package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-i-name.md +4 -5
  80. package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-ii-role.md +1 -4
  81. package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-iii-value.md +0 -4
  82. package/skills/experience-design-validate/SKILL.md +163 -0
  83. package/skills/experience-design-validate/references/ai.md +54 -0
  84. package/skills/experience-design-validate/references/components.md +61 -0
  85. package/skills/experience-design-validate/references/craft.md +158 -0
  86. package/skills/experience-design-validate/references/data.md +59 -0
  87. package/skills/experience-design-validate/references/forms-flows.md +57 -0
  88. package/skills/experience-design-validate/references/interaction.md +53 -0
  89. package/skills/experience-design-validate/references/navigation.md +51 -0
  90. package/skills/experience-design-validate/references/performance.md +56 -0
  91. package/skills/experience-design-validate/references/records.md +60 -0
  92. package/skills/experience-design-validate/references/responsive.md +48 -0
  93. package/skills/experience-design-validate/references/scoring-rubric.md +257 -0
  94. package/skills/experience-design-validate/references/state.md +53 -0
  95. package/skills/experience-design-validate/references/trust.md +47 -0
  96. package/skills/experience-design-validate/references/usability.md +35 -0
  97. package/skills/experience-design-validate/references/visual-system.md +183 -0
  98. package/skills/experience-lwc-accessibility-jest-run/SKILL.md +104 -25
  99. package/skills/experience-lwc-accessibility-jest-run/assets/jest.config.js +4 -0
  100. package/skills/experience-lwc-accessibility-jest-run/assets/sa11y-jest-setup.js +5 -0
  101. package/skills/experience-ui-bundle-app-coordinate/SKILL.md +5 -5
  102. package/skills/experience-ui-bundle-features-generate/SKILL.md +65 -36
  103. package/skills/experience-ui-bundle-features-generate/references/angular/features.md +74 -0
  104. package/skills/experience-ui-bundle-features-generate/references/react/features.md +59 -0
  105. package/skills/experience-ui-bundle-features-generate/scripts/detect-framework.sh +73 -0
  106. package/skills/experience-ui-bundle-frontend-generate/SKILL.md +2 -2
  107. package/skills/experience-ui-bundle-metadata-generate/SKILL.md +26 -14
  108. package/skills/experience-ui-bundle-metadata-generate/references/angular-metadata-generate.md +37 -0
  109. package/skills/experience-ui-bundle-metadata-generate/references/react-metadata-generate.md +32 -0
  110. package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.sh +73 -0
  111. package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.sh +30 -8
  112. package/skills/field-service-data-capture-migrate/SKILL.md +391 -0
  113. package/skills/field-service-data-capture-migrate/assets/sample-legacy-flow.flow-meta.xml +163 -0
  114. package/skills/field-service-data-capture-migrate/references/architecture-notes.md +40 -0
  115. package/skills/field-service-data-capture-migrate/references/component-mapping.md +278 -0
  116. package/skills/field-service-data-capture-migrate/references/converter-builder-contract.md +183 -0
  117. package/skills/field-service-data-capture-migrate/references/dc-platform-rules.md +130 -0
  118. package/skills/field-service-data-capture-migrate/references/fsm-dc-capability-catalog.md +215 -0
  119. package/skills/field-service-data-capture-migrate/references/known-deploy-errors.md +36 -0
  120. package/skills/field-service-data-capture-migrate/references/migration-checklist.md +121 -0
  121. package/skills/field-service-data-capture-migrate/references/transformer-rules.md +132 -0
  122. package/skills/field-service-data-capture-migrate/scripts/analyze_flow.py +277 -0
  123. package/skills/field-service-data-capture-migrate/scripts/convert_to_dc_spec.py +1311 -0
  124. package/skills/field-service-data-capture-migrate/scripts/cud_analysis.py +402 -0
  125. package/skills/field-service-data-capture-migrate/scripts/deploy_flow.sh +230 -0
  126. package/skills/field-service-data-capture-migrate/scripts/discover_subflow_tree.py +230 -0
  127. package/skills/field-service-data-capture-migrate/scripts/flow_input.py +186 -0
  128. package/skills/field-service-data-capture-migrate/scripts/flow_xml_utils.py +39 -0
  129. package/skills/field-service-data-capture-migrate/scripts/fsm_dc_catalog.py +413 -0
  130. package/skills/field-service-data-capture-migrate/scripts/generate_summary.py +199 -0
  131. package/skills/field-service-data-capture-migrate/scripts/json_to_flow_xml.py +146 -0
  132. package/skills/field-service-data-capture-migrate/scripts/manual_review_flags.py +42 -0
  133. package/skills/field-service-data-capture-migrate/scripts/retrieve_flow_rest.sh +155 -0
  134. package/skills/field-service-data-capture-migrate/scripts/subflow_names.py +49 -0
  135. package/skills/field-service-data-capture-migrate/scripts/transform_flow.py +1661 -0
  136. package/skills/field-service-data-capture-migrate/scripts/validate_flow.sh +147 -0
  137. package/skills/field-service-data-capture-migrate/scripts/vendor/build_flow.py +1258 -0
  138. package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +1 -1
  139. package/skills/life-sciences-fieldsalesrep-coordinate/references/orchestration-flow.md +1 -1
  140. package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +14 -1
  141. package/skills/mobile-apps-create/SKILL.md +1 -1
  142. package/skills/{platform-agentsetup-categories-fetch → platform-agenticsetup-categories-get}/SKILL.md +7 -7
  143. package/skills/platform-sandbox-configure/SKILL.md +108 -133
  144. package/skills/platform-sandbox-configure/references/api-response-shapes.md +39 -0
  145. package/skills/platform-sandbox-configure/references/definition-file-approach.md +73 -0
  146. package/skills/platform-widget-generate/SKILL.md +26 -18
  147. package/skills/platform-widget-generate/examples/formulas.json +191 -0
  148. package/skills/platform-widget-generate/references/widget-formulas.md +123 -0
  149. package/skills/platform-widget-generate/references/widget-meta-directives.md +4 -4
  150. package/skills/sales-call-scoring-configure/SKILL.md +318 -0
  151. package/skills/sales-call-scoring-configure/assets/best-practice-competencies.json +67 -0
  152. package/skills/sales-call-scoring-configure/assets/ootb-competencies.json +58 -0
  153. package/skills/sales-call-scoring-configure/references/admin-communication.md +79 -0
  154. package/skills/sales-call-scoring-configure/references/competency-crud.md +130 -0
  155. package/skills/sales-call-scoring-configure/scripts/create-competency.sh +166 -0
  156. package/skills/sales-call-scoring-configure/scripts/create-custom-competency.sh +166 -0
  157. package/skills/sales-call-scoring-configure/scripts/edit-competency.sh +185 -0
  158. package/skills/sales-call-scoring-configure/scripts/edit-custom-competency.sh +190 -0
  159. package/skills/sales-call-scoring-configure/scripts/enable-call-scoring.sh +436 -0
  160. package/skills/sales-call-scoring-configure/scripts/get-competency.sh +72 -0
  161. package/skills/sales-call-scoring-configure/scripts/get-custom-competency.sh +78 -0
  162. package/skills/sales-call-scoring-configure/scripts/install-best-practice-competencies.sh +223 -0
  163. package/skills/sales-call-scoring-configure/scripts/install-ootb-competencies.sh +237 -0
  164. package/skills/sales-call-scoring-configure/scripts/list-competencies.sh +99 -0
  165. package/skills/sales-call-scoring-configure/scripts/shared/auth.sh +116 -0
  166. package/skills/sales-call-scoring-configure/scripts/shared/cap.sh +86 -0
  167. package/skills/sales-call-scoring-configure/scripts/shared/soap.sh +267 -0
  168. package/skills/sales-call-scoring-configure/scripts/shared/soql.sh +25 -0
  169. package/skills/sales-call-scoring-configure/scripts/toggle-competency.sh +112 -0
  170. package/skills/sales-call-scoring-configure/scripts/toggle-custom-competency.sh +125 -0
  171. package/skills/sales-call-scoring-configure/scripts/verify-ootb-competencies.sh +116 -0
  172. package/skills/service-concierge-portal-generate/references/portal-deploy-runbook.md +1 -0
  173. package/skills/service-de-channel-activate/SKILL.md +6 -5
  174. package/skills/service-de-channel-create/SKILL.md +3 -3
  175. package/skills/service-de-channel-routing-configure/SKILL.md +3 -3
  176. package/skills/service-de-channel-settings-configure/SKILL.md +195 -0
  177. package/skills/service-de-channel-settings-configure/references/channel-settings-facets.md +152 -0
  178. package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/gotchas.md +3 -3
  179. package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/language-keywords.md +4 -4
  180. package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/worked-examples.md +14 -14
  181. package/skills/service-de-headless-channel-configure/SKILL.md +6 -6
  182. package/skills/service-de-headless-channel-configure/references/worked-examples.md +1 -1
  183. package/skills/service-helpagent-coordinate/SKILL.md +3 -2
  184. package/skills/service-helpagent-coordinate/references/channel-voice.md +15 -4
  185. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +49 -31
  186. package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +71 -6
  187. package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +26 -4
  188. package/skills/service-itsm-agentic-setup-cmdb-access-assign/SKILL.md +35 -10
  189. package/skills/service-itsm-agentic-setup-cmdb-access-assign/references/mcp-invocation.md +25 -5
  190. package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/SKILL.md +1 -1
  191. package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +5 -5
  192. package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +1 -1
  193. package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +2 -2
  194. package/skills/service-itsm-agentic-setup-cmdb-coordinate/examples/output-templates.md +1 -1
  195. package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/SKILL.md +25 -15
  196. package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +8 -5
  197. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +4 -2
  198. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +1 -1
  199. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +29 -16
  200. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +8 -5
  201. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +4 -2
  202. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +1 -1
  203. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +29 -16
  204. package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +138 -68
  205. package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +31 -15
  206. package/skills/service-itsm-agentic-setup-incident-management/references/incident-persona-psg.md +156 -0
  207. package/skills/service-itsm-agentic-setup-incident-management/references/incident-preferences.md +148 -0
  208. package/skills/service-itsm-agentic-setup-incident-management/references/major-incident-management.md +162 -0
  209. package/skills/service-itsm-agentic-setup-incident-management/references/service-mgmt-privilege.md +149 -0
  210. package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +103 -89
  211. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +2 -2
  212. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +21 -39
  213. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +3 -3
  214. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +18 -1
  215. package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +63 -37
  216. package/skills/service-omni-attribute-routing-configure/SKILL.md +53 -0
  217. package/skills/service-omni-attribute-routing-configure/references/api-notes.md +7 -0
  218. package/skills/service-omni-attribute-routing-configure/scripts/configure-and-report.sh +224 -0
  219. package/skills/service-omni-attribute-routing-configure/scripts/tests/test_attribute_routing_contracts.py +137 -0
  220. package/skills/service-omni-channel-inventory-analyze/SKILL.md +96 -0
  221. package/skills/service-omni-channel-inventory-analyze/references/api-notes.md +52 -0
  222. package/skills/service-omni-channel-inventory-analyze/scripts/analyze.sh +185 -0
  223. package/skills/service-omni-channel-inventory-analyze/scripts/tests/_bootstrap.py +84 -0
  224. package/skills/service-omni-channel-inventory-analyze/scripts/tests/test_inventory_analyze_contracts.py +141 -0
  225. package/skills/service-omni-channel-limits-analyze/SKILL.md +70 -0
  226. package/skills/service-omni-channel-limits-analyze/references/api-notes.md +22 -0
  227. package/skills/service-omni-channel-limits-analyze/scripts/analyze.sh +159 -0
  228. package/skills/service-omni-channel-limits-analyze/scripts/tests/_bootstrap.py +87 -0
  229. package/skills/service-omni-channel-limits-analyze/scripts/tests/test_limits_analyze_contracts.py +99 -0
  230. package/skills/service-omni-channel-setup-coordinate/SKILL.md +12 -20
  231. package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +55 -5
  232. package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +38 -0
  233. package/skills/service-omni-command-center-analyze/SKILL.md +2 -2
  234. package/skills/service-omni-command-center-analyze/scripts/analyze.sh +3 -3
  235. package/skills/dx-org-manage/examples/snapshots/error_output.json +0 -9
  236. package/skills/dx-org-manage/examples/snapshots/success_output.json +0 -15
  237. package/skills/dx-org-manage/references/cli_flags.md +0 -67
  238. package/skills/dx-org-manage/references/creating-snapshot.md +0 -103
  239. package/skills/dx-org-manage/references/snapshot_usage.md +0 -74
  240. package/skills/experience-accessibility-validate/scripts/contrast-ratio.py +0 -153
  241. package/skills/experience-lwc-accessibility-jest-run/references/running-sa11y-jest-tests.md +0 -205
  242. package/skills/experience-ui-bundle-features-generate/scripts/verify-react-bundle.sh +0 -14
  243. /package/skills/experience-ui-bundle-features-generate/references/{conflict-resolution-schema.json → common/conflict-resolution-schema.json} +0 -0
  244. /package/skills/{platform-agentsetup-categories-fetch → platform-agenticsetup-categories-get}/references/api-response-schema.md +0 -0
@@ -0,0 +1,400 @@
1
+ #!/usr/bin/env python3
2
+ """Generate a single-org introspection report.
3
+
4
+ Takes one collected org data directory (output of collect_org_data.py)
5
+ and produces a summary report in markdown and/or JSON.
6
+
7
+ Usage:
8
+ introspect_org.py --org /tmp/org-data --output /tmp/report
9
+ introspect_org.py --org /tmp/org-data --output /tmp/report --format markdown
10
+ """
11
+
12
+ import argparse
13
+ import json
14
+ import os
15
+ import sys
16
+ from datetime import date
17
+
18
+ # ── Reuse categorization from compute_diff ──────────────────────────
19
+
20
+ PERM_CATEGORIES = [
21
+ ("Commerce", ["commerce", "b2b", "b2c", "order", "cart", "store", "checkout"]),
22
+ ("Platform/API", ["platform", "api", "rest", "soap", "bulk", "streaming", "connect", "metadata"]),
23
+ ("Security", ["security", "auth", "login", "mfa", "sso", "encryption", "certificate", "session", "password", "oauth"]),
24
+ ("Einstein/AI", ["einstein", "ai", "predict", "ml", "copilot", "agent"]),
25
+ ("Service", ["service", "case", "knowledge", "chat", "messaging", "omni", "entitlement"]),
26
+ ("Data", ["data", "record", "report", "dashboard", "analytics", "tableau"]),
27
+ ("Trialforce", ["trialforce", "tso", "tmo", "signup", "template"]),
28
+ ("Sales", ["sales", "opportunity", "lead", "forecast", "quote", "contract"]),
29
+ ("Work/HR", ["work", "hr", "employee", "shift", "wellness"]),
30
+ ]
31
+
32
+ VALUE_CATEGORIES = [
33
+ ("Identity", ["name", "edition", "org", "domain", "id", "type", "instance", "locale"]),
34
+ ("Storage", ["storage", "file", "size", "space", "quota"]),
35
+ ("API", ["api", "request", "daily", "hourly", "concurrent", "streaming", "bulk"]),
36
+ ("Feature Limits", ["custom", "rule", "flow", "process", "workflow", "approval", "limit", "max"]),
37
+ ]
38
+
39
+
40
+ def classify(name, categories, default="Other"):
41
+ lower = name.lower()
42
+ for cat, keywords in categories:
43
+ if any(kw in lower for kw in keywords):
44
+ return cat
45
+ return default
46
+
47
+
48
+ # ── Data loading (same as compute_diff.py) ──────────────────────────
49
+
50
+ def load_org_data(path):
51
+ if os.path.isdir(path):
52
+ combined = os.path.join(path, "combined.json")
53
+ if os.path.exists(combined):
54
+ with open(combined) as f:
55
+ return json.load(f)
56
+ manifest_path = os.path.join(path, "manifest.json")
57
+ if not os.path.exists(manifest_path):
58
+ raise FileNotFoundError(f"Directory {path} has no manifest.json or combined.json")
59
+ with open(manifest_path) as f:
60
+ manifest = json.load(f)
61
+ data = {}
62
+ for cat, fname in manifest.get("files", {}).items():
63
+ fpath = os.path.join(path, fname)
64
+ with open(fpath) as f:
65
+ chunk = json.load(f)
66
+ if isinstance(chunk, dict):
67
+ data.update(chunk)
68
+ else:
69
+ data[cat] = chunk
70
+ return data
71
+
72
+ with open(path) as f:
73
+ return json.load(f)
74
+
75
+
76
+ # ── Analysis ────────────────────────────────────────────────────────
77
+
78
+ def analyze_metadata(data):
79
+ types = data.get("metadata_types", [])
80
+ components = data.get("metadata_components", {})
81
+ by_type = {}
82
+ total = 0
83
+ namespaced_total = 0
84
+ for mtype, items in sorted(components.items()):
85
+ org_native = [c for c in items if not c.get("namespace")]
86
+ namespaced = [c for c in items if c.get("namespace")]
87
+ by_type[mtype] = {
88
+ "total": len(items),
89
+ "org_native": len(org_native),
90
+ "namespaced": len(namespaced),
91
+ }
92
+ total += len(org_native)
93
+ namespaced_total += len(namespaced)
94
+ return {
95
+ "types_discovered": len(types),
96
+ "types_with_components": len(components),
97
+ "total_org_native": total,
98
+ "total_namespaced": namespaced_total,
99
+ "by_type": by_type,
100
+ }
101
+
102
+
103
+ def analyze_permissions(data):
104
+ perms = data.get("permissions", {})
105
+ by_category = {}
106
+ enabled = 0
107
+ disabled = 0
108
+ non_boolean = 0
109
+ for name, val in perms.items():
110
+ cat = classify(name, PERM_CATEGORIES)
111
+ if cat not in by_category:
112
+ by_category[cat] = {"enabled": 0, "disabled": 0, "non_boolean": 0, "items": []}
113
+ v = val if isinstance(val, str) else val.get("value", str(val)) if isinstance(val, dict) else str(val)
114
+ if v.lower() in ("enabled", "true"):
115
+ by_category[cat]["enabled"] += 1
116
+ enabled += 1
117
+ elif v.lower() in ("disabled", "false"):
118
+ by_category[cat]["disabled"] += 1
119
+ disabled += 1
120
+ else:
121
+ by_category[cat]["non_boolean"] += 1
122
+ non_boolean += 1
123
+ by_category[cat]["items"].append((name, v))
124
+ return {
125
+ "total": len(perms),
126
+ "enabled": enabled,
127
+ "disabled": disabled,
128
+ "non_boolean": non_boolean,
129
+ "by_category": by_category,
130
+ }
131
+
132
+
133
+ def analyze_org_values(data):
134
+ vals = data.get("org_values", {})
135
+ by_category = {}
136
+ for name, val in vals.items():
137
+ cat = classify(name, VALUE_CATEGORIES)
138
+ if cat not in by_category:
139
+ by_category[cat] = []
140
+ by_category[cat].append((name, val))
141
+ return {"total": len(vals), "by_category": by_category}
142
+
143
+
144
+ def analyze_packages(data):
145
+ pkgs = data.get("installed_packages", [])
146
+ return {
147
+ "count": len(pkgs),
148
+ "packages": [
149
+ {"name": p.get("name", ""), "namespace": p.get("namespace") or "", "version": p.get("version", "")}
150
+ for p in pkgs
151
+ ],
152
+ }
153
+
154
+
155
+ def analyze_licenses(data):
156
+ lics = data.get("licenses", {})
157
+ result = {}
158
+ for category in ("user", "permission_set", "package"):
159
+ items = lics.get(category, [])
160
+ result[category] = {
161
+ "count": len(items),
162
+ "items": items,
163
+ }
164
+ return result
165
+
166
+
167
+ def analyze_system_permissions(data):
168
+ sp_raw = data.get("system_permissions", {})
169
+ if isinstance(sp_raw, dict):
170
+ sp = sp_raw.get("permission_sets", [])
171
+ else:
172
+ sp = sp_raw
173
+ total_enabled = 0
174
+ sets = []
175
+ for ps in sp:
176
+ name = ps.get("name", ps.get("label", "Unknown"))
177
+ perms = ps.get("permissions", {})
178
+ enabled = sum(1 for v in perms.values() if v)
179
+ total_enabled += enabled
180
+ sets.append({"name": name, "enabled": enabled, "total": len(perms)})
181
+ return {"permission_sets": len(sp), "total_enabled": total_enabled, "sets": sets}
182
+
183
+
184
+ def analyze_deep_data(data):
185
+ dd = data.get("deep_data", {})
186
+ result = {}
187
+ for category, records in dd.items():
188
+ result[category] = len(records) if isinstance(records, list) else 0
189
+ return result
190
+
191
+
192
+ # ── Render markdown ─────────────────────────────────────────────────
193
+
194
+ def render_markdown(data, meta, perms, vals, pkgs, lics, sys_perms, deep, label):
195
+ lines = []
196
+ lines.append(f"# Org Analysis Report: {label}\n")
197
+ lines.append(f"| Field | Value |")
198
+ lines.append(f"|-------|-------|")
199
+ lines.append(f"| **Org ID** | {data.get('org_id', 'N/A')} |")
200
+ lines.append(f"| **Name** | {data.get('org_name', 'N/A')} |")
201
+ lines.append(f"| **Edition** | {data.get('org_edition', 'N/A')} |")
202
+ lines.append(f"| **Date** | {date.today()} |")
203
+ lines.append("")
204
+
205
+ # Summary
206
+ lines.append("---\n")
207
+ lines.append("## Summary\n")
208
+ lines.append("| Category | Count |")
209
+ lines.append("|----------|-------|")
210
+ lines.append(f"| Metadata types discovered | {meta['types_discovered']} |")
211
+ lines.append(f"| Types with components | {meta['types_with_components']} |")
212
+ lines.append(f"| Org-native components | {meta['total_org_native']} |")
213
+ lines.append(f"| Namespaced components | {meta['total_namespaced']} |")
214
+ lines.append(f"| Org settings | {perms['total']} ({perms['enabled']} enabled, {perms['disabled']} disabled) |")
215
+ lines.append(f"| Org limits | {vals['total']} |")
216
+ lines.append(f"| Installed packages | {pkgs['count']} |")
217
+ lines.append(f"| System permission sets | {sys_perms['permission_sets']} |")
218
+ deep_total = sum(deep.values())
219
+ lines.append(f"| Deep data records | {deep_total} |")
220
+ errors = data.get("errors", [])
221
+ if errors:
222
+ lines.append(f"| Collection warnings | {len(errors)} |")
223
+ lines.append("")
224
+
225
+ # Metadata inventory
226
+ lines.append("---\n")
227
+ lines.append("## Metadata Inventory\n")
228
+ lines.append("| Type | Org-Native | Namespaced | Total |")
229
+ lines.append("|------|-----------|------------|-------|")
230
+ for mtype, counts in sorted(meta["by_type"].items()):
231
+ if counts["total"] > 0:
232
+ lines.append(f"| {mtype} | {counts['org_native']} | {counts['namespaced']} | {counts['total']} |")
233
+ lines.append(f"| **Total** | **{meta['total_org_native']}** | **{meta['total_namespaced']}** | **{meta['total_org_native'] + meta['total_namespaced']}** |")
234
+ lines.append("")
235
+
236
+ # Installed packages
237
+ lines.append("---\n")
238
+ lines.append("## Installed Packages\n")
239
+ if pkgs["packages"]:
240
+ lines.append("| Package | Namespace | Version |")
241
+ lines.append("|---------|-----------|---------|")
242
+ for p in pkgs["packages"]:
243
+ lines.append(f"| {p['name']} | {p.get('namespace') or '—'} | {p['version']} |")
244
+ else:
245
+ lines.append("No installed packages.\n")
246
+ lines.append("")
247
+
248
+ # Org settings by category
249
+ lines.append("---\n")
250
+ lines.append("## Org Settings\n")
251
+ lines.append("| Category | Enabled | Disabled | Non-Boolean |")
252
+ lines.append("|----------|---------|----------|-------------|")
253
+ for cat in sorted(perms["by_category"].keys()):
254
+ info = perms["by_category"][cat]
255
+ lines.append(f"| {cat} | {info['enabled']} | {info['disabled']} | {info['non_boolean']} |")
256
+ lines.append(f"| **Total** | **{perms['enabled']}** | **{perms['disabled']}** | **{perms['non_boolean']}** |")
257
+ lines.append("")
258
+
259
+ # Org limits by category
260
+ lines.append("---\n")
261
+ lines.append("## Org Limits\n")
262
+ for cat in sorted(vals["by_category"].keys()):
263
+ items = vals["by_category"][cat]
264
+ lines.append(f"### {cat}\n")
265
+ lines.append("| Limit | Value |")
266
+ lines.append("|-------|-------|")
267
+ for name, val in sorted(items):
268
+ lines.append(f"| {name} | {val} |")
269
+ lines.append("")
270
+
271
+ # Licenses
272
+ lines.append("---\n")
273
+ lines.append("## Licenses\n")
274
+ for category in ("user", "permission_set", "package"):
275
+ info = lics[category]
276
+ title = category.replace("_", " ").title()
277
+ lines.append(f"### {title} Licenses ({info['count']})\n")
278
+ if info["items"]:
279
+ sample = info["items"][0]
280
+ if isinstance(sample, dict):
281
+ keys = [k for k in sample.keys() if k not in ("attributes",)]
282
+ if keys:
283
+ lines.append("| " + " | ".join(keys) + " |")
284
+ lines.append("| " + " | ".join(["---"] * len(keys)) + " |")
285
+ for item in info["items"]:
286
+ vals_row = [str(item.get(k, "")) for k in keys]
287
+ lines.append("| " + " | ".join(vals_row) + " |")
288
+ else:
289
+ for item in info["items"]:
290
+ lines.append(f"- {item}")
291
+ else:
292
+ lines.append("None.\n")
293
+ lines.append("")
294
+
295
+ # System permissions
296
+ lines.append("---\n")
297
+ lines.append("## System Permissions\n")
298
+ lines.append(f"**{sys_perms['permission_sets']}** permission sets, **{sys_perms['total_enabled']}** total enabled permissions.\n")
299
+ if sys_perms["sets"]:
300
+ lines.append("| Permission Set | Enabled | Total Fields |")
301
+ lines.append("|---------------|---------|-------------|")
302
+ for s in sorted(sys_perms["sets"], key=lambda x: x["enabled"], reverse=True):
303
+ lines.append(f"| {s['name']} | {s['enabled']} | {s['total']} |")
304
+ lines.append("")
305
+
306
+ # Deep data
307
+ lines.append("---\n")
308
+ lines.append("## Deep Data\n")
309
+ lines.append("| Category | Records |")
310
+ lines.append("|----------|---------|")
311
+ for cat, count in sorted(deep.items()):
312
+ lines.append(f"| {cat} | {count} |")
313
+ lines.append(f"| **Total** | **{deep_total}** |")
314
+ lines.append("")
315
+
316
+ # Collection warnings
317
+ if errors:
318
+ lines.append("---\n")
319
+ lines.append("## Collection Warnings\n")
320
+ for err in errors:
321
+ lines.append(f"- {err}")
322
+ lines.append("")
323
+
324
+ lines.append("---\n")
325
+ lines.append("*Report generated by dx-org-analyze. Read-only — no changes were made to the org.*\n")
326
+
327
+ return "\n".join(lines)
328
+
329
+
330
+ # ── Main ────────────────────────────────────────────────────────────
331
+
332
+ def main():
333
+ parser = argparse.ArgumentParser(description="Generate a single-org introspection report.")
334
+ parser.add_argument("--org", required=True, help="Path to org data directory or JSON file (from collect_org_data.py)")
335
+ parser.add_argument("--output", required=True, help="Output path prefix (writes .json and/or .md)")
336
+ parser.add_argument("--format", choices=["markdown", "json", "both"], default="both",
337
+ help="Output format (default: both)")
338
+ parser.add_argument("--label", default=None, help="Display name for the org (default: org name from data)")
339
+ args = parser.parse_args()
340
+
341
+ try:
342
+ data = load_org_data(args.org)
343
+ except (FileNotFoundError, json.JSONDecodeError) as e:
344
+ print(f"Error loading org data: {e}", file=sys.stderr)
345
+ sys.exit(1)
346
+
347
+ label = args.label or data.get("org_name", "Unknown Org")
348
+
349
+ meta = analyze_metadata(data)
350
+ perms = analyze_permissions(data)
351
+ vals = analyze_org_values(data)
352
+ pkgs = analyze_packages(data)
353
+ lics = analyze_licenses(data)
354
+ sys_perms = analyze_system_permissions(data)
355
+ deep = analyze_deep_data(data)
356
+
357
+ result = {
358
+ "org_id": data.get("org_id"),
359
+ "org_name": data.get("org_name"),
360
+ "org_edition": data.get("org_edition"),
361
+ "label": label,
362
+ "metadata": meta,
363
+ "permissions": perms,
364
+ "org_values": vals,
365
+ "packages": pkgs,
366
+ "licenses": lics,
367
+ "system_permissions": sys_perms,
368
+ "deep_data": deep,
369
+ "errors": data.get("errors", []),
370
+ }
371
+
372
+ if args.format in ("json", "both"):
373
+ json_path = args.output + ".json"
374
+ serializable = json.loads(json.dumps(result, default=str))
375
+ with open(json_path, "w") as f:
376
+ json.dump(serializable, f, indent=2)
377
+ print(f"Wrote {json_path}")
378
+
379
+ if args.format in ("markdown", "both"):
380
+ md_path = args.output + ".md"
381
+ md = render_markdown(data, meta, perms, vals, pkgs, lics, sys_perms, deep, label)
382
+ with open(md_path, "w") as f:
383
+ f.write(md)
384
+ print(f"Wrote {md_path}")
385
+
386
+ # Print summary
387
+ print(f"\n# Org Analysis Report: {label}")
388
+ print(f" Edition: {data.get('org_edition', 'N/A')}")
389
+ print(f" Metadata: {meta['types_discovered']} types, {meta['total_org_native']} org-native + {meta['total_namespaced']} namespaced components")
390
+ print(f" Org settings: {perms['total']} ({perms['enabled']} enabled)")
391
+ print(f" Org limits: {vals['total']}")
392
+ print(f" Packages: {pkgs['count']}")
393
+ print(f" Licenses: {lics['user']['count']} user, {lics['permission_set']['count']} PSL, {lics['package']['count']} package")
394
+ print(f" System permissions: {sys_perms['permission_sets']} sets, {sys_perms['total_enabled']} enabled")
395
+ deep_total = sum(deep.values())
396
+ print(f" Deep data: {deep_total} records")
397
+
398
+
399
+ if __name__ == "__main__":
400
+ main()
@@ -0,0 +1,46 @@
1
+ # dx-org-analyze Tests
2
+
3
+ Structural consistency tests and diff computation tests for the `dx-org-analyze` skill.
4
+
5
+ ## What's covered
6
+
7
+ | Test | What it checks |
8
+ |------|----------------|
9
+ | `test_consistency.sh` | Frontmatter fields, SF CLI auth documented, drift formula, severity levels, public API usage, no internal tool references, core rules |
10
+ | `test_compute_diff.sh` | Diff computation against fixture data: metadata, permissions, org values, packages, licenses, markdown report structure |
11
+
12
+ ## What's not covered
13
+
14
+ - **Live org comparison** — requires two authenticated orgs. Keep as manual smoke test.
15
+ - **Drift calculation accuracy** — verify manually against known org pairs.
16
+ - **Package comparison** — requires real managed packages on the instance.
17
+ - **OrganizationSettingsDetail** — not available on all editions; test graceful fallback manually.
18
+
19
+ ## Running
20
+
21
+ ```bash
22
+ # Run all tests
23
+ bash tests/test_consistency.sh && bash tests/test_compute_diff.sh
24
+
25
+ # Run individually
26
+ bash tests/test_consistency.sh # Skill structure tests
27
+ bash tests/test_compute_diff.sh # Diff computation tests
28
+ ```
29
+
30
+ Exit code `0` on pass, `1` on fail.
31
+
32
+ ## Manual smoke checklist
33
+
34
+ - [ ] Triggers on "compare these two orgs"
35
+ - [ ] Lists authenticated orgs from `sf org list`
36
+ - [ ] Asks user to pick source and target
37
+ - [ ] Handles `sf org login web` when org not authenticated
38
+ - [ ] Report order: Drift Score → Summary → Details
39
+ - [ ] Drift percentages are 0-100%
40
+ - [ ] Shared components show field/body-level diff
41
+ - [ ] Permissions categorized correctly
42
+ - [ ] Handles 0 packages gracefully
43
+ - [ ] Handles different editions without breaking
44
+ - [ ] Gracefully degrades when OrganizationSettingsDetail unavailable
45
+ - [ ] Falls back to SecurityHealthCheckRisks for settings
46
+ - [ ] REST /limits/ endpoint populates org values
@@ -0,0 +1,76 @@
1
+ {
2
+ "org_id": "00Dxx0000000001",
3
+ "org_name": "TestOrgA",
4
+ "org_edition": "Developer Edition",
5
+ "base_url": "https://org-a.example.com",
6
+ "collected_at": "2026-05-13T00:00:00Z",
7
+ "api_version": "62.0",
8
+ "metadata_types": ["ApexClass", "CustomObject", "Profile"],
9
+ "metadata_components": {
10
+ "ApexClass": [
11
+ {"fullName": "SharedClass", "namespace": null},
12
+ {"fullName": "OnlyInA", "namespace": null},
13
+ {"fullName": "ManagedPkg", "namespace": "pkg"}
14
+ ],
15
+ "CustomObject": [
16
+ {"fullName": "Project__c", "namespace": null}
17
+ ],
18
+ "Profile": [
19
+ {"fullName": "Admin", "namespace": null},
20
+ {"fullName": "Standard User", "namespace": null},
21
+ {"fullName": "Custom Profile", "namespace": null}
22
+ ]
23
+ },
24
+ "permissions": {
25
+ "ApiEnabled": {"value": "true"},
26
+ "ApexRest": {"value": "true"},
27
+ "SharedPerm": {"value": "true"},
28
+ "DisabledInA": {"value": "false"}
29
+ },
30
+ "org_values": {
31
+ "OrgEdition": "DE",
32
+ "MaxCustomObjects": "400",
33
+ "DataStorage": "5",
34
+ "SharedValue": "same"
35
+ },
36
+ "licenses": {
37
+ "user": [
38
+ {"Name": "Salesforce", "TotalLicenses": 10, "UsedLicenses": 1, "Status": "Active"},
39
+ {"Name": "Chatter Free", "TotalLicenses": 5000, "UsedLicenses": 0, "Status": "Active"},
40
+ {"Name": "OnlyInA License", "TotalLicenses": 5, "UsedLicenses": 0, "Status": "Active"}
41
+ ],
42
+ "permission_set": [
43
+ {"DeveloperName": "SalesforceCPQ", "TotalLicenses": 10, "UsedLicenses": 0}
44
+ ],
45
+ "package": []
46
+ },
47
+ "installed_packages": [
48
+ {"name": "Shared Package", "namespace": "sharedpkg", "version": "1.5"},
49
+ {"name": "Only In A", "namespace": "apkg", "version": "2.0"},
50
+ {"name": "Version Mismatch", "namespace": "vmpkg", "version": "3.1"}
51
+ ],
52
+ "system_permissions": {
53
+ "fields_discovered": ["PermissionsApiEnabled", "PermissionsAuthorApex", "PermissionsBulkApiHardDelete", "PermissionsManageUsers", "PermissionsViewSetup"],
54
+ "permission_sets": [
55
+ {
56
+ "name": "Admin",
57
+ "label": "System Administrator",
58
+ "is_profile": true,
59
+ "permissions": {"PermissionsApiEnabled": true, "PermissionsAuthorApex": true, "PermissionsManageUsers": true, "PermissionsViewSetup": true}
60
+ },
61
+ {
62
+ "name": "StandardUser",
63
+ "label": "Standard User",
64
+ "is_profile": true,
65
+ "permissions": {"PermissionsApiEnabled": true, "PermissionsViewSetup": true}
66
+ },
67
+ {
68
+ "name": "OnlyInAPermSet",
69
+ "label": "Only In A PermSet",
70
+ "is_profile": false,
71
+ "permissions": {"PermissionsBulkApiHardDelete": true}
72
+ }
73
+ ]
74
+ },
75
+ "errors": []
76
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "org_id": "00Dxx0000000002",
3
+ "org_name": "TestOrgB",
4
+ "org_edition": "Professional Edition",
5
+ "base_url": "https://org-b.example.com",
6
+ "collected_at": "2026-05-13T00:00:00Z",
7
+ "api_version": "62.0",
8
+ "metadata_types": ["ApexClass", "Profile"],
9
+ "metadata_components": {
10
+ "ApexClass": [
11
+ {"fullName": "SharedClass", "namespace": null},
12
+ {"fullName": "OnlyInB", "namespace": null}
13
+ ],
14
+ "Profile": [
15
+ {"fullName": "Admin", "namespace": null},
16
+ {"fullName": "Standard User", "namespace": null}
17
+ ]
18
+ },
19
+ "permissions": {
20
+ "SharedPerm": {"value": "true"},
21
+ "DisabledInA": {"value": "true"},
22
+ "OnlyInB": {"value": "true"}
23
+ },
24
+ "org_values": {
25
+ "OrgEdition": "PE",
26
+ "MaxCustomObjects": "50",
27
+ "DataStorage": "10240",
28
+ "SharedValue": "same"
29
+ },
30
+ "licenses": {
31
+ "user": [
32
+ {"Name": "Salesforce", "TotalLicenses": 25, "UsedLicenses": 3, "Status": "Active"},
33
+ {"Name": "Chatter Free", "TotalLicenses": 5000, "UsedLicenses": 0, "Status": "Active"},
34
+ {"Name": "OnlyInB License", "TotalLicenses": 100, "UsedLicenses": 0, "Status": "Active"}
35
+ ],
36
+ "permission_set": [
37
+ {"DeveloperName": "SalesforceCPQ", "TotalLicenses": 25, "UsedLicenses": 0}
38
+ ],
39
+ "package": []
40
+ },
41
+ "installed_packages": [
42
+ {"name": "Shared Package", "namespace": "sharedpkg", "version": "1.5"},
43
+ {"name": "Only In B", "namespace": "bpkg", "version": "1.0"},
44
+ {"name": "Version Mismatch", "namespace": "vmpkg", "version": "4.0"}
45
+ ],
46
+ "system_permissions": {
47
+ "fields_discovered": ["PermissionsApiEnabled", "PermissionsAuthorApex", "PermissionsBulkApiHardDelete", "PermissionsManageUsers", "PermissionsViewSetup"],
48
+ "permission_sets": [
49
+ {
50
+ "name": "Admin",
51
+ "label": "System Administrator",
52
+ "is_profile": true,
53
+ "permissions": {"PermissionsApiEnabled": true, "PermissionsAuthorApex": true, "PermissionsManageUsers": true, "PermissionsViewSetup": true, "PermissionsBulkApiHardDelete": true}
54
+ },
55
+ {
56
+ "name": "StandardUser",
57
+ "label": "Standard User",
58
+ "is_profile": true,
59
+ "permissions": {"PermissionsApiEnabled": true}
60
+ },
61
+ {
62
+ "name": "OnlyInBPermSet",
63
+ "label": "Only In B PermSet",
64
+ "is_profile": false,
65
+ "permissions": {"PermissionsManageUsers": true}
66
+ }
67
+ ]
68
+ },
69
+ "errors": []
70
+ }