snow-flow 8.3.2 โ†’ 8.4.0

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.
Files changed (45) hide show
  1. package/OPENCODE-SETUP.md +312 -0
  2. package/OPENCODE-TROUBLESHOOTING.md +381 -0
  3. package/dist/agents/index.d.ts +2 -2
  4. package/dist/agents/index.d.ts.map +1 -1
  5. package/dist/agents/index.js +2 -4
  6. package/dist/agents/index.js.map +1 -1
  7. package/dist/cli.js +208 -244
  8. package/dist/cli.js.map +1 -1
  9. package/dist/memory/session-memory.d.ts +80 -0
  10. package/dist/memory/session-memory.d.ts.map +1 -0
  11. package/dist/memory/session-memory.js +468 -0
  12. package/dist/memory/session-memory.js.map +1 -0
  13. package/dist/sdk/claude-agent-sdk-integration.d.ts +4 -1
  14. package/dist/sdk/claude-agent-sdk-integration.d.ts.map +1 -1
  15. package/dist/sdk/claude-agent-sdk-integration.js.map +1 -1
  16. package/dist/sdk/index.d.ts +2 -7
  17. package/dist/sdk/index.d.ts.map +1 -1
  18. package/dist/sdk/index.js +2 -7
  19. package/dist/sdk/index.js.map +1 -1
  20. package/dist/snow-flow-system.d.ts +3 -7
  21. package/dist/snow-flow-system.d.ts.map +1 -1
  22. package/dist/snow-flow-system.js +59 -40
  23. package/dist/snow-flow-system.js.map +1 -1
  24. package/dist/utils/mcp-output-formatter.d.ts +128 -0
  25. package/dist/utils/mcp-output-formatter.d.ts.map +1 -0
  26. package/dist/utils/mcp-output-formatter.js +442 -0
  27. package/dist/utils/mcp-output-formatter.js.map +1 -0
  28. package/dist/utils/opencode-output-interceptor.d.ts +40 -0
  29. package/dist/utils/opencode-output-interceptor.d.ts.map +1 -0
  30. package/dist/utils/opencode-output-interceptor.js +258 -0
  31. package/dist/utils/opencode-output-interceptor.js.map +1 -0
  32. package/package.json +4 -2
  33. package/scripts/bulk-optimize-tools.js +486 -0
  34. package/scripts/cleanup-mcp-servers.js +115 -0
  35. package/scripts/generate-mcp-config.js +45 -0
  36. package/scripts/mcp-server-manager.sh +320 -0
  37. package/scripts/optimize-mcp-tools.ts +410 -0
  38. package/scripts/reset-mcp-servers.js +266 -0
  39. package/scripts/safe-mcp-cleanup.js +151 -0
  40. package/scripts/setup-mcp.js +106 -0
  41. package/scripts/start-mcp-proper.js +76 -0
  42. package/scripts/start-opencode.sh +123 -0
  43. package/scripts/start-sysprops-mcp.js +43 -0
  44. package/scripts/test-todowrite-timeout.js +108 -0
  45. package/scripts/update-version.js +31 -0
@@ -0,0 +1,486 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Bulk MCP Tool Optimization Script
4
+ *
5
+ * Optimizes ALL Snow-Flow MCP tools:
6
+ * - Compresses verbose descriptions โ†’ concise
7
+ * - Adds categorization metadata
8
+ * - Calculates token savings
9
+ * - Validates changes
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ // ============================================================================
16
+ // CONFIGURATION
17
+ // ============================================================================
18
+
19
+ const TOOL_DIRS = [
20
+ 'dist/mcp/servicenow-mcp-unified/tools',
21
+ 'dist/mcp/snow-flow/tools'
22
+ ];
23
+
24
+ const DRY_RUN = process.argv.includes('--dry-run');
25
+ const VERBOSE = process.argv.includes('--verbose');
26
+
27
+ // Description optimization patterns
28
+ const OPTIMIZATIONS = {
29
+ // Remove verbose phrases
30
+ removes: [
31
+ /Executes all \d+ steps automatically:/gi,
32
+ /with automatic/gi,
33
+ /comprehensive/gi,
34
+ /advanced/gi,
35
+ /flexible/gi,
36
+ /powerful/gi,
37
+ /complete/gi,
38
+ /full support for/gi,
39
+ /provides capability to/gi,
40
+ /allows you to/gi,
41
+ /enables you to/gi,
42
+ /enables/gi
43
+ ],
44
+
45
+ // Shorten common phrases
46
+ replaces: [
47
+ ['Create a new', 'Create'],
48
+ ['Create an', 'Create'],
49
+ ['Update an existing', 'Update'],
50
+ ['Update the', 'Update'],
51
+ ['Delete an existing', 'Delete'],
52
+ ['Delete the', 'Delete'],
53
+ ['Query for', 'Query'],
54
+ ['Search for', 'Search'],
55
+ ['Retrieve information about', 'Get'],
56
+ ['Retrieve', 'Get'],
57
+ ['with filtering and pagination', ': filter, paginate'],
58
+ ['with pagination and filtering', ': filter, paginate'],
59
+ ['with role-based access control', 'with RBAC'],
60
+ ['Now Experience Framework', 'UX'],
61
+ ['UI Builder', 'UIB'],
62
+ ['Service Portal', 'SP'],
63
+ ['Configuration Management Database', 'CMDB'],
64
+ ['Predictive Intelligence', 'PI'],
65
+ ['Performance Analytics', 'PA'],
66
+ ['and configuration', ''],
67
+ [' and ', ', ']
68
+ ]
69
+ };
70
+
71
+ // Property description shortcuts
72
+ const PROPERTY_SHORTCUTS = {
73
+ 'Table name to query': 'Table name',
74
+ 'Table name to create record in': 'Table name',
75
+ 'Table name to update': 'Table name',
76
+ 'Encoded query string': 'Encoded query',
77
+ 'Fields to return': 'Fields',
78
+ 'Maximum number of records': 'Max records',
79
+ 'Number of records to skip': 'Records to skip',
80
+ 'Field to order by': 'Order by',
81
+ 'Return display values': 'Display values',
82
+ 'Workspace name': 'Name',
83
+ 'Page name': 'Name',
84
+ 'Component name': 'Name',
85
+ 'Description of the': 'Description',
86
+ 'System ID of the': 'System ID'
87
+ };
88
+
89
+ // Metadata taxonomy by directory
90
+ const CATEGORY_TAXONOMY = {
91
+ 'operations': {
92
+ category: 'core-operations',
93
+ subcategory: 'general',
94
+ complexity: 'beginner',
95
+ frequency: 'very-high'
96
+ },
97
+ 'ui-builder': {
98
+ category: 'ui-frameworks',
99
+ subcategory: 'ui-builder',
100
+ complexity: 'intermediate',
101
+ frequency: 'high'
102
+ },
103
+ 'workspace': {
104
+ category: 'ui-frameworks',
105
+ subcategory: 'workspace',
106
+ complexity: 'intermediate',
107
+ frequency: 'high'
108
+ },
109
+ 'service-portal': {
110
+ category: 'ui-frameworks',
111
+ subcategory: 'service-portal',
112
+ complexity: 'intermediate',
113
+ frequency: 'medium'
114
+ },
115
+ 'update-sets': {
116
+ category: 'development',
117
+ subcategory: 'update-sets',
118
+ complexity: 'beginner',
119
+ frequency: 'very-high'
120
+ },
121
+ 'deployment': {
122
+ category: 'development',
123
+ subcategory: 'deployment',
124
+ complexity: 'intermediate',
125
+ frequency: 'high'
126
+ },
127
+ 'development': {
128
+ category: 'development',
129
+ subcategory: 'platform',
130
+ complexity: 'intermediate',
131
+ frequency: 'high'
132
+ },
133
+ 'automation': {
134
+ category: 'automation',
135
+ subcategory: 'script-execution',
136
+ complexity: 'intermediate',
137
+ frequency: 'high'
138
+ },
139
+ 'integration': {
140
+ category: 'integration',
141
+ subcategory: 'rest-soap',
142
+ complexity: 'advanced',
143
+ frequency: 'medium'
144
+ },
145
+ 'cmdb': {
146
+ category: 'cmdb',
147
+ subcategory: 'ci-management',
148
+ complexity: 'intermediate',
149
+ frequency: 'medium'
150
+ },
151
+ 'knowledge': {
152
+ category: 'itsm',
153
+ subcategory: 'knowledge',
154
+ complexity: 'beginner',
155
+ frequency: 'medium'
156
+ },
157
+ 'change': {
158
+ category: 'itsm',
159
+ subcategory: 'change',
160
+ complexity: 'intermediate',
161
+ frequency: 'high'
162
+ },
163
+ 'catalog': {
164
+ category: 'itsm',
165
+ subcategory: 'catalog',
166
+ complexity: 'intermediate',
167
+ frequency: 'medium'
168
+ },
169
+ 'predictive-intelligence': {
170
+ category: 'ml-analytics',
171
+ subcategory: 'predictive-intelligence',
172
+ complexity: 'advanced',
173
+ frequency: 'medium'
174
+ },
175
+ 'performance-analytics': {
176
+ category: 'ml-analytics',
177
+ subcategory: 'performance-analytics',
178
+ complexity: 'intermediate',
179
+ frequency: 'medium'
180
+ },
181
+ 'ai-ml': {
182
+ category: 'ml-analytics',
183
+ subcategory: 'machine-learning',
184
+ complexity: 'advanced',
185
+ frequency: 'low'
186
+ },
187
+ 'flow-designer': {
188
+ category: 'automation',
189
+ subcategory: 'flow-designer',
190
+ complexity: 'intermediate',
191
+ frequency: 'medium'
192
+ },
193
+ 'local-sync': {
194
+ category: 'development',
195
+ subcategory: 'local-sync',
196
+ complexity: 'intermediate',
197
+ frequency: 'high'
198
+ },
199
+ 'system-properties': {
200
+ category: 'core-operations',
201
+ subcategory: 'properties',
202
+ complexity: 'beginner',
203
+ frequency: 'high'
204
+ }
205
+ };
206
+
207
+ // ============================================================================
208
+ // UTILITY FUNCTIONS
209
+ // ============================================================================
210
+
211
+ function estimateTokens(text) {
212
+ // Rough estimation: 1 token โ‰ˆ 4 characters
213
+ return Math.ceil(text.length / 4);
214
+ }
215
+
216
+ function optimizeDescription(desc) {
217
+ let optimized = desc;
218
+
219
+ // Apply removals
220
+ OPTIMIZATIONS.removes.forEach(pattern => {
221
+ optimized = optimized.replace(pattern, '');
222
+ });
223
+
224
+ // Apply replacements
225
+ OPTIMIZATIONS.replaces.forEach(([from, to]) => {
226
+ optimized = optimized.replace(new RegExp(from, 'gi'), to);
227
+ });
228
+
229
+ // Clean up whitespace
230
+ optimized = optimized.replace(/\s+/g, ' ').trim();
231
+ optimized = optimized.replace(/,\s*,/g, ',');
232
+ optimized = optimized.replace(/:\s*,/g, ':');
233
+
234
+ return optimized;
235
+ }
236
+
237
+ function optimizePropertyDesc(desc) {
238
+ let optimized = desc;
239
+
240
+ // Try exact matches first
241
+ for (const [from, to] of Object.entries(PROPERTY_SHORTCUTS)) {
242
+ if (desc.includes(from)) {
243
+ optimized = optimized.replace(from, to);
244
+ }
245
+ }
246
+
247
+ // Remove common redundancies
248
+ optimized = optimized
249
+ .replace(/\(e\.g\.,.*?\)/g, '')
250
+ .replace(/\(default:.*?\)/g, '')
251
+ .replace(/\(optional\)/g, '')
252
+ .trim();
253
+
254
+ return optimized;
255
+ }
256
+
257
+ function inferMetadata(filePath) {
258
+ // Extract directory name
259
+ const parts = filePath.split(path.sep);
260
+ const toolsIndex = parts.findIndex(p => p === 'tools');
261
+ const dirName = parts[toolsIndex + 1] || 'general';
262
+
263
+ const metadata = CATEGORY_TAXONOMY[dirName] || {
264
+ category: 'advanced',
265
+ subcategory: 'specialized',
266
+ complexity: 'intermediate',
267
+ frequency: 'low'
268
+ };
269
+
270
+ return {
271
+ ...metadata,
272
+ use_cases: [dirName.replace(/-/g, '_')]
273
+ };
274
+ }
275
+
276
+ // ============================================================================
277
+ // FILE PROCESSING
278
+ // ============================================================================
279
+
280
+ function processToolFile(filePath) {
281
+ try {
282
+ let content = fs.readFileSync(filePath, 'utf-8');
283
+
284
+ // Skip index files and non-tool files
285
+ if (filePath.includes('index.js') || !content.includes('toolDefinition')) {
286
+ return null;
287
+ }
288
+
289
+ // Extract toolDefinition
290
+ const toolDefStart = content.indexOf('exports.toolDefinition = {');
291
+ const toolDefEnd = content.indexOf('};', toolDefStart);
292
+
293
+ if (toolDefStart === -1 || toolDefEnd === -1) {
294
+ if (VERBOSE) console.warn(`โš ๏ธ Could not find toolDefinition in ${filePath}`);
295
+ return null;
296
+ }
297
+
298
+ const toolDefSection = content.substring(toolDefStart, toolDefEnd + 2);
299
+
300
+ // Extract current description
301
+ const descMatch = toolDefSection.match(/description:\s*['"](.*?)['"]/);
302
+ if (!descMatch) {
303
+ if (VERBOSE) console.warn(`โš ๏ธ No description found in ${filePath}`);
304
+ return null;
305
+ }
306
+
307
+ const originalDesc = descMatch[1];
308
+ const optimizedDesc = optimizeDescription(originalDesc);
309
+
310
+ // Calculate token savings
311
+ const originalTokens = estimateTokens(originalDesc);
312
+ const optimizedTokens = estimateTokens(optimizedDesc);
313
+ const savings = originalTokens - optimizedTokens;
314
+
315
+ // Get metadata
316
+ const metadata = inferMetadata(filePath);
317
+
318
+ // Build new toolDefinition with metadata
319
+ let newToolDef = toolDefSection.replace(
320
+ /description:\s*['"].*?['"]/,
321
+ `description: '${optimizedDesc}',\n // Metadata for tool discovery (not sent to LLM)\n category: '${metadata.category}',\n subcategory: '${metadata.subcategory}',\n use_cases: ${JSON.stringify(metadata.use_cases)},\n complexity: '${metadata.complexity}',\n frequency: '${metadata.frequency}'`
322
+ );
323
+
324
+ // Optimize property descriptions
325
+ newToolDef = newToolDef.replace(/description:\s*['"]([^'"]+)['"]/g, (match, desc) => {
326
+ if (match.includes('category:') || match.includes('subcategory:')) {
327
+ return match; // Don't optimize metadata
328
+ }
329
+ const optimized = optimizePropertyDesc(desc);
330
+ return `description: '${optimized}'`;
331
+ });
332
+
333
+ // Replace in content
334
+ const newContent = content.substring(0, toolDefStart) + newToolDef + content.substring(toolDefEnd + 2);
335
+
336
+ // Write back
337
+ if (!DRY_RUN) {
338
+ fs.writeFileSync(filePath, newContent, 'utf-8');
339
+ }
340
+
341
+ return {
342
+ file: path.relative(process.cwd(), filePath),
343
+ originalDesc,
344
+ optimizedDesc,
345
+ originalTokens,
346
+ optimizedTokens,
347
+ savings,
348
+ metadata
349
+ };
350
+
351
+ } catch (error) {
352
+ console.error(`โŒ Error processing ${filePath}:`, error.message);
353
+ return null;
354
+ }
355
+ }
356
+
357
+ function findToolFiles(dir) {
358
+ const files = [];
359
+
360
+ function traverse(currentDir) {
361
+ try {
362
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
363
+
364
+ for (const entry of entries) {
365
+ const fullPath = path.join(currentDir, entry.name);
366
+
367
+ if (entry.isDirectory()) {
368
+ traverse(fullPath);
369
+ } else if (entry.isFile() && entry.name.endsWith('.js') && !entry.name.endsWith('.map.js')) {
370
+ files.push(fullPath);
371
+ }
372
+ }
373
+ } catch (error) {
374
+ console.warn(`โš ๏ธ Could not read directory ${currentDir}:`, error.message);
375
+ }
376
+ }
377
+
378
+ traverse(dir);
379
+ return files;
380
+ }
381
+
382
+ // ============================================================================
383
+ // MAIN EXECUTION
384
+ // ============================================================================
385
+
386
+ async function main() {
387
+ console.log('๐Ÿš€ Starting Bulk MCP Tool Optimization...\n');
388
+ console.log(`Mode: ${DRY_RUN ? 'DRY RUN (no files will be modified)' : 'LIVE (files will be modified)'}\n`);
389
+
390
+ const results = [];
391
+ let totalOriginalTokens = 0;
392
+ let totalOptimizedTokens = 0;
393
+ let totalFiles = 0;
394
+
395
+ for (const toolDir of TOOL_DIRS) {
396
+ const fullPath = path.join(process.cwd(), toolDir);
397
+
398
+ if (!fs.existsSync(fullPath)) {
399
+ console.warn(`โš ๏ธ Directory not found: ${toolDir}`);
400
+ continue;
401
+ }
402
+
403
+ console.log(`๐Ÿ“ Processing: ${toolDir}`);
404
+ const files = findToolFiles(fullPath);
405
+ console.log(` Found ${files.length} JavaScript files`);
406
+
407
+ let processed = 0;
408
+ for (const file of files) {
409
+ const result = processToolFile(file);
410
+ if (result) {
411
+ results.push(result);
412
+ totalOriginalTokens += result.originalTokens;
413
+ totalOptimizedTokens += result.optimizedTokens;
414
+ processed++;
415
+
416
+ if (VERBOSE) {
417
+ console.log(` โœ“ ${result.file} (${result.savings} tokens saved)`);
418
+ }
419
+ }
420
+ }
421
+
422
+ totalFiles += processed;
423
+ console.log(` โœ… Processed ${processed} tool files\n`);
424
+ }
425
+
426
+ // Print summary
427
+ console.log('='.repeat(80));
428
+ console.log('๐Ÿ“Š OPTIMIZATION SUMMARY');
429
+ console.log('='.repeat(80));
430
+ console.log(`Total tools optimized: ${totalFiles}`);
431
+ console.log(`Original description tokens: ${totalOriginalTokens.toLocaleString()}`);
432
+ console.log(`Optimized description tokens: ${totalOptimizedTokens.toLocaleString()}`);
433
+ console.log(`Total savings: ${(totalOriginalTokens - totalOptimizedTokens).toLocaleString()} tokens`);
434
+ console.log(`Reduction: ${((1 - totalOptimizedTokens / totalOriginalTokens) * 100).toFixed(1)}%`);
435
+ console.log('='.repeat(80));
436
+
437
+ // Category breakdown
438
+ const byCategory = {};
439
+ results.forEach(r => {
440
+ const cat = r.metadata.category;
441
+ if (!byCategory[cat]) {
442
+ byCategory[cat] = { count: 0, savings: 0 };
443
+ }
444
+ byCategory[cat].count++;
445
+ byCategory[cat].savings += r.savings;
446
+ });
447
+
448
+ console.log('\n๐Ÿ“ˆ BY CATEGORY:');
449
+ Object.entries(byCategory)
450
+ .sort((a, b) => b[1].savings - a[1].savings)
451
+ .forEach(([cat, data]) => {
452
+ console.log(` ${cat.padEnd(25)} ${data.count.toString().padStart(3)} tools, ${data.savings.toString().padStart(5)} tokens saved`);
453
+ });
454
+
455
+ // Save detailed report
456
+ const report = {
457
+ timestamp: new Date().toISOString(),
458
+ mode: DRY_RUN ? 'dry-run' : 'live',
459
+ summary: {
460
+ totalTools: totalFiles,
461
+ originalTokens: totalOriginalTokens,
462
+ optimizedTokens: totalOptimizedTokens,
463
+ savings: totalOriginalTokens - totalOptimizedTokens,
464
+ reductionPercent: parseFloat(((1 - totalOptimizedTokens / totalOriginalTokens) * 100).toFixed(1))
465
+ },
466
+ byCategory,
467
+ results: results.map(r => ({
468
+ file: r.file,
469
+ category: r.metadata.category,
470
+ originalDesc: r.originalDesc,
471
+ optimizedDesc: r.optimizedDesc,
472
+ savings: r.savings
473
+ }))
474
+ };
475
+
476
+ const reportPath = path.join(process.cwd(), 'docs/optimization-report.json');
477
+ fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
478
+ console.log(`\nโœ… Detailed report saved to: ${reportPath}`);
479
+
480
+ if (DRY_RUN) {
481
+ console.log('\nโš ๏ธ DRY RUN MODE: No files were modified. Run without --dry-run to apply changes.');
482
+ }
483
+ }
484
+
485
+ // Run
486
+ main().catch(console.error);
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MCP Server Cleanup Script
5
+ * Prevents duplicate MCP servers and memory exhaustion
6
+ */
7
+
8
+ const { exec } = require('child_process');
9
+ const { promisify } = require('util');
10
+ const execAsync = promisify(exec);
11
+
12
+ async function cleanupMCPServers() {
13
+ console.log('๐Ÿงน Cleaning up MCP servers...\n');
14
+
15
+ try {
16
+ // 1. Check for running MCP processes
17
+ const { stdout: psOutput } = await execAsync('ps aux | grep -E "node.*mcp" | grep -v grep | wc -l');
18
+ const processCount = parseInt(psOutput.trim());
19
+
20
+ if (processCount > 0) {
21
+ console.log(`โš ๏ธ Found ${processCount} running MCP processes`);
22
+ console.log('๐Ÿ”ช Killing all MCP processes...');
23
+
24
+ // Kill all MCP processes
25
+ await execAsync('pkill -f "node.*mcp"').catch(() => {
26
+ // Ignore errors if no processes found
27
+ });
28
+
29
+ // Wait for processes to terminate
30
+ await new Promise(resolve => setTimeout(resolve, 2000));
31
+
32
+ console.log('โœ… All MCP processes terminated\n');
33
+ } else {
34
+ console.log('โœ… No MCP processes running\n');
35
+ }
36
+
37
+ // 2. Clean up any stale lock files
38
+ console.log('๐Ÿ”’ Cleaning up lock files...');
39
+ await execAsync('rm -f /tmp/mcp-*.lock').catch(() => {});
40
+ await execAsync('rm -f ~/.claude/mcp-*.lock').catch(() => {});
41
+ await execAsync('rm -f ~/.claude/mcp-servers.lock').catch(() => {});
42
+
43
+ // 3. Check memory usage
44
+ const { stdout: memOutput } = await execAsync('ps aux | grep node | awk \'{sum+=$6} END {print sum/1024}\'');
45
+ const nodeMemoryMB = parseFloat(memOutput.trim());
46
+
47
+ console.log(`๐Ÿ“Š Node.js memory usage: ${nodeMemoryMB.toFixed(2)} MB\n`);
48
+
49
+ if (nodeMemoryMB > 1000) {
50
+ console.log('โš ๏ธ High memory usage detected!');
51
+ console.log('๐Ÿ’ก Recommendation: Restart your terminal or run "killall node"\n');
52
+ }
53
+
54
+ // 4. Create singleton lock mechanism
55
+ console.log('๐Ÿ” Setting up singleton lock mechanism...');
56
+ const lockScript = `
57
+ const fs = require('fs');
58
+ const path = require('path');
59
+
60
+ const lockFile = path.join(process.env.HOME, '.claude', 'mcp-singleton.lock');
61
+ const pid = process.pid;
62
+
63
+ // Check if lock exists
64
+ if (fs.existsSync(lockFile)) {
65
+ const existingPid = fs.readFileSync(lockFile, 'utf8');
66
+ try {
67
+ // Check if process is still running
68
+ process.kill(existingPid, 0);
69
+ console.error('MCP servers already running with PID:', existingPid);
70
+ process.exit(1);
71
+ } catch (e) {
72
+ // Process not running, remove stale lock
73
+ fs.unlinkSync(lockFile);
74
+ }
75
+ }
76
+
77
+ // Create lock
78
+ fs.mkdirSync(path.dirname(lockFile), { recursive: true });
79
+ fs.writeFileSync(lockFile, pid.toString());
80
+
81
+ // Clean up on exit
82
+ process.on('exit', () => {
83
+ try {
84
+ fs.unlinkSync(lockFile);
85
+ } catch (e) {}
86
+ });
87
+ `;
88
+
89
+ // Save singleton script
90
+ const fs = require('fs');
91
+ const path = require('path');
92
+ const singletonPath = path.join(__dirname, '..', 'dist', 'mcp', 'singleton-check.js');
93
+ fs.writeFileSync(singletonPath, lockScript);
94
+ console.log('โœ… Singleton mechanism created\n');
95
+
96
+ // 5. Report status
97
+ console.log('๐Ÿ“‹ Cleanup Summary:');
98
+ console.log('โ”€'.repeat(40));
99
+ console.log('โœ… All MCP processes terminated');
100
+ console.log('โœ… Lock files cleaned');
101
+ console.log('โœ… Singleton mechanism installed');
102
+ console.log(`โœ… Memory usage: ${nodeMemoryMB.toFixed(2)} MB`);
103
+ console.log('\n๐ŸŽฏ Next Steps:');
104
+ console.log('1. Run "npm run build" to rebuild');
105
+ console.log('2. Use "snow-flow mcp start" to start servers properly');
106
+ console.log('3. Monitor with "snow-flow mcp status"');
107
+
108
+ } catch (error) {
109
+ console.error('โŒ Cleanup failed:', error.message);
110
+ process.exit(1);
111
+ }
112
+ }
113
+
114
+ // Run cleanup
115
+ cleanupMCPServers().catch(console.error);
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const dotenv = require('dotenv');
6
+
7
+ // Load environment variables
8
+ const envPath = path.join(__dirname, '..', '.env');
9
+ if (fs.existsSync(envPath)) {
10
+ dotenv.config({ path: envPath });
11
+ } else {
12
+ console.error('โŒ .env file not found!');
13
+ process.exit(1);
14
+ }
15
+
16
+ // Read template
17
+ const templatePath = path.join(__dirname, '..', '.mcp.json.template');
18
+ const template = JSON.parse(fs.readFileSync(templatePath, 'utf-8'));
19
+
20
+ // Process template - replace variables
21
+ const config = JSON.parse(JSON.stringify(template)
22
+ .replace(/{{PROJECT_ROOT}}/g, path.resolve(__dirname, '..'))
23
+ .replace(/{{SNOW_INSTANCE}}/g, process.env.SNOW_INSTANCE || '')
24
+ .replace(/{{SNOW_CLIENT_ID}}/g, process.env.SNOW_CLIENT_ID || '')
25
+ .replace(/{{SNOW_CLIENT_SECRET}}/g, process.env.SNOW_CLIENT_SECRET || '')
26
+ .replace(/{{SNOW_DEPLOYMENT_TIMEOUT}}/g, process.env.SNOW_DEPLOYMENT_TIMEOUT || '300000')
27
+ .replace(/{{MCP_DEPLOYMENT_TIMEOUT}}/g, process.env.MCP_DEPLOYMENT_TIMEOUT || '360000')
28
+ .replace(/{{SNOW_FLOW_ENV}}/g, process.env.SNOW_FLOW_ENV || 'production')
29
+ );
30
+
31
+ // Write config
32
+ const outputPath = path.join(__dirname, '..', '.mcp.json');
33
+ fs.writeFileSync(outputPath, JSON.stringify(config, null, 2));
34
+
35
+ console.log('โœ… Generated .mcp.json with all ServiceNow MCP servers');
36
+ console.log(`๐Ÿ“ Location: ${outputPath}`);
37
+ console.log(`๐Ÿ”ง Servers configured: ${Object.keys(config.servers).length}`);
38
+ console.log('\nServers:');
39
+ Object.keys(config.servers).forEach(server => {
40
+ console.log(` โœ“ ${server}`);
41
+ });
42
+
43
+ console.log('\n๐Ÿ’ก Next steps:');
44
+ console.log('1. Restart Claude Code to load the new configuration');
45
+ console.log('2. Run /doctor again to verify everything is working');