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.
@@ -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.39",
4
- "description": "ServiceNow development framework with MCP server integration. Executes background scripts using ES5 JavaScript only (ServiceNow Rhino engine requirement). Provides 17 MCP servers for complete ServiceNow operations including widget deployment with coherence validation, table operations, script execution, machine learning, advanced features, and comprehensive platform management.",
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;"]