@salesforce/afv-skills 1.7.3 → 1.7.5

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 (90) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/skills/developing-agentforce/README.md +4 -4
  4. package/skills/developing-agentforce/SKILL.md +37 -37
  5. package/skills/developing-agentforce/assets/README-legacy.md +8 -8
  6. package/skills/developing-agentforce/assets/agent-spec-template.md +9 -9
  7. package/skills/developing-agentforce/assets/agents/README.md +4 -4
  8. package/skills/developing-agentforce/assets/agents/hello-world.agent +3 -3
  9. package/skills/developing-agentforce/assets/agents/{multi-topic.agent → multi-subagent.agent} +30 -30
  10. package/skills/developing-agentforce/assets/agents/order-service.agent +25 -25
  11. package/skills/developing-agentforce/assets/agents/production-faq.agent +12 -12
  12. package/skills/developing-agentforce/assets/agents/simple-qa.agent +8 -8
  13. package/skills/developing-agentforce/assets/agents/verification-gate.agent +19 -19
  14. package/skills/developing-agentforce/assets/components/apex-action.agent +3 -3
  15. package/skills/developing-agentforce/assets/components/error-handling.agent +7 -7
  16. package/skills/developing-agentforce/assets/components/escalation-setup.agent +11 -11
  17. package/skills/developing-agentforce/assets/components/flow-action.agent +5 -5
  18. package/skills/developing-agentforce/assets/components/n-ary-conditions.agent +11 -11
  19. package/skills/developing-agentforce/assets/components/{topic-with-actions.agent → subagent-with-actions.agent} +9 -9
  20. package/skills/developing-agentforce/assets/deterministic-routing.agent +19 -19
  21. package/skills/developing-agentforce/assets/escalation-pattern.agent +13 -13
  22. package/skills/developing-agentforce/assets/flow-action-lookup.agent +3 -3
  23. package/skills/developing-agentforce/assets/hub-and-spoke.agent +18 -18
  24. package/skills/developing-agentforce/assets/local-info-agent-annotated.agent +37 -37
  25. package/skills/developing-agentforce/assets/metadata/genai-function-apex.xml +3 -3
  26. package/skills/developing-agentforce/assets/metadata/genai-function-flow.xml +1 -1
  27. package/skills/developing-agentforce/assets/metadata/genai-plugin.xml +10 -10
  28. package/skills/developing-agentforce/assets/minimal-starter.agent +4 -4
  29. package/skills/developing-agentforce/assets/patterns/README.md +21 -21
  30. package/skills/developing-agentforce/assets/patterns/action-callbacks.agent +4 -4
  31. package/skills/developing-agentforce/assets/patterns/advanced-input-bindings.agent +1 -1
  32. package/skills/developing-agentforce/assets/patterns/bidirectional-routing.agent +25 -25
  33. package/skills/developing-agentforce/assets/patterns/critical-input-collection.agent +8 -8
  34. package/skills/developing-agentforce/assets/patterns/delegation-routing.agent +21 -21
  35. package/skills/developing-agentforce/assets/patterns/lifecycle-events.agent +8 -8
  36. package/skills/developing-agentforce/assets/patterns/llm-controlled-actions.agent +5 -5
  37. package/skills/developing-agentforce/assets/patterns/multi-step-workflow.agent +3 -3
  38. package/skills/developing-agentforce/assets/patterns/open-gate-routing.agent +59 -58
  39. package/skills/developing-agentforce/assets/patterns/procedural-instructions.agent +15 -15
  40. package/skills/developing-agentforce/assets/patterns/prompt-template-action.agent +8 -8
  41. package/skills/developing-agentforce/assets/patterns/system-instruction-overrides.agent +40 -40
  42. package/skills/developing-agentforce/assets/prompt-rag-search.agent +9 -9
  43. package/skills/developing-agentforce/assets/{template-multi-topic.agent → template-multi-subagent.agent} +25 -25
  44. package/skills/developing-agentforce/assets/{template-single-topic.agent → template-single-subagent.agent} +14 -14
  45. package/skills/developing-agentforce/assets/verification-gate.agent +16 -16
  46. package/skills/developing-agentforce/references/action-prompt-templates.md +1 -1
  47. package/skills/developing-agentforce/references/actions-reference.md +4 -4
  48. package/skills/developing-agentforce/references/agent-design-and-spec-creation.md +107 -107
  49. package/skills/developing-agentforce/references/agent-metadata-and-lifecycle.md +5 -5
  50. package/skills/developing-agentforce/references/agent-script-core-language.md +79 -79
  51. package/skills/developing-agentforce/references/{agent-topic-map-diagrams.md → agent-subagent-map-diagrams.md} +65 -65
  52. package/skills/developing-agentforce/references/agent-user-setup.md +2 -2
  53. package/skills/developing-agentforce/references/agent-validation-and-debugging.md +55 -55
  54. package/skills/developing-agentforce/references/architecture-patterns.md +33 -33
  55. package/skills/developing-agentforce/references/deploy-reference.md +1 -1
  56. package/skills/developing-agentforce/references/discover-reference.md +1 -1
  57. package/skills/developing-agentforce/references/examples.md +32 -32
  58. package/skills/developing-agentforce/references/feature-validity.md +3 -3
  59. package/skills/developing-agentforce/references/instruction-resolution.md +29 -29
  60. package/skills/developing-agentforce/references/known-issues.md +10 -10
  61. package/skills/developing-agentforce/references/minimal-examples.md +6 -6
  62. package/skills/developing-agentforce/references/production-gotchas.md +22 -22
  63. package/skills/developing-agentforce/references/safety-review-reference.md +2 -2
  64. package/skills/developing-agentforce/references/scoring-rubric.md +3 -3
  65. package/skills/developing-datacloud-code-extension/SKILL.md +321 -0
  66. package/skills/developing-datacloud-code-extension/references/README.md +193 -0
  67. package/skills/developing-datacloud-code-extension/references/quick-reference.md +269 -0
  68. package/skills/generating-permission-set/SKILL.md +1 -1
  69. package/skills/getting-datacloud-schema/SKILL.md +380 -0
  70. package/skills/getting-datacloud-schema/references/README.md +191 -0
  71. package/skills/getting-datacloud-schema/scripts/get_dlo_schema.py +244 -0
  72. package/skills/getting-datacloud-schema/scripts/get_dmo_schema.py +233 -0
  73. package/skills/observing-agentforce/SKILL.md +8 -8
  74. package/skills/observing-agentforce/apex/AgentforceOptimizeService.cls +2 -2
  75. package/skills/observing-agentforce/references/improve-reference.md +40 -40
  76. package/skills/observing-agentforce/references/issue-classification.md +47 -47
  77. package/skills/observing-agentforce/references/reproduce-reference.md +7 -7
  78. package/skills/observing-agentforce/references/stdm-queries.md +7 -7
  79. package/skills/observing-agentforce/references/stdm-schema.md +2 -2
  80. package/skills/testing-agentforce/SKILL.md +9 -9
  81. package/skills/testing-agentforce/assets/basic-test-spec.yaml +4 -0
  82. package/skills/testing-agentforce/assets/guardrail-test-spec.yaml +4 -0
  83. package/skills/testing-agentforce/assets/standard-test-spec.yaml +8 -4
  84. package/skills/testing-agentforce/references/batch-testing.md +17 -17
  85. package/skills/testing-agentforce/references/preview-testing.md +25 -25
  86. package/skills/testing-agentforce/references/test-report-format.md +6 -6
  87. package/skills/trigger-refactor-pipeline/SKILL.md +0 -191
  88. package/skills/trigger-refactor-pipeline/assets/test_template.apex +0 -321
  89. package/skills/trigger-refactor-pipeline/references/handler_patterns.md +0 -442
  90. package/skills/trigger-refactor-pipeline/scripts/analyze_trigger.py +0 -258
@@ -0,0 +1,191 @@
1
+ # getting-datacloud-schema Skill
2
+
3
+ ## Overview
4
+
5
+ A skill that retrieves Data Lake Object (DLO) and Data Model Object (DMO) schema information from Salesforce Data Cloud using REST APIs.
6
+
7
+ ## Usage
8
+
9
+ **List all DLOs:**
10
+ ```
11
+ "Show me all DLOs in afvibe org"
12
+ "List Data Lake Objects in myorg"
13
+ ```
14
+
15
+ **Get specific DLO schema:**
16
+ ```
17
+ "Get the schema for Employee__dll in afvibe"
18
+ "What fields does the Employee__dll DLO have in myorg?"
19
+ ```
20
+
21
+ **List all DMOs:**
22
+ ```
23
+ "Show me all DMOs in afvibe org"
24
+ "List Data Model Objects in myorg"
25
+ ```
26
+
27
+ **Get specific DMO schema:**
28
+ ```
29
+ "Get the schema for Individual__dlm in afvibe"
30
+ "What fields does the Individual__dlm DMO have in myorg?"
31
+ ```
32
+
33
+ ### Direct Script Usage
34
+
35
+ You can also run the scripts directly:
36
+
37
+ ```bash
38
+ # List all DLOs
39
+ python3 scripts/get_dlo_schema.py <org_alias>
40
+
41
+ # Get specific DLO schema
42
+ python3 scripts/get_dlo_schema.py <org_alias> <dlo_name>
43
+
44
+ # List all DMOs
45
+ python3 scripts/get_dmo_schema.py <org_alias>
46
+
47
+ # Get specific DMO schema
48
+ python3 scripts/get_dmo_schema.py <org_alias> <dmo_name>
49
+ ```
50
+
51
+ **Examples:**
52
+ ```bash
53
+ # List all DLOs in afvibe org
54
+ python3 scripts/get_dlo_schema.py afvibe
55
+
56
+ # Get Employee__dll schema from afvibe
57
+ python3 scripts/get_dlo_schema.py afvibe Employee__dll
58
+
59
+ # List all DMOs in afvibe org
60
+ python3 scripts/get_dmo_schema.py afvibe
61
+
62
+ # Get Individual__dlm schema from afvibe
63
+ python3 scripts/get_dmo_schema.py afvibe Individual__dlm
64
+ ```
65
+
66
+ ## Prerequisites
67
+
68
+ 1. **SF CLI Installed**
69
+ ```bash
70
+ sf --version
71
+ ```
72
+
73
+ 2. **Authenticated to Target Org**
74
+ ```bash
75
+ sf org login web --alias <org_alias>
76
+ ```
77
+
78
+ 3. **Python 3 and Dependencies**
79
+ ```bash
80
+ pip install requests pyyaml
81
+ ```
82
+
83
+ 4. **Data Cloud Enabled**
84
+ - Org must have Data Cloud provisioned
85
+ - User must have Data Cloud permissions
86
+
87
+ ## What It Does
88
+
89
+ ### List All DLOs
90
+ - Calls: `GET /services/data/v64.0/ssot/data-lake-objects`
91
+ - Returns: All DLOs with name, label, category, ID, record count
92
+ - Shows paginated results
93
+
94
+ ### Get DLO Schema
95
+ - Calls: `GET /services/data/v64.0/ssot/data-lake-objects/{dlo_name}`
96
+ - Returns: Detailed field schema including field names, data types, primary key indicators, nullable status
97
+
98
+ ### List All DMOs
99
+ - Calls: `GET /services/data/v64.0/ssot/data-model-objects`
100
+ - Returns: All DMOs with name, label, category, ID
101
+ - Shows paginated results
102
+
103
+ ### Get DMO Schema
104
+ - Calls: `GET /services/data/v64.0/ssot/data-model-objects/{dmo_name}`
105
+ - Returns: Detailed field schema including field names, data types, primary key indicators, nullable status
106
+
107
+ ## API Endpoints
108
+
109
+ | Endpoint | Method | Purpose |
110
+ |----------|--------|---------|
111
+ | `/services/data/v64.0/ssot/data-lake-objects` | GET | List all DLOs |
112
+ | `/services/data/v64.0/ssot/data-lake-objects/{name}` | GET | Get DLO schema |
113
+ | `/services/data/v64.0/ssot/data-model-objects` | GET | List all DMOs |
114
+ | `/services/data/v64.0/ssot/data-model-objects/{name}` | GET | Get DMO schema |
115
+
116
+ ## Output Format
117
+
118
+ ### DLO List
119
+ ```
120
+ Found 5 DLOs in org 'afvibe':
121
+
122
+ 1. DataCustomCodeLogs__dll
123
+ Label: DataCustomCodeLogs
124
+ Category: Engagement
125
+ Records: 233
126
+
127
+ 2. Employee__dll
128
+ Label: Employee
129
+ Category: Profile
130
+ Records: 12
131
+ ```
132
+
133
+ ### DLO Schema
134
+ ```
135
+ DLO: Employee__dll
136
+ Label: Employee
137
+ Category: Profile
138
+ Status: ACTIVE
139
+ Records: 12
140
+
141
+ Fields (9 total):
142
+ - id__c (Text) - Primary Key
143
+ - name__c (Text)
144
+ - position__c (Text)
145
+ - manager_id__c (Number)
146
+ - DataSource__c (Text)
147
+ [...]
148
+ ```
149
+
150
+ ### DMO List
151
+ ```
152
+ Found 10 DMOs in org 'afvibe':
153
+
154
+ 1. Individual__dlm
155
+ Label: Individual
156
+ Category: Profile
157
+
158
+ 2. ContactPointEmail__dlm
159
+ Label: Contact Point Email
160
+ Category: Profile
161
+ ```
162
+
163
+ ### DMO Schema
164
+ ```
165
+ DMO: Individual__dlm
166
+ Label: Individual
167
+ Category: Profile
168
+
169
+ Fields (8 total):
170
+ - Id__c (Text) - Primary Key
171
+ - FirstName__c (Text)
172
+ - LastName__c (Text)
173
+ - BirthDate__c (DateTime)
174
+ [...]
175
+ ```
176
+
177
+ ## Troubleshooting
178
+
179
+ | Issue | Fix |
180
+ |-------|-----|
181
+ | Org not connected | `sf org login web --alias <org_alias>` |
182
+ | Module not found: requests | `pip install requests pyyaml` |
183
+ | DLO not found | Verify name ends with `__dll`, list all DLOs first |
184
+ | DMO not found | Verify name ends with `__dlm`, list all DMOs first |
185
+ | Permission denied | Verify user has Data Cloud permissions |
186
+
187
+ ## Related Skills
188
+
189
+ - **datakit workflow**: For DMO mapping operations
190
+ - **datakit validation**: For validating datakit configurations
191
+ - Use this skill before creating DMO mappings to understand source DLO structure
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ List all Data Lake Objects and retrieve schema for one DLO using REST API.
4
+ Uses SF CLI for authentication.
5
+ """
6
+
7
+ import subprocess
8
+ import json
9
+ import sys
10
+ import requests
11
+
12
+
13
+ def authenticate_to_org(org_alias):
14
+ """
15
+ Authenticate to Salesforce org using SF CLI.
16
+
17
+ Args:
18
+ org_alias: SF CLI org alias (e.g., 'afvibe')
19
+
20
+ Returns:
21
+ Tuple of (instance_url, access_token, username)
22
+ """
23
+ print(f"🔐 Authenticating to Salesforce org '{org_alias}'...")
24
+
25
+ try:
26
+ result = subprocess.run(
27
+ ['sf', 'org', 'display', '--target-org', org_alias, '--json'],
28
+ capture_output=True,
29
+ text=True,
30
+ check=True
31
+ )
32
+
33
+ org_data = json.loads(result.stdout)
34
+
35
+ if org_data.get('status') != 0:
36
+ raise Exception(f"SF CLI returned error: {org_data}")
37
+
38
+ org_info = org_data['result']
39
+
40
+ if org_info.get('connectedStatus') != 'Connected':
41
+ raise Exception(f"Org '{org_alias}' is not connected. Run: sf org login web --alias {org_alias}")
42
+
43
+ instance_url = org_info['instanceUrl']
44
+ access_token = org_info['accessToken']
45
+ username = org_info.get('username', 'Unknown')
46
+
47
+ print(f"✅ Authenticated as: {username}")
48
+ print(f"📍 Instance: {instance_url}\n")
49
+
50
+ return instance_url, access_token, username
51
+
52
+ except subprocess.CalledProcessError as e:
53
+ raise Exception(f"SF CLI command failed: {e.stderr}")
54
+ except (json.JSONDecodeError, KeyError) as e:
55
+ raise Exception(f"Failed to parse SF CLI output: {e}")
56
+
57
+
58
+ def list_all_dlos(instance_url, access_token, api_version='v64.0'):
59
+ """
60
+ List all Data Lake Objects using SSOT REST API.
61
+
62
+ Args:
63
+ instance_url: Salesforce instance URL
64
+ access_token: OAuth access token
65
+ api_version: API version (default: v64.0)
66
+
67
+ Returns:
68
+ List of DLO dictionaries
69
+ """
70
+ url = f"{instance_url}/services/data/{api_version}/ssot/data-lake-objects"
71
+
72
+ headers = {
73
+ 'Authorization': f'Bearer {access_token}',
74
+ 'Content-Type': 'application/json',
75
+ 'Accept': 'application/json'
76
+ }
77
+
78
+ print("📋 Fetching all Data Lake Objects...")
79
+ response = requests.get(url, headers=headers)
80
+
81
+ if response.status_code != 200:
82
+ raise Exception(f"API Error: HTTP {response.status_code}\n{response.text[:500]}")
83
+
84
+ response_data = response.json()
85
+
86
+ # Extract DLO list from paginated response
87
+ if isinstance(response_data, dict) and 'dataLakeObjects' in response_data:
88
+ dlos = response_data['dataLakeObjects']
89
+ total_size = response_data.get('totalSize', len(dlos))
90
+ print(f"✅ Found {len(dlos)} DLOs (Total: {total_size})\n")
91
+ else:
92
+ # Fallback if response format is different
93
+ dlos = response_data if isinstance(response_data, list) else []
94
+ print(f"✅ Found {len(dlos)} DLOs\n")
95
+
96
+ return dlos
97
+
98
+
99
+ def get_dlo_schema(instance_url, access_token, dlo_name, api_version='v64.0'):
100
+ """
101
+ Get detailed schema for a specific DLO.
102
+
103
+ Args:
104
+ instance_url: Salesforce instance URL
105
+ access_token: OAuth access token
106
+ dlo_name: DLO developer name (e.g., 'Employee__dll')
107
+ api_version: API version (default: v64.0)
108
+
109
+ Returns:
110
+ DLO detail dictionary with full schema
111
+ """
112
+ url = f"{instance_url}/services/data/{api_version}/ssot/data-lake-objects/{dlo_name}"
113
+
114
+ headers = {
115
+ 'Authorization': f'Bearer {access_token}',
116
+ 'Content-Type': 'application/json',
117
+ 'Accept': 'application/json'
118
+ }
119
+
120
+ print(f"🔍 Fetching schema for DLO: {dlo_name}...")
121
+ response = requests.get(url, headers=headers)
122
+
123
+ if response.status_code != 200:
124
+ raise Exception(f"API Error: HTTP {response.status_code}\n{response.text[:500]}")
125
+
126
+ response_data = response.json()
127
+
128
+ # Extract DLO from paginated response
129
+ if isinstance(response_data, dict) and 'dataLakeObjects' in response_data:
130
+ dlos = response_data['dataLakeObjects']
131
+ if dlos:
132
+ return dlos[0] # Return first (should be only) DLO
133
+ else:
134
+ raise Exception(f"DLO '{dlo_name}' not found")
135
+ else:
136
+ # Fallback if response format is different
137
+ return response_data
138
+
139
+
140
+ def display_dlo_list(dlos):
141
+ """Display summary of all DLOs."""
142
+ print("=" * 80)
143
+ print("📊 DATA LAKE OBJECTS")
144
+ print("=" * 80)
145
+
146
+ for idx, dlo in enumerate(dlos, 1):
147
+ print(f"\n{idx}. {dlo.get('name', 'Unknown')}")
148
+ print(f" Label: {dlo.get('label', 'N/A')}")
149
+ print(f" Category: {dlo.get('category', 'N/A')}")
150
+ if 'id' in dlo:
151
+ print(f" ID: {dlo['id']}")
152
+
153
+
154
+ def display_dlo_schema(dlo_detail):
155
+ """Display detailed schema information for a DLO."""
156
+ print("\n" + "=" * 80)
157
+ print(f"🔍 SCHEMA DETAILS FOR: {dlo_detail.get('name')}")
158
+ print("=" * 80)
159
+
160
+ print(f"\n📝 Basic Information:")
161
+ print(f" Name: {dlo_detail.get('name')}")
162
+ print(f" Label: {dlo_detail.get('label')}")
163
+ print(f" Category: {dlo_detail.get('category')}")
164
+ print(f" Description: {dlo_detail.get('description', 'N/A')}")
165
+
166
+ if 'dataspaceInfo' in dlo_detail:
167
+ dataspaces = dlo_detail['dataspaceInfo']
168
+ dataspace_names = [ds.get('name', 'Unknown') for ds in dataspaces]
169
+ print(f" Dataspaces: {', '.join(dataspace_names)}")
170
+
171
+ # Display field schema
172
+ fields = dlo_detail.get('fields', [])
173
+
174
+ if fields:
175
+ print(f"\n🔧 Fields ({len(fields)} total):")
176
+ print("-" * 80)
177
+
178
+ # Show all fields with detailed info
179
+ for field in fields:
180
+ print(f"\n • {field.get('name')}")
181
+ print(f" Label: {field.get('label', 'N/A')}")
182
+ print(f" Data Type: {field.get('dataType', 'Unknown')}")
183
+ print(f" Primary Key: {field.get('isPrimaryKey', False)}")
184
+ print(f" Nullable: {field.get('isNullable', True)}")
185
+
186
+ if 'length' in field:
187
+ print(f" Length: {field['length']}")
188
+ if 'precision' in field:
189
+ print(f" Precision: {field['precision']}")
190
+ if 'scale' in field:
191
+ print(f" Scale: {field['scale']}")
192
+ else:
193
+ print("\n ⚠️ No fields found in schema")
194
+
195
+ # Show full JSON (optional, can be commented out)
196
+ print("\n" + "=" * 80)
197
+ print("📄 FULL SCHEMA (JSON):")
198
+ print("=" * 80)
199
+ print(json.dumps(dlo_detail, indent=2))
200
+
201
+
202
+ def main():
203
+ """Main execution function."""
204
+ if len(sys.argv) < 2:
205
+ print("Usage: python list_dlos_and_schema.py <org_alias> [dlo_name]")
206
+ print("\nExamples:")
207
+ print(" python list_dlos_and_schema.py afvibe")
208
+ print(" python list_dlos_and_schema.py afvibe Employee__dll")
209
+ sys.exit(1)
210
+
211
+ org_alias = sys.argv[1]
212
+ specific_dlo = sys.argv[2] if len(sys.argv) > 2 else None
213
+
214
+ try:
215
+ # Step 1: Authenticate
216
+ instance_url, access_token, username = authenticate_to_org(org_alias)
217
+
218
+ # Step 2: List all DLOs
219
+ dlos = list_all_dlos(instance_url, access_token)
220
+ display_dlo_list(dlos)
221
+
222
+ # Step 3: Get schema for a specific DLO
223
+ if specific_dlo:
224
+ # User specified a DLO name
225
+ dlo_detail = get_dlo_schema(instance_url, access_token, specific_dlo)
226
+ display_dlo_schema(dlo_detail)
227
+ elif dlos:
228
+ # Get schema for the first DLO
229
+ first_dlo = dlos[0]
230
+ dlo_name = first_dlo.get('name')
231
+ dlo_detail = get_dlo_schema(instance_url, access_token, dlo_name)
232
+ display_dlo_schema(dlo_detail)
233
+ else:
234
+ print("\n⚠️ No DLOs found in this org")
235
+
236
+ print("\n✅ Done!")
237
+
238
+ except Exception as e:
239
+ print(f"\n❌ Error: {e}")
240
+ sys.exit(1)
241
+
242
+
243
+ if __name__ == '__main__':
244
+ main()
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ List all Data Model Objects and retrieve schema for one DMO using REST API.
4
+ Uses SF CLI for authentication.
5
+ """
6
+
7
+ import subprocess
8
+ import json
9
+ import sys
10
+ import requests
11
+
12
+
13
+ def authenticate_to_org(org_alias):
14
+ """
15
+ Authenticate to Salesforce org using SF CLI.
16
+
17
+ Args:
18
+ org_alias: SF CLI org alias (e.g., 'afvibe')
19
+
20
+ Returns:
21
+ Tuple of (instance_url, access_token, username)
22
+ """
23
+ print(f"🔐 Authenticating to Salesforce org '{org_alias}'...")
24
+
25
+ try:
26
+ result = subprocess.run(
27
+ ['sf', 'org', 'display', '--target-org', org_alias, '--json'],
28
+ capture_output=True,
29
+ text=True,
30
+ check=True
31
+ )
32
+
33
+ org_data = json.loads(result.stdout)
34
+
35
+ if org_data.get('status') != 0:
36
+ raise Exception(f"SF CLI returned error: {org_data}")
37
+
38
+ org_info = org_data['result']
39
+
40
+ if org_info.get('connectedStatus') != 'Connected':
41
+ raise Exception(f"Org '{org_alias}' is not connected. Run: sf org login web --alias {org_alias}")
42
+
43
+ instance_url = org_info['instanceUrl']
44
+ access_token = org_info['accessToken']
45
+ username = org_info.get('username', 'Unknown')
46
+
47
+ print(f"✅ Authenticated as: {username}")
48
+ print(f"📍 Instance: {instance_url}\n")
49
+
50
+ return instance_url, access_token, username
51
+
52
+ except subprocess.CalledProcessError as e:
53
+ raise Exception(f"SF CLI command failed: {e.stderr}")
54
+ except (json.JSONDecodeError, KeyError) as e:
55
+ raise Exception(f"Failed to parse SF CLI output: {e}")
56
+
57
+
58
+ def list_all_dmos(instance_url, access_token, api_version='v64.0'):
59
+ """
60
+ List all Data Model Objects using SSOT REST API.
61
+
62
+ Args:
63
+ instance_url: Salesforce instance URL
64
+ access_token: OAuth access token
65
+ api_version: API version (default: v64.0)
66
+
67
+ Returns:
68
+ List of DMO dictionaries
69
+ """
70
+ url = f"{instance_url}/services/data/{api_version}/ssot/data-model-objects"
71
+
72
+ headers = {
73
+ 'Authorization': f'Bearer {access_token}',
74
+ 'Content-Type': 'application/json',
75
+ 'Accept': 'application/json'
76
+ }
77
+
78
+ print("📋 Fetching all Data Model Objects...")
79
+ response = requests.get(url, headers=headers)
80
+
81
+ if response.status_code != 200:
82
+ raise Exception(f"API Error: HTTP {response.status_code}\n{response.text[:500]}")
83
+
84
+ response_data = response.json()
85
+
86
+ # Extract DMO list from paginated response
87
+ if isinstance(response_data, dict) and 'dataModelObject' in response_data:
88
+ dmos = response_data['dataModelObject']
89
+ total_size = response_data.get('totalSize', len(dmos))
90
+ print(f"✅ Found {len(dmos)} DMOs (Total: {total_size})\n")
91
+ else:
92
+ # Fallback if response format is different
93
+ dmos = response_data if isinstance(response_data, list) else []
94
+ print(f"✅ Found {len(dmos)} DMOs\n")
95
+
96
+ return dmos
97
+
98
+
99
+ def get_dmo_schema(instance_url, access_token, dmo_name, api_version='v64.0'):
100
+ """
101
+ Get detailed schema for a specific DMO.
102
+
103
+ Args:
104
+ instance_url: Salesforce instance URL
105
+ access_token: OAuth access token
106
+ dmo_name: DMO developer name (e.g., 'Individual__dlm')
107
+ api_version: API version (default: v64.0)
108
+
109
+ Returns:
110
+ DMO detail dictionary with full schema
111
+ """
112
+ url = f"{instance_url}/services/data/{api_version}/ssot/data-model-objects/{dmo_name}"
113
+
114
+ headers = {
115
+ 'Authorization': f'Bearer {access_token}',
116
+ 'Content-Type': 'application/json',
117
+ 'Accept': 'application/json'
118
+ }
119
+
120
+ print(f"🔍 Fetching schema for DMO: {dmo_name}...")
121
+ response = requests.get(url, headers=headers)
122
+
123
+ if response.status_code != 200:
124
+ raise Exception(f"API Error: HTTP {response.status_code}\n{response.text[:500]}")
125
+
126
+ response_data = response.json()
127
+
128
+ # Single DMO endpoint returns the object directly (not wrapped in an array)
129
+ return response_data
130
+
131
+
132
+ def display_dmo_list(dmos):
133
+ """Display summary of all DMOs."""
134
+ print("=" * 80)
135
+ print("📊 DATA MODEL OBJECTS")
136
+ print("=" * 80)
137
+
138
+ for idx, dmo in enumerate(dmos, 1):
139
+ print(f"\n{idx}. {dmo.get('name', 'Unknown')}")
140
+ print(f" Label: {dmo.get('label', 'N/A')}")
141
+ print(f" Category: {dmo.get('category', 'N/A')}")
142
+ print(f" Creation Type: {dmo.get('creationType', 'N/A')}")
143
+ print(f" Data Space: {dmo.get('dataSpaceName', 'N/A')}")
144
+
145
+
146
+ def display_dmo_schema(dmo_detail):
147
+ """Display detailed schema information for a DMO."""
148
+ print("\n" + "=" * 80)
149
+ print(f"🔍 SCHEMA DETAILS FOR: {dmo_detail.get('name')}")
150
+ print("=" * 80)
151
+
152
+ print(f"\n📝 Basic Information:")
153
+ print(f" Name: {dmo_detail.get('name')}")
154
+ print(f" Label: {dmo_detail.get('label')}")
155
+ print(f" Category: {dmo_detail.get('category')}")
156
+ print(f" Creation Type: {dmo_detail.get('creationType', 'N/A')}")
157
+ print(f" Data Space: {dmo_detail.get('dataSpaceName', 'N/A')}")
158
+
159
+ # Display field schema
160
+ fields = dmo_detail.get('fields', [])
161
+
162
+ if fields:
163
+ print(f"\n🔧 Fields ({len(fields)} total):")
164
+ print("-" * 80)
165
+
166
+ # Show all fields with detailed info
167
+ for field in fields:
168
+ print(f"\n • {field.get('name')}")
169
+ print(f" Label: {field.get('label', 'N/A')}")
170
+ print(f" Data Type: {field.get('type', 'Unknown')}")
171
+ print(f" Primary Key: {field.get('isPrimaryKey', False)}")
172
+ print(f" Creation Type: {field.get('creationType', 'N/A')}")
173
+ print(f" Usage Tag: {field.get('usageTag', 'N/A')}")
174
+
175
+ if 'length' in field:
176
+ print(f" Length: {field['length']}")
177
+ if 'precision' in field:
178
+ print(f" Precision: {field['precision']}")
179
+ if 'scale' in field:
180
+ print(f" Scale: {field['scale']}")
181
+ else:
182
+ print("\n ⚠️ No fields found in schema")
183
+
184
+ # Show full JSON
185
+ print("\n" + "=" * 80)
186
+ print("📄 FULL SCHEMA (JSON):")
187
+ print("=" * 80)
188
+ print(json.dumps(dmo_detail, indent=2))
189
+
190
+
191
+ def main():
192
+ """Main execution function."""
193
+ if len(sys.argv) < 2:
194
+ print("Usage: python get_dmo_schema.py <org_alias> [dmo_name]")
195
+ print("\nExamples:")
196
+ print(" python get_dmo_schema.py afvibe")
197
+ print(" python get_dmo_schema.py afvibe Individual__dlm")
198
+ sys.exit(1)
199
+
200
+ org_alias = sys.argv[1]
201
+ specific_dmo = sys.argv[2] if len(sys.argv) > 2 else None
202
+
203
+ try:
204
+ # Step 1: Authenticate
205
+ instance_url, access_token, username = authenticate_to_org(org_alias)
206
+
207
+ # Step 2: List all DMOs
208
+ dmos = list_all_dmos(instance_url, access_token)
209
+ display_dmo_list(dmos)
210
+
211
+ # Step 3: Get schema for a specific DMO
212
+ if specific_dmo:
213
+ # User specified a DMO name
214
+ dmo_detail = get_dmo_schema(instance_url, access_token, specific_dmo)
215
+ display_dmo_schema(dmo_detail)
216
+ elif dmos:
217
+ # Get schema for the first DMO
218
+ first_dmo = dmos[0]
219
+ dmo_name = first_dmo.get('name')
220
+ dmo_detail = get_dmo_schema(instance_url, access_token, dmo_name)
221
+ display_dmo_schema(dmo_detail)
222
+ else:
223
+ print("\n⚠️ No DMOs found in this org")
224
+
225
+ print("\n✅ Done!")
226
+
227
+ except Exception as e:
228
+ print(f"\n❌ Error: {e}")
229
+ sys.exit(1)
230
+
231
+
232
+ if __name__ == '__main__':
233
+ main()