@mcp-consultant-tools/powerplatform-customization 25.0.0-beta.1 → 25.0.0-beta.2
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/build/PowerPlatformService.d.ts +23 -0
- package/build/PowerPlatformService.d.ts.map +1 -1
- package/build/PowerPlatformService.js +92 -8
- package/build/PowerPlatformService.js.map +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +298 -38
- package/build/index.js.map +1 -1
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -792,12 +792,39 @@ export function registerPowerplatformCustomizationTools(server, service) {
|
|
|
792
792
|
};
|
|
793
793
|
}
|
|
794
794
|
});
|
|
795
|
-
server.tool("update-attribute", "Update an existing attribute on an entity. Supports
|
|
795
|
+
server.tool("update-attribute", "Update an existing attribute on an entity. Supports updating display properties, numeric constraints, date/time format, string format, and auditing settings.", {
|
|
796
796
|
entityLogicalName: z.string().describe("Entity logical name"),
|
|
797
797
|
attributeLogicalName: z.string().describe("Attribute logical name"),
|
|
798
798
|
displayName: z.string().optional().describe("New display name"),
|
|
799
799
|
description: z.string().optional().describe("New description"),
|
|
800
800
|
requiredLevel: z.enum(["None", "Recommended", "ApplicationRequired"]).optional().describe("Required level"),
|
|
801
|
+
// String/Memo properties
|
|
802
|
+
maxLength: z.number().optional().describe("Maximum length for String/Memo attributes. " +
|
|
803
|
+
"String (single-line): 1-4000 characters. " +
|
|
804
|
+
"Memo (multi-line): 1-1048576 characters. " +
|
|
805
|
+
"Note: Reducing maxLength won't truncate existing data."),
|
|
806
|
+
formatName: z.enum(["Text", "TextArea", "Email", "Phone", "Url", "TickerSymbol"]).optional().describe("Format for String attributes. Text=single line, TextArea=multi-line, " +
|
|
807
|
+
"Email/Phone/Url/TickerSymbol=formatted input with validation."),
|
|
808
|
+
// Numeric properties (Integer, Decimal, Money)
|
|
809
|
+
minValue: z.number().optional().describe("Minimum value for Integer/Decimal/Money attributes. " +
|
|
810
|
+
"Integer: -2147483648 to 2147483647. " +
|
|
811
|
+
"Decimal: -100000000000 to 100000000000. " +
|
|
812
|
+
"Money: -922337203685477 to 922337203685477."),
|
|
813
|
+
maxValue: z.number().optional().describe("Maximum value for Integer/Decimal/Money attributes. " +
|
|
814
|
+
"Integer: -2147483648 to 2147483647. " +
|
|
815
|
+
"Decimal: -100000000000 to 100000000000. " +
|
|
816
|
+
"Money: -922337203685477 to 922337203685477."),
|
|
817
|
+
precision: z.number().optional().describe("Decimal precision for Decimal/Money attributes (0-10 decimal places)."),
|
|
818
|
+
precisionSource: z.enum(["Precision", "Pricing", "Currency"]).optional().describe("Precision source for Money attributes. " +
|
|
819
|
+
"Precision=use precision property, Pricing=org pricing setting, Currency=currency precision."),
|
|
820
|
+
// DateTime properties
|
|
821
|
+
format: z.enum(["DateAndTime", "DateOnly"]).optional().describe("Display format for DateTime attributes."),
|
|
822
|
+
dateTimeBehavior: z.enum(["UserLocal", "DateOnly", "TimeZoneIndependent"]).optional().describe("Time zone behavior for DateTime attributes. Only changeable if CanChangeDateTimeBehavior=true. " +
|
|
823
|
+
"UserLocal=adjusted to user timezone, DateOnly=date without time, TimeZoneIndependent=stored as-is."),
|
|
824
|
+
// Auditing and search properties
|
|
825
|
+
isAuditEnabled: z.boolean().optional().describe("Enable/disable auditing for this attribute. Tracks changes to field values."),
|
|
826
|
+
isValidForAdvancedFind: z.boolean().optional().describe("Show this attribute in Advanced Find queries."),
|
|
827
|
+
// AutoNumber conversion
|
|
801
828
|
autoNumberFormat: z.string().optional().describe("Auto-number format string to convert String attribute to AutoNumber. " +
|
|
802
829
|
"Use placeholders: {SEQNUM:n} for sequential number (min length n), " +
|
|
803
830
|
"{RANDSTRING:n} for random alphanumeric (length 1-6 only), " +
|
|
@@ -823,6 +850,69 @@ export function registerPowerplatformCustomizationTools(server, service) {
|
|
|
823
850
|
if (params.requiredLevel) {
|
|
824
851
|
updates.RequiredLevel = { Value: params.requiredLevel, CanBeChanged: true };
|
|
825
852
|
}
|
|
853
|
+
// Handle MaxLength update for String/Memo attributes
|
|
854
|
+
if (params.maxLength !== undefined) {
|
|
855
|
+
if (params.maxLength < 1) {
|
|
856
|
+
throw new Error("maxLength must be at least 1 character.");
|
|
857
|
+
}
|
|
858
|
+
if (params.maxLength > 1048576) {
|
|
859
|
+
throw new Error("maxLength cannot exceed 1,048,576 characters (Memo maximum).");
|
|
860
|
+
}
|
|
861
|
+
updates.MaxLength = params.maxLength;
|
|
862
|
+
}
|
|
863
|
+
// Handle FormatName update for String attributes
|
|
864
|
+
if (params.formatName) {
|
|
865
|
+
updates.FormatName = { Value: params.formatName };
|
|
866
|
+
}
|
|
867
|
+
// Handle MinValue update for Integer/Decimal/Money attributes
|
|
868
|
+
if (params.minValue !== undefined) {
|
|
869
|
+
updates.MinValue = params.minValue;
|
|
870
|
+
}
|
|
871
|
+
// Handle MaxValue update for Integer/Decimal/Money attributes
|
|
872
|
+
if (params.maxValue !== undefined) {
|
|
873
|
+
updates.MaxValue = params.maxValue;
|
|
874
|
+
}
|
|
875
|
+
// Handle Precision update for Decimal/Money attributes
|
|
876
|
+
if (params.precision !== undefined) {
|
|
877
|
+
if (params.precision < 0 || params.precision > 10) {
|
|
878
|
+
throw new Error("precision must be between 0 and 10 decimal places.");
|
|
879
|
+
}
|
|
880
|
+
updates.Precision = params.precision;
|
|
881
|
+
}
|
|
882
|
+
// Handle PrecisionSource update for Money attributes
|
|
883
|
+
if (params.precisionSource) {
|
|
884
|
+
const precisionSourceMap = {
|
|
885
|
+
"Precision": 0,
|
|
886
|
+
"Pricing": 1,
|
|
887
|
+
"Currency": 2
|
|
888
|
+
};
|
|
889
|
+
updates.PrecisionSource = precisionSourceMap[params.precisionSource];
|
|
890
|
+
}
|
|
891
|
+
// Handle Format update for DateTime attributes
|
|
892
|
+
if (params.format) {
|
|
893
|
+
updates.Format = params.format;
|
|
894
|
+
}
|
|
895
|
+
// Handle DateTimeBehavior update for DateTime attributes
|
|
896
|
+
if (params.dateTimeBehavior) {
|
|
897
|
+
updates.DateTimeBehavior = {
|
|
898
|
+
"@odata.type": "Microsoft.Dynamics.CRM.DateTimeBehavior",
|
|
899
|
+
Value: params.dateTimeBehavior
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
// Handle IsAuditEnabled update
|
|
903
|
+
if (params.isAuditEnabled !== undefined) {
|
|
904
|
+
updates.IsAuditEnabled = {
|
|
905
|
+
Value: params.isAuditEnabled,
|
|
906
|
+
CanBeChanged: true
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
// Handle IsValidForAdvancedFind update
|
|
910
|
+
if (params.isValidForAdvancedFind !== undefined) {
|
|
911
|
+
updates.IsValidForAdvancedFind = {
|
|
912
|
+
Value: params.isValidForAdvancedFind,
|
|
913
|
+
CanBeChanged: true
|
|
914
|
+
};
|
|
915
|
+
}
|
|
826
916
|
// Handle AutoNumber format conversion
|
|
827
917
|
if (params.autoNumberFormat) {
|
|
828
918
|
// Validate RANDSTRING lengths (common error - API rejects length > 6)
|
|
@@ -845,10 +935,45 @@ export function registerPowerplatformCustomizationTools(server, service) {
|
|
|
845
935
|
}
|
|
846
936
|
await service.updateAttribute(params.entityLogicalName, params.attributeLogicalName, updates, params.solutionUniqueName);
|
|
847
937
|
let successMessage = `✅ Successfully updated attribute '${params.attributeLogicalName}' on entity '${params.entityLogicalName}'`;
|
|
938
|
+
// Build list of changes made
|
|
939
|
+
const changes = [];
|
|
940
|
+
if (params.displayName)
|
|
941
|
+
changes.push(`Display name: "${params.displayName}"`);
|
|
942
|
+
if (params.description)
|
|
943
|
+
changes.push(`Description updated`);
|
|
944
|
+
if (params.requiredLevel)
|
|
945
|
+
changes.push(`Required level: ${params.requiredLevel}`);
|
|
946
|
+
if (params.maxLength !== undefined)
|
|
947
|
+
changes.push(`Max length: ${params.maxLength} characters`);
|
|
948
|
+
if (params.formatName)
|
|
949
|
+
changes.push(`Format: ${params.formatName}`);
|
|
950
|
+
if (params.minValue !== undefined)
|
|
951
|
+
changes.push(`Min value: ${params.minValue}`);
|
|
952
|
+
if (params.maxValue !== undefined)
|
|
953
|
+
changes.push(`Max value: ${params.maxValue}`);
|
|
954
|
+
if (params.precision !== undefined)
|
|
955
|
+
changes.push(`Precision: ${params.precision} decimal places`);
|
|
956
|
+
if (params.precisionSource)
|
|
957
|
+
changes.push(`Precision source: ${params.precisionSource}`);
|
|
958
|
+
if (params.format)
|
|
959
|
+
changes.push(`DateTime format: ${params.format}`);
|
|
960
|
+
if (params.dateTimeBehavior)
|
|
961
|
+
changes.push(`DateTime behavior: ${params.dateTimeBehavior}`);
|
|
962
|
+
if (params.isAuditEnabled !== undefined)
|
|
963
|
+
changes.push(`Auditing: ${params.isAuditEnabled ? 'enabled' : 'disabled'}`);
|
|
964
|
+
if (params.isValidForAdvancedFind !== undefined)
|
|
965
|
+
changes.push(`Advanced Find: ${params.isValidForAdvancedFind ? 'enabled' : 'disabled'}`);
|
|
966
|
+
if (params.autoNumberFormat)
|
|
967
|
+
changes.push(`AutoNumber format: ${params.autoNumberFormat}`);
|
|
968
|
+
if (changes.length > 0) {
|
|
969
|
+
successMessage += `\n\n📝 Changes made:\n${changes.map(c => ` • ${c}`).join('\n')}`;
|
|
970
|
+
}
|
|
848
971
|
if (params.autoNumberFormat) {
|
|
849
|
-
successMessage += `\n\n📋 Auto-number format set to: ${params.autoNumberFormat}`;
|
|
850
972
|
successMessage += `\n\n⚠️ NOTE: Converting to AutoNumber is irreversible. The attribute will now auto-generate values based on the format.`;
|
|
851
973
|
}
|
|
974
|
+
if (params.dateTimeBehavior) {
|
|
975
|
+
successMessage += `\n\n⚠️ NOTE: DateTimeBehavior changes may affect existing data interpretation. Review dependent workflows and business rules.`;
|
|
976
|
+
}
|
|
852
977
|
successMessage += `\n\n⚠️ IMPORTANT: You must publish this customization using the 'publish-customizations' tool before it becomes active.`;
|
|
853
978
|
return {
|
|
854
979
|
content: [{ type: "text", text: successMessage }]
|
|
@@ -1983,43 +2108,51 @@ export function registerPowerplatformCustomizationTools(server, service) {
|
|
|
1983
2108
|
solutionUniqueName: z.string().optional(),
|
|
1984
2109
|
replaceExisting: z.boolean().optional().describe("Update existing assembly vs. create new"),
|
|
1985
2110
|
}, async (params) => {
|
|
2111
|
+
const service = getPowerPlatformService();
|
|
2112
|
+
// Track created resources for potential rollback
|
|
2113
|
+
let createdAssemblyId = null;
|
|
2114
|
+
let isNewAssembly = false;
|
|
2115
|
+
const createdStepIds = [];
|
|
2116
|
+
const summary = {
|
|
2117
|
+
phases: {
|
|
2118
|
+
deploy: {},
|
|
2119
|
+
register: { stepsCreated: 0, imagesCreated: 0 },
|
|
2120
|
+
},
|
|
2121
|
+
};
|
|
2122
|
+
let dllBuffer;
|
|
1986
2123
|
try {
|
|
1987
|
-
const service = getPowerPlatformService();
|
|
1988
|
-
const summary = {
|
|
1989
|
-
phases: {
|
|
1990
|
-
deploy: {},
|
|
1991
|
-
register: { stepsCreated: 0, imagesCreated: 0 },
|
|
1992
|
-
},
|
|
1993
|
-
};
|
|
1994
2124
|
// Read DLL file
|
|
1995
2125
|
const fs = await import('fs/promises');
|
|
1996
2126
|
const normalizedPath = params.assemblyPath.replace(/\\/g, '/');
|
|
1997
|
-
|
|
2127
|
+
dllBuffer = await fs.readFile(normalizedPath);
|
|
1998
2128
|
const dllBase64 = dllBuffer.toString('base64');
|
|
1999
2129
|
const version = await service.extractAssemblyVersion(params.assemblyPath);
|
|
2000
|
-
// Phase 1: Deploy assembly
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
}
|
|
2012
|
-
else {
|
|
2013
|
-
throw new Error(`Assembly '${params.assemblyName}' not found for update`);
|
|
2014
|
-
}
|
|
2130
|
+
// Phase 1: Deploy assembly (UPSERT logic)
|
|
2131
|
+
const existingAssemblyId = await service.queryPluginAssemblyByName(params.assemblyName);
|
|
2132
|
+
if (existingAssemblyId) {
|
|
2133
|
+
// Assembly exists - update it (no rollback needed for updates)
|
|
2134
|
+
await service.updatePluginAssembly(existingAssemblyId, dllBase64, version, params.solutionUniqueName || POWERPLATFORM_DEFAULT_SOLUTION);
|
|
2135
|
+
summary.phases.deploy = {
|
|
2136
|
+
action: 'updated',
|
|
2137
|
+
assemblyId: existingAssemblyId,
|
|
2138
|
+
version,
|
|
2139
|
+
pluginTypes: await service.getPluginTypesForAssembly(existingAssemblyId),
|
|
2140
|
+
};
|
|
2015
2141
|
}
|
|
2016
2142
|
else {
|
|
2143
|
+
// Assembly doesn't exist - create it
|
|
2144
|
+
if (params.replaceExisting) {
|
|
2145
|
+
// User expected update but assembly not found - warn but proceed with create
|
|
2146
|
+
console.error(`Warning: Assembly '${params.assemblyName}' not found for update. Creating new assembly instead.`);
|
|
2147
|
+
}
|
|
2017
2148
|
const uploadResult = await service.createPluginAssembly({
|
|
2018
2149
|
name: params.assemblyName,
|
|
2019
2150
|
content: dllBase64,
|
|
2020
2151
|
version,
|
|
2021
2152
|
solutionUniqueName: params.solutionUniqueName || POWERPLATFORM_DEFAULT_SOLUTION,
|
|
2022
2153
|
});
|
|
2154
|
+
createdAssemblyId = uploadResult.pluginAssemblyId; // Track for rollback
|
|
2155
|
+
isNewAssembly = true;
|
|
2023
2156
|
summary.phases.deploy = {
|
|
2024
2157
|
action: 'created',
|
|
2025
2158
|
assemblyId: uploadResult.pluginAssemblyId,
|
|
@@ -2027,7 +2160,7 @@ export function registerPowerplatformCustomizationTools(server, service) {
|
|
|
2027
2160
|
pluginTypes: uploadResult.pluginTypes,
|
|
2028
2161
|
};
|
|
2029
2162
|
}
|
|
2030
|
-
// Phase 2: Register steps
|
|
2163
|
+
// Phase 2: Register steps (with rollback tracking)
|
|
2031
2164
|
if (params.stepConfigurations) {
|
|
2032
2165
|
const stageMap = {
|
|
2033
2166
|
PreValidation: 10,
|
|
@@ -2050,6 +2183,7 @@ export function registerPowerplatformCustomizationTools(server, service) {
|
|
|
2050
2183
|
filteringAttributes: stepConfig.filteringAttributes?.join(','),
|
|
2051
2184
|
solutionUniqueName: params.solutionUniqueName || POWERPLATFORM_DEFAULT_SOLUTION,
|
|
2052
2185
|
});
|
|
2186
|
+
createdStepIds.push(stepResult.stepId); // Track for rollback
|
|
2053
2187
|
summary.phases.register.stepsCreated++;
|
|
2054
2188
|
// Register pre-image
|
|
2055
2189
|
if (stepConfig.preImage) {
|
|
@@ -2081,28 +2215,154 @@ export function registerPowerplatformCustomizationTools(server, service) {
|
|
|
2081
2215
|
return {
|
|
2082
2216
|
content: [{
|
|
2083
2217
|
type: "text",
|
|
2084
|
-
text:
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
(summary.phases.deploy.pluginTypes ?
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2218
|
+
text: `Plugin deployment completed successfully!\n\n` +
|
|
2219
|
+
`Assembly: ${summary.phases.deploy.action === 'created' ? 'Created' : 'Updated'}\n` +
|
|
2220
|
+
`Assembly ID: ${summary.phases.deploy.assemblyId}\n` +
|
|
2221
|
+
`Version: ${summary.phases.deploy.version}\n` +
|
|
2222
|
+
`Size: ${(dllBuffer.length / 1024).toFixed(2)} KB\n` +
|
|
2223
|
+
(summary.phases.deploy.pluginTypes ? `Plugin Types: ${summary.phases.deploy.pluginTypes.length}\n` : '') +
|
|
2224
|
+
`Steps Created: ${summary.phases.register.stepsCreated}\n` +
|
|
2225
|
+
`Images Created: ${summary.phases.register.imagesCreated}\n` +
|
|
2226
|
+
`Published: ${summary.phases.publish.success ? 'Yes' : 'No'}\n\n` +
|
|
2227
|
+
`Deployment is complete and active in the environment!`
|
|
2094
2228
|
}]
|
|
2095
2229
|
};
|
|
2096
2230
|
}
|
|
2097
2231
|
catch (error) {
|
|
2232
|
+
// ROLLBACK: Clean up created resources on failure
|
|
2233
|
+
let rollbackMessage = '';
|
|
2234
|
+
if (createdStepIds.length > 0 || (createdAssemblyId && isNewAssembly)) {
|
|
2235
|
+
rollbackMessage = '\n\nRollback initiated:\n';
|
|
2236
|
+
// Delete created steps first (reverse order)
|
|
2237
|
+
for (const stepId of createdStepIds.reverse()) {
|
|
2238
|
+
try {
|
|
2239
|
+
await service.deletePluginStep(stepId);
|
|
2240
|
+
rollbackMessage += `- Deleted step: ${stepId}\n`;
|
|
2241
|
+
}
|
|
2242
|
+
catch (rollbackError) {
|
|
2243
|
+
rollbackMessage += `- Failed to delete step ${stepId}: ${rollbackError.message}\n`;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
// Delete the assembly if we created it (cascade deletes remaining components)
|
|
2247
|
+
if (createdAssemblyId && isNewAssembly) {
|
|
2248
|
+
try {
|
|
2249
|
+
await service.deletePluginAssembly(createdAssemblyId);
|
|
2250
|
+
rollbackMessage += `- Deleted assembly: ${createdAssemblyId}\n`;
|
|
2251
|
+
}
|
|
2252
|
+
catch (rollbackError) {
|
|
2253
|
+
rollbackMessage += `- Failed to delete assembly ${createdAssemblyId}: ${rollbackError.message}\n`;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
rollbackMessage += '\nPlease verify cleanup in Power Platform.';
|
|
2257
|
+
}
|
|
2098
2258
|
console.error("Error deploying plugin:", error);
|
|
2099
2259
|
return {
|
|
2100
|
-
content: [{ type: "text", text:
|
|
2260
|
+
content: [{ type: "text", text: `Failed to deploy plugin: ${error.message}${rollbackMessage}` }],
|
|
2261
|
+
isError: true
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
});
|
|
2265
|
+
server.tool("get-plugin-deployment-status", "Get the current deployment status of a plugin assembly, including all registered types, steps, and images. Useful for verifying deployments and troubleshooting.", {
|
|
2266
|
+
assemblyName: z.string().describe("Name of the plugin assembly to check"),
|
|
2267
|
+
includeDisabled: z.boolean().optional().describe("Include disabled steps (default: false)"),
|
|
2268
|
+
}, async (params) => {
|
|
2269
|
+
try {
|
|
2270
|
+
const service = getPowerPlatformService();
|
|
2271
|
+
// Check if assembly exists
|
|
2272
|
+
const assemblyId = await service.queryPluginAssemblyByName(params.assemblyName);
|
|
2273
|
+
if (!assemblyId) {
|
|
2274
|
+
return {
|
|
2275
|
+
content: [{
|
|
2276
|
+
type: "text",
|
|
2277
|
+
text: `Assembly '${params.assemblyName}' not found in Dataverse.\n\n` +
|
|
2278
|
+
`Possible reasons:\n` +
|
|
2279
|
+
`- Assembly has not been deployed yet\n` +
|
|
2280
|
+
`- Assembly name is incorrect (case-sensitive)\n` +
|
|
2281
|
+
`- Assembly was deleted\n\n` +
|
|
2282
|
+
`Use 'create-plugin-assembly' or 'deploy-plugin-complete' to deploy.`
|
|
2283
|
+
}]
|
|
2284
|
+
};
|
|
2285
|
+
}
|
|
2286
|
+
// Get complete assembly information
|
|
2287
|
+
const result = await service.getPluginAssemblyComplete(params.assemblyName, params.includeDisabled || false);
|
|
2288
|
+
// Build status report
|
|
2289
|
+
let statusReport = `PLUGIN DEPLOYMENT STATUS\n`;
|
|
2290
|
+
statusReport += `${'='.repeat(50)}\n\n`;
|
|
2291
|
+
// Assembly info
|
|
2292
|
+
statusReport += `ASSEMBLY\n`;
|
|
2293
|
+
statusReport += `---------\n`;
|
|
2294
|
+
statusReport += `Name: ${result.assembly.name}\n`;
|
|
2295
|
+
statusReport += `Version: ${result.assembly.version}\n`;
|
|
2296
|
+
statusReport += `ID: ${result.assembly.pluginassemblyid}\n`;
|
|
2297
|
+
statusReport += `Isolation Mode: ${result.assembly.isolationmode === 2 ? 'Sandbox' : 'None'}\n`;
|
|
2298
|
+
statusReport += `Is Managed: ${result.assembly.ismanaged ? 'Yes' : 'No'}\n`;
|
|
2299
|
+
statusReport += `Modified: ${result.assembly.modifiedon}\n`;
|
|
2300
|
+
statusReport += `Modified By: ${result.assembly.modifiedby?.fullname || 'Unknown'}\n\n`;
|
|
2301
|
+
// Plugin types
|
|
2302
|
+
statusReport += `PLUGIN TYPES (${result.pluginTypes.length})\n`;
|
|
2303
|
+
statusReport += `-------------\n`;
|
|
2304
|
+
if (result.pluginTypes.length === 0) {
|
|
2305
|
+
statusReport += `No plugin types found. This may indicate:\n`;
|
|
2306
|
+
statusReport += `- Dataverse is still processing the assembly\n`;
|
|
2307
|
+
statusReport += `- The DLL does not contain any IPlugin implementations\n\n`;
|
|
2308
|
+
}
|
|
2309
|
+
else {
|
|
2310
|
+
for (const type of result.pluginTypes) {
|
|
2311
|
+
statusReport += `- ${type.typename}\n`;
|
|
2312
|
+
statusReport += ` ID: ${type.plugintypeid}\n`;
|
|
2313
|
+
}
|
|
2314
|
+
statusReport += `\n`;
|
|
2315
|
+
}
|
|
2316
|
+
// Steps
|
|
2317
|
+
const stageNames = { 10: 'PreValidation', 20: 'PreOperation', 40: 'PostOperation' };
|
|
2318
|
+
const modeNames = { 0: 'Sync', 1: 'Async' };
|
|
2319
|
+
statusReport += `REGISTERED STEPS (${result.steps.length})\n`;
|
|
2320
|
+
statusReport += `------------------\n`;
|
|
2321
|
+
if (result.steps.length === 0) {
|
|
2322
|
+
statusReport += `No steps registered.\n\n`;
|
|
2323
|
+
}
|
|
2324
|
+
else {
|
|
2325
|
+
for (const step of result.steps) {
|
|
2326
|
+
const status = step.statuscode === 1 ? 'Active' : 'Disabled';
|
|
2327
|
+
statusReport += `- ${step.name}\n`;
|
|
2328
|
+
statusReport += ` Message: ${step.sdkmessageid?.name || 'Unknown'} on ${step.sdkmessagefilterid?.primaryobjecttypecode || 'Unknown'}\n`;
|
|
2329
|
+
statusReport += ` Stage: ${stageNames[step.stage] || step.stage}, Mode: ${modeNames[step.mode] || step.mode}\n`;
|
|
2330
|
+
statusReport += ` Status: ${status}, Rank: ${step.rank}\n`;
|
|
2331
|
+
statusReport += ` ID: ${step.sdkmessageprocessingstepid}\n`;
|
|
2332
|
+
if (step.images && step.images.length > 0) {
|
|
2333
|
+
statusReport += ` Images:\n`;
|
|
2334
|
+
for (const img of step.images) {
|
|
2335
|
+
const imgType = img.imagetype === 0 ? 'Pre' : img.imagetype === 1 ? 'Post' : 'Both';
|
|
2336
|
+
statusReport += ` - ${img.name} (${imgType}Image, alias: ${img.entityalias})\n`;
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
statusReport += `\n`;
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
// Validation
|
|
2343
|
+
statusReport += `VALIDATION\n`;
|
|
2344
|
+
statusReport += `----------\n`;
|
|
2345
|
+
if (result.validation.potentialIssues.length === 0) {
|
|
2346
|
+
statusReport += `No issues detected.\n`;
|
|
2347
|
+
}
|
|
2348
|
+
else {
|
|
2349
|
+
for (const issue of result.validation.potentialIssues) {
|
|
2350
|
+
statusReport += `Warning: ${issue}\n`;
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
return {
|
|
2354
|
+
content: [{ type: "text", text: statusReport }]
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
catch (error) {
|
|
2358
|
+
console.error("Error getting plugin deployment status:", error);
|
|
2359
|
+
return {
|
|
2360
|
+
content: [{ type: "text", text: `Failed to get plugin deployment status: ${error.message}` }],
|
|
2101
2361
|
isError: true
|
|
2102
2362
|
};
|
|
2103
2363
|
}
|
|
2104
2364
|
});
|
|
2105
|
-
console.error(
|
|
2365
|
+
console.error(`powerplatform-customization tools registered (${46} tools)`);
|
|
2106
2366
|
}
|
|
2107
2367
|
// CLI entry point (standalone execution)
|
|
2108
2368
|
// Uses realpathSync to resolve symlinks created by npx
|