delegate-sf-mcp 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +20 -0
- package/LICENSE +24 -0
- package/README.md +76 -0
- package/auth.js +148 -0
- package/bin/config-helper.js +51 -0
- package/bin/mcp-salesforce.js +12 -0
- package/bin/setup.js +266 -0
- package/bin/status.js +134 -0
- package/docs/README.md +52 -0
- package/docs/step1.png +0 -0
- package/docs/step2.png +0 -0
- package/docs/step3.png +0 -0
- package/docs/step4.png +0 -0
- package/examples/README.md +35 -0
- package/package.json +16 -0
- package/scripts/README.md +30 -0
- package/src/auth/file-storage.js +447 -0
- package/src/auth/oauth.js +417 -0
- package/src/auth/token-manager.js +207 -0
- package/src/backup/manager.js +949 -0
- package/src/index.js +168 -0
- package/src/salesforce/client.js +388 -0
- package/src/sf-client.js +79 -0
- package/src/tools/auth.js +190 -0
- package/src/tools/backup.js +486 -0
- package/src/tools/create.js +109 -0
- package/src/tools/delegate-hygiene.js +268 -0
- package/src/tools/delegate-validate.js +212 -0
- package/src/tools/delegate-verify.js +143 -0
- package/src/tools/delete.js +72 -0
- package/src/tools/describe.js +132 -0
- package/src/tools/installation-info.js +656 -0
- package/src/tools/learn-context.js +1077 -0
- package/src/tools/learn.js +351 -0
- package/src/tools/query.js +82 -0
- package/src/tools/repair-credentials.js +77 -0
- package/src/tools/setup.js +120 -0
- package/src/tools/time_machine.js +347 -0
- package/src/tools/update.js +138 -0
- package/src/tools.js +214 -0
- package/src/utils/cache.js +120 -0
- package/src/utils/debug.js +52 -0
- package/src/utils/logger.js +19 -0
- package/tokens.json +8 -0
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Salesforce Installation Info Tool
|
|
3
|
+
*
|
|
4
|
+
* This tool provides information about the learned Salesforce installation,
|
|
5
|
+
* including objects, fields, and customizations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getInstallationDocumentation, hasInstallationDocumentation } from './learn.js';
|
|
9
|
+
import { getUserContext } from './learn-context.js';
|
|
10
|
+
import { logger } from '../utils/debug.js';
|
|
11
|
+
|
|
12
|
+
export const salesforceInstallationInfoTool = {
|
|
13
|
+
name: "salesforce_installation_info",
|
|
14
|
+
description: "Returns comprehensive information about the learned Salesforce installation, including all object details, field specifications, relationships, permissions, and customizations from the learned installation data.",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
object_name: {
|
|
19
|
+
type: "string",
|
|
20
|
+
description: "Specific object for detailed information (optional). Example: 'Account', 'Contact', 'CustomObject__c'"
|
|
21
|
+
},
|
|
22
|
+
field_search: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "Search for fields with this name or label (optional)"
|
|
25
|
+
},
|
|
26
|
+
show_custom_only: {
|
|
27
|
+
type: "boolean",
|
|
28
|
+
description: "Show only custom objects and custom fields",
|
|
29
|
+
default: false
|
|
30
|
+
},
|
|
31
|
+
include_relationships: {
|
|
32
|
+
type: "boolean",
|
|
33
|
+
description: "Include relationship information between objects",
|
|
34
|
+
default: true
|
|
35
|
+
},
|
|
36
|
+
detailed_fields: {
|
|
37
|
+
type: "boolean",
|
|
38
|
+
description: "Show detailed field information including data types, constraints, and metadata",
|
|
39
|
+
default: true
|
|
40
|
+
},
|
|
41
|
+
include_permissions: {
|
|
42
|
+
type: "boolean",
|
|
43
|
+
description: "Include detailed permission information for objects and fields",
|
|
44
|
+
default: true
|
|
45
|
+
},
|
|
46
|
+
max_fields_per_object: {
|
|
47
|
+
type: "number",
|
|
48
|
+
description: "Maximum number of fields to show per object (default: all fields)",
|
|
49
|
+
default: 0
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export async function handleSalesforceInstallationInfo(args) {
|
|
56
|
+
const {
|
|
57
|
+
object_name,
|
|
58
|
+
field_search,
|
|
59
|
+
show_custom_only = false,
|
|
60
|
+
include_relationships = true,
|
|
61
|
+
detailed_fields = true,
|
|
62
|
+
include_permissions = true,
|
|
63
|
+
max_fields_per_object = 0
|
|
64
|
+
} = args;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
// Check if installation has been learned
|
|
68
|
+
const hasDocumentation = await hasInstallationDocumentation();
|
|
69
|
+
if (!hasDocumentation) {
|
|
70
|
+
return {
|
|
71
|
+
content: [{
|
|
72
|
+
type: "text",
|
|
73
|
+
text: `⚠️ **Salesforce installation not yet learned**\n\n` +
|
|
74
|
+
`The Salesforce installation has not been analyzed and documented yet.\n\n` +
|
|
75
|
+
`🚀 **Solution:** First run the \`salesforce_learn\` tool:\n` +
|
|
76
|
+
`\`\`\`\n` +
|
|
77
|
+
`{\n` +
|
|
78
|
+
` "tool": "salesforce_learn"\n` +
|
|
79
|
+
`}\n` +
|
|
80
|
+
`\`\`\`\n\n` +
|
|
81
|
+
`Then I can provide detailed information about your Salesforce installation.`
|
|
82
|
+
}]
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const documentation = await getInstallationDocumentation();
|
|
87
|
+
|
|
88
|
+
// Handle specific object request
|
|
89
|
+
if (object_name) {
|
|
90
|
+
return handleSpecificObjectInfo(object_name, documentation, {
|
|
91
|
+
include_relationships,
|
|
92
|
+
detailed_fields,
|
|
93
|
+
include_permissions,
|
|
94
|
+
max_fields_per_object
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Handle field search
|
|
99
|
+
if (field_search) {
|
|
100
|
+
return handleFieldSearch(field_search, documentation, {
|
|
101
|
+
show_custom_only,
|
|
102
|
+
detailed_fields,
|
|
103
|
+
max_fields_per_object
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// General installation overview
|
|
108
|
+
return await handleGeneralOverview(documentation, {
|
|
109
|
+
show_custom_only,
|
|
110
|
+
include_relationships,
|
|
111
|
+
detailed_fields,
|
|
112
|
+
include_permissions
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
} catch (error) {
|
|
116
|
+
logger.error('❌ Error retrieving installation info:', error);
|
|
117
|
+
return {
|
|
118
|
+
content: [{
|
|
119
|
+
type: "text",
|
|
120
|
+
text: `❌ **Error retrieving installation information:**\n\n${error.message}`
|
|
121
|
+
}]
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function handleSpecificObjectInfo(objectName, documentation, options) {
|
|
127
|
+
const { include_relationships, detailed_fields, include_permissions, max_fields_per_object } = options;
|
|
128
|
+
|
|
129
|
+
const obj = documentation.objects[objectName];
|
|
130
|
+
if (!obj) {
|
|
131
|
+
// Try to find similar object names
|
|
132
|
+
const availableObjects = Object.keys(documentation.objects);
|
|
133
|
+
const similarObjects = availableObjects.filter(name =>
|
|
134
|
+
name.toLowerCase().includes(objectName.toLowerCase()) ||
|
|
135
|
+
documentation.objects[name].basic_info?.label?.toLowerCase().includes(objectName.toLowerCase())
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
let suggestion = '';
|
|
139
|
+
if (similarObjects.length > 0) {
|
|
140
|
+
suggestion = `\n\n🔍 **Similar objects found:**\n${similarObjects.slice(0, 5).map(name => `- ${name} (${documentation.objects[name].basic_info?.label})`).join('\n')}`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
content: [{
|
|
145
|
+
type: "text",
|
|
146
|
+
text: `❌ **Object '${objectName}' not found**\n\n` +
|
|
147
|
+
`The object does not exist in the learned Salesforce installation.${suggestion}\n\n` +
|
|
148
|
+
`💡 Use the tool without parameters to see all available objects.`
|
|
149
|
+
}]
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (obj.error) {
|
|
154
|
+
return {
|
|
155
|
+
content: [{
|
|
156
|
+
type: "text",
|
|
157
|
+
text: `⚠️ **Object '${objectName}' - Analysis Error**\n\n${obj.error}`
|
|
158
|
+
}]
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let result = `📋 **${obj.basic_info.label} (${obj.basic_info.name})**\n\n`;
|
|
163
|
+
|
|
164
|
+
// Basic info with all available details
|
|
165
|
+
result += `## 📝 Basic Information\n`;
|
|
166
|
+
result += `- **API Name:** \`${obj.basic_info.name}\`\n`;
|
|
167
|
+
result += `- **Label:** ${obj.basic_info.label}\n`;
|
|
168
|
+
result += `- **Plural Label:** ${obj.basic_info.label_plural}\n`;
|
|
169
|
+
result += `- **Custom Object:** ${obj.basic_info.custom ? '✅ Yes' : '❌ No'}\n`;
|
|
170
|
+
|
|
171
|
+
// Extended metadata if available
|
|
172
|
+
if (obj.metadata) {
|
|
173
|
+
result += `\n## 🔐 Permissions & Capabilities\n`;
|
|
174
|
+
result += `- **Createable:** ${obj.metadata.createable ? '✅' : '❌'}\n`;
|
|
175
|
+
result += `- **Updateable:** ${obj.metadata.updateable ? '✅' : '❌'}\n`;
|
|
176
|
+
result += `- **Deletable:** ${obj.metadata.deletable ? '✅' : '❌'}\n`;
|
|
177
|
+
result += `- **Queryable:** ${obj.metadata.queryable ? '✅' : '❌'}\n`;
|
|
178
|
+
if (obj.metadata.searchable !== undefined) {
|
|
179
|
+
result += `- **Searchable:** ${obj.metadata.searchable ? '✅' : '❌'}\n`;
|
|
180
|
+
}
|
|
181
|
+
if (obj.metadata.retrieveable !== undefined) {
|
|
182
|
+
result += `- **Retrieveable:** ${obj.metadata.retrieveable ? '✅' : '❌'}\n`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Fields overview with detailed statistics
|
|
187
|
+
result += `\n## 📊 Fields Overview\n`;
|
|
188
|
+
result += `- **Total Fields:** ${obj.field_count}\n`;
|
|
189
|
+
result += `- **Custom Fields:** ${obj.custom_field_count}\n`;
|
|
190
|
+
result += `- **Standard Fields:** ${obj.field_count - obj.custom_field_count}\n`;
|
|
191
|
+
|
|
192
|
+
// Detailed field information
|
|
193
|
+
if (detailed_fields && obj.fields) {
|
|
194
|
+
result += `\n## 📋 Detailed Field Information\n`;
|
|
195
|
+
|
|
196
|
+
const fieldEntries = Object.entries(obj.fields);
|
|
197
|
+
const fieldsToShow = max_fields_per_object > 0 ? fieldEntries.slice(0, max_fields_per_object) : fieldEntries;
|
|
198
|
+
|
|
199
|
+
// Group fields by type for better organization
|
|
200
|
+
const fieldsByType = {};
|
|
201
|
+
for (const [fieldName, field] of fieldsToShow) {
|
|
202
|
+
const type = field.type || 'unknown';
|
|
203
|
+
if (!fieldsByType[type]) {
|
|
204
|
+
fieldsByType[type] = [];
|
|
205
|
+
}
|
|
206
|
+
fieldsByType[type].push([fieldName, field]);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
for (const [fieldType, fields] of Object.entries(fieldsByType)) {
|
|
210
|
+
result += `\n### ${fieldType.toUpperCase()} Fields (${fields.length})\n`;
|
|
211
|
+
|
|
212
|
+
for (const [fieldName, field] of fields) {
|
|
213
|
+
result += `\n**${field.label || fieldName}** (\`${fieldName}\`)\n`;
|
|
214
|
+
result += `- **Type:** ${field.type}\n`;
|
|
215
|
+
result += `- **Required:** ${field.required ? '✅ Yes' : '❌ No'}\n`;
|
|
216
|
+
result += `- **Custom:** ${field.custom ? '✅ Yes' : '❌ No'}\n`;
|
|
217
|
+
result += `- **Updateable:** ${field.updateable ? '✅' : '❌'}\n`;
|
|
218
|
+
result += `- **Createable:** ${field.createable ? '✅' : '❌'}\n`;
|
|
219
|
+
|
|
220
|
+
// Enhanced writability information
|
|
221
|
+
if (field.writability) {
|
|
222
|
+
const writabilityStatus = getWritabilityStatus(field.writability);
|
|
223
|
+
result += `- **Writability:** ${writabilityStatus}\n`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Type-specific information
|
|
227
|
+
if (field.max_length) {
|
|
228
|
+
result += `- **Max Length:** ${field.max_length}\n`;
|
|
229
|
+
}
|
|
230
|
+
if (field.precision !== undefined) {
|
|
231
|
+
result += `- **Precision:** ${field.precision}\n`;
|
|
232
|
+
}
|
|
233
|
+
if (field.scale !== undefined) {
|
|
234
|
+
result += `- **Scale:** ${field.scale}\n`;
|
|
235
|
+
}
|
|
236
|
+
if (field.picklist_values && field.picklist_values.length > 0) {
|
|
237
|
+
result += `- **Picklist Values:** ${field.picklist_values.slice(0, 5).map(v => `"${v}"`).join(', ')}`;
|
|
238
|
+
if (field.picklist_values.length > 5) {
|
|
239
|
+
result += ` (and ${field.picklist_values.length - 5} more)`;
|
|
240
|
+
}
|
|
241
|
+
result += `\n`;
|
|
242
|
+
}
|
|
243
|
+
if (field.references && field.references.length > 0) {
|
|
244
|
+
result += `- **References:** ${field.references.join(', ')}\n`;
|
|
245
|
+
}
|
|
246
|
+
if (field.default_value !== undefined && field.default_value !== null) {
|
|
247
|
+
result += `- **Default Value:** ${field.default_value}\n`;
|
|
248
|
+
}
|
|
249
|
+
if (field.help_text) {
|
|
250
|
+
result += `- **Help Text:** ${field.help_text}\n`;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (max_fields_per_object > 0 && fieldEntries.length > max_fields_per_object) {
|
|
256
|
+
result += `\n*... and ${fieldEntries.length - max_fields_per_object} more fields*\n`;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Relationships with complete details
|
|
261
|
+
if (include_relationships && obj.relationships) {
|
|
262
|
+
result += `\n## 🔗 Relationships\n`;
|
|
263
|
+
|
|
264
|
+
if (obj.relationships.parent_relationships && obj.relationships.parent_relationships.length > 0) {
|
|
265
|
+
result += `\n### Parent Relationships (${obj.relationships.parent_relationships.length})\n`;
|
|
266
|
+
for (const rel of obj.relationships.parent_relationships) {
|
|
267
|
+
result += `- **${rel.field}** → References: ${rel.references.join(', ')}\n`;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (obj.relationships.child_relationships && obj.relationships.child_relationships.length > 0) {
|
|
272
|
+
result += `\n### Child Relationships (${obj.relationships.child_relationships.length})\n`;
|
|
273
|
+
for (const rel of obj.relationships.child_relationships) {
|
|
274
|
+
result += `- **${rel.child_object}** (Relationship: ${rel.relationship_name})\n`;
|
|
275
|
+
if (rel.field) {
|
|
276
|
+
result += ` - Field: ${rel.field}\n`;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if ((!obj.relationships.parent_relationships || obj.relationships.parent_relationships.length === 0) &&
|
|
282
|
+
(!obj.relationships.child_relationships || obj.relationships.child_relationships.length === 0)) {
|
|
283
|
+
result += `\n*No relationships found for this object.*\n`;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
content: [{
|
|
289
|
+
type: "text",
|
|
290
|
+
text: result
|
|
291
|
+
}]
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function handleFieldSearch(searchTerm, documentation, options) {
|
|
296
|
+
const { show_custom_only, detailed_fields, max_fields_per_object } = options;
|
|
297
|
+
const searchResults = [];
|
|
298
|
+
|
|
299
|
+
for (const [objectName, obj] of Object.entries(documentation.objects)) {
|
|
300
|
+
if (obj.error) continue;
|
|
301
|
+
|
|
302
|
+
for (const [fieldName, field] of Object.entries(obj.fields || {})) {
|
|
303
|
+
if (show_custom_only && !field.custom) continue;
|
|
304
|
+
|
|
305
|
+
const matchesName = fieldName.toLowerCase().includes(searchTerm.toLowerCase());
|
|
306
|
+
const matchesLabel = field.label?.toLowerCase().includes(searchTerm.toLowerCase());
|
|
307
|
+
|
|
308
|
+
if (matchesName || matchesLabel) {
|
|
309
|
+
searchResults.push({
|
|
310
|
+
object: objectName,
|
|
311
|
+
objectLabel: obj.basic_info.label,
|
|
312
|
+
field: fieldName,
|
|
313
|
+
fieldData: field
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (searchResults.length === 0) {
|
|
320
|
+
return {
|
|
321
|
+
content: [{
|
|
322
|
+
type: "text",
|
|
323
|
+
text: `🔍 **No fields found for: "${searchTerm}"**\n\n` +
|
|
324
|
+
`${show_custom_only ? 'When searching for custom fields, ' : ''}no matching fields were found.\n\n` +
|
|
325
|
+
`💡 **Tips:**\n` +
|
|
326
|
+
`- Try part of the field name\n` +
|
|
327
|
+
`- Search by label instead of API name\n` +
|
|
328
|
+
`- Use \`show_custom_only: false\` to also search standard fields`
|
|
329
|
+
}]
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
let result = `🔍 **Search results for "${searchTerm}"** (${searchResults.length} fields found)\n\n`;
|
|
334
|
+
|
|
335
|
+
const groupedResults = {};
|
|
336
|
+
for (const item of searchResults) {
|
|
337
|
+
if (!groupedResults[item.object]) {
|
|
338
|
+
groupedResults[item.object] = [];
|
|
339
|
+
}
|
|
340
|
+
groupedResults[item.object].push(item);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
for (const [objectName, fields] of Object.entries(groupedResults)) {
|
|
344
|
+
const objectLabel = fields[0].objectLabel;
|
|
345
|
+
result += `## ${objectLabel} (${objectName})\n`;
|
|
346
|
+
|
|
347
|
+
const fieldsToShow = max_fields_per_object > 0 ? fields.slice(0, max_fields_per_object) : fields;
|
|
348
|
+
|
|
349
|
+
for (const item of fieldsToShow) {
|
|
350
|
+
const field = item.fieldData;
|
|
351
|
+
result += `\n### ${field.label || item.field} (\`${item.field}\`)\n`;
|
|
352
|
+
|
|
353
|
+
if (detailed_fields) {
|
|
354
|
+
result += `- **Type:** ${field.type}\n`;
|
|
355
|
+
result += `- **Required:** ${field.required ? '✅ Yes' : '❌ No'}\n`;
|
|
356
|
+
result += `- **Custom:** ${field.custom ? '✅ Yes' : '❌ No'}\n`;
|
|
357
|
+
result += `- **Updateable:** ${field.updateable ? '✅' : '❌'}\n`;
|
|
358
|
+
result += `- **Createable:** ${field.createable ? '✅' : '❌'}\n`;
|
|
359
|
+
|
|
360
|
+
// Enhanced writability information
|
|
361
|
+
if (field.writability) {
|
|
362
|
+
const writabilityStatus = getWritabilityStatus(field.writability);
|
|
363
|
+
result += `- **Writability:** ${writabilityStatus}\n`;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (field.max_length) {
|
|
367
|
+
result += `- **Max Length:** ${field.max_length}\n`;
|
|
368
|
+
}
|
|
369
|
+
if (field.precision !== undefined) {
|
|
370
|
+
result += `- **Precision:** ${field.precision}\n`;
|
|
371
|
+
}
|
|
372
|
+
if (field.scale !== undefined) {
|
|
373
|
+
result += `- **Scale:** ${field.scale}\n`;
|
|
374
|
+
}
|
|
375
|
+
if (field.picklist_values && field.picklist_values.length > 0) {
|
|
376
|
+
result += `- **Picklist Values:** ${field.picklist_values.slice(0, 3).map(v => `"${v}"`).join(', ')}`;
|
|
377
|
+
if (field.picklist_values.length > 3) {
|
|
378
|
+
result += ` (and ${field.picklist_values.length - 3} more)`;
|
|
379
|
+
}
|
|
380
|
+
result += `\n`;
|
|
381
|
+
}
|
|
382
|
+
if (field.references && field.references.length > 0) {
|
|
383
|
+
result += `- **References:** ${field.references.join(', ')}\n`;
|
|
384
|
+
}
|
|
385
|
+
if (field.help_text) {
|
|
386
|
+
result += `- **Help Text:** ${field.help_text}\n`;
|
|
387
|
+
}
|
|
388
|
+
} else {
|
|
389
|
+
const custom = field.custom ? ' 🔧' : '';
|
|
390
|
+
const required = field.required ? ' ⚠️' : '';
|
|
391
|
+
result += `- **Type:** ${field.type}${required}${custom}\n`;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (max_fields_per_object > 0 && fields.length > max_fields_per_object) {
|
|
396
|
+
result += `\n*... and ${fields.length - max_fields_per_object} more fields in this object*\n`;
|
|
397
|
+
}
|
|
398
|
+
result += '\n';
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return {
|
|
402
|
+
content: [{
|
|
403
|
+
type: "text",
|
|
404
|
+
text: result
|
|
405
|
+
}]
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async function handleGeneralOverview(documentation, options) {
|
|
410
|
+
const { show_custom_only, include_relationships, detailed_fields, include_permissions } = options;
|
|
411
|
+
|
|
412
|
+
let result = `📊 **Salesforce Installation - Complete Overview**\n\n`;
|
|
413
|
+
|
|
414
|
+
// Add user context if available and check for missing information
|
|
415
|
+
let contextWarning = '';
|
|
416
|
+
try {
|
|
417
|
+
const context = await getUserContext();
|
|
418
|
+
|
|
419
|
+
// Check if we have basic user information
|
|
420
|
+
const hasPersonalInfo = context.personal?.name && context.personal?.email;
|
|
421
|
+
const hasBusinessInfo = context.business?.company_name && context.business?.industry;
|
|
422
|
+
const hasDataModelInfo = Object.keys(context.data_model || {}).length > 0;
|
|
423
|
+
|
|
424
|
+
if (hasPersonalInfo || hasBusinessInfo) {
|
|
425
|
+
result = `📊 **Salesforce Installation - Complete Overview**\n`;
|
|
426
|
+
if (context.personal?.name) {
|
|
427
|
+
result += `*Kontext für: ${context.personal.name}`;
|
|
428
|
+
if (context.business?.company_name) {
|
|
429
|
+
result += ` (${context.business.company_name})`;
|
|
430
|
+
}
|
|
431
|
+
result += `*\n\n`;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Generate warnings for missing context
|
|
436
|
+
const missingContext = [];
|
|
437
|
+
if (!hasPersonalInfo) {
|
|
438
|
+
missingContext.push("👤 **Persönliche Informationen**");
|
|
439
|
+
}
|
|
440
|
+
if (!hasBusinessInfo) {
|
|
441
|
+
missingContext.push("🏢 **Geschäftliche Informationen**");
|
|
442
|
+
}
|
|
443
|
+
if (!hasDataModelInfo && documentation.summary?.custom_objects > 0) {
|
|
444
|
+
missingContext.push("🗃️ **Datenmodell-Kontext**");
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (missingContext.length > 0) {
|
|
448
|
+
contextWarning = `\n## ⚠️ Fehlender Kontext für bessere Unterstützung\n\n`;
|
|
449
|
+
contextWarning += `Um Ihnen personalisierte und kontextbezogene Hilfe zu bieten, fehlen noch wichtige Informationen:\n\n`;
|
|
450
|
+
for (const missing of missingContext) {
|
|
451
|
+
contextWarning += `- ${missing}\n`;
|
|
452
|
+
}
|
|
453
|
+
contextWarning += `\n💡 **Empfehlung:** Starten Sie das Kontext-Interview:\n`;
|
|
454
|
+
contextWarning += `\`\`\`json\n`;
|
|
455
|
+
contextWarning += `{\n`;
|
|
456
|
+
contextWarning += ` "tool": "salesforce_learn_context",\n`;
|
|
457
|
+
contextWarning += ` "action": "start_interview"\n`;
|
|
458
|
+
contextWarning += `}\n`;
|
|
459
|
+
contextWarning += `\`\`\`\n\n`;
|
|
460
|
+
|
|
461
|
+
if (hasPersonalInfo && hasBusinessInfo && !hasDataModelInfo) {
|
|
462
|
+
contextWarning += `Oder für erweiterte Datenmodell-Fragen:\n`;
|
|
463
|
+
contextWarning += `\`\`\`json\n`;
|
|
464
|
+
contextWarning += `{\n`;
|
|
465
|
+
contextWarning += ` "tool": "salesforce_learn_context",\n`;
|
|
466
|
+
contextWarning += ` "action": "suggest_questions",\n`;
|
|
467
|
+
contextWarning += ` "context_type": "data_model"\n`;
|
|
468
|
+
contextWarning += `}\n`;
|
|
469
|
+
contextWarning += `\`\`\`\n\n`;
|
|
470
|
+
}
|
|
471
|
+
contextWarning += `---\n\n`;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
} catch (error) {
|
|
475
|
+
// Context not available, suggest learning it
|
|
476
|
+
contextWarning = `\n## 💡 Personalisierung verfügbar\n\n`;
|
|
477
|
+
contextWarning += `Für bessere, personalisierte Unterstützung können Sie ein Kontext-Interview durchführen:\n\n`;
|
|
478
|
+
contextWarning += `\`\`\`json\n`;
|
|
479
|
+
contextWarning += `{\n`;
|
|
480
|
+
contextWarning += ` "tool": "salesforce_learn_context",\n`;
|
|
481
|
+
contextWarning += ` "action": "start_interview"\n`;
|
|
482
|
+
contextWarning += `}\n`;
|
|
483
|
+
contextWarning += `\`\`\`\n\n`;
|
|
484
|
+
contextWarning += `Dies hilft mir, Sie und Ihr Unternehmen kennenzulernen.\n\n`;
|
|
485
|
+
contextWarning += `---\n\n`;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Add context warning if needed
|
|
489
|
+
result += contextWarning;
|
|
490
|
+
|
|
491
|
+
// Enhanced metadata info
|
|
492
|
+
result += `## 📋 Installation Metadata\n`;
|
|
493
|
+
result += `- **Last Learned:** ${new Date(documentation.metadata.learned_at).toLocaleString()}\n`;
|
|
494
|
+
if (documentation.metadata.salesforce_instance) {
|
|
495
|
+
result += `- **Salesforce Instance:** ${documentation.metadata.salesforce_instance}\n`;
|
|
496
|
+
}
|
|
497
|
+
result += `- **API Version:** ${documentation.metadata.api_version}\n`;
|
|
498
|
+
if (documentation.metadata.learning_options) {
|
|
499
|
+
result += `- **Learning Options:**\n`;
|
|
500
|
+
result += ` - Include Unused: ${documentation.metadata.learning_options.include_unused}\n`;
|
|
501
|
+
result += ` - Detailed Relationships: ${documentation.metadata.learning_options.detailed_relationships}\n`;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Enhanced summary with more statistics
|
|
505
|
+
result += `\n## 📊 Installation Statistics\n`;
|
|
506
|
+
result += `- **Total Objects:** ${documentation.summary.total_objects}\n`;
|
|
507
|
+
result += `- **Standard Objects:** ${documentation.summary.standard_objects}\n`;
|
|
508
|
+
result += `- **Custom Objects:** ${documentation.summary.custom_objects}\n`;
|
|
509
|
+
result += `- **Total Fields:** ${documentation.summary.total_fields}\n`;
|
|
510
|
+
result += `- **Custom Fields:** ${documentation.summary.custom_fields}\n`;
|
|
511
|
+
|
|
512
|
+
// Calculate additional statistics
|
|
513
|
+
const objectsWithErrors = Object.values(documentation.objects).filter(obj => obj.error).length;
|
|
514
|
+
if (objectsWithErrors > 0) {
|
|
515
|
+
result += `- **Objects with Errors:** ${objectsWithErrors}\n`;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Field type statistics
|
|
519
|
+
const fieldTypes = {};
|
|
520
|
+
let totalRelationships = 0;
|
|
521
|
+
|
|
522
|
+
for (const [objectName, obj] of Object.entries(documentation.objects)) {
|
|
523
|
+
if (obj.error) continue;
|
|
524
|
+
|
|
525
|
+
if (obj.relationships) {
|
|
526
|
+
totalRelationships += (obj.relationships.parent_relationships?.length || 0) +
|
|
527
|
+
(obj.relationships.child_relationships?.length || 0);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
for (const [fieldName, field] of Object.entries(obj.fields || {})) {
|
|
531
|
+
const type = field.type || 'unknown';
|
|
532
|
+
fieldTypes[type] = (fieldTypes[type] || 0) + 1;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (include_relationships) {
|
|
537
|
+
result += `- **Total Relationships:** ${totalRelationships}\n`;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Field type breakdown
|
|
541
|
+
if (detailed_fields && Object.keys(fieldTypes).length > 0) {
|
|
542
|
+
result += `\n### Field Type Distribution\n`;
|
|
543
|
+
const sortedTypes = Object.entries(fieldTypes).sort(([,a], [,b]) => b - a);
|
|
544
|
+
for (const [type, count] of sortedTypes.slice(0, 10)) {
|
|
545
|
+
result += `- **${type}:** ${count} fields\n`;
|
|
546
|
+
}
|
|
547
|
+
if (sortedTypes.length > 10) {
|
|
548
|
+
result += `- *... and ${sortedTypes.length - 10} more field types*\n`;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Complete object list with detailed information
|
|
553
|
+
const objects = Object.entries(documentation.objects)
|
|
554
|
+
.filter(([name, obj]) => !obj.error && (!show_custom_only || obj.basic_info.custom))
|
|
555
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
556
|
+
|
|
557
|
+
if (objects.length > 0) {
|
|
558
|
+
result += `\n## 📦 ${show_custom_only ? 'Custom Objects' : 'All Objects'} (${objects.length})\n`;
|
|
559
|
+
|
|
560
|
+
for (const [objectName, obj] of objects) {
|
|
561
|
+
const custom = obj.basic_info.custom ? ' 🔧' : '';
|
|
562
|
+
const hasRelationships = obj.relationships &&
|
|
563
|
+
((obj.relationships.parent_relationships?.length || 0) + (obj.relationships.child_relationships?.length || 0)) > 0;
|
|
564
|
+
const relationshipIndicator = include_relationships && hasRelationships ? ' 🔗' : '';
|
|
565
|
+
|
|
566
|
+
result += `\n### ${obj.basic_info.label} (\`${objectName}\`)${custom}${relationshipIndicator}\n`;
|
|
567
|
+
result += `- **Fields:** ${obj.field_count} total, ${obj.custom_field_count} custom\n`;
|
|
568
|
+
|
|
569
|
+
if (include_permissions && obj.metadata) {
|
|
570
|
+
const permissions = [];
|
|
571
|
+
if (obj.metadata.createable) permissions.push('Create');
|
|
572
|
+
if (obj.metadata.updateable) permissions.push('Update');
|
|
573
|
+
if (obj.metadata.deletable) permissions.push('Delete');
|
|
574
|
+
if (obj.metadata.queryable) permissions.push('Query');
|
|
575
|
+
result += `- **Permissions:** ${permissions.join(', ')}\n`;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (include_relationships && obj.relationships) {
|
|
579
|
+
const parentCount = obj.relationships.parent_relationships?.length || 0;
|
|
580
|
+
const childCount = obj.relationships.child_relationships?.length || 0;
|
|
581
|
+
if (parentCount > 0 || childCount > 0) {
|
|
582
|
+
result += `- **Relationships:** ${parentCount} parent, ${childCount} child\n`;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Show some important fields
|
|
587
|
+
if (detailed_fields && obj.fields) {
|
|
588
|
+
const importantFields = Object.entries(obj.fields)
|
|
589
|
+
.filter(([name, field]) => field.required || field.custom || ['Name', 'Email'].includes(name))
|
|
590
|
+
.slice(0, 3);
|
|
591
|
+
|
|
592
|
+
if (importantFields.length > 0) {
|
|
593
|
+
result += `- **Key Fields:** ${importantFields.map(([name, field]) => {
|
|
594
|
+
const indicators = [];
|
|
595
|
+
if (field.required) indicators.push('⚠️');
|
|
596
|
+
if (field.custom) indicators.push('🔧');
|
|
597
|
+
return `${field.label || name}${indicators.join('')}`;
|
|
598
|
+
}).join(', ')}\n`;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Objects with errors
|
|
605
|
+
const errorObjects = Object.entries(documentation.objects)
|
|
606
|
+
.filter(([name, obj]) => obj.error);
|
|
607
|
+
|
|
608
|
+
if (errorObjects.length > 0) {
|
|
609
|
+
result += `\n## ⚠️ Objects with Analysis Errors (${errorObjects.length})\n`;
|
|
610
|
+
for (const [objectName, obj] of errorObjects.slice(0, 10)) {
|
|
611
|
+
result += `- **${objectName}:** ${obj.error}\n`;
|
|
612
|
+
}
|
|
613
|
+
if (errorObjects.length > 10) {
|
|
614
|
+
result += `- *... and ${errorObjects.length - 10} more objects with errors*\n`;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
result += `\n## 💡 Usage Tips\n`;
|
|
619
|
+
result += `- **Specific Object:** Use \`object_name: "ObjectName"\` for complete object details\n`;
|
|
620
|
+
result += `- **Field Search:** Use \`field_search: "searchterm"\` to find specific fields\n`;
|
|
621
|
+
result += `- **Custom Only:** Use \`show_custom_only: true\` to focus on customizations\n`;
|
|
622
|
+
result += `- **Detailed Fields:** Use \`detailed_fields: true\` for complete field information\n`;
|
|
623
|
+
result += `- **Relationships:** Use \`include_relationships: true\` for relationship mapping\n`;
|
|
624
|
+
result += `- **Limit Results:** Use \`max_fields_per_object: N\` to limit field display\n`;
|
|
625
|
+
|
|
626
|
+
return {
|
|
627
|
+
content: [{
|
|
628
|
+
type: "text",
|
|
629
|
+
text: result
|
|
630
|
+
}]
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function getWritabilityStatus(writability) {
|
|
635
|
+
if (!writability) return 'Unknown';
|
|
636
|
+
|
|
637
|
+
if (writability.read_only) {
|
|
638
|
+
if (writability.formula || writability.calculated) {
|
|
639
|
+
return '🔒 Read-Only (Formula/Calculated)';
|
|
640
|
+
} else if (writability.rollup_summary) {
|
|
641
|
+
return '🔒 Read-Only (Rollup Summary)';
|
|
642
|
+
} else if (writability.auto_number) {
|
|
643
|
+
return '🔒 Read-Only (Auto Number)';
|
|
644
|
+
} else if (writability.system_managed) {
|
|
645
|
+
return '🔒 Read-Only (System Managed)';
|
|
646
|
+
} else {
|
|
647
|
+
return '🔒 Read-Only';
|
|
648
|
+
}
|
|
649
|
+
} else if (writability.create_only) {
|
|
650
|
+
return '📝 Create Only';
|
|
651
|
+
} else if (writability.fully_writable) {
|
|
652
|
+
return '✅ Fully Writable';
|
|
653
|
+
} else {
|
|
654
|
+
return '⚠️ Limited Writability';
|
|
655
|
+
}
|
|
656
|
+
}
|