snow-flow 3.4.39 → 3.5.1
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 +11 -9
- package/dist/index.d.ts +4 -0
- package/dist/index.js +10 -2
- package/dist/mcp/enhancements/smart-query-enhancement.d.ts +49 -0
- package/dist/mcp/enhancements/smart-query-enhancement.js +233 -0
- package/dist/mcp/servicenow-local-development-mcp.d.ts +48 -0
- package/dist/mcp/servicenow-local-development-mcp.js +570 -0
- package/dist/queen/queen-knowledge-base.d.ts +151 -0
- package/dist/queen/queen-knowledge-base.js +283 -0
- package/dist/queen/servicenow-queen.d.ts +2 -0
- package/dist/queen/servicenow-queen.js +91 -0
- package/dist/utils/artifact-local-sync.d.ts +115 -0
- package/dist/utils/artifact-local-sync.js +705 -0
- package/dist/utils/artifact-sync/artifact-registry.d.ts +66 -0
- package/dist/utils/artifact-sync/artifact-registry.js +450 -0
- package/dist/utils/artifact-sync/index.d.ts +33 -0
- package/dist/utils/artifact-sync/index.js +52 -0
- package/dist/utils/mcp-tool-registry.js +109 -0
- package/dist/utils/smart-field-fetcher.d.ts +68 -0
- package/dist/utils/smart-field-fetcher.js +395 -0
- package/package.json +2 -2
- package/website/.dockerignore +64 -0
- package/website/Dockerfile +36 -0
- package/website/README.md +40 -1
- package/website/cloudbuild.yaml +69 -0
- package/website/css/style.css +119 -1
- package/website/index.html +385 -39
- package/website/js/main.js +26 -1
- package/website/nginx.conf +116 -0
- package/website/service.yaml +61 -0
|
@@ -75,6 +75,115 @@ class MCPToolRegistry {
|
|
|
75
75
|
actualTool: 'mcp__servicenow-deployment__snow_auth_diagnostics',
|
|
76
76
|
description: 'Authentication and permission diagnostics'
|
|
77
77
|
});
|
|
78
|
+
// Local Development Sync Tools
|
|
79
|
+
this.registerTool({
|
|
80
|
+
canonicalName: 'pull_artifact',
|
|
81
|
+
aliases: [
|
|
82
|
+
'mcp__servicenow-local-development__snow_pull_artifact',
|
|
83
|
+
'snow_pull_artifact',
|
|
84
|
+
'pull_artifact',
|
|
85
|
+
'sync_artifact',
|
|
86
|
+
'local_sync'
|
|
87
|
+
],
|
|
88
|
+
provider: 'servicenow-local-development',
|
|
89
|
+
actualTool: 'mcp__servicenow-local-development__snow_pull_artifact',
|
|
90
|
+
description: 'Pull any ServiceNow artifact to local files for editing'
|
|
91
|
+
});
|
|
92
|
+
this.registerTool({
|
|
93
|
+
canonicalName: 'push_artifact',
|
|
94
|
+
aliases: [
|
|
95
|
+
'mcp__servicenow-local-development__snow_push_artifact',
|
|
96
|
+
'snow_push_artifact',
|
|
97
|
+
'push_artifact',
|
|
98
|
+
'sync_back'
|
|
99
|
+
],
|
|
100
|
+
provider: 'servicenow-local-development',
|
|
101
|
+
actualTool: 'mcp__servicenow-local-development__snow_push_artifact',
|
|
102
|
+
description: 'Push local artifact changes back to ServiceNow'
|
|
103
|
+
});
|
|
104
|
+
this.registerTool({
|
|
105
|
+
canonicalName: 'validate_artifact_coherence',
|
|
106
|
+
aliases: [
|
|
107
|
+
'mcp__servicenow-local-development__snow_validate_artifact_coherence',
|
|
108
|
+
'snow_validate_artifact_coherence',
|
|
109
|
+
'validate_coherence',
|
|
110
|
+
'check_coherence'
|
|
111
|
+
],
|
|
112
|
+
provider: 'servicenow-local-development',
|
|
113
|
+
actualTool: 'mcp__servicenow-local-development__snow_validate_artifact_coherence',
|
|
114
|
+
description: 'Validate artifact coherence and relationships'
|
|
115
|
+
});
|
|
116
|
+
this.registerTool({
|
|
117
|
+
canonicalName: 'list_supported_artifacts',
|
|
118
|
+
aliases: [
|
|
119
|
+
'mcp__servicenow-local-development__snow_list_supported_artifacts',
|
|
120
|
+
'snow_list_supported_artifacts',
|
|
121
|
+
'supported_artifacts',
|
|
122
|
+
'artifact_types'
|
|
123
|
+
],
|
|
124
|
+
provider: 'servicenow-local-development',
|
|
125
|
+
actualTool: 'mcp__servicenow-local-development__snow_list_supported_artifacts',
|
|
126
|
+
description: 'List all supported artifact types for local sync'
|
|
127
|
+
});
|
|
128
|
+
this.registerTool({
|
|
129
|
+
canonicalName: 'sync_status',
|
|
130
|
+
aliases: [
|
|
131
|
+
'mcp__servicenow-local-development__snow_sync_status',
|
|
132
|
+
'snow_sync_status',
|
|
133
|
+
'local_status',
|
|
134
|
+
'sync_check'
|
|
135
|
+
],
|
|
136
|
+
provider: 'servicenow-local-development',
|
|
137
|
+
actualTool: 'mcp__servicenow-local-development__snow_sync_status',
|
|
138
|
+
description: 'Check sync status of local artifacts'
|
|
139
|
+
});
|
|
140
|
+
this.registerTool({
|
|
141
|
+
canonicalName: 'sync_cleanup',
|
|
142
|
+
aliases: [
|
|
143
|
+
'mcp__servicenow-local-development__snow_sync_cleanup',
|
|
144
|
+
'snow_sync_cleanup',
|
|
145
|
+
'cleanup_local',
|
|
146
|
+
'remove_local'
|
|
147
|
+
],
|
|
148
|
+
provider: 'servicenow-local-development',
|
|
149
|
+
actualTool: 'mcp__servicenow-local-development__snow_sync_cleanup',
|
|
150
|
+
description: 'Clean up local artifact files'
|
|
151
|
+
});
|
|
152
|
+
this.registerTool({
|
|
153
|
+
canonicalName: 'convert_to_es5',
|
|
154
|
+
aliases: [
|
|
155
|
+
'mcp__servicenow-local-development__snow_convert_to_es5',
|
|
156
|
+
'snow_convert_to_es5',
|
|
157
|
+
'es5_convert',
|
|
158
|
+
'transpile_es5'
|
|
159
|
+
],
|
|
160
|
+
provider: 'servicenow-local-development',
|
|
161
|
+
actualTool: 'mcp__servicenow-local-development__snow_convert_to_es5',
|
|
162
|
+
description: 'Convert modern JavaScript to ES5 for ServiceNow'
|
|
163
|
+
});
|
|
164
|
+
// Legacy widget/script tools (backward compatibility)
|
|
165
|
+
this.registerTool({
|
|
166
|
+
canonicalName: 'pull_widget',
|
|
167
|
+
aliases: [
|
|
168
|
+
'mcp__servicenow-local-development__snow_pull_widget',
|
|
169
|
+
'snow_pull_widget',
|
|
170
|
+
'pull_widget'
|
|
171
|
+
],
|
|
172
|
+
provider: 'servicenow-local-development',
|
|
173
|
+
actualTool: 'mcp__servicenow-local-development__snow_pull_widget',
|
|
174
|
+
description: 'Pull widget to local files (legacy - use pull_artifact)'
|
|
175
|
+
});
|
|
176
|
+
this.registerTool({
|
|
177
|
+
canonicalName: 'push_widget',
|
|
178
|
+
aliases: [
|
|
179
|
+
'mcp__servicenow-local-development__snow_push_widget',
|
|
180
|
+
'snow_push_widget',
|
|
181
|
+
'push_widget'
|
|
182
|
+
],
|
|
183
|
+
provider: 'servicenow-local-development',
|
|
184
|
+
actualTool: 'mcp__servicenow-local-development__snow_push_widget',
|
|
185
|
+
description: 'Push widget changes (legacy - use push_artifact)'
|
|
186
|
+
});
|
|
78
187
|
// Catalog item management
|
|
79
188
|
this.registerTool({
|
|
80
189
|
canonicalName: 'catalog_item_manager',
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Field Fetcher for ServiceNow Artifacts
|
|
3
|
+
*
|
|
4
|
+
* Intelligently fetches large artifacts by splitting fields into chunks
|
|
5
|
+
* while maintaining context relationships between fields.
|
|
6
|
+
*/
|
|
7
|
+
import { ServiceNowClient } from './servicenow-client';
|
|
8
|
+
export interface FetchStrategy {
|
|
9
|
+
table: string;
|
|
10
|
+
sys_id: string;
|
|
11
|
+
primaryFields: string[];
|
|
12
|
+
contentFields: string[];
|
|
13
|
+
contextHint?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface FieldGroup {
|
|
16
|
+
groupName: string;
|
|
17
|
+
fields: string[];
|
|
18
|
+
description: string;
|
|
19
|
+
maxTokens?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare class SmartFieldFetcher {
|
|
22
|
+
private client;
|
|
23
|
+
constructor(client: ServiceNowClient);
|
|
24
|
+
/**
|
|
25
|
+
* DYNAMIC fetch any artifact using registry configuration
|
|
26
|
+
*/
|
|
27
|
+
fetchArtifact(table: string, sys_id: string): Promise<any>;
|
|
28
|
+
/**
|
|
29
|
+
* Intelligently fetch widget fields with context preservation
|
|
30
|
+
* (Wrapper for backward compatibility)
|
|
31
|
+
*/
|
|
32
|
+
fetchWidget(sys_id: string): Promise<any>;
|
|
33
|
+
/**
|
|
34
|
+
* Fetch flow with intelligent chunking
|
|
35
|
+
* (Wrapper for backward compatibility)
|
|
36
|
+
*/
|
|
37
|
+
fetchFlow(sys_id: string): Promise<any>;
|
|
38
|
+
/**
|
|
39
|
+
* Fetch business rule with intelligent chunking
|
|
40
|
+
* (Wrapper for backward compatibility)
|
|
41
|
+
*/
|
|
42
|
+
fetchBusinessRule(sys_id: string): Promise<any>;
|
|
43
|
+
/**
|
|
44
|
+
* Fetch fields one by one when group is too large
|
|
45
|
+
*/
|
|
46
|
+
private fetchFieldsIndividually;
|
|
47
|
+
/**
|
|
48
|
+
* Generate coherence hints for widget validation
|
|
49
|
+
*/
|
|
50
|
+
private generateCoherenceHints;
|
|
51
|
+
/**
|
|
52
|
+
* Search within fields using GlideRecord queries
|
|
53
|
+
*/
|
|
54
|
+
searchInField(table: string, field: string, searchTerm: string, additionalQuery?: string): Promise<any[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Get smart fetch strategy based on table - NOW USES ARTIFACT REGISTRY!
|
|
57
|
+
*/
|
|
58
|
+
getFieldGroups(table: string): FieldGroup[];
|
|
59
|
+
/**
|
|
60
|
+
* Create field groups from artifact registry configuration
|
|
61
|
+
*/
|
|
62
|
+
private createFieldGroupsFromRegistry;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Helper function to create fetch strategy hint for Claude
|
|
66
|
+
*/
|
|
67
|
+
export declare function createFetchStrategyHint(table: string, sys_id: string): string;
|
|
68
|
+
//# sourceMappingURL=smart-field-fetcher.d.ts.map
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Smart Field Fetcher for ServiceNow Artifacts
|
|
4
|
+
*
|
|
5
|
+
* Intelligently fetches large artifacts by splitting fields into chunks
|
|
6
|
+
* while maintaining context relationships between fields.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.SmartFieldFetcher = void 0;
|
|
10
|
+
exports.createFetchStrategyHint = createFetchStrategyHint;
|
|
11
|
+
const artifact_registry_1 = require("./artifact-sync/artifact-registry");
|
|
12
|
+
// Widget field groups with relationship context - 20K per field for better context
|
|
13
|
+
const WIDGET_FIELD_GROUPS = [
|
|
14
|
+
{
|
|
15
|
+
groupName: 'metadata',
|
|
16
|
+
fields: ['sys_id', 'name', 'title', 'id', 'sys_created_on', 'sys_updated_on', 'sys_scope'],
|
|
17
|
+
description: 'Basic widget identification and metadata',
|
|
18
|
+
maxTokens: 2000
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
groupName: 'template',
|
|
22
|
+
fields: ['template'],
|
|
23
|
+
description: 'HTML template - defines UI structure and Angular bindings (ng-click, {{data.x}})',
|
|
24
|
+
maxTokens: 20000 // Increased to 20K
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
groupName: 'server_script',
|
|
28
|
+
fields: ['script'], // Note: 'script' is the actual field name, not 'server_script'
|
|
29
|
+
description: 'Server-side script (ES5 only) - initializes data object and handles input.action requests',
|
|
30
|
+
maxTokens: 20000 // Increased to 20K
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
groupName: 'client_script',
|
|
34
|
+
fields: ['client_script'],
|
|
35
|
+
description: 'Client-side AngularJS controller - implements methods called by template ng-click and calls c.server.get()',
|
|
36
|
+
maxTokens: 20000 // Increased to 20K
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
groupName: 'styling',
|
|
40
|
+
fields: ['css'],
|
|
41
|
+
description: 'Widget-specific CSS styles - classes used in template',
|
|
42
|
+
maxTokens: 20000 // Increased to 20K
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
groupName: 'configuration',
|
|
46
|
+
fields: ['option_schema', 'data_table', 'demo_data', 'public', 'roles'],
|
|
47
|
+
description: 'Widget configuration options, data sources and access control',
|
|
48
|
+
maxTokens: 10000 // Increased for better config context
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
groupName: 'dependencies',
|
|
52
|
+
fields: ['dependencies', 'link'],
|
|
53
|
+
description: 'Widget dependencies and Angular providers required',
|
|
54
|
+
maxTokens: 5000
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
// Flow field groups
|
|
58
|
+
const FLOW_FIELD_GROUPS = [
|
|
59
|
+
{
|
|
60
|
+
groupName: 'metadata',
|
|
61
|
+
fields: ['sys_id', 'name', 'label', 'description', 'active'],
|
|
62
|
+
description: 'Flow identification and basic info',
|
|
63
|
+
maxTokens: 1000
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
groupName: 'definition',
|
|
67
|
+
fields: ['definition'],
|
|
68
|
+
description: 'Complete flow definition JSON - contains all steps, actions, and conditions',
|
|
69
|
+
maxTokens: 20000
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
groupName: 'configuration',
|
|
73
|
+
fields: ['trigger_type', 'trigger_condition', 'run_as'],
|
|
74
|
+
description: 'Flow trigger and execution configuration',
|
|
75
|
+
maxTokens: 2000
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
// Business Rule field groups
|
|
79
|
+
const BUSINESS_RULE_FIELD_GROUPS = [
|
|
80
|
+
{
|
|
81
|
+
groupName: 'metadata',
|
|
82
|
+
fields: ['sys_id', 'name', 'collection', 'active', 'order'],
|
|
83
|
+
description: 'Business rule identification and table',
|
|
84
|
+
maxTokens: 1000
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
groupName: 'conditions',
|
|
88
|
+
fields: ['when', 'condition', 'filter_condition'],
|
|
89
|
+
description: 'When rule runs and filter conditions',
|
|
90
|
+
maxTokens: 2000
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
groupName: 'script',
|
|
94
|
+
fields: ['script'],
|
|
95
|
+
description: 'Business rule script (ES5) - current, previous, gs available',
|
|
96
|
+
maxTokens: 10000
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
groupName: 'advanced',
|
|
100
|
+
fields: ['advanced', 'role_conditions', 'abort_action'],
|
|
101
|
+
description: 'Advanced configuration and actions',
|
|
102
|
+
maxTokens: 2000
|
|
103
|
+
}
|
|
104
|
+
];
|
|
105
|
+
class SmartFieldFetcher {
|
|
106
|
+
constructor(client) {
|
|
107
|
+
this.client = client;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* DYNAMIC fetch any artifact using registry configuration
|
|
111
|
+
*/
|
|
112
|
+
async fetchArtifact(table, sys_id) {
|
|
113
|
+
console.log(`\n🔍 Smart fetching ${table}: ${sys_id}`);
|
|
114
|
+
const fieldGroups = this.getFieldGroups(table);
|
|
115
|
+
const config = (0, artifact_registry_1.getArtifactConfig)(table);
|
|
116
|
+
const results = {
|
|
117
|
+
_fetch_strategy: 'smart_chunked',
|
|
118
|
+
_context_hint: config ? `${config.displayName} - fields fetched in groups to respect token limits` : 'Fields fetched separately but are related',
|
|
119
|
+
_field_groups: {}
|
|
120
|
+
};
|
|
121
|
+
// Fetch each field group
|
|
122
|
+
for (const group of fieldGroups) {
|
|
123
|
+
console.log(`📦 Fetching ${group.groupName}: ${group.description}`);
|
|
124
|
+
try {
|
|
125
|
+
const response = await this.client.query(table, {
|
|
126
|
+
query: `sys_id=${sys_id}`,
|
|
127
|
+
fields: group.fields,
|
|
128
|
+
limit: 1
|
|
129
|
+
});
|
|
130
|
+
if (response.result?.[0]) {
|
|
131
|
+
results._field_groups[group.groupName] = {
|
|
132
|
+
data: response.result[0],
|
|
133
|
+
description: group.description,
|
|
134
|
+
fields: group.fields
|
|
135
|
+
};
|
|
136
|
+
// Add to flat structure for easy access
|
|
137
|
+
Object.assign(results, response.result[0]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.log(`⚠️ Failed to fetch ${group.groupName}: ${error.message}`);
|
|
142
|
+
// If group fails due to size, fetch fields individually
|
|
143
|
+
if (error.message?.includes('exceeds maximum allowed tokens')) {
|
|
144
|
+
results._field_groups[group.groupName] = await this.fetchFieldsIndividually(table, sys_id, group.fields, group.description);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Add coherence validation hints if it's a widget
|
|
149
|
+
if (table === 'sp_widget') {
|
|
150
|
+
results._coherence_hints = this.generateCoherenceHints(results);
|
|
151
|
+
}
|
|
152
|
+
return results;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Intelligently fetch widget fields with context preservation
|
|
156
|
+
* (Wrapper for backward compatibility)
|
|
157
|
+
*/
|
|
158
|
+
async fetchWidget(sys_id) {
|
|
159
|
+
return this.fetchArtifact('sp_widget', sys_id);
|
|
160
|
+
console.log(`\n🔍 Smart fetching widget: ${sys_id}`);
|
|
161
|
+
const results = {
|
|
162
|
+
_fetch_strategy: 'smart_chunked',
|
|
163
|
+
_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
|
+
_field_groups: {}
|
|
165
|
+
};
|
|
166
|
+
// Fetch each field group
|
|
167
|
+
for (const group of WIDGET_FIELD_GROUPS) {
|
|
168
|
+
console.log(`📦 Fetching ${group.groupName}: ${group.description}`);
|
|
169
|
+
try {
|
|
170
|
+
const response = await this.client.query('sp_widget', {
|
|
171
|
+
query: `sys_id=${sys_id}`,
|
|
172
|
+
fields: group.fields,
|
|
173
|
+
limit: 1
|
|
174
|
+
});
|
|
175
|
+
if (response.result?.[0]) {
|
|
176
|
+
results._field_groups[group.groupName] = {
|
|
177
|
+
data: response.result[0],
|
|
178
|
+
description: group.description,
|
|
179
|
+
fields: group.fields
|
|
180
|
+
};
|
|
181
|
+
// Add to flat structure for easy access
|
|
182
|
+
Object.assign(results, response.result[0]);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
console.log(`⚠️ Failed to fetch ${group.groupName}: ${error.message}`);
|
|
187
|
+
// If group fails due to size, fetch fields individually
|
|
188
|
+
if (error.message?.includes('exceeds maximum allowed tokens')) {
|
|
189
|
+
results._field_groups[group.groupName] = await this.fetchFieldsIndividually('sp_widget', sys_id, group.fields, group.description);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Add coherence validation hints
|
|
194
|
+
results._coherence_hints = this.generateCoherenceHints(results);
|
|
195
|
+
return results;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Fetch flow with intelligent chunking
|
|
199
|
+
* (Wrapper for backward compatibility)
|
|
200
|
+
*/
|
|
201
|
+
async fetchFlow(sys_id) {
|
|
202
|
+
return this.fetchArtifact('sys_hub_flow', sys_id);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Fetch business rule with intelligent chunking
|
|
206
|
+
* (Wrapper for backward compatibility)
|
|
207
|
+
*/
|
|
208
|
+
async fetchBusinessRule(sys_id) {
|
|
209
|
+
return this.fetchArtifact('sys_script', sys_id);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Fetch fields one by one when group is too large
|
|
213
|
+
*/
|
|
214
|
+
async fetchFieldsIndividually(table, sys_id, fields, groupDescription) {
|
|
215
|
+
console.log(` ↪️ Group too large, fetching fields individually...`);
|
|
216
|
+
const result = {
|
|
217
|
+
data: {},
|
|
218
|
+
description: groupDescription,
|
|
219
|
+
_fetched_individually: true,
|
|
220
|
+
_field_status: {}
|
|
221
|
+
};
|
|
222
|
+
for (const field of fields) {
|
|
223
|
+
try {
|
|
224
|
+
console.log(` 📄 Fetching field: ${field}`);
|
|
225
|
+
const response = await this.client.query(table, {
|
|
226
|
+
query: `sys_id=${sys_id}`,
|
|
227
|
+
fields: [field],
|
|
228
|
+
limit: 1
|
|
229
|
+
});
|
|
230
|
+
if (response.result?.[0]) {
|
|
231
|
+
result.data[field] = response.result[0][field];
|
|
232
|
+
result._field_status[field] = 'success';
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
catch (fieldError) {
|
|
236
|
+
console.log(` ⚠️ Field ${field} failed: ${fieldError.message}`);
|
|
237
|
+
result._field_status[field] = 'failed';
|
|
238
|
+
result.data[field] = `[Error: Field too large or inaccessible]`;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Generate coherence hints for widget validation
|
|
245
|
+
*/
|
|
246
|
+
generateCoherenceHints(widget) {
|
|
247
|
+
const hints = [];
|
|
248
|
+
// Check template references
|
|
249
|
+
if (widget.template) {
|
|
250
|
+
const dataRefs = widget.template.match(/\{\{data\.(\w+)\}\}/g) || [];
|
|
251
|
+
const methodRefs = widget.template.match(/ng-click="(\w+)\(/g) || [];
|
|
252
|
+
if (dataRefs.length > 0) {
|
|
253
|
+
hints.push(`Template references data properties: ${dataRefs.join(', ')}`);
|
|
254
|
+
}
|
|
255
|
+
if (methodRefs.length > 0) {
|
|
256
|
+
hints.push(`Template calls methods: ${methodRefs.join(', ')}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Check server script data initialization
|
|
260
|
+
if (widget.script) {
|
|
261
|
+
const dataInits = widget.script.match(/data\.(\w+)\s*=/g) || [];
|
|
262
|
+
if (dataInits.length > 0) {
|
|
263
|
+
hints.push(`Server script initializes: ${dataInits.join(', ')}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Check client script methods
|
|
267
|
+
if (widget.client_script) {
|
|
268
|
+
const scopeMethods = widget.client_script.match(/\$scope\.(\w+)\s*=/g) || [];
|
|
269
|
+
const serverCalls = widget.client_script.match(/c\.server\.get\(\{action:\s*['"](\w+)['"]/g) || [];
|
|
270
|
+
if (scopeMethods.length > 0) {
|
|
271
|
+
hints.push(`Client script implements: ${scopeMethods.join(', ')}`);
|
|
272
|
+
}
|
|
273
|
+
if (serverCalls.length > 0) {
|
|
274
|
+
hints.push(`Client calls server actions: ${serverCalls.join(', ')}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return hints;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Search within fields using GlideRecord queries
|
|
281
|
+
*/
|
|
282
|
+
async searchInField(table, field, searchTerm, additionalQuery) {
|
|
283
|
+
console.log(`\n🔎 Searching in ${table}.${field} for: ${searchTerm}`);
|
|
284
|
+
// Use CONTAINS operator for field search
|
|
285
|
+
const query = `${field}CONTAINS${searchTerm}${additionalQuery ? '^' + additionalQuery : ''}`;
|
|
286
|
+
try {
|
|
287
|
+
const response = await this.client.query(table, {
|
|
288
|
+
query: query,
|
|
289
|
+
fields: ['sys_id', 'name', field.substring(0, 50)], // Get preview of field
|
|
290
|
+
limit: 10
|
|
291
|
+
});
|
|
292
|
+
console.log(` ✅ Found ${response.result?.length || 0} matches`);
|
|
293
|
+
return response.result || [];
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
console.log(` ⚠️ Search failed: ${error}`);
|
|
297
|
+
return [];
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Get smart fetch strategy based on table - NOW USES ARTIFACT REGISTRY!
|
|
302
|
+
*/
|
|
303
|
+
getFieldGroups(table) {
|
|
304
|
+
// First check if we have specific groups defined
|
|
305
|
+
switch (table) {
|
|
306
|
+
case 'sp_widget':
|
|
307
|
+
return WIDGET_FIELD_GROUPS;
|
|
308
|
+
case 'sys_hub_flow':
|
|
309
|
+
return FLOW_FIELD_GROUPS;
|
|
310
|
+
case 'sys_script':
|
|
311
|
+
return BUSINESS_RULE_FIELD_GROUPS;
|
|
312
|
+
}
|
|
313
|
+
// Try to get from artifact registry
|
|
314
|
+
const config = (0, artifact_registry_1.getArtifactConfig)(table);
|
|
315
|
+
if (config) {
|
|
316
|
+
return this.createFieldGroupsFromRegistry(config);
|
|
317
|
+
}
|
|
318
|
+
// Generic strategy for unknown tables
|
|
319
|
+
return [
|
|
320
|
+
{
|
|
321
|
+
groupName: 'metadata',
|
|
322
|
+
fields: ['sys_id', 'name', 'sys_created_on', 'sys_updated_on'],
|
|
323
|
+
description: 'Basic record information',
|
|
324
|
+
maxTokens: 1000
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
groupName: 'content',
|
|
328
|
+
fields: ['*'], // Fetch all other fields
|
|
329
|
+
description: 'Record content',
|
|
330
|
+
maxTokens: 20000
|
|
331
|
+
}
|
|
332
|
+
];
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Create field groups from artifact registry configuration
|
|
336
|
+
*/
|
|
337
|
+
createFieldGroupsFromRegistry(config) {
|
|
338
|
+
const groups = [];
|
|
339
|
+
// Group 1: Metadata fields
|
|
340
|
+
const metadataFields = ['sys_id', 'sys_created_on', 'sys_updated_on', config.identifierField];
|
|
341
|
+
groups.push({
|
|
342
|
+
groupName: 'metadata',
|
|
343
|
+
fields: [...new Set(metadataFields)], // Remove duplicates
|
|
344
|
+
description: `${config.displayName} metadata`,
|
|
345
|
+
maxTokens: 2000
|
|
346
|
+
});
|
|
347
|
+
// Group 2-N: Each field mapping as its own group if large
|
|
348
|
+
for (const mapping of config.fieldMappings) {
|
|
349
|
+
if (mapping.maxTokens > 5000) {
|
|
350
|
+
// Large field gets its own group
|
|
351
|
+
groups.push({
|
|
352
|
+
groupName: mapping.serviceNowField,
|
|
353
|
+
fields: [mapping.serviceNowField],
|
|
354
|
+
description: mapping.description,
|
|
355
|
+
maxTokens: mapping.maxTokens
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// Group N+1: Small fields together
|
|
360
|
+
const smallFields = config.fieldMappings
|
|
361
|
+
.filter(m => m.maxTokens <= 5000)
|
|
362
|
+
.map(m => m.serviceNowField);
|
|
363
|
+
if (smallFields.length > 0) {
|
|
364
|
+
groups.push({
|
|
365
|
+
groupName: 'configuration',
|
|
366
|
+
fields: smallFields,
|
|
367
|
+
description: `${config.displayName} configuration`,
|
|
368
|
+
maxTokens: 10000
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
return groups;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
exports.SmartFieldFetcher = SmartFieldFetcher;
|
|
375
|
+
/**
|
|
376
|
+
* Helper function to create fetch strategy hint for Claude
|
|
377
|
+
*/
|
|
378
|
+
function createFetchStrategyHint(table, sys_id) {
|
|
379
|
+
return `
|
|
380
|
+
🔍 SMART FETCH STRATEGY for ${table} (${sys_id}):
|
|
381
|
+
|
|
382
|
+
When the artifact is too large (>25000 tokens), I'll fetch fields in intelligent groups:
|
|
383
|
+
1. First fetch metadata (name, title, sys_id)
|
|
384
|
+
2. Then fetch each content field separately (template, script, client_script, css)
|
|
385
|
+
3. Maintain context: These fields work together!
|
|
386
|
+
- Template HTML references {{data.x}} from server script
|
|
387
|
+
- Template ng-click calls methods from client script
|
|
388
|
+
- CSS classes are used in template
|
|
389
|
+
- Server script handles input.action from client script
|
|
390
|
+
|
|
391
|
+
This ensures you get ALL necessary fields while respecting token limits.
|
|
392
|
+
The fields are fetched separately but represent ONE cohesive widget.
|
|
393
|
+
`;
|
|
394
|
+
}
|
|
395
|
+
//# sourceMappingURL=smart-field-fetcher.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "ServiceNow development framework with MCP server integration. Executes background scripts using ES5 JavaScript only (ServiceNow Rhino engine requirement). Provides
|
|
3
|
+
"version": "3.5.1",
|
|
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",
|
|
7
7
|
"bin": {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Docker ignore file for Snow-Flow Website
|
|
2
|
+
|
|
3
|
+
# Git
|
|
4
|
+
.git
|
|
5
|
+
.gitignore
|
|
6
|
+
|
|
7
|
+
# Documentation
|
|
8
|
+
README.md
|
|
9
|
+
*.md
|
|
10
|
+
|
|
11
|
+
# Node modules (if any)
|
|
12
|
+
node_modules
|
|
13
|
+
npm-debug.log*
|
|
14
|
+
|
|
15
|
+
# Build artifacts
|
|
16
|
+
.DS_Store
|
|
17
|
+
Thumbs.db
|
|
18
|
+
|
|
19
|
+
# Editor files
|
|
20
|
+
.vscode
|
|
21
|
+
.idea
|
|
22
|
+
*.swp
|
|
23
|
+
*.swo
|
|
24
|
+
*~
|
|
25
|
+
|
|
26
|
+
# Logs
|
|
27
|
+
logs
|
|
28
|
+
*.log
|
|
29
|
+
|
|
30
|
+
# Runtime data
|
|
31
|
+
pids
|
|
32
|
+
*.pid
|
|
33
|
+
*.seed
|
|
34
|
+
|
|
35
|
+
# Coverage directory used by tools like istanbul
|
|
36
|
+
coverage
|
|
37
|
+
|
|
38
|
+
# Dependency directories
|
|
39
|
+
node_modules/
|
|
40
|
+
|
|
41
|
+
# Optional npm cache directory
|
|
42
|
+
.npm
|
|
43
|
+
|
|
44
|
+
# Optional REPL history
|
|
45
|
+
.node_repl_history
|
|
46
|
+
|
|
47
|
+
# Output of 'npm pack'
|
|
48
|
+
*.tgz
|
|
49
|
+
|
|
50
|
+
# Docker files (except the one we need)
|
|
51
|
+
Dockerfile.*
|
|
52
|
+
!Dockerfile
|
|
53
|
+
|
|
54
|
+
# Cloud Build
|
|
55
|
+
cloudbuild.yaml
|
|
56
|
+
|
|
57
|
+
# Environment files
|
|
58
|
+
.env
|
|
59
|
+
.env.local
|
|
60
|
+
.env.production
|
|
61
|
+
|
|
62
|
+
# Temporary files
|
|
63
|
+
tmp/
|
|
64
|
+
temp/
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Snow-Flow Website - Production Docker Image
|
|
2
|
+
FROM nginx:alpine
|
|
3
|
+
|
|
4
|
+
# Install security updates
|
|
5
|
+
RUN apk update && apk upgrade
|
|
6
|
+
|
|
7
|
+
# Remove default nginx website
|
|
8
|
+
RUN rm -rf /usr/share/nginx/html/*
|
|
9
|
+
|
|
10
|
+
# Copy website files
|
|
11
|
+
COPY . /usr/share/nginx/html/
|
|
12
|
+
|
|
13
|
+
# Copy custom nginx configuration
|
|
14
|
+
COPY nginx.conf /etc/nginx/nginx.conf
|
|
15
|
+
|
|
16
|
+
# Create directory for logs
|
|
17
|
+
RUN mkdir -p /var/log/nginx
|
|
18
|
+
|
|
19
|
+
# Set proper permissions
|
|
20
|
+
RUN chown -R nginx:nginx /usr/share/nginx/html && \
|
|
21
|
+
chmod -R 755 /usr/share/nginx/html
|
|
22
|
+
|
|
23
|
+
# Health check
|
|
24
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
25
|
+
CMD curl -f http://localhost/ || exit 1
|
|
26
|
+
|
|
27
|
+
# Expose port 80
|
|
28
|
+
EXPOSE 80
|
|
29
|
+
|
|
30
|
+
# Add metadata
|
|
31
|
+
LABEL maintainer="Snow-Flow Team" \
|
|
32
|
+
description="Snow-Flow Documentation Website" \
|
|
33
|
+
version="3.4.39"
|
|
34
|
+
|
|
35
|
+
# Start nginx
|
|
36
|
+
CMD ["nginx", "-g", "daemon off;"]
|