snow-flow 3.3.2 → 3.3.3
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/README.md +2 -2
- package/dist/dynamic-version.js +1 -1
- package/dist/mcp/servicenow-deployment-mcp.js +294 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -97,7 +97,7 @@ Snow-Flow provides 180+ tools across 17 specialized MCP servers:
|
|
|
97
97
|
| Server | Tools | Primary Focus |
|
|
98
98
|
|--------|-------|---------------|
|
|
99
99
|
| servicenow-operations | 15 | CRUD operations, data management |
|
|
100
|
-
| servicenow-deployment |
|
|
100
|
+
| servicenow-deployment | 21 | Widget, portal, and application deployment (create & update) |
|
|
101
101
|
| servicenow-platform-development | 12 | Table creation, field management |
|
|
102
102
|
| servicenow-machine-learning | 15 | Neural networks, predictions, anomaly detection |
|
|
103
103
|
| servicenow-reporting-analytics | 18 | Dashboards, reports, KPIs |
|
|
@@ -288,7 +288,7 @@ snow_query_table({
|
|
|
288
288
|
```
|
|
289
289
|
|
|
290
290
|
### Development Tools
|
|
291
|
-
- Widget creation and deployment
|
|
291
|
+
- Widget creation and deployment (snow_deploy for new, snow_update for existing)
|
|
292
292
|
- Business rule development
|
|
293
293
|
- Script include management
|
|
294
294
|
- Flow Designer automation
|
package/dist/dynamic-version.js
CHANGED
|
@@ -36,7 +36,7 @@ function getDynamicVersion() {
|
|
|
36
36
|
console.warn('Warning: Could not read version from package.json:', error);
|
|
37
37
|
}
|
|
38
38
|
// Fallback to hardcoded version
|
|
39
|
-
return '3.3.
|
|
39
|
+
return '3.3.3';
|
|
40
40
|
}
|
|
41
41
|
// Export a constant that uses the dynamic version
|
|
42
42
|
exports.VERSION = getDynamicVersion();
|
|
@@ -234,9 +234,46 @@ class ServiceNowDeploymentMCP {
|
|
|
234
234
|
required: ['name', 'artifacts'],
|
|
235
235
|
},
|
|
236
236
|
},
|
|
237
|
+
{
|
|
238
|
+
name: 'snow_update',
|
|
239
|
+
description: 'Updates existing ServiceNow artifacts (widgets, applications, etc.). Finds artifact by name or sys_id and modifies it. Use snow_deploy for creating new artifacts.',
|
|
240
|
+
inputSchema: {
|
|
241
|
+
type: 'object',
|
|
242
|
+
properties: {
|
|
243
|
+
type: {
|
|
244
|
+
type: 'string',
|
|
245
|
+
enum: ['widget', 'application', 'business_rule', 'script_include', 'ui_page'],
|
|
246
|
+
description: 'Type of artifact to update'
|
|
247
|
+
},
|
|
248
|
+
identifier: {
|
|
249
|
+
type: 'string',
|
|
250
|
+
description: 'sys_id or name of existing artifact to update'
|
|
251
|
+
},
|
|
252
|
+
config: {
|
|
253
|
+
type: 'object',
|
|
254
|
+
description: 'New configuration/content for the artifact'
|
|
255
|
+
},
|
|
256
|
+
instruction: {
|
|
257
|
+
type: 'string',
|
|
258
|
+
description: 'Natural language description of changes to make'
|
|
259
|
+
},
|
|
260
|
+
create_if_not_exists: {
|
|
261
|
+
type: 'boolean',
|
|
262
|
+
default: false,
|
|
263
|
+
description: 'Create artifact if it does not exist'
|
|
264
|
+
},
|
|
265
|
+
auto_update_set: {
|
|
266
|
+
type: 'boolean',
|
|
267
|
+
default: true,
|
|
268
|
+
description: 'Automatically manage update set'
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
required: ['type', 'identifier']
|
|
272
|
+
}
|
|
273
|
+
},
|
|
237
274
|
{
|
|
238
275
|
name: 'snow_deploy',
|
|
239
|
-
description: 'Universal deployment tool for
|
|
276
|
+
description: 'Universal deployment tool for creating NEW ServiceNow artifacts. For updating existing artifacts, use snow_update. Features automatic update set management, permission escalation, retry logic, and comprehensive error recovery.',
|
|
240
277
|
inputSchema: {
|
|
241
278
|
type: 'object',
|
|
242
279
|
properties: {
|
|
@@ -313,6 +350,8 @@ class ServiceNowDeploymentMCP {
|
|
|
313
350
|
return await this.createSolutionPackage(args);
|
|
314
351
|
case 'snow_deploy':
|
|
315
352
|
return await this.unifiedDeploy(args);
|
|
353
|
+
case 'snow_update':
|
|
354
|
+
return await this.updateArtifact(args);
|
|
316
355
|
default:
|
|
317
356
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
318
357
|
}
|
|
@@ -8092,6 +8131,260 @@ ${updateSetSession ? `📋 **Update Set**: ${updateSetSession.name}
|
|
|
8092
8131
|
throw new Error(`Update Set session required for deployment. Error: ${error.message}`);
|
|
8093
8132
|
}
|
|
8094
8133
|
}
|
|
8134
|
+
/**
|
|
8135
|
+
* Update existing ServiceNow artifact
|
|
8136
|
+
*/
|
|
8137
|
+
async updateArtifact(args) {
|
|
8138
|
+
try {
|
|
8139
|
+
this.logger.info('Starting artifact update', args);
|
|
8140
|
+
// Check authentication first
|
|
8141
|
+
const isAuthenticated = await this.oauth.isAuthenticated();
|
|
8142
|
+
if (!isAuthenticated) {
|
|
8143
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, 'Not authenticated. Run "snow-flow auth login" first.');
|
|
8144
|
+
}
|
|
8145
|
+
const { type, identifier, config, instruction, create_if_not_exists = false, auto_update_set = true } = args;
|
|
8146
|
+
// Step 1: Ensure Update Set if requested
|
|
8147
|
+
let updateSetSession = null;
|
|
8148
|
+
if (auto_update_set) {
|
|
8149
|
+
try {
|
|
8150
|
+
const ensureResponse = await this.ensureActiveUpdateSet(`${type} update: ${identifier}`);
|
|
8151
|
+
updateSetSession = ensureResponse.session;
|
|
8152
|
+
}
|
|
8153
|
+
catch (error) {
|
|
8154
|
+
this.logger.warn('Failed to ensure Update Set, continuing without', error);
|
|
8155
|
+
}
|
|
8156
|
+
}
|
|
8157
|
+
// Step 2: Determine table name
|
|
8158
|
+
let tableName;
|
|
8159
|
+
switch (type) {
|
|
8160
|
+
case 'widget':
|
|
8161
|
+
tableName = 'sp_widget';
|
|
8162
|
+
break;
|
|
8163
|
+
case 'application':
|
|
8164
|
+
tableName = 'sys_app';
|
|
8165
|
+
break;
|
|
8166
|
+
case 'business_rule':
|
|
8167
|
+
tableName = 'sys_script';
|
|
8168
|
+
break;
|
|
8169
|
+
case 'script_include':
|
|
8170
|
+
tableName = 'sys_script_include';
|
|
8171
|
+
break;
|
|
8172
|
+
case 'ui_page':
|
|
8173
|
+
tableName = 'sys_ui_page';
|
|
8174
|
+
break;
|
|
8175
|
+
default:
|
|
8176
|
+
throw new Error(`Unsupported artifact type: ${type}`);
|
|
8177
|
+
}
|
|
8178
|
+
// Step 3: Find existing artifact
|
|
8179
|
+
let existingArtifact = null;
|
|
8180
|
+
let searchQuery = '';
|
|
8181
|
+
// Check if identifier is a sys_id (32 char hex) or a name
|
|
8182
|
+
const isSysId = /^[a-f0-9]{32}$/.test(identifier);
|
|
8183
|
+
if (isSysId) {
|
|
8184
|
+
searchQuery = `sys_id=${identifier}`;
|
|
8185
|
+
}
|
|
8186
|
+
else {
|
|
8187
|
+
searchQuery = `name=${identifier}`;
|
|
8188
|
+
}
|
|
8189
|
+
this.logger.info(`Searching for ${type} with query: ${searchQuery}`);
|
|
8190
|
+
try {
|
|
8191
|
+
const searchResponse = await this.client.searchRecords(tableName, searchQuery, 1);
|
|
8192
|
+
if (searchResponse?.data?.result?.length > 0) {
|
|
8193
|
+
existingArtifact = searchResponse.data.result[0];
|
|
8194
|
+
this.logger.info(`Found existing ${type}: ${existingArtifact.sys_id}`);
|
|
8195
|
+
}
|
|
8196
|
+
}
|
|
8197
|
+
catch (searchError) {
|
|
8198
|
+
this.logger.error(`Failed to search for ${type}:`, searchError);
|
|
8199
|
+
}
|
|
8200
|
+
// Step 4: Handle artifact not found
|
|
8201
|
+
if (!existingArtifact) {
|
|
8202
|
+
if (create_if_not_exists) {
|
|
8203
|
+
this.logger.info(`${type} not found, creating new one as requested`);
|
|
8204
|
+
// Delegate to snow_deploy for creation
|
|
8205
|
+
return await this.unifiedDeploy({
|
|
8206
|
+
type,
|
|
8207
|
+
config,
|
|
8208
|
+
instruction,
|
|
8209
|
+
auto_update_set
|
|
8210
|
+
});
|
|
8211
|
+
}
|
|
8212
|
+
else {
|
|
8213
|
+
return {
|
|
8214
|
+
content: [{
|
|
8215
|
+
type: 'text',
|
|
8216
|
+
text: `❌ ${type} not found: "${identifier}"
|
|
8217
|
+
|
|
8218
|
+
🔍 **Search Details:**
|
|
8219
|
+
- Table: ${tableName}
|
|
8220
|
+
- Search Query: ${searchQuery}
|
|
8221
|
+
- Results: 0
|
|
8222
|
+
|
|
8223
|
+
💡 **Suggestions:**
|
|
8224
|
+
1. Check the ${isSysId ? 'sys_id' : 'name'} is correct
|
|
8225
|
+
2. Verify you have read permissions for ${tableName}
|
|
8226
|
+
3. Use exact ${isSysId ? 'sys_id format (32 char hex)' : 'name (case sensitive)'}
|
|
8227
|
+
4. Add create_if_not_exists: true to create if missing
|
|
8228
|
+
|
|
8229
|
+
🔧 **Alternative Commands:**
|
|
8230
|
+
- List existing: \`snow_query_table({ table: "${tableName}", limit: 10 })\`
|
|
8231
|
+
- Create new: \`snow_deploy({ type: "${type}", ... })\`
|
|
8232
|
+
- Find by name: \`snow_update({ type: "${type}", identifier: "exact_name" })\``
|
|
8233
|
+
}]
|
|
8234
|
+
};
|
|
8235
|
+
}
|
|
8236
|
+
}
|
|
8237
|
+
// Step 5: Process update configuration
|
|
8238
|
+
let updateData = {};
|
|
8239
|
+
if (instruction) {
|
|
8240
|
+
// Natural language instruction - convert to specific updates
|
|
8241
|
+
updateData = await this.processUpdateInstruction(type, instruction, existingArtifact);
|
|
8242
|
+
}
|
|
8243
|
+
else if (config) {
|
|
8244
|
+
updateData = config;
|
|
8245
|
+
}
|
|
8246
|
+
else {
|
|
8247
|
+
throw new Error('Either instruction or config must be provided for update');
|
|
8248
|
+
}
|
|
8249
|
+
// Step 6: Perform the update
|
|
8250
|
+
this.logger.info(`Updating ${type} ${existingArtifact.sys_id}`, updateData);
|
|
8251
|
+
const updateResponse = await this.client.updateRecord(tableName, existingArtifact.sys_id, updateData);
|
|
8252
|
+
if (!updateResponse?.success) {
|
|
8253
|
+
throw new Error(`Failed to update ${type}: ${updateResponse?.error || 'Unknown error'}`);
|
|
8254
|
+
}
|
|
8255
|
+
// Step 7: Track the update
|
|
8256
|
+
if (updateSetSession) {
|
|
8257
|
+
artifact_tracker_js_1.artifactTracker.trackArtifact({
|
|
8258
|
+
type: type,
|
|
8259
|
+
name: existingArtifact.name,
|
|
8260
|
+
sys_id: existingArtifact.sys_id,
|
|
8261
|
+
operation: 'update',
|
|
8262
|
+
table: tableName,
|
|
8263
|
+
update_set_id: updateSetSession.update_set_id
|
|
8264
|
+
});
|
|
8265
|
+
}
|
|
8266
|
+
// Step 8: Return success response
|
|
8267
|
+
const updatedFields = Object.keys(updateData);
|
|
8268
|
+
return {
|
|
8269
|
+
content: [{
|
|
8270
|
+
type: 'text',
|
|
8271
|
+
text: `✅ ${type} updated successfully!
|
|
8272
|
+
|
|
8273
|
+
📝 **Updated Artifact:**
|
|
8274
|
+
- Name: ${existingArtifact.name}
|
|
8275
|
+
- sys_id: ${existingArtifact.sys_id}
|
|
8276
|
+
- Table: ${tableName}
|
|
8277
|
+
|
|
8278
|
+
🔧 **Fields Updated:**
|
|
8279
|
+
${updatedFields.map(field => `- ${field}`).join('\n')}
|
|
8280
|
+
|
|
8281
|
+
${updateSetSession ? `📦 **Update Set:**
|
|
8282
|
+
- Name: ${updateSetSession.name}
|
|
8283
|
+
- sys_id: ${updateSetSession.update_set_id}
|
|
8284
|
+
- Ready for promotion to higher environments` : '🔄 Changes made outside Update Set - track manually'}
|
|
8285
|
+
|
|
8286
|
+
💡 **Next Steps:**
|
|
8287
|
+
1. Test the updated ${type} in your environment
|
|
8288
|
+
2. ${updateSetSession ? 'Preview and commit Update Set when ready' : 'Create Update Set to track changes'}
|
|
8289
|
+
3. Promote to production after validation
|
|
8290
|
+
|
|
8291
|
+
🔗 **ServiceNow Links:**
|
|
8292
|
+
- View artifact: /nav_to.do?uri=${tableName}.do?sys_id=${existingArtifact.sys_id}
|
|
8293
|
+
${updateSetSession ? `- View Update Set: /nav_to.do?uri=sys_update_set.do?sys_id=${updateSetSession.update_set_id}` : ''}`
|
|
8294
|
+
}]
|
|
8295
|
+
};
|
|
8296
|
+
}
|
|
8297
|
+
catch (error) {
|
|
8298
|
+
this.logger.error('Artifact update failed:', error);
|
|
8299
|
+
return {
|
|
8300
|
+
content: [{
|
|
8301
|
+
type: 'text',
|
|
8302
|
+
text: `❌ Failed to update ${args.type}: ${error.message}
|
|
8303
|
+
|
|
8304
|
+
🔍 **Troubleshooting:**
|
|
8305
|
+
1. Verify the artifact exists: \`snow_query_table({ table: "${this.getTableName(args.type)}", query: "name=${args.identifier}" })\`
|
|
8306
|
+
2. Check permissions for ${this.getTableName(args.type)} table
|
|
8307
|
+
3. Ensure Update Set is active (if required)
|
|
8308
|
+
4. Try with create_if_not_exists: true if artifact might not exist
|
|
8309
|
+
|
|
8310
|
+
💡 **Alternative:**
|
|
8311
|
+
Use \`snow_deploy\` to create a new ${args.type} instead.`
|
|
8312
|
+
}]
|
|
8313
|
+
};
|
|
8314
|
+
}
|
|
8315
|
+
}
|
|
8316
|
+
/**
|
|
8317
|
+
* Process natural language instruction for updates
|
|
8318
|
+
*/
|
|
8319
|
+
async processUpdateInstruction(type, instruction, existingArtifact) {
|
|
8320
|
+
const updateData = {};
|
|
8321
|
+
// Simple natural language processing for common update patterns
|
|
8322
|
+
const lowerInstruction = instruction.toLowerCase();
|
|
8323
|
+
if (type === 'widget') {
|
|
8324
|
+
// Widget-specific updates
|
|
8325
|
+
if (lowerInstruction.includes('html') || lowerInstruction.includes('template')) {
|
|
8326
|
+
if (lowerInstruction.includes('add') || lowerInstruction.includes('update')) {
|
|
8327
|
+
// Extract HTML content if provided
|
|
8328
|
+
const htmlMatch = instruction.match(/```html\s*\n([\s\S]*?)\n```/);
|
|
8329
|
+
if (htmlMatch) {
|
|
8330
|
+
updateData.template = htmlMatch[1];
|
|
8331
|
+
}
|
|
8332
|
+
}
|
|
8333
|
+
}
|
|
8334
|
+
if (lowerInstruction.includes('css') || lowerInstruction.includes('style')) {
|
|
8335
|
+
const cssMatch = instruction.match(/```css\s*\n([\s\S]*?)\n```/);
|
|
8336
|
+
if (cssMatch) {
|
|
8337
|
+
updateData.css = cssMatch[1];
|
|
8338
|
+
}
|
|
8339
|
+
}
|
|
8340
|
+
if (lowerInstruction.includes('script') || lowerInstruction.includes('javascript')) {
|
|
8341
|
+
const jsMatch = instruction.match(/```javascript\s*\n([\s\S]*?)\n```/);
|
|
8342
|
+
if (jsMatch) {
|
|
8343
|
+
updateData.script = jsMatch[1];
|
|
8344
|
+
}
|
|
8345
|
+
}
|
|
8346
|
+
if (lowerInstruction.includes('server') || lowerInstruction.includes('server script')) {
|
|
8347
|
+
const serverMatch = instruction.match(/```javascript\s*\n([\s\S]*?)\n```/);
|
|
8348
|
+
if (serverMatch) {
|
|
8349
|
+
updateData.script = serverMatch[1];
|
|
8350
|
+
}
|
|
8351
|
+
}
|
|
8352
|
+
// Update description if mentioned
|
|
8353
|
+
if (lowerInstruction.includes('description')) {
|
|
8354
|
+
const descMatch = instruction.match(/description:?\s*["']([^"']+)["']/i);
|
|
8355
|
+
if (descMatch) {
|
|
8356
|
+
updateData.short_description = descMatch[1];
|
|
8357
|
+
}
|
|
8358
|
+
}
|
|
8359
|
+
}
|
|
8360
|
+
// If no specific patterns matched, add as general update
|
|
8361
|
+
if (Object.keys(updateData).length === 0) {
|
|
8362
|
+
// For now, return instruction for manual processing
|
|
8363
|
+
updateData._instruction = instruction;
|
|
8364
|
+
// You could add more sophisticated NLP processing here
|
|
8365
|
+
// or integrate with AI services to interpret the instruction
|
|
8366
|
+
}
|
|
8367
|
+
return updateData;
|
|
8368
|
+
}
|
|
8369
|
+
/**
|
|
8370
|
+
* Get table name for artifact type
|
|
8371
|
+
*/
|
|
8372
|
+
getTableName(type) {
|
|
8373
|
+
switch (type) {
|
|
8374
|
+
case 'widget':
|
|
8375
|
+
return 'sp_widget';
|
|
8376
|
+
case 'application':
|
|
8377
|
+
return 'sys_app';
|
|
8378
|
+
case 'business_rule':
|
|
8379
|
+
return 'sys_script';
|
|
8380
|
+
case 'script_include':
|
|
8381
|
+
return 'sys_script_include';
|
|
8382
|
+
case 'ui_page':
|
|
8383
|
+
return 'sys_ui_page';
|
|
8384
|
+
default:
|
|
8385
|
+
return 'sys_metadata';
|
|
8386
|
+
}
|
|
8387
|
+
}
|
|
8095
8388
|
async start() {
|
|
8096
8389
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
8097
8390
|
await this.server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.3.
|
|
4
|
-
"description": "Snow-Flow v3.3.
|
|
3
|
+
"version": "3.3.3",
|
|
4
|
+
"description": "Snow-Flow v3.3.3: ServiceNow development platform with 180+ MCP tools. NEW: snow_update tool for updating existing artifacts (vs snow_deploy for new). Enhanced MCP servers with real-time progress indicators, per-operation token tracking (tokens reset per call), and comprehensive operation logging. Supports ATF Testing, Knowledge Management, Service Catalog, Change Management, Virtual Agent, Performance Analytics, Flow Designer, Agent Workspace, Mobile, CMDB/Discovery, Event Management, HR Service Delivery, Customer Service Management, and DevOps integration. All tools use official ServiceNow REST APIs across 17 specialized MCP servers with full visibility into API operations.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|