snow-flow 3.5.9 → 3.5.10

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.
@@ -21,6 +21,7 @@ export declare class ServiceNowLocalDevelopmentMCP extends EnhancedBaseMCPServer
21
21
  private validateArtifactCoherence;
22
22
  private syncCleanup;
23
23
  private convertToES5;
24
+ private debugWidgetFetch;
24
25
  private pullWidget;
25
26
  private pushWidget;
26
27
  }
@@ -143,6 +143,20 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
143
143
  required: ['code']
144
144
  }
145
145
  },
146
+ {
147
+ name: 'snow_debug_widget_fetch',
148
+ description: 'Debug widget fetching to diagnose API issues',
149
+ inputSchema: {
150
+ type: 'object',
151
+ properties: {
152
+ sys_id: {
153
+ type: 'string',
154
+ description: 'Widget sys_id to debug'
155
+ }
156
+ },
157
+ required: ['sys_id']
158
+ }
159
+ },
146
160
  // Legacy compatibility tools
147
161
  {
148
162
  name: 'snow_pull_widget',
@@ -201,6 +215,9 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
201
215
  case 'snow_convert_to_es5':
202
216
  result = await this.convertToES5(args);
203
217
  break;
218
+ case 'snow_debug_widget_fetch':
219
+ result = await this.debugWidgetFetch(args);
220
+ break;
204
221
  // Legacy compatibility
205
222
  case 'snow_pull_widget':
206
223
  result = await this.pullWidget(args);
@@ -412,6 +429,58 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
412
429
  ]
413
430
  };
414
431
  }
432
+ async debugWidgetFetch(args) {
433
+ const { sys_id } = args;
434
+ try {
435
+ const debugResults = await this.syncManager['smartFetcher'].debugFetchWidget(sys_id);
436
+ let summaryText = `šŸ” Debug Results for Widget ${sys_id}\n\n`;
437
+ // Check which methods worked
438
+ const methods = ['searchRecords', 'getRecord', 'searchRecordsWithFields'];
439
+ for (const method of methods) {
440
+ if (debugResults[method]) {
441
+ const widget = debugResults[method];
442
+ summaryText += `āœ… ${method}:\n`;
443
+ summaryText += ` - Fields: ${Object.keys(widget).length}\n`;
444
+ summaryText += ` - Has script: ${!!widget.script}\n`;
445
+ summaryText += ` - Has client_script: ${!!widget.client_script}\n`;
446
+ summaryText += ` - Has template: ${!!widget.template}\n`;
447
+ summaryText += ` - Script size: ${widget.script?.length || 0} chars\n`;
448
+ summaryText += ` - Client script size: ${widget.client_script?.length || 0} chars\n`;
449
+ summaryText += ` - Template size: ${widget.template?.length || 0} chars\n\n`;
450
+ }
451
+ else {
452
+ summaryText += `āŒ ${method}: Failed\n\n`;
453
+ }
454
+ }
455
+ // Recommend best approach
456
+ const workingMethods = methods.filter(m => debugResults[m]);
457
+ if (workingMethods.length > 0) {
458
+ summaryText += `\nšŸ“Š Recommendation: Use ${workingMethods[0]} for fetching this widget.`;
459
+ }
460
+ else {
461
+ summaryText += `\nāš ļø All fetch methods failed. There may be an authentication or permission issue.`;
462
+ }
463
+ return {
464
+ content: [
465
+ {
466
+ type: 'text',
467
+ text: summaryText
468
+ }
469
+ ]
470
+ };
471
+ }
472
+ catch (error) {
473
+ const errorMessage = error instanceof Error ? error.message : String(error);
474
+ return {
475
+ content: [
476
+ {
477
+ type: 'text',
478
+ text: `āŒ Debug failed: ${errorMessage}`
479
+ }
480
+ ]
481
+ };
482
+ }
483
+ }
415
484
  // Legacy compatibility methods
416
485
  async pullWidget(args) {
417
486
  return this.pullArtifact({ ...args, table: 'sp_widget' });
@@ -52,24 +52,29 @@ class ArtifactLocalSync {
52
52
  this.artifacts = new Map();
53
53
  this.client = client;
54
54
  this.smartFetcher = new smart_field_fetcher_js_1.SmartFieldFetcher(client);
55
+ // Version check for debugging
56
+ console.log(`šŸ”§ ArtifactLocalSync v3.5.10 initializing...`);
55
57
  // Use custom directory, environment variable, or default to current project's servicenow folder
56
58
  if (customBaseDir) {
57
59
  this.baseDir = customBaseDir;
60
+ console.log(` šŸ“ Using custom directory: ${customBaseDir}`);
58
61
  }
59
62
  else if (process.env.SNOW_FLOW_ARTIFACTS_DIR) {
60
63
  this.baseDir = process.env.SNOW_FLOW_ARTIFACTS_DIR;
64
+ console.log(` šŸ“ Using environment variable directory: ${this.baseDir}`);
61
65
  }
62
66
  else {
63
67
  // Default to 'servicenow' folder in current working directory
64
68
  this.baseDir = path.join(process.cwd(), 'servicenow');
69
+ console.log(` šŸ“ Using project directory: ${this.baseDir}`);
65
70
  }
66
71
  // Create base directory if it doesn't exist
67
72
  if (!fs.existsSync(this.baseDir)) {
68
73
  fs.mkdirSync(this.baseDir, { recursive: true });
69
- console.log(`šŸ“ Created ServiceNow artifacts directory: ${this.baseDir}`);
74
+ console.log(` āœ… Created ServiceNow artifacts directory`);
70
75
  }
71
76
  else {
72
- console.log(`šŸ“ Using ServiceNow artifacts directory: ${this.baseDir}`);
77
+ console.log(` āœ… Directory exists`);
73
78
  }
74
79
  // Create .gitignore if it doesn't exist to optionally exclude from version control
75
80
  const gitignorePath = path.join(this.baseDir, '.gitignore');
@@ -46,7 +46,7 @@ class ServiceNowClientWithTracking extends servicenow_client_js_1.ServiceNowClie
46
46
  // Estimate tokens based on fields requested
47
47
  const fieldCount = fields.length;
48
48
  const estimatedTokens = Math.min(fieldCount * 100, 1000); // Rough estimate
49
- this.mcpLogger.trackTokens(estimatedTokens, 0);
49
+ this.mcpLogger.addTokens(estimatedTokens, 0);
50
50
  if (result?.data?.result?.length > 0) {
51
51
  this.mcpLogger.info(`Found ${result.data.result.length} records with ${fieldCount} fields`);
52
52
  }
@@ -52,6 +52,10 @@ export declare class SmartFieldFetcher {
52
52
  * Search within fields using GlideRecord queries
53
53
  */
54
54
  searchInField(table: string, field: string, searchTerm: string, additionalQuery?: string): Promise<any[]>;
55
+ /**
56
+ * Debug method to directly test API calls
57
+ */
58
+ debugFetchWidget(sys_id: string): Promise<any>;
55
59
  /**
56
60
  * Get smart fetch strategy based on table - NOW USES ARTIFACT REGISTRY!
57
61
  */
@@ -163,8 +163,8 @@ class SmartFieldFetcher {
163
163
  try {
164
164
  // Try to get all fields at once
165
165
  const response = await this.client.searchRecords('sp_widget', `sys_id=${sys_id}`, 1);
166
- if (response && response.result && response.result.length > 0) {
167
- const widgetData = response.result[0];
166
+ if (response && response.success && response.data && response.data.result && response.data.result.length > 0) {
167
+ const widgetData = response.data.result[0];
168
168
  console.log(`āœ… Successfully fetched complete widget`);
169
169
  // Organize into field groups for better context
170
170
  for (const group of WIDGET_FIELD_GROUPS) {
@@ -184,68 +184,72 @@ class SmartFieldFetcher {
184
184
  Object.assign(results, widgetData);
185
185
  }
186
186
  else {
187
- throw new Error('Widget not found');
187
+ throw new Error('Widget not found or no data returned');
188
188
  }
189
189
  }
190
190
  catch (error) {
191
191
  console.log(`āš ļø Complete fetch failed: ${error.message}`);
192
- console.log(`šŸ”„ Switching to field-by-field fetching...`);
193
- // Fall back to fetching fields per group or individually
194
- for (const group of WIDGET_FIELD_GROUPS) {
195
- console.log(`šŸ“¦ Fetching ${group.groupName}: ${group.description}`);
196
- try {
197
- // Try to fetch all fields in this group at once
198
- const groupResponse = await this.client.searchRecordsWithFields('sp_widget', `sys_id=${sys_id}`, group.fields, 1);
199
- if (groupResponse && groupResponse.success && groupResponse.data && groupResponse.data.result && groupResponse.data.result.length > 0) {
200
- const groupData = groupResponse.data.result[0];
201
- console.log(` āœ… Successfully fetched ${group.groupName}`);
192
+ console.log(`šŸ”„ Switching to more robust fetching approach...`);
193
+ // First, get the widget with minimal fields to ensure it exists
194
+ try {
195
+ const basicResponse = await this.client.searchRecords('sp_widget', `sys_id=${sys_id}`, 1);
196
+ if (!basicResponse || !basicResponse.success || !basicResponse.data || !basicResponse.data.result || basicResponse.data.result.length === 0) {
197
+ throw new Error(`Widget with sys_id ${sys_id} not found`);
198
+ }
199
+ // Widget exists, now get it via getRecord which might handle large fields better
200
+ const widgetData = basicResponse.data.result[0];
201
+ // Store what we got
202
+ if (widgetData) {
203
+ // Add all available fields to results
204
+ Object.assign(results, widgetData);
205
+ // Organize into field groups
206
+ for (const group of WIDGET_FIELD_GROUPS) {
207
+ const groupData = {};
208
+ for (const fieldName of group.fields) {
209
+ if (widgetData[fieldName] !== undefined) {
210
+ groupData[fieldName] = widgetData[fieldName];
211
+ }
212
+ }
202
213
  results._field_groups[group.groupName] = {
203
214
  data: groupData,
204
215
  description: group.description,
205
216
  fields: group.fields
206
217
  };
207
- // Add to flat structure
208
- Object.assign(results, groupData);
209
- }
210
- else {
211
- throw new Error('No data returned for group');
212
218
  }
219
+ // Log what we got
220
+ console.log(`šŸ“Š Retrieved widget fields:`);
221
+ console.log(` - name: ${widgetData.name || 'N/A'}`);
222
+ console.log(` - template: ${widgetData.template ? widgetData.template.length + ' chars' : 'empty'}`);
223
+ console.log(` - script: ${widgetData.script ? widgetData.script.length + ' chars' : 'empty'}`);
224
+ console.log(` - client_script: ${widgetData.client_script ? widgetData.client_script.length + ' chars' : 'empty'}`);
225
+ console.log(` - css: ${widgetData.css ? widgetData.css.length + ' chars' : 'empty'}`);
213
226
  }
214
- catch (groupError) {
215
- console.log(` āš ļø Group ${group.groupName} failed, fetching fields individually...`);
216
- // If group fails, fetch fields one by one
217
- const groupData = {};
218
- for (const fieldName of group.fields) {
219
- console.log(` šŸ“„ Fetching field: ${fieldName}`);
220
- try {
221
- // Fetch just this single field
222
- const fieldResponse = await this.client.searchRecordsWithFields('sp_widget', `sys_id=${sys_id}`, [fieldName], 1);
223
- if (fieldResponse && fieldResponse.success && fieldResponse.data && fieldResponse.data.result && fieldResponse.data.result.length > 0) {
224
- const fieldValue = fieldResponse.data.result[0][fieldName];
225
- if (fieldValue !== undefined && fieldValue !== null) {
226
- groupData[fieldName] = fieldValue;
227
- results[fieldName] = fieldValue; // Also add to flat structure
228
- console.log(` āœ… Got ${fieldName} (${typeof fieldValue === 'string' ? fieldValue.length : 0} chars)`);
229
- }
230
- else {
231
- groupData[fieldName] = '';
232
- console.log(` āš ļø ${fieldName} is empty`);
233
- }
234
- }
235
- }
236
- catch (fieldError) {
237
- console.log(` āŒ Failed to fetch ${fieldName}: ${fieldError.message}`);
238
- groupData[fieldName] = ''; // Empty string for failed fields
239
- }
227
+ // If critical fields are missing, try alternative approach
228
+ if (!widgetData.script && !widgetData.client_script && !widgetData.template) {
229
+ console.log(`āš ļø Critical fields missing, trying direct API call...`);
230
+ // Try using getRecord instead of searchRecords
231
+ const directResponse = await this.client.getRecord('sp_widget', sys_id);
232
+ if (directResponse && directResponse.success && directResponse.data && directResponse.data.result) {
233
+ const directData = directResponse.data.result;
234
+ // Merge any new data we got
235
+ Object.assign(results, directData);
236
+ console.log(`šŸ“Š Direct API retrieved:`);
237
+ console.log(` - template: ${directData.template ? directData.template.length + ' chars' : 'empty'}`);
238
+ console.log(` - script: ${directData.script ? directData.script.length + ' chars' : 'empty'}`);
239
+ console.log(` - client_script: ${directData.client_script ? directData.client_script.length + ' chars' : 'empty'}`);
240
240
  }
241
- results._field_groups[group.groupName] = {
242
- data: groupData,
243
- description: group.description,
244
- fields: group.fields,
245
- _fetched_individually: true
246
- };
247
241
  }
248
242
  }
243
+ catch (fallbackError) {
244
+ console.log(`āŒ All fetch attempts failed: ${fallbackError.message}`);
245
+ // At least return basic structure with sys_id
246
+ results.sys_id = sys_id;
247
+ results.name = 'Unknown Widget';
248
+ results.template = '';
249
+ results.script = '';
250
+ results.client_script = '';
251
+ results.css = '';
252
+ }
249
253
  // Make sure we have at least the sys_id
250
254
  if (!results.sys_id) {
251
255
  results.sys_id = sys_id;
@@ -350,6 +354,69 @@ class SmartFieldFetcher {
350
354
  return [];
351
355
  }
352
356
  }
357
+ /**
358
+ * Debug method to directly test API calls
359
+ */
360
+ async debugFetchWidget(sys_id) {
361
+ console.log(`\nšŸ” DEBUG: Testing different fetch approaches for widget ${sys_id}\n`);
362
+ const results = {};
363
+ // Test 1: Basic searchRecords
364
+ try {
365
+ console.log(`Test 1: searchRecords...`);
366
+ const test1 = await this.client.searchRecords('sp_widget', `sys_id=${sys_id}`, 1);
367
+ console.log(` - Response structure: success=${test1?.success}, has data=${!!test1?.data}, has result=${!!test1?.data?.result}`);
368
+ if (test1?.data?.result?.[0]) {
369
+ const widget = test1.data.result[0];
370
+ console.log(` - Fields received: ${Object.keys(widget).join(', ')}`);
371
+ console.log(` - Script length: ${widget.script?.length || 0}`);
372
+ console.log(` - Client script length: ${widget.client_script?.length || 0}`);
373
+ console.log(` - Template length: ${widget.template?.length || 0}`);
374
+ results.searchRecords = widget;
375
+ }
376
+ }
377
+ catch (e) {
378
+ console.log(` āŒ Error: ${e.message}`);
379
+ }
380
+ // Test 2: getRecord
381
+ try {
382
+ console.log(`Test 2: getRecord...`);
383
+ const test2 = await this.client.getRecord('sp_widget', sys_id);
384
+ console.log(` - Response structure: success=${test2?.success}, has data=${!!test2?.data}, has result=${!!test2?.data?.result}`);
385
+ if (test2?.data?.result) {
386
+ const widget = test2.data.result;
387
+ console.log(` - Fields received: ${Object.keys(widget).join(', ')}`);
388
+ console.log(` - Script length: ${widget.script?.length || 0}`);
389
+ console.log(` - Client script length: ${widget.client_script?.length || 0}`);
390
+ console.log(` - Template length: ${widget.template?.length || 0}`);
391
+ results.getRecord = widget;
392
+ }
393
+ }
394
+ catch (e) {
395
+ console.log(` āŒ Error: ${e.message}`);
396
+ }
397
+ // Test 3: searchRecordsWithFields
398
+ try {
399
+ console.log(`Test 3: searchRecordsWithFields with specific fields...`);
400
+ const test3 = await this.client.searchRecordsWithFields('sp_widget', `sys_id=${sys_id}`, ['name', 'script', 'client_script', 'template', 'css'], 1);
401
+ console.log(` - Response structure: success=${test3?.success}, has data=${!!test3?.data}, has result=${!!test3?.data?.result}`);
402
+ if (test3?.data?.result?.[0]) {
403
+ const widget = test3.data.result[0];
404
+ console.log(` - Fields received: ${Object.keys(widget).join(', ')}`);
405
+ console.log(` - Script length: ${widget.script?.length || 0}`);
406
+ console.log(` - Client script length: ${widget.client_script?.length || 0}`);
407
+ console.log(` - Template length: ${widget.template?.length || 0}`);
408
+ results.searchRecordsWithFields = widget;
409
+ }
410
+ }
411
+ catch (e) {
412
+ console.log(` āŒ Error: ${e.message}`);
413
+ }
414
+ console.log(`\nšŸ“Š Debug Results Summary:`);
415
+ console.log(` - searchRecords got: ${results.searchRecords ? Object.keys(results.searchRecords).length + ' fields' : 'failed'}`);
416
+ console.log(` - getRecord got: ${results.getRecord ? Object.keys(results.getRecord).length + ' fields' : 'failed'}`);
417
+ console.log(` - searchRecordsWithFields got: ${results.searchRecordsWithFields ? Object.keys(results.searchRecordsWithFields).length + ' fields' : 'failed'}`);
418
+ return results;
419
+ }
353
420
  /**
354
421
  * Get smart fetch strategy based on table - NOW USES ARTIFACT REGISTRY!
355
422
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "3.5.9",
3
+ "version": "3.5.10",
4
4
  "description": "ServiceNow development framework with MCP server integration. Executes background scripts using ES5 JavaScript only (ServiceNow Rhino engine requirement). Provides 18 MCP servers including local development sync for editing ServiceNow artifacts with Claude Code native tools, widget deployment with coherence validation, table operations, script execution, machine learning, advanced features, and comprehensive platform management.",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",