snow-flow 3.5.8 → 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' });
@@ -37,7 +37,7 @@ export declare class ArtifactLocalSync {
37
37
  private artifacts;
38
38
  private client;
39
39
  private smartFetcher;
40
- constructor(client: ServiceNowClient);
40
+ constructor(client: ServiceNowClient, customBaseDir?: string);
41
41
  /**
42
42
  * DYNAMIC pull artifact from ServiceNow using artifact registry
43
43
  * Works with ANY artifact type defined in the registry!
@@ -45,20 +45,76 @@ Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.ArtifactLocalSync = void 0;
46
46
  const fs = __importStar(require("fs"));
47
47
  const path = __importStar(require("path"));
48
- const os = __importStar(require("os"));
49
48
  const smart_field_fetcher_js_1 = require("./smart-field-fetcher.js");
50
49
  const artifact_registry_1 = require("./artifact-sync/artifact-registry");
51
50
  class ArtifactLocalSync {
52
- constructor(client) {
51
+ constructor(client, customBaseDir) {
53
52
  this.artifacts = new Map();
54
53
  this.client = client;
55
54
  this.smartFetcher = new smart_field_fetcher_js_1.SmartFieldFetcher(client);
56
- // Create base directory for Snow-Flow artifacts
57
- this.baseDir = path.join(os.tmpdir(), 'snow-flow-artifacts');
55
+ // Version check for debugging
56
+ console.log(`šŸ”§ ArtifactLocalSync v3.5.10 initializing...`);
57
+ // Use custom directory, environment variable, or default to current project's servicenow folder
58
+ if (customBaseDir) {
59
+ this.baseDir = customBaseDir;
60
+ console.log(` šŸ“ Using custom directory: ${customBaseDir}`);
61
+ }
62
+ else if (process.env.SNOW_FLOW_ARTIFACTS_DIR) {
63
+ this.baseDir = process.env.SNOW_FLOW_ARTIFACTS_DIR;
64
+ console.log(` šŸ“ Using environment variable directory: ${this.baseDir}`);
65
+ }
66
+ else {
67
+ // Default to 'servicenow' folder in current working directory
68
+ this.baseDir = path.join(process.cwd(), 'servicenow');
69
+ console.log(` šŸ“ Using project directory: ${this.baseDir}`);
70
+ }
71
+ // Create base directory if it doesn't exist
58
72
  if (!fs.existsSync(this.baseDir)) {
59
73
  fs.mkdirSync(this.baseDir, { recursive: true });
74
+ console.log(` āœ… Created ServiceNow artifacts directory`);
75
+ }
76
+ else {
77
+ console.log(` āœ… Directory exists`);
78
+ }
79
+ // Create .gitignore if it doesn't exist to optionally exclude from version control
80
+ const gitignorePath = path.join(this.baseDir, '.gitignore');
81
+ if (!fs.existsSync(gitignorePath)) {
82
+ fs.writeFileSync(gitignorePath, '# ServiceNow Artifacts\n' +
83
+ '# Uncomment the following lines to exclude from version control:\n' +
84
+ '# *\n' +
85
+ '# !.gitignore\n' +
86
+ '# !README.md\n');
87
+ }
88
+ // Create README if it doesn't exist
89
+ const readmePath = path.join(this.baseDir, 'README.md');
90
+ if (!fs.existsSync(readmePath)) {
91
+ fs.writeFileSync(readmePath, '# ServiceNow Artifacts Directory\n\n' +
92
+ 'This directory contains ServiceNow artifacts synchronized from your instance for local development.\n\n' +
93
+ '## Structure\n\n' +
94
+ '```\n' +
95
+ 'servicenow/\n' +
96
+ 'ā”œā”€ā”€ widgets/ # Service Portal widgets\n' +
97
+ 'ā”œā”€ā”€ script_includes/ # Script Includes\n' +
98
+ 'ā”œā”€ā”€ business_rules/ # Business Rules\n' +
99
+ 'ā”œā”€ā”€ flows/ # Flow Designer flows\n' +
100
+ 'ā”œā”€ā”€ ui_pages/ # UI Pages\n' +
101
+ '└── ... # Other artifact types\n' +
102
+ '```\n\n' +
103
+ '## Workflow\n\n' +
104
+ '1. **Pull artifacts**: `snow_pull_artifact` downloads artifacts here\n' +
105
+ '2. **Edit locally**: Use your IDE/editor to modify files\n' +
106
+ '3. **Push changes**: `snow_push_artifact` syncs changes back to ServiceNow\n' +
107
+ '4. **Clean up**: `snow_sync_cleanup` removes local files after sync\n\n' +
108
+ '## Version Control\n\n' +
109
+ 'You can choose to:\n' +
110
+ '- **Track changes**: Keep artifacts in git for version history\n' +
111
+ '- **Ignore artifacts**: Edit `.gitignore` to exclude from git\n\n' +
112
+ '## Configuration\n\n' +
113
+ 'Set custom location with environment variable:\n' +
114
+ '```bash\n' +
115
+ 'export SNOW_FLOW_ARTIFACTS_DIR=/path/to/artifacts\n' +
116
+ '```\n');
60
117
  }
61
- console.log(`šŸ“ Snow-Flow local sync directory: ${this.baseDir}`);
62
118
  }
63
119
  /**
64
120
  * DYNAMIC pull artifact from ServiceNow using artifact registry
@@ -143,8 +199,11 @@ class ArtifactLocalSync {
143
199
  artifactConfig: config
144
200
  };
145
201
  this.artifacts.set(sys_id, artifact);
202
+ // Show relative path if in project directory
203
+ const relativePath = path.relative(process.cwd(), artifactPath);
204
+ const displayPath = relativePath.startsWith('..') ? artifactPath : relativePath;
146
205
  console.log(`āœ… ${config.displayName} synced to local files:`);
147
- console.log(`šŸ“ Location: ${artifactPath}`);
206
+ console.log(`šŸ“ Location: ${displayPath}`);
148
207
  console.log(`šŸ“„ Files created:`);
149
208
  files.forEach(f => console.log(` - ${f.filename} (${f.type})`));
150
209
  console.log(`\nšŸ’” Claude Code can now use its native tools on these files!`);
@@ -158,77 +217,6 @@ class ArtifactLocalSync {
158
217
  */
159
218
  async pullWidget(sys_id) {
160
219
  return this.pullArtifact('sp_widget', sys_id);
161
- console.log(`\nšŸ”„ Pulling widget ${sys_id} to local files...`);
162
- // Fetch widget with smart chunking
163
- const widget = await this.smartFetcher.fetchWidget(sys_id);
164
- // Create local directory structure
165
- const widgetName = this.sanitizeFilename(widget.name || `widget_${sys_id}`);
166
- const widgetPath = path.join(this.baseDir, 'widgets', widgetName);
167
- // Clean up any existing files
168
- if (fs.existsSync(widgetPath)) {
169
- fs.rmSync(widgetPath, { recursive: true });
170
- }
171
- fs.mkdirSync(widgetPath, { recursive: true });
172
- // Create local files for each widget component
173
- const files = [];
174
- // 1. HTML Template
175
- if (widget.template) {
176
- const htmlFile = this.createLocalFile(widgetPath, `${widgetName}.html`, widget.template, 'template', 'html', '<!-- ServiceNow Widget Template -->\n<!-- Widget: ' + widget.name + ' -->\n<!-- Bindings: {{data.x}} from server, ng-click calls client methods -->\n\n');
177
- files.push(htmlFile);
178
- }
179
- // 2. Server Script (ES5)
180
- if (widget.script) {
181
- const serverFile = this.createLocalFile(widgetPath, `${widgetName}.server.js`, widget.script, 'script', 'js', '/**\n * ServiceNow Widget Server Script (ES5 ONLY!)\n * Widget: ' + widget.name + '\n * \n * Available objects:\n * - data: Object to send to client\n * - input: Data from client\n * - options: Widget instance options\n * - gs: GlideSystem\n * - $sp: Service Portal API\n */\n\n(function() {\n', '\n})();');
182
- files.push(serverFile);
183
- }
184
- // 3. Client Script (AngularJS)
185
- if (widget.client_script) {
186
- const clientFile = this.createLocalFile(widgetPath, `${widgetName}.client.js`, widget.client_script, 'client_script', 'js', '/**\n * ServiceNow Widget Client Controller (AngularJS)\n * Widget: ' + widget.name + '\n * \n * Available objects:\n * - c: Widget controller (this)\n * - c.data: Data from server\n * - c.server: Server communication\n * - $scope: Angular scope\n */\n\nfunction(');
187
- files.push(clientFile);
188
- }
189
- // 4. CSS
190
- if (widget.css) {
191
- const cssFile = this.createLocalFile(widgetPath, `${widgetName}.css`, widget.css, 'css', 'css', '/* ServiceNow Widget Styles */\n/* Widget: ' + widget.name + ' */\n/* Prefix classes to avoid conflicts */\n\n');
192
- files.push(cssFile);
193
- }
194
- // 5. Widget Configuration (JSON)
195
- const config = {
196
- sys_id: widget.sys_id,
197
- name: widget.name,
198
- title: widget.title,
199
- option_schema: widget.option_schema,
200
- data_table: widget.data_table,
201
- roles: widget.roles,
202
- public: widget.public,
203
- _coherence_hints: widget._coherence_hints || []
204
- };
205
- const configFile = this.createLocalFile(widgetPath, `${widgetName}.config.json`, JSON.stringify(config, null, 2), 'metadata', 'json');
206
- files.push(configFile);
207
- // 6. README with context
208
- const readmeContent = this.generateWidgetReadme(widget, files);
209
- const readmeFile = this.createLocalFile(widgetPath, 'README.md', readmeContent, 'documentation', 'md');
210
- files.push(readmeFile);
211
- // Create artifact record
212
- const artifact = {
213
- sys_id: widget.sys_id,
214
- name: widget.name,
215
- type: 'widget',
216
- tableName: 'sp_widget', // Added missing tableName
217
- localPath: widgetPath,
218
- files: files,
219
- metadata: widget,
220
- syncStatus: 'synced',
221
- createdAt: new Date(),
222
- lastSyncedAt: new Date()
223
- };
224
- this.artifacts.set(sys_id, artifact);
225
- console.log(`āœ… Widget synced to local files:`);
226
- console.log(`šŸ“ Location: ${widgetPath}`);
227
- console.log(`šŸ“„ Files created:`);
228
- files.forEach(f => console.log(` - ${f.filename} (${f.type})`));
229
- console.log(`\nšŸ’” Claude Code can now use its native tools on these files!`);
230
- console.log(` Edit, search, refactor - then run 'pushWidget' to sync back.`);
231
- return artifact;
232
220
  }
233
221
  /**
234
222
  * DYNAMIC push local changes back to ServiceNow using artifact registry
@@ -336,60 +324,6 @@ class ArtifactLocalSync {
336
324
  */
337
325
  async pushWidget(sys_id) {
338
326
  return this.pushArtifact(sys_id);
339
- const artifact = this.artifacts.get(sys_id);
340
- if (!artifact) {
341
- throw new Error(`No local artifact found for ${sys_id}. Run pullWidget first.`);
342
- }
343
- console.log(`\nšŸ”„ Pushing local changes back to ServiceNow...`);
344
- // Read current content from all files
345
- const updates = {};
346
- let hasChanges = false;
347
- for (const file of artifact.files) {
348
- if (fs.existsSync(file.path)) {
349
- const currentContent = fs.readFileSync(file.path, 'utf8');
350
- // Strip our added headers/footers for comparison
351
- const cleanContent = this.stripAddedWrappers(currentContent, file.type);
352
- if (cleanContent !== file.originalContent) {
353
- hasChanges = true;
354
- file.currentContent = cleanContent;
355
- file.isModified = true;
356
- // Map back to ServiceNow field
357
- if (file.field && file.field !== 'documentation' && file.field !== 'metadata') {
358
- updates[file.field] = cleanContent;
359
- console.log(` šŸ“ Changed: ${file.filename} (${file.field})`);
360
- }
361
- }
362
- }
363
- }
364
- if (!hasChanges) {
365
- console.log(`āœ… No changes detected. Widget is up to date.`);
366
- return true;
367
- }
368
- // Validate ES5 compliance for server script
369
- if (updates.script) {
370
- const es5Issues = this.validateES5(updates.script);
371
- if (es5Issues.length > 0) {
372
- console.log(`\nāš ļø ES5 Validation Issues in server script:`);
373
- es5Issues.forEach(issue => console.log(` - ${issue}`));
374
- console.log(`\nā“ Continue with deployment anyway? (ServiceNow might fail)`);
375
- // In real implementation, prompt for confirmation
376
- }
377
- }
378
- // Update in ServiceNow
379
- try {
380
- console.log(`\nšŸ“¤ Updating widget in ServiceNow...`);
381
- await this.client.updateRecord('sp_widget', sys_id, updates);
382
- artifact.syncStatus = 'synced';
383
- artifact.lastSyncedAt = new Date();
384
- console.log(`āœ… Widget successfully updated in ServiceNow!`);
385
- console.log(`šŸ”— sys_id: ${sys_id}`);
386
- return true;
387
- }
388
- catch (error) {
389
- console.error(`āŒ Failed to update widget:`, error);
390
- artifact.syncStatus = 'pending_upload';
391
- return false;
392
- }
393
327
  }
394
328
  /**
395
329
  * Clean up local files after successful sync
@@ -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.8",
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",