snow-flow 3.5.5 → 3.5.8
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/dist/mcp/servicenow-local-development-mcp.d.ts +16 -1
- package/dist/mcp/servicenow-local-development-mcp.js +8 -3
- package/dist/mcp/shared/enhanced-base-mcp-server.d.ts +3 -2
- package/dist/mcp/shared/enhanced-base-mcp-server.js +1 -1
- package/dist/utils/artifact-local-sync.d.ts +1 -1
- package/dist/utils/artifact-local-sync.js +6 -14
- package/dist/utils/servicenow-client-with-tracking.d.ts +4 -0
- package/dist/utils/servicenow-client-with-tracking.js +22 -1
- package/dist/utils/servicenow-client.d.ts +4 -0
- package/dist/utils/servicenow-client.js +27 -0
- package/dist/utils/smart-field-fetcher.d.ts +1 -1
- package/dist/utils/smart-field-fetcher.js +94 -41
- package/package.json +1 -1
|
@@ -8,5 +8,20 @@
|
|
|
8
8
|
*
|
|
9
9
|
* THIS IS THE KEY TO POWERFUL SERVICENOW DEVELOPMENT!
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
import { EnhancedBaseMCPServer } from './shared/enhanced-base-mcp-server.js';
|
|
12
|
+
export declare class ServiceNowLocalDevelopmentMCP extends EnhancedBaseMCPServer {
|
|
13
|
+
private syncManager;
|
|
14
|
+
constructor();
|
|
15
|
+
private setupSyncManager;
|
|
16
|
+
private setupHandlers;
|
|
17
|
+
private pullArtifact;
|
|
18
|
+
private pushArtifact;
|
|
19
|
+
private getSyncStatus;
|
|
20
|
+
private listSupportedArtifacts;
|
|
21
|
+
private validateArtifactCoherence;
|
|
22
|
+
private syncCleanup;
|
|
23
|
+
private convertToES5;
|
|
24
|
+
private pullWidget;
|
|
25
|
+
private pushWidget;
|
|
26
|
+
}
|
|
12
27
|
//# sourceMappingURL=servicenow-local-development-mcp.d.ts.map
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* THIS IS THE KEY TO POWERFUL SERVICENOW DEVELOPMENT!
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.ServiceNowLocalDevelopmentMCP = void 0;
|
|
13
14
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
14
15
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
15
16
|
const enhanced_base_mcp_server_js_1 = require("./shared/enhanced-base-mcp-server.js");
|
|
@@ -211,7 +212,9 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
|
|
|
211
212
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
212
213
|
}
|
|
213
214
|
this.logger.info(`✅ Tool ${name} completed successfully`);
|
|
214
|
-
return
|
|
215
|
+
return {
|
|
216
|
+
content: result.content
|
|
217
|
+
};
|
|
215
218
|
}
|
|
216
219
|
catch (error) {
|
|
217
220
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -417,11 +420,13 @@ class ServiceNowLocalDevelopmentMCP extends enhanced_base_mcp_server_js_1.Enhanc
|
|
|
417
420
|
return this.pushArtifact(args);
|
|
418
421
|
}
|
|
419
422
|
}
|
|
423
|
+
exports.ServiceNowLocalDevelopmentMCP = ServiceNowLocalDevelopmentMCP;
|
|
420
424
|
// Start the server
|
|
421
425
|
async function main() {
|
|
422
|
-
const
|
|
426
|
+
const mcpServer = new ServiceNowLocalDevelopmentMCP();
|
|
423
427
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
424
|
-
|
|
428
|
+
// Access server through a public method
|
|
429
|
+
await mcpServer.server.connect(transport);
|
|
425
430
|
console.error('🚀 ServiceNow Local Development MCP Server started');
|
|
426
431
|
}
|
|
427
432
|
if (require.main === module) {
|
|
@@ -4,18 +4,19 @@
|
|
|
4
4
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
5
|
import { ServiceNowClientWithTracking } from '../../utils/servicenow-client-with-tracking.js';
|
|
6
6
|
import { MCPLogger } from './mcp-logger.js';
|
|
7
|
-
import {
|
|
7
|
+
import { ServiceNowOAuth } from '../../utils/snow-oauth.js';
|
|
8
8
|
export interface MCPToolResult {
|
|
9
9
|
content: Array<{
|
|
10
10
|
type: string;
|
|
11
11
|
text: string;
|
|
12
12
|
}>;
|
|
13
|
+
[key: string]: unknown;
|
|
13
14
|
}
|
|
14
15
|
export declare abstract class EnhancedBaseMCPServer {
|
|
15
16
|
protected server: Server;
|
|
16
17
|
protected client: ServiceNowClientWithTracking;
|
|
17
18
|
protected logger: MCPLogger;
|
|
18
|
-
protected oauth:
|
|
19
|
+
protected oauth: ServiceNowOAuth;
|
|
19
20
|
protected isAuthenticated: boolean;
|
|
20
21
|
constructor(name: string, version?: string);
|
|
21
22
|
/**
|
|
@@ -19,7 +19,7 @@ class EnhancedBaseMCPServer {
|
|
|
19
19
|
// Create enhanced client with tracking
|
|
20
20
|
this.client = new servicenow_client_with_tracking_js_1.ServiceNowClientWithTracking(this.logger);
|
|
21
21
|
// Initialize OAuth
|
|
22
|
-
this.oauth = new snow_oauth_js_1.
|
|
22
|
+
this.oauth = new snow_oauth_js_1.ServiceNowOAuth();
|
|
23
23
|
// Create server with capabilities
|
|
24
24
|
this.server = new index_js_1.Server({
|
|
25
25
|
name,
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* THIS IS THE BRIDGE BETWEEN SERVICENOW AND CLAUDE CODE!
|
|
9
9
|
*/
|
|
10
|
-
import { ServiceNowClient } from './servicenow-client';
|
|
10
|
+
import { ServiceNowClient } from './servicenow-client.js';
|
|
11
11
|
import { ArtifactTypeConfig, FieldMapping, ValidationResult } from './artifact-sync/artifact-registry';
|
|
12
12
|
export interface LocalArtifact {
|
|
13
13
|
sys_id: string;
|
|
@@ -46,13 +46,13 @@ exports.ArtifactLocalSync = void 0;
|
|
|
46
46
|
const fs = __importStar(require("fs"));
|
|
47
47
|
const path = __importStar(require("path"));
|
|
48
48
|
const os = __importStar(require("os"));
|
|
49
|
-
const
|
|
49
|
+
const smart_field_fetcher_js_1 = require("./smart-field-fetcher.js");
|
|
50
50
|
const artifact_registry_1 = require("./artifact-sync/artifact-registry");
|
|
51
51
|
class ArtifactLocalSync {
|
|
52
52
|
constructor(client) {
|
|
53
53
|
this.artifacts = new Map();
|
|
54
54
|
this.client = client;
|
|
55
|
-
this.smartFetcher = new
|
|
55
|
+
this.smartFetcher = new smart_field_fetcher_js_1.SmartFieldFetcher(client);
|
|
56
56
|
// Create base directory for Snow-Flow artifacts
|
|
57
57
|
this.baseDir = path.join(os.tmpdir(), 'snow-flow-artifacts');
|
|
58
58
|
if (!fs.existsSync(this.baseDir)) {
|
|
@@ -84,11 +84,7 @@ class ArtifactLocalSync {
|
|
|
84
84
|
else {
|
|
85
85
|
// Generic fetch for other types
|
|
86
86
|
const allFields = config.fieldMappings.map(fm => fm.serviceNowField);
|
|
87
|
-
const response = await this.client.
|
|
88
|
-
query: `sys_id=${sys_id}`,
|
|
89
|
-
fields: allFields.concat(['sys_id', 'sys_created_on', 'sys_updated_on']),
|
|
90
|
-
limit: 1
|
|
91
|
-
});
|
|
87
|
+
const response = await this.client.searchRecords(tableName, `sys_id=${sys_id}`, 1);
|
|
92
88
|
artifactData = response.result?.[0];
|
|
93
89
|
}
|
|
94
90
|
if (!artifactData) {
|
|
@@ -320,7 +316,7 @@ class ArtifactLocalSync {
|
|
|
320
316
|
// Update in ServiceNow
|
|
321
317
|
try {
|
|
322
318
|
console.log(`\n📤 Updating ${config.displayName} in ServiceNow...`);
|
|
323
|
-
await this.client.
|
|
319
|
+
await this.client.updateRecord(config.tableName, sys_id, updates);
|
|
324
320
|
artifact.syncStatus = 'synced';
|
|
325
321
|
artifact.lastSyncedAt = new Date();
|
|
326
322
|
console.log(`✅ ${config.displayName} successfully updated in ServiceNow!`);
|
|
@@ -382,7 +378,7 @@ class ArtifactLocalSync {
|
|
|
382
378
|
// Update in ServiceNow
|
|
383
379
|
try {
|
|
384
380
|
console.log(`\n📤 Updating widget in ServiceNow...`);
|
|
385
|
-
await this.client.
|
|
381
|
+
await this.client.updateRecord('sp_widget', sys_id, updates);
|
|
386
382
|
artifact.syncStatus = 'synced';
|
|
387
383
|
artifact.lastSyncedAt = new Date();
|
|
388
384
|
console.log(`✅ Widget successfully updated in ServiceNow!`);
|
|
@@ -647,11 +643,7 @@ snow-flow sync status ${widget.sys_id}
|
|
|
647
643
|
const tables = Object.keys(artifact_registry_1.ARTIFACT_REGISTRY);
|
|
648
644
|
for (const table of tables) {
|
|
649
645
|
try {
|
|
650
|
-
const response = await this.client.
|
|
651
|
-
query: `sys_id=${sys_id}`,
|
|
652
|
-
fields: ['sys_id'],
|
|
653
|
-
limit: 1
|
|
654
|
-
});
|
|
646
|
+
const response = await this.client.searchRecords(table, `sys_id=${sys_id}`, 1);
|
|
655
647
|
if (response.result?.[0]) {
|
|
656
648
|
console.log(`🎆 Found artifact in table: ${table}`);
|
|
657
649
|
return this.pullArtifact(table, sys_id);
|
|
@@ -10,6 +10,10 @@ export declare class ServiceNowClientWithTracking extends ServiceNowClient {
|
|
|
10
10
|
* Override makeRequest to add tracking
|
|
11
11
|
*/
|
|
12
12
|
makeRequest(config: any): Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* Override searchRecordsWithFields to add tracking
|
|
15
|
+
*/
|
|
16
|
+
searchRecordsWithFields(table: string, query: string, fields: string[], limit?: number): Promise<any>;
|
|
13
17
|
/**
|
|
14
18
|
* Override searchRecords to add tracking
|
|
15
19
|
*/
|
|
@@ -36,6 +36,27 @@ class ServiceNowClientWithTracking extends servicenow_client_js_1.ServiceNowClie
|
|
|
36
36
|
throw error;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Override searchRecordsWithFields to add tracking
|
|
41
|
+
*/
|
|
42
|
+
async searchRecordsWithFields(table, query, fields, limit = 10) {
|
|
43
|
+
this.mcpLogger.progress(`Searching ${table} with specific fields: ${fields.join(', ')}`);
|
|
44
|
+
try {
|
|
45
|
+
const result = await super.searchRecordsWithFields(table, query, fields, limit);
|
|
46
|
+
// Estimate tokens based on fields requested
|
|
47
|
+
const fieldCount = fields.length;
|
|
48
|
+
const estimatedTokens = Math.min(fieldCount * 100, 1000); // Rough estimate
|
|
49
|
+
this.mcpLogger.trackTokens(estimatedTokens, 0);
|
|
50
|
+
if (result?.data?.result?.length > 0) {
|
|
51
|
+
this.mcpLogger.info(`Found ${result.data.result.length} records with ${fieldCount} fields`);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
this.mcpLogger.error('Search with fields failed', error);
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
39
60
|
/**
|
|
40
61
|
* Override searchRecords to add tracking
|
|
41
62
|
*/
|
|
@@ -106,7 +127,7 @@ class ServiceNowClientWithTracking extends servicenow_client_js_1.ServiceNowClie
|
|
|
106
127
|
async getRecord(table, sysId, fields) {
|
|
107
128
|
this.mcpLogger.progress(`Fetching ${table} record: ${sysId}`);
|
|
108
129
|
try {
|
|
109
|
-
const result = await super.getRecord(table, sysId
|
|
130
|
+
const result = await super.getRecord(table, sysId);
|
|
110
131
|
// Estimate tokens
|
|
111
132
|
if (result?.data?.result) {
|
|
112
133
|
const responseSize = JSON.stringify(result.data.result).length;
|
|
@@ -156,6 +156,10 @@ export declare class ServiceNowClient {
|
|
|
156
156
|
* Get multiple records from a table
|
|
157
157
|
*/
|
|
158
158
|
getRecords(table: string, params?: any): Promise<ServiceNowAPIResponse<any[]>>;
|
|
159
|
+
/**
|
|
160
|
+
* Search records with specific fields
|
|
161
|
+
*/
|
|
162
|
+
searchRecordsWithFields(table: string, query: string, fields: string[], limit?: number): Promise<ServiceNowAPIResponse<any>>;
|
|
159
163
|
/**
|
|
160
164
|
* Search records in a table using encoded query
|
|
161
165
|
*/
|
|
@@ -1039,6 +1039,33 @@ class ServiceNowClient {
|
|
|
1039
1039
|
};
|
|
1040
1040
|
}
|
|
1041
1041
|
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Search records with specific fields
|
|
1044
|
+
*/
|
|
1045
|
+
async searchRecordsWithFields(table, query, fields, limit = 10) {
|
|
1046
|
+
try {
|
|
1047
|
+
await this.ensureAuthenticated();
|
|
1048
|
+
const url = `/api/now/table/${table}`;
|
|
1049
|
+
const params = {
|
|
1050
|
+
sysparm_query: query,
|
|
1051
|
+
sysparm_limit: limit.toString(),
|
|
1052
|
+
sysparm_fields: fields.join(',')
|
|
1053
|
+
};
|
|
1054
|
+
const response = await this.client.get(url, { params });
|
|
1055
|
+
return {
|
|
1056
|
+
success: true,
|
|
1057
|
+
data: response.data
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
catch (error) {
|
|
1061
|
+
console.error('API Error:', error);
|
|
1062
|
+
return {
|
|
1063
|
+
success: false,
|
|
1064
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1065
|
+
data: null
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1042
1069
|
/**
|
|
1043
1070
|
* Search records in a table using encoded query
|
|
1044
1071
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Intelligently fetches large artifacts by splitting fields into chunks
|
|
5
5
|
* while maintaining context relationships between fields.
|
|
6
6
|
*/
|
|
7
|
-
import { ServiceNowClient } from './servicenow-client';
|
|
7
|
+
import { ServiceNowClient } from './servicenow-client.js';
|
|
8
8
|
export interface FetchStrategy {
|
|
9
9
|
table: string;
|
|
10
10
|
sys_id: string;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.SmartFieldFetcher = void 0;
|
|
10
10
|
exports.createFetchStrategyHint = createFetchStrategyHint;
|
|
11
|
-
const
|
|
11
|
+
const artifact_registry_js_1 = require("./artifact-sync/artifact-registry.js");
|
|
12
12
|
// Widget field groups with relationship context - 20K per field for better context
|
|
13
13
|
const WIDGET_FIELD_GROUPS = [
|
|
14
14
|
{
|
|
@@ -112,7 +112,7 @@ class SmartFieldFetcher {
|
|
|
112
112
|
async fetchArtifact(table, sys_id) {
|
|
113
113
|
console.log(`\n🔍 Smart fetching ${table}: ${sys_id}`);
|
|
114
114
|
const fieldGroups = this.getFieldGroups(table);
|
|
115
|
-
const config = (0,
|
|
115
|
+
const config = (0, artifact_registry_js_1.getArtifactConfig)(table);
|
|
116
116
|
const results = {
|
|
117
117
|
_fetch_strategy: 'smart_chunked',
|
|
118
118
|
_context_hint: config ? `${config.displayName} - fields fetched in groups to respect token limits` : 'Fields fetched separately but are related',
|
|
@@ -122,14 +122,10 @@ class SmartFieldFetcher {
|
|
|
122
122
|
for (const group of fieldGroups) {
|
|
123
123
|
console.log(`📦 Fetching ${group.groupName}: ${group.description}`);
|
|
124
124
|
try {
|
|
125
|
-
const response = await this.client.
|
|
126
|
-
|
|
127
|
-
fields: group.fields,
|
|
128
|
-
limit: 1
|
|
129
|
-
});
|
|
130
|
-
if (response.result?.[0]) {
|
|
125
|
+
const response = await this.client.getRecord(table, sys_id);
|
|
126
|
+
if (response) {
|
|
131
127
|
results._field_groups[group.groupName] = {
|
|
132
|
-
data: response
|
|
128
|
+
data: response,
|
|
133
129
|
description: group.description,
|
|
134
130
|
fields: group.fields
|
|
135
131
|
};
|
|
@@ -156,38 +152,103 @@ class SmartFieldFetcher {
|
|
|
156
152
|
* (Wrapper for backward compatibility)
|
|
157
153
|
*/
|
|
158
154
|
async fetchWidget(sys_id) {
|
|
159
|
-
return this.fetchArtifact('sp_widget', sys_id);
|
|
160
155
|
console.log(`\n🔍 Smart fetching widget: ${sys_id}`);
|
|
161
156
|
const results = {
|
|
162
157
|
_fetch_strategy: 'smart_chunked',
|
|
163
158
|
_context_hint: 'Widget fields fetched separately but are interconnected: template references {{data.x}} from server script, calls methods from client script, and uses CSS classes',
|
|
164
159
|
_field_groups: {}
|
|
165
160
|
};
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
161
|
+
// Try to fetch all fields first, then fall back to individual fields if too large
|
|
162
|
+
console.log(`📦 Attempting to fetch complete widget data...`);
|
|
163
|
+
try {
|
|
164
|
+
// Try to get all fields at once
|
|
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];
|
|
168
|
+
console.log(`✅ Successfully fetched complete widget`);
|
|
169
|
+
// Organize into field groups for better context
|
|
170
|
+
for (const group of WIDGET_FIELD_GROUPS) {
|
|
171
|
+
const groupData = {};
|
|
172
|
+
for (const fieldName of group.fields) {
|
|
173
|
+
if (widgetData[fieldName] !== undefined) {
|
|
174
|
+
groupData[fieldName] = widgetData[fieldName];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
176
177
|
results._field_groups[group.groupName] = {
|
|
177
|
-
data:
|
|
178
|
+
data: groupData,
|
|
178
179
|
description: group.description,
|
|
179
180
|
fields: group.fields
|
|
180
181
|
};
|
|
181
|
-
// Add to flat structure for easy access
|
|
182
|
-
Object.assign(results, response.result[0]);
|
|
183
182
|
}
|
|
183
|
+
// Add complete widget data to flat structure
|
|
184
|
+
Object.assign(results, widgetData);
|
|
184
185
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
else {
|
|
187
|
+
throw new Error('Widget not found');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
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}`);
|
|
202
|
+
results._field_groups[group.groupName] = {
|
|
203
|
+
data: groupData,
|
|
204
|
+
description: group.description,
|
|
205
|
+
fields: group.fields
|
|
206
|
+
};
|
|
207
|
+
// Add to flat structure
|
|
208
|
+
Object.assign(results, groupData);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
throw new Error('No data returned for group');
|
|
212
|
+
}
|
|
190
213
|
}
|
|
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
|
+
}
|
|
240
|
+
}
|
|
241
|
+
results._field_groups[group.groupName] = {
|
|
242
|
+
data: groupData,
|
|
243
|
+
description: group.description,
|
|
244
|
+
fields: group.fields,
|
|
245
|
+
_fetched_individually: true
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// Make sure we have at least the sys_id
|
|
250
|
+
if (!results.sys_id) {
|
|
251
|
+
results.sys_id = sys_id;
|
|
191
252
|
}
|
|
192
253
|
}
|
|
193
254
|
// Add coherence validation hints
|
|
@@ -222,13 +283,9 @@ class SmartFieldFetcher {
|
|
|
222
283
|
for (const field of fields) {
|
|
223
284
|
try {
|
|
224
285
|
console.log(` 📄 Fetching field: ${field}`);
|
|
225
|
-
const response = await this.client.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
limit: 1
|
|
229
|
-
});
|
|
230
|
-
if (response.result?.[0]) {
|
|
231
|
-
result.data[field] = response.result[0][field];
|
|
286
|
+
const response = await this.client.getRecord(table, sys_id);
|
|
287
|
+
if (response) {
|
|
288
|
+
result.data[field] = response[field];
|
|
232
289
|
result._field_status[field] = 'success';
|
|
233
290
|
}
|
|
234
291
|
}
|
|
@@ -284,11 +341,7 @@ class SmartFieldFetcher {
|
|
|
284
341
|
// Use CONTAINS operator for field search
|
|
285
342
|
const query = `${field}CONTAINS${searchTerm}${additionalQuery ? '^' + additionalQuery : ''}`;
|
|
286
343
|
try {
|
|
287
|
-
const response = await this.client.
|
|
288
|
-
query: query,
|
|
289
|
-
fields: ['sys_id', 'name', field.substring(0, 50)], // Get preview of field
|
|
290
|
-
limit: 10
|
|
291
|
-
});
|
|
344
|
+
const response = await this.client.searchRecords(table, query, 10);
|
|
292
345
|
console.log(` ✅ Found ${response.result?.length || 0} matches`);
|
|
293
346
|
return response.result || [];
|
|
294
347
|
}
|
|
@@ -311,7 +364,7 @@ class SmartFieldFetcher {
|
|
|
311
364
|
return BUSINESS_RULE_FIELD_GROUPS;
|
|
312
365
|
}
|
|
313
366
|
// Try to get from artifact registry
|
|
314
|
-
const config = (0,
|
|
367
|
+
const config = (0, artifact_registry_js_1.getArtifactConfig)(table);
|
|
315
368
|
if (config) {
|
|
316
369
|
return this.createFieldGroupsFromRegistry(config);
|
|
317
370
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.8",
|
|
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",
|