@salesforce/afv-skills 1.55.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 (220) 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/SKILL.md +0 -1
  41. package/skills/dx-org-analyze/scripts/collect_org_data.py +2 -2
  42. package/skills/dx-org-analyze/scripts/compute_diff.py +2 -4
  43. package/skills/dx-org-analyze/scripts/introspect_org.py +4 -40
  44. package/skills/dx-org-manage/SKILL.md +6 -50
  45. package/skills/dx-org-manage/examples/README.md +10 -16
  46. package/skills/dx-org-manage/references/scratch-org-create.md +1 -1
  47. package/skills/dx-org-manage/references/scratch-org-operations.md +1 -1
  48. package/skills/dx-org-shape-manage/SKILL.md +4 -3
  49. package/skills/education-cloud-domain-configure/references/gotchas-extended.md +1 -0
  50. package/skills/experience-accessibility-validate/SKILL.md +8 -5
  51. package/skills/experience-accessibility-validate/references/reviewers/sc-1-1-1-non-text-content.md +1 -4
  52. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-i-lists.md +0 -4
  53. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-ii-tables.md +20 -85
  54. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iii-form-labels.md +4 -4
  55. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iv-regions.md +0 -4
  56. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-v-groups.md +2 -4
  57. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-5-identify-input.md +0 -4
  58. package/skills/experience-accessibility-validate/references/reviewers/sc-1-4-3-contrast.md +4 -14
  59. package/skills/experience-accessibility-validate/references/reviewers/sc-2-1-1-keyboard.md +9 -5
  60. package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-4-link-purpose.md +1 -4
  61. package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-6-headings-labels.md +0 -4
  62. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-1-pointer-gestures.md +0 -4
  63. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-2-pointer-cancellation.md +0 -4
  64. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-3-label-in-name.md +0 -4
  65. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-7-dragging-movement.md +0 -4
  66. package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-1-on-focus.md +0 -4
  67. package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-2-on-input.md +1 -4
  68. package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-1-error-identification.md +1 -4
  69. package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-2-labels-instructions.md +1 -4
  70. package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-3-error-suggestion.md +1 -4
  71. package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-i-name.md +4 -5
  72. package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-ii-role.md +1 -4
  73. package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-iii-value.md +0 -4
  74. package/skills/experience-lwc-accessibility-jest-run/SKILL.md +104 -25
  75. package/skills/experience-lwc-accessibility-jest-run/assets/jest.config.js +4 -0
  76. package/skills/experience-lwc-accessibility-jest-run/assets/sa11y-jest-setup.js +5 -0
  77. package/skills/experience-ui-bundle-app-coordinate/SKILL.md +5 -5
  78. package/skills/experience-ui-bundle-features-generate/SKILL.md +65 -36
  79. package/skills/experience-ui-bundle-features-generate/references/angular/features.md +74 -0
  80. package/skills/experience-ui-bundle-features-generate/references/react/features.md +59 -0
  81. package/skills/experience-ui-bundle-features-generate/scripts/detect-framework.sh +73 -0
  82. package/skills/experience-ui-bundle-frontend-generate/SKILL.md +2 -2
  83. package/skills/experience-ui-bundle-metadata-generate/SKILL.md +26 -14
  84. package/skills/experience-ui-bundle-metadata-generate/references/angular-metadata-generate.md +37 -0
  85. package/skills/experience-ui-bundle-metadata-generate/references/react-metadata-generate.md +32 -0
  86. package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.sh +73 -0
  87. package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.sh +30 -8
  88. package/skills/field-service-data-capture-migrate/SKILL.md +391 -0
  89. package/skills/field-service-data-capture-migrate/assets/sample-legacy-flow.flow-meta.xml +163 -0
  90. package/skills/field-service-data-capture-migrate/references/architecture-notes.md +40 -0
  91. package/skills/field-service-data-capture-migrate/references/component-mapping.md +278 -0
  92. package/skills/field-service-data-capture-migrate/references/converter-builder-contract.md +183 -0
  93. package/skills/field-service-data-capture-migrate/references/dc-platform-rules.md +130 -0
  94. package/skills/field-service-data-capture-migrate/references/fsm-dc-capability-catalog.md +215 -0
  95. package/skills/field-service-data-capture-migrate/references/known-deploy-errors.md +36 -0
  96. package/skills/field-service-data-capture-migrate/references/migration-checklist.md +121 -0
  97. package/skills/field-service-data-capture-migrate/references/transformer-rules.md +132 -0
  98. package/skills/field-service-data-capture-migrate/scripts/analyze_flow.py +277 -0
  99. package/skills/field-service-data-capture-migrate/scripts/convert_to_dc_spec.py +1311 -0
  100. package/skills/field-service-data-capture-migrate/scripts/cud_analysis.py +402 -0
  101. package/skills/field-service-data-capture-migrate/scripts/deploy_flow.sh +230 -0
  102. package/skills/field-service-data-capture-migrate/scripts/discover_subflow_tree.py +230 -0
  103. package/skills/field-service-data-capture-migrate/scripts/flow_input.py +186 -0
  104. package/skills/field-service-data-capture-migrate/scripts/flow_xml_utils.py +39 -0
  105. package/skills/field-service-data-capture-migrate/scripts/fsm_dc_catalog.py +413 -0
  106. package/skills/field-service-data-capture-migrate/scripts/generate_summary.py +199 -0
  107. package/skills/field-service-data-capture-migrate/scripts/json_to_flow_xml.py +146 -0
  108. package/skills/field-service-data-capture-migrate/scripts/manual_review_flags.py +42 -0
  109. package/skills/field-service-data-capture-migrate/scripts/retrieve_flow_rest.sh +155 -0
  110. package/skills/field-service-data-capture-migrate/scripts/subflow_names.py +49 -0
  111. package/skills/field-service-data-capture-migrate/scripts/transform_flow.py +1661 -0
  112. package/skills/field-service-data-capture-migrate/scripts/validate_flow.sh +147 -0
  113. package/skills/field-service-data-capture-migrate/scripts/vendor/build_flow.py +1258 -0
  114. package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +1 -1
  115. package/skills/life-sciences-fieldsalesrep-coordinate/references/orchestration-flow.md +1 -1
  116. package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +14 -1
  117. package/skills/mobile-apps-create/SKILL.md +1 -1
  118. package/skills/{platform-agentsetup-categories-fetch → platform-agenticsetup-categories-get}/SKILL.md +7 -7
  119. package/skills/platform-sandbox-configure/SKILL.md +108 -133
  120. package/skills/platform-sandbox-configure/references/api-response-shapes.md +39 -0
  121. package/skills/platform-sandbox-configure/references/definition-file-approach.md +73 -0
  122. package/skills/platform-widget-generate/SKILL.md +26 -18
  123. package/skills/platform-widget-generate/examples/formulas.json +191 -0
  124. package/skills/platform-widget-generate/references/widget-formulas.md +123 -0
  125. package/skills/platform-widget-generate/references/widget-meta-directives.md +4 -4
  126. package/skills/sales-call-scoring-configure/SKILL.md +318 -0
  127. package/skills/sales-call-scoring-configure/assets/best-practice-competencies.json +67 -0
  128. package/skills/sales-call-scoring-configure/assets/ootb-competencies.json +58 -0
  129. package/skills/sales-call-scoring-configure/references/admin-communication.md +79 -0
  130. package/skills/sales-call-scoring-configure/references/competency-crud.md +130 -0
  131. package/skills/sales-call-scoring-configure/scripts/create-competency.sh +166 -0
  132. package/skills/sales-call-scoring-configure/scripts/create-custom-competency.sh +166 -0
  133. package/skills/sales-call-scoring-configure/scripts/edit-competency.sh +185 -0
  134. package/skills/sales-call-scoring-configure/scripts/edit-custom-competency.sh +190 -0
  135. package/skills/sales-call-scoring-configure/scripts/enable-call-scoring.sh +436 -0
  136. package/skills/sales-call-scoring-configure/scripts/get-competency.sh +72 -0
  137. package/skills/sales-call-scoring-configure/scripts/get-custom-competency.sh +78 -0
  138. package/skills/sales-call-scoring-configure/scripts/install-best-practice-competencies.sh +223 -0
  139. package/skills/sales-call-scoring-configure/scripts/install-ootb-competencies.sh +237 -0
  140. package/skills/sales-call-scoring-configure/scripts/list-competencies.sh +99 -0
  141. package/skills/sales-call-scoring-configure/scripts/shared/auth.sh +116 -0
  142. package/skills/sales-call-scoring-configure/scripts/shared/cap.sh +86 -0
  143. package/skills/sales-call-scoring-configure/scripts/shared/soap.sh +267 -0
  144. package/skills/sales-call-scoring-configure/scripts/shared/soql.sh +25 -0
  145. package/skills/sales-call-scoring-configure/scripts/toggle-competency.sh +112 -0
  146. package/skills/sales-call-scoring-configure/scripts/toggle-custom-competency.sh +125 -0
  147. package/skills/sales-call-scoring-configure/scripts/verify-ootb-competencies.sh +116 -0
  148. package/skills/service-concierge-portal-generate/references/portal-deploy-runbook.md +1 -0
  149. package/skills/service-de-channel-activate/SKILL.md +6 -5
  150. package/skills/service-de-channel-create/SKILL.md +3 -3
  151. package/skills/service-de-channel-routing-configure/SKILL.md +3 -3
  152. package/skills/service-de-channel-settings-configure/SKILL.md +195 -0
  153. package/skills/service-de-channel-settings-configure/references/channel-settings-facets.md +152 -0
  154. package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/gotchas.md +3 -3
  155. package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/language-keywords.md +4 -4
  156. package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/worked-examples.md +14 -14
  157. package/skills/service-de-headless-channel-configure/SKILL.md +6 -6
  158. package/skills/service-de-headless-channel-configure/references/worked-examples.md +1 -1
  159. package/skills/service-helpagent-coordinate/SKILL.md +3 -2
  160. package/skills/service-helpagent-coordinate/references/channel-voice.md +15 -4
  161. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +49 -31
  162. package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +71 -6
  163. package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +26 -4
  164. package/skills/service-itsm-agentic-setup-cmdb-access-assign/SKILL.md +35 -10
  165. package/skills/service-itsm-agentic-setup-cmdb-access-assign/references/mcp-invocation.md +25 -5
  166. package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/SKILL.md +1 -1
  167. package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +5 -5
  168. package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +1 -1
  169. package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +2 -2
  170. package/skills/service-itsm-agentic-setup-cmdb-coordinate/examples/output-templates.md +1 -1
  171. package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/SKILL.md +25 -15
  172. package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +8 -5
  173. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +4 -2
  174. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +1 -1
  175. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +29 -16
  176. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +8 -5
  177. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +4 -2
  178. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +1 -1
  179. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +29 -16
  180. package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +138 -68
  181. package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +31 -15
  182. package/skills/service-itsm-agentic-setup-incident-management/references/incident-persona-psg.md +156 -0
  183. package/skills/service-itsm-agentic-setup-incident-management/references/incident-preferences.md +148 -0
  184. package/skills/service-itsm-agentic-setup-incident-management/references/major-incident-management.md +162 -0
  185. package/skills/service-itsm-agentic-setup-incident-management/references/service-mgmt-privilege.md +149 -0
  186. package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +103 -89
  187. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +2 -2
  188. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +21 -39
  189. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +3 -3
  190. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +18 -1
  191. package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +63 -37
  192. package/skills/service-omni-attribute-routing-configure/SKILL.md +53 -0
  193. package/skills/service-omni-attribute-routing-configure/references/api-notes.md +7 -0
  194. package/skills/service-omni-attribute-routing-configure/scripts/configure-and-report.sh +224 -0
  195. package/skills/service-omni-attribute-routing-configure/scripts/tests/test_attribute_routing_contracts.py +137 -0
  196. package/skills/service-omni-channel-inventory-analyze/SKILL.md +96 -0
  197. package/skills/service-omni-channel-inventory-analyze/references/api-notes.md +52 -0
  198. package/skills/service-omni-channel-inventory-analyze/scripts/analyze.sh +185 -0
  199. package/skills/service-omni-channel-inventory-analyze/scripts/tests/_bootstrap.py +84 -0
  200. package/skills/service-omni-channel-inventory-analyze/scripts/tests/test_inventory_analyze_contracts.py +141 -0
  201. package/skills/service-omni-channel-limits-analyze/SKILL.md +70 -0
  202. package/skills/service-omni-channel-limits-analyze/references/api-notes.md +22 -0
  203. package/skills/service-omni-channel-limits-analyze/scripts/analyze.sh +159 -0
  204. package/skills/service-omni-channel-limits-analyze/scripts/tests/_bootstrap.py +87 -0
  205. package/skills/service-omni-channel-limits-analyze/scripts/tests/test_limits_analyze_contracts.py +99 -0
  206. package/skills/service-omni-channel-setup-coordinate/SKILL.md +12 -20
  207. package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +55 -5
  208. package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +38 -0
  209. package/skills/service-omni-command-center-analyze/SKILL.md +2 -2
  210. package/skills/service-omni-command-center-analyze/scripts/analyze.sh +3 -3
  211. package/skills/dx-org-manage/examples/snapshots/error_output.json +0 -9
  212. package/skills/dx-org-manage/examples/snapshots/success_output.json +0 -15
  213. package/skills/dx-org-manage/references/cli_flags.md +0 -67
  214. package/skills/dx-org-manage/references/creating-snapshot.md +0 -103
  215. package/skills/dx-org-manage/references/snapshot_usage.md +0 -74
  216. package/skills/experience-accessibility-validate/scripts/contrast-ratio.py +0 -153
  217. package/skills/experience-lwc-accessibility-jest-run/references/running-sa11y-jest-tests.md +0 -205
  218. package/skills/experience-ui-bundle-features-generate/scripts/verify-react-bundle.sh +0 -14
  219. /package/skills/experience-ui-bundle-features-generate/references/{conflict-resolution-schema.json → common/conflict-resolution-schema.json} +0 -0
  220. /package/skills/{platform-agentsetup-categories-fetch → platform-agenticsetup-categories-get}/references/api-response-schema.md +0 -0
@@ -0,0 +1,324 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path');
4
+ const { getOrgDetails, getOrgNamespace } = require('./steps/utils');
5
+
6
+ // Import all step modules
7
+ const checkPrerequisites = require('./steps/00-check-prerequisites');
8
+ const downloadStaticResource = require('./steps/01-download-static-resource');
9
+ const replaceOrgId = require('./steps/02-replace-org-id');
10
+ const deployMetadata = require('./steps/03-deploy-metadata');
11
+ const deployEngine = require('./steps/04-deploy-engine');
12
+ const deployTPMAccruals = require('./steps/05-deploy-tpm-accruals');
13
+ const createDataSpace = require('./steps/06-create-dataspace');
14
+ const deployAccrualsReports = require('./steps/07-deploy-accruals-reports');
15
+ const deployUI = require('./steps/08-deploy-ui');
16
+ const completion = require('./steps/09-completion');
17
+
18
+ /**
19
+ * Parse command line arguments
20
+ * Supports both flags (--flag=value, --flag value, -f value) and positional arguments
21
+ * @returns {{ orgAlias: string|null, skipDataSpace: boolean, salesOrg: string, dryRun: boolean, namespace: string|null }}
22
+ */
23
+ function parseArgs() {
24
+ const args = process.argv.slice(2);
25
+ const result = {
26
+ orgAlias: null,
27
+ skipDataSpace: false,
28
+ salesOrg: null,
29
+ dryRun: false,
30
+ namespace: null,
31
+ };
32
+
33
+ for (let i = 0; i < args.length; i++) {
34
+ const arg = args[i];
35
+
36
+ // Handle --flag=value format
37
+ if (arg.includes('=')) {
38
+ const [key, value] = arg.split('=');
39
+ switch (key) {
40
+ case '--org':
41
+ case '-o':
42
+ result.orgAlias = value;
43
+ break;
44
+ case '--sales-org':
45
+ case '-s':
46
+ result.salesOrg = value;
47
+ break;
48
+ case '--skip-dataspace':
49
+ result.skipDataSpace = value === 'true';
50
+ break;
51
+ case '--dry-run':
52
+ result.dryRun = value === 'true';
53
+ break;
54
+ case '--namespace':
55
+ case '-n':
56
+ result.namespace = value;
57
+ break;
58
+ }
59
+ continue;
60
+ }
61
+
62
+ // Handle --flag value format and boolean flags
63
+ switch (arg) {
64
+ case '--org':
65
+ case '-o':
66
+ result.orgAlias = args[++i];
67
+ break;
68
+ case '--sales-org':
69
+ case '-s':
70
+ result.salesOrg = args[++i];
71
+ break;
72
+ case '--skip-dataspace':
73
+ result.skipDataSpace = true;
74
+ break;
75
+ case '--dry-run':
76
+ case '-d':
77
+ result.dryRun = true;
78
+ break;
79
+ case '--namespace':
80
+ case '-n':
81
+ result.namespace = args[++i];
82
+ break;
83
+ case '--help':
84
+ case '-h':
85
+ printHelp();
86
+ process.exit(0);
87
+ break;
88
+ default:
89
+ // Positional argument (org alias for backward compatibility)
90
+ if (!arg.startsWith('-') && !result.orgAlias) {
91
+ result.orgAlias = arg;
92
+ }
93
+ break;
94
+ }
95
+ }
96
+
97
+ return result;
98
+ }
99
+
100
+ /**
101
+ * Print help message
102
+ */
103
+ function printHelp() {
104
+ console.log(`
105
+ Usage: node setup.js [options] [org-alias]
106
+
107
+ Options:
108
+ -o, --org <alias> Salesforce org alias (can also use SF_ORG_ALIAS env var)
109
+ -s, --sales-org <org> Sales org identifier (required; can also use SALES_ORG env var)
110
+ -n, --namespace <ns> Org namespace prefix WITHOUT trailing "__" (e.g. "cgcloud_dev").
111
+ If omitted, the namespace is auto-detected from the org.
112
+ Use empty string ("") to force unmanaged behavior.
113
+ --skip-dataspace Skip Data Space creation (can also use SKIP_DATASPACE=true env var)
114
+ -d, --dry-run Show what would be done without making any changes
115
+ -h, --help Show this help message
116
+
117
+ Examples:
118
+ node setup.js --org my-org --sales-org 0001
119
+ node setup.js --org my-org --sales-org 0002
120
+ node setup.js -o my-org -s 0002 --skip-dataspace
121
+ node setup.js --dry-run --org my-org --sales-org 0001
122
+ node setup.js --org my-org --namespace cgcloud_dev
123
+
124
+ Environment variables:
125
+ SF_ORG_ALIAS Salesforce org alias
126
+ SALES_ORG Sales org identifier (required)
127
+ SKIP_DATASPACE Set to "true" to skip Data Space creation
128
+ DRY_RUN Set to "true" for dry run mode
129
+ ORG_NAMESPACE Org namespace prefix WITHOUT trailing "__" (overrides auto-detection)
130
+ `);
131
+ }
132
+
133
+ /**
134
+ * Get configuration from CLI args and environment variables
135
+ * CLI args take precedence over environment variables
136
+ * @returns {{ orgAlias: string, skipDataSpace: boolean, salesOrg: string, dryRun: boolean, namespaceOverride: string|null }}
137
+ */
138
+ function getConfig() {
139
+ const cliArgs = parseArgs();
140
+
141
+ // CLI args take precedence over environment variables
142
+ const orgAlias = cliArgs.orgAlias || process.env.SF_ORG_ALIAS;
143
+ const skipDataSpace = cliArgs.skipDataSpace || process.env.SKIP_DATASPACE === 'true';
144
+ const salesOrg = cliArgs.salesOrg || process.env.SALES_ORG || null;
145
+ const dryRun = cliArgs.dryRun || process.env.DRY_RUN === 'true';
146
+
147
+ // namespaceOverride is null when neither CLI nor env was provided (=> auto-detect),
148
+ // or a string (possibly empty) when the user explicitly specified one.
149
+ let namespaceOverride = null;
150
+ if (cliArgs.namespace !== null && cliArgs.namespace !== undefined) {
151
+ namespaceOverride = cliArgs.namespace;
152
+ } else if (process.env.ORG_NAMESPACE !== undefined) {
153
+ namespaceOverride = process.env.ORG_NAMESPACE;
154
+ }
155
+
156
+ if (!orgAlias) {
157
+ console.error('Error: Org alias not provided.');
158
+ console.error('Usage: node setup.js <org-alias>');
159
+ console.error(' OR: node setup.js --org <org-alias>');
160
+ console.error(' OR: SF_ORG_ALIAS=<org-alias> node setup.js');
161
+ console.error('\nRun "node setup.js --help" for more options.');
162
+ process.exit(1);
163
+ }
164
+
165
+ if (!salesOrg) {
166
+ console.error('Error: Sales org not provided.');
167
+ console.error('Usage: node setup.js --sales-org <value>');
168
+ console.error(' OR: SALES_ORG=<value> node setup.js');
169
+ console.error('\nRun "node setup.js --help" for available options.');
170
+ process.exit(1);
171
+ }
172
+
173
+ return { orgAlias, skipDataSpace, salesOrg, dryRun, namespaceOverride };
174
+ }
175
+
176
+ /**
177
+ * Validate salesOrg and namespaceOverride inputs.
178
+ * Exits the process with an error message if validation fails.
179
+ * @param {string} salesOrg - Must be exactly 4 alphanumeric characters.
180
+ * @param {string|null} namespaceOverride - When non-null, must be 1-15 alphanumeric characters.
181
+ */
182
+ function validateInputs(salesOrg, namespaceOverride, orgAlias) {
183
+ // Org alias: Salesforce allows alphanumeric, hyphens, underscores, dots, and @ (usernames).
184
+ // Restrict to safe characters to prevent shell metacharacter injection on Windows cmd.exe.
185
+ // Allow alphanumeric, hyphens, underscores, dots, @, and + (valid in Salesforce usernames, e.g. user+ci@example.com).
186
+ // None of these characters are cmd.exe metacharacters, so shell injection via org alias is prevented.
187
+ if (!/^[A-Za-z0-9_\-@.+]+$/.test(orgAlias)) {
188
+ console.error(`Error: Invalid org alias "${orgAlias}". Must contain only alphanumeric characters, hyphens, underscores, dots, @, or +.`);
189
+ process.exit(1);
190
+ }
191
+
192
+ if (!/^[A-Za-z0-9]{4}$/.test(salesOrg)) {
193
+ console.error('Error: Invalid sales org.');
194
+ process.exit(1);
195
+ }
196
+
197
+ if (namespaceOverride !== null && namespaceOverride !== '' && !/^[A-Za-z0-9]{1,15}$/.test(namespaceOverride)) {
198
+ console.error('Error: Invalid namespace.');
199
+ process.exit(1);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Format a namespace value into the prefix form used in metadata
205
+ * (i.e. always ends with "__", or is the empty string).
206
+ */
207
+ function formatNamespace(value) {
208
+ if (!value) return '';
209
+ return value.endsWith('__') ? value : `${value}__`;
210
+ }
211
+
212
+ /**
213
+ * Derive Data Space name and prefix from sales org
214
+ * @param {string} salesOrg - The sales org value
215
+ * @returns {{ dataSpaceName: string, dataSpacePrefix: string }}
216
+ */
217
+ function getDataSpaceConfig(salesOrg) {
218
+ const lastChar = salesOrg.slice(-1);
219
+ return {
220
+ dataSpaceName: `DataSpace_${salesOrg}`,
221
+ dataSpacePrefix: `DS${lastChar}_`,
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Main setup function
227
+ */
228
+ async function main() {
229
+ console.log('=== Salesforce Org Setup ===\n');
230
+
231
+ const config = getConfig();
232
+ const { orgAlias, skipDataSpace, salesOrg, dryRun, namespaceOverride } = config;
233
+
234
+ // Validate inputs before any org access or step execution
235
+ validateInputs(salesOrg, namespaceOverride, orgAlias);
236
+
237
+ const { dataSpaceName, dataSpacePrefix } = getDataSpaceConfig(salesOrg);
238
+
239
+ if (dryRun) {
240
+ console.log('+============================================================================+');
241
+ console.log('| DRY RUN MODE |');
242
+ console.log('| All read-only steps will execute. Deployments to org will be skipped. |');
243
+ console.log('| Temp directories will be preserved for inspection. |');
244
+ console.log('+============================================================================+\n');
245
+ }
246
+
247
+ console.log(`Target org: ${orgAlias}`);
248
+
249
+ // Verify org is accessible and get org details
250
+ console.log('Verifying org connection...');
251
+ let orgId;
252
+ try {
253
+ const orgDetails = getOrgDetails(orgAlias);
254
+ orgId = orgDetails.orgId;
255
+ console.log(`[OK] Org connection verified (Org ID: ${orgId})\n`);
256
+ } catch (error) {
257
+ console.error(`Error: Cannot connect to org "${orgAlias}"`);
258
+ console.error('Make sure you are logged in via: sf org login web');
259
+ process.exit(1);
260
+ }
261
+
262
+ // Resolve org namespace: CLI/env override wins; otherwise query the org.
263
+ // This is needed because component names in DataKitDeploymentLog and field
264
+ // references in the Accruals Reports payload can carry a namespace prefix
265
+ // depending on the org (e.g. "cgcloud_dev__" in this repo's dev org).
266
+ let namespace;
267
+ if (namespaceOverride !== null && namespaceOverride !== undefined) {
268
+ namespace = formatNamespace(namespaceOverride);
269
+ console.log(`Using namespace override: "${namespace || '(none)'}"`);
270
+ } else {
271
+ console.log('Detecting org namespace...');
272
+ namespace = getOrgNamespace(orgAlias);
273
+ console.log(`Detected namespace: "${namespace || '(none)'}"`);
274
+ }
275
+
276
+ const setupDir = __dirname;
277
+
278
+ console.log(`Sales Org: ${salesOrg}`);
279
+ if (!skipDataSpace) {
280
+ console.log(`Data Space Name: ${dataSpaceName}`);
281
+ console.log(`Data Space Prefix: ${dataSpacePrefix}\n`);
282
+ }
283
+
284
+ // Step 0: Check Prerequisites (skip in dry run)
285
+ if (!dryRun) {
286
+ await checkPrerequisites();
287
+ } else {
288
+ console.log('\n=== Step 0: Check Prerequisites (skipped in dry run) ===\n');
289
+ }
290
+
291
+ // Run all steps in order
292
+ // Step 1 returns the extraction dir; derive dataKitPath and scriptsDir from it.
293
+ const cgcloudAddonsDir = await downloadStaticResource(orgAlias, setupDir);
294
+ const dataKitPath = path.join(cgcloudAddonsDir, 'TPM', 'Accruals', 'TPM Accruals Data Kit');
295
+ const scriptsDir = path.join(cgcloudAddonsDir, 'TPM', 'Accruals', 'Accruals Data Kit Deployment Scripts');
296
+ await replaceOrgId(orgId, dataKitPath);
297
+ await deployMetadata(orgAlias, dataKitPath, dryRun);
298
+ await deployEngine(orgAlias, scriptsDir, orgId, namespace, dryRun);
299
+ await deployTPMAccruals(orgAlias, scriptsDir, dataKitPath, orgId, namespace, dryRun);
300
+
301
+ // Step 6: Create Data Space (only if Data Spaces are available)
302
+ if (!skipDataSpace) {
303
+ await createDataSpace(orgAlias, salesOrg, dataSpaceName, dataSpacePrefix, dryRun);
304
+ } else {
305
+ console.log('\n=== Step 6: Skipping Data Space creation (--skip-dataspace) ===\n');
306
+ }
307
+
308
+ // Step 7: Deploy Accruals Reports with Data Space replacements
309
+ await deployAccrualsReports(orgAlias, cgcloudAddonsDir, skipDataSpace, dataSpaceName, dataSpacePrefix, namespace, dryRun);
310
+
311
+ // Step 8: Deploy UI components (TPMAccrualTacticSummary)
312
+ await deployUI(orgAlias, cgcloudAddonsDir, skipDataSpace, dataSpaceName, dataSpacePrefix, salesOrg, namespace, dryRun);
313
+
314
+ // Step 9: Completion and next steps
315
+ await completion(dryRun);
316
+
317
+ console.log('=== Setup completed successfully ===');
318
+ }
319
+
320
+ // Run the script
321
+ main().catch(error => {
322
+ console.error('Unexpected error:', error);
323
+ process.exit(1);
324
+ });
@@ -0,0 +1,63 @@
1
+ const readline = require('readline');
2
+
3
+ /**
4
+ * Step 0: Check Prerequisites
5
+ * Presents prerequisites to the user and waits for confirmation
6
+ */
7
+ async function checkPrerequisites() {
8
+ console.log('\n=== Step 0: Prerequisites ===');
9
+
10
+ console.log('\nBefore proceeding, confirm ALL of the following are complete in your org.\n');
11
+
12
+ console.log('--- PERMISSIONS ---');
13
+ console.log('\n1. Assign permission set "Data Cloud Architect" to:');
14
+ console.log(' - The System Admin user');
15
+ console.log(' - The user assigned to the Accrual Ingestion Process');
16
+ console.log('\n2. Enable CRM Analytics (if you need Accruals dashboards):');
17
+ console.log(' Setup > Feature Settings > Analytics > Analytics > Getting Started > Enable CRM Analytics');
18
+ console.log(' Then assign permission set "CRM Analytics Plus Admin" to the System Admin.');
19
+
20
+ console.log('\n--- DATA CLOUD ---');
21
+ console.log('\n3. Data Cloud is enabled and set up (via the Data Cloud app, not Setup).');
22
+ console.log('\n4. Salesforce CRM connector is active:');
23
+ console.log(' Data Cloud app > Data Cloud Setup > Salesforce CRM > enable Home Org connection.');
24
+ console.log(' Also activate any other required connectors using the dropdown button.');
25
+ console.log('\n5. A user is assigned to the Accrual Ingestion Process:');
26
+ console.log(' Setup > Processing Services Pairing > Accrual Ingestion Process.');
27
+
28
+ console.log('\n--- INTEGRATION ---');
29
+ console.log('\n6. OAuth scope "cdp_ingest_api" is configured on the integration app used by TPM Offcore.');
30
+ console.log(' Check Setup > App Manager (Connected Apps) or Setup > External Client Apps.');
31
+ console.log(' The app name varies by org — locate the one used by TPM Offcore.');
32
+
33
+ console.log('\n');
34
+
35
+ // Wait for user confirmation
36
+ await waitForUserConfirmation();
37
+
38
+ console.log('[OK] Prerequisites confirmed. Proceeding to next step...\n');
39
+ }
40
+
41
+ /**
42
+ * Wait for user to press Enter.
43
+ * Auto-confirms immediately when stdin is not a TTY (piped / headless run).
44
+ */
45
+ function waitForUserConfirmation() {
46
+ if (!process.stdin.isTTY) {
47
+ console.log('[Auto-confirmed: running non-interactively]');
48
+ return Promise.resolve();
49
+ }
50
+ return new Promise((resolve) => {
51
+ const rl = readline.createInterface({
52
+ input: process.stdin,
53
+ output: process.stdout
54
+ });
55
+
56
+ rl.question('Press Enter when you have confirmed all prerequisites are met...', () => {
57
+ rl.close();
58
+ resolve();
59
+ });
60
+ });
61
+ }
62
+
63
+ module.exports = checkPrerequisites;
@@ -0,0 +1,100 @@
1
+ const fs = require('fs');
2
+ const https = require('https');
3
+ const os = require('os');
4
+ const path = require('path');
5
+ const { execFileSync } = require('child_process');
6
+ const { execSfJson, getOrgDetails } = require('./utils');
7
+
8
+ /**
9
+ * Step 1: Download and extract the CGCloudAddons static resource
10
+ */
11
+ async function downloadStaticResource(orgAlias, setupDir) {
12
+ console.log('\n=== Step 1: Downloading CGCloudAddons static resource ===');
13
+
14
+ const staticResourceName = 'CGCloudAddons';
15
+ // Extract to os.tmpdir() to avoid EBUSY locks in the script tree on Windows
16
+ const extractBase = path.join(os.tmpdir(), `tpm_accruals_extract_${Date.now()}`);
17
+
18
+ // Get org details for REST API call
19
+ console.log('Getting org connection details...');
20
+ const orgDetails = getOrgDetails(orgAlias);
21
+
22
+ // Query for the static resource
23
+ console.log(`Looking up ${staticResourceName} in org...`);
24
+ const queryResult = execSfJson(['data', 'query', '--query', `SELECT Id, Name FROM StaticResource WHERE Name = '${staticResourceName}'`, '--target-org', orgAlias, '--json']);
25
+
26
+ if (queryResult.status !== 0 || !queryResult.result.records || queryResult.result.records.length === 0) {
27
+ console.error(`Error: Static resource ${staticResourceName} not found in org`);
28
+ process.exit(1);
29
+ }
30
+
31
+ const staticResourceId = queryResult.result.records[0].Id;
32
+ console.log(`Found ${staticResourceName} (ID: ${staticResourceId})`);
33
+
34
+ // Download the static resource body using REST API
35
+ console.log('Downloading static resource content...');
36
+ fs.mkdirSync(extractBase, { recursive: true });
37
+ const targetFile = path.join(extractBase, `${staticResourceName}.zip`);
38
+ const bodyUrl = `${orgDetails.instanceUrl}/services/data/v${orgDetails.apiVersion}/sobjects/StaticResource/${staticResourceId}/Body`;
39
+
40
+ await new Promise((resolve, reject) => {
41
+ const url = new URL(bodyUrl);
42
+ const req = https.get({
43
+ hostname: url.hostname,
44
+ path: url.pathname + url.search,
45
+ headers: { Authorization: `Bearer ${orgDetails.accessToken}` }
46
+ }, res => {
47
+ if (res.statusCode !== 200) {
48
+ reject(new Error(`HTTP ${res.statusCode} downloading static resource`));
49
+ res.resume();
50
+ return;
51
+ }
52
+ const out = fs.createWriteStream(targetFile);
53
+ res.pipe(out);
54
+ out.on('finish', resolve);
55
+ out.on('error', reject);
56
+ });
57
+ req.on('error', reject);
58
+ });
59
+
60
+ if (!fs.existsSync(targetFile)) {
61
+ console.error('Error: Failed to download static resource');
62
+ process.exit(1);
63
+ }
64
+
65
+ console.log(`Static resource saved to: ${targetFile}`);
66
+
67
+ // Extract the zip file
68
+ console.log('Extracting static resource...');
69
+ const extractDir = path.join(extractBase, staticResourceName);
70
+ fs.mkdirSync(extractDir, { recursive: true });
71
+
72
+ // Extract: use Windows System32 bsdtar on Windows (Git Bash's GNU tar cannot
73
+ // read ZIP and misinterprets Windows drive letters as URLs). Convert paths to
74
+ // forward-slash POSIX form so bsdtar receives them correctly.
75
+ function toPosix(p) { return p.replace(/\\/g, '/'); }
76
+ const [unzipCmd, unzipArgs] = process.platform === 'win32'
77
+ ? ['C:\\Windows\\System32\\tar.exe', ['-xf', toPosix(targetFile), '-C', toPosix(extractDir)]]
78
+ : ['unzip', ['-o', '-q', targetFile, '-d', extractDir]];
79
+ try {
80
+ execFileSync(unzipCmd, unzipArgs, { stdio: 'pipe' });
81
+ console.log(`Extracted to: ${extractDir}`);
82
+ } catch (error) {
83
+ if (error.code === 'ENOENT') {
84
+ console.error(
85
+ `Error: "${unzipCmd}" is not installed or not on PATH — ` +
86
+ (process.platform === 'win32'
87
+ ? 'expected the tar.exe bundled with Windows 10 (1803+) / 11'
88
+ : 'install it (e.g. `apt install unzip`) and retry')
89
+ );
90
+ } else {
91
+ console.error(`Error: Failed to extract zip file — ${error.message}`);
92
+ }
93
+ process.exit(1);
94
+ }
95
+
96
+ console.log('[OK] CGCloudAddons static resource downloaded and extracted successfully\n');
97
+ return extractDir;
98
+ }
99
+
100
+ module.exports = downloadStaticResource;
@@ -0,0 +1,46 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function walkFiles(dir, extensions) {
5
+ const results = [];
6
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
7
+ const full = path.join(dir, entry.name);
8
+ if (entry.isDirectory()) results.push(...walkFiles(full, extensions));
9
+ else if (extensions.some(ext => entry.name.endsWith(ext))) results.push(full);
10
+ }
11
+ return results;
12
+ }
13
+
14
+ /**
15
+ * Step 2: Replace __SF_ORG_ID__ placeholder with actual org ID in all metadata files
16
+ */
17
+ async function replaceOrgId(orgId, dataKitPath) {
18
+ console.log('\n=== Step 2: Replacing org ID placeholders ===');
19
+ console.log(`Target directory: ${dataKitPath}`);
20
+ console.log(`Org ID: ${orgId} (truncated to 15 chars: ${orgId.slice(0, 15)})`);
21
+
22
+ // Truncate org ID to 15 characters
23
+ const truncatedOrgId = orgId.slice(0, 15);
24
+
25
+ // Find all XML and JSON files
26
+ const files = walkFiles(dataKitPath, ['.xml', '.json']);
27
+
28
+ let replacementCount = 0;
29
+
30
+ files.forEach(file => {
31
+ try {
32
+ const content = fs.readFileSync(file, 'utf8');
33
+ if (content.includes('__SF_ORG_ID__')) {
34
+ const newContent = content.replace(/__SF_ORG_ID__/g, truncatedOrgId);
35
+ fs.writeFileSync(file, newContent, 'utf8');
36
+ replacementCount++;
37
+ }
38
+ } catch (error) {
39
+ console.error(`Warning: Failed to process file ${file}: ${error.message}`);
40
+ }
41
+ });
42
+
43
+ console.log(`[OK] Replaced org ID placeholder in ${replacementCount} file(s)\n`);
44
+ }
45
+
46
+ module.exports = replaceOrgId;
@@ -0,0 +1,46 @@
1
+ const os = require('os');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const { exec, execDeployJson, execSfJson } = require('./utils');
5
+
6
+ /**
7
+ * Step 3: Deploy TPM Accruals Data Kit metadata to the org
8
+ * @param {string} orgAlias - The Salesforce org alias
9
+ * @param {string} dataKitPath - Path to the data kit
10
+ * @param {boolean} dryRun - If true, skip actual deployment
11
+ */
12
+ async function deployMetadata(orgAlias, dataKitPath, dryRun = false) {
13
+ console.log('\n=== Step 3: Deploying TPM Accruals Data Kit ===');
14
+ console.log(`Source: ${dataKitPath}`);
15
+ console.log(`Target org: ${orgAlias}`);
16
+
17
+ if (dryRun) {
18
+ console.log('[DRY RUN] Skipping deployment - files prepared at:');
19
+ console.log(` ${dataKitPath}/force-app`);
20
+ console.log('[OK] Step 3 completed (dry run)\n');
21
+ return;
22
+ }
23
+
24
+ // Convert to MDAPI format first, then deploy via --metadata-dir.
25
+ // This bypasses SF CLI source-tracking ("NothingToDeploy" errors on non-scratch
26
+ // orgs where tracking state diverges from org reality).
27
+ const mdapiOut = path.join(os.tmpdir(), `tpm_accruals_mdapi_${Date.now()}`);
28
+ console.log('Converting source to MDAPI format...');
29
+ const convertResult = execSfJson(['project', 'convert', 'source', '--output-dir', mdapiOut, '--json'], { cwd: dataKitPath });
30
+ if (convertResult.status !== 0) {
31
+ throw new Error(`Source conversion failed: ${convertResult.message || JSON.stringify(convertResult)}`);
32
+ }
33
+ console.log(`Converted to: ${convertResult.result && convertResult.result.location || mdapiOut}`);
34
+
35
+ console.log('Deploying metadata...');
36
+ execDeployJson(['project', 'deploy', 'start', '--metadata-dir', mdapiOut, '--target-org', orgAlias]);
37
+
38
+ // Clean up temp dir
39
+ try { fs.rmSync(mdapiOut, { recursive: true }); } catch (cleanupErr) {
40
+ console.warn(`[WARN] Could not remove temp directory ${mdapiOut}: ${cleanupErr.message}`);
41
+ }
42
+
43
+ console.log('[OK] TPM Accruals Data Kit deployed successfully\n');
44
+ }
45
+
46
+ module.exports = deployMetadata;