snow-flow 8.5.7 → 8.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/CLAUDE.md +52 -4
- package/README.md +99 -30
- package/{OPENCODE-SETUP.md → SNOWCODE-SETUP.md} +47 -21
- package/{OPENCODE-TROUBLESHOOTING.md → SNOWCODE-TROUBLESHOOTING.md} +18 -18
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +526 -280
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +528 -250
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/claude-md-template.d.ts +1 -1
- package/dist/templates/claude-md-template.js +1 -1
- package/dist/templates/readme-template.d.ts +1 -1
- package/dist/templates/readme-template.js +18 -18
- package/dist/utils/artifact-local-sync.d.ts +1 -1
- package/dist/utils/artifact-local-sync.js +4 -4
- package/dist/utils/snow-oauth.d.ts +11 -5
- package/dist/utils/snow-oauth.d.ts.map +1 -1
- package/dist/utils/snow-oauth.js +337 -90
- package/dist/utils/snow-oauth.js.map +1 -1
- package/dist/utils/{opencode-output-interceptor.d.ts → snowcode-output-interceptor.d.ts} +7 -7
- package/dist/utils/{opencode-output-interceptor.d.ts.map → snowcode-output-interceptor.d.ts.map} +1 -1
- package/dist/utils/{opencode-output-interceptor.js → snowcode-output-interceptor.js} +10 -10
- package/dist/utils/{opencode-output-interceptor.js.map → snowcode-output-interceptor.js.map} +1 -1
- package/package.json +20 -9
- package/scripts/{start-opencode.sh → start-snowcode.sh} +28 -28
- package/scripts/verify-snowcode-fork.sh +141 -0
- package/templates/snowcode-package.json +5 -0
- package/THEMES.md +0 -223
- package/bin/opencode +0 -17
- package/dist/mcp/servicenow-mcp-unified/config/tool-definitions.json +0 -3935
- package/dist/mcp/servicenow-mcp-unified/tools/automation/snow_automation_discover.js +0 -164
- package/dist/mcp/servicenow-mcp-unified/tools/deployment/snow_artifact_transfer.js +0 -282
- package/dist/mcp/servicenow-mcp-unified/tools/filters/snow_build_filter.js +0 -171
- package/dist/mcp/servicenow-mcp-unified/tools/formatters/snow_format_value.js +0 -164
- package/dist/mcp/servicenow-mcp-unified/tools/knowledge/index.js.bak +0 -45
- package/dist/mcp/servicenow-mcp-unified/tools/local-sync/snow_artifact_sync.js +0 -172
- package/dist/mcp/servicenow-mcp-unified/tools/system-properties/index.js +0 -36
- package/dist/mcp/servicenow-mcp-unified/tools/ui-builder/snow_discover_uib.js +0 -296
- package/dist/mcp/servicenow-mcp-unified/tools/workspace/snow_create_ux_component.js +0 -292
- package/dist/memory/session-memory.d.ts +0 -80
- package/dist/memory/session-memory.d.ts.map +0 -1
- package/dist/memory/session-memory.js +0 -468
- package/dist/memory/session-memory.js.map +0 -1
- package/dist/templates/opencode-agents-template.d.ts +0 -2
- package/dist/templates/opencode-agents-template.d.ts.map +0 -1
- package/dist/templates/opencode-agents-template.js +0 -469
- package/dist/templates/opencode-agents-template.js.map +0 -1
- package/scripts/bulk-optimize-tools.js +0 -486
- package/scripts/optimize-mcp-tools.ts +0 -410
- package/themes/README.md +0 -83
- package/themes/servicenow.json +0 -117
- /package/{opencode-config.example.json → snowcode-config.example.json} +0 -0
package/dist/cli.js
CHANGED
|
@@ -40,6 +40,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
40
40
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
41
|
};
|
|
42
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.setupMCPConfig = setupMCPConfig;
|
|
43
44
|
const commander_1 = require("commander");
|
|
44
45
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
45
46
|
const fs_1 = require("fs");
|
|
@@ -326,13 +327,13 @@ program
|
|
|
326
327
|
started_at: new Date().toISOString(),
|
|
327
328
|
is_authenticated: isAuthenticated
|
|
328
329
|
});
|
|
329
|
-
// Start
|
|
330
|
+
// Start SnowCode multi-agent orchestration
|
|
330
331
|
try {
|
|
331
332
|
// Generate the orchestration prompt
|
|
332
333
|
const orchestrationPrompt = buildQueenAgentPrompt(objective, taskAnalysis, options, isAuthenticated, sessionId);
|
|
333
334
|
if (options.verbose) {
|
|
334
|
-
cliLogger.info('\n👑 Initializing multi-agent orchestration with
|
|
335
|
-
cliLogger.info('🎯
|
|
335
|
+
cliLogger.info('\n👑 Initializing multi-agent orchestration with SnowCode...');
|
|
336
|
+
cliLogger.info('🎯 SnowCode will coordinate the following:');
|
|
336
337
|
cliLogger.info(` - Analyze objective: "${objective}"`);
|
|
337
338
|
cliLogger.info(` - Spawn ${taskAnalysis.estimatedAgentCount} specialized agents via Task() system`);
|
|
338
339
|
cliLogger.info(` - Coordinate through shared memory (session: ${sessionId})`);
|
|
@@ -344,7 +345,7 @@ program
|
|
|
344
345
|
options.sharedMemory || options.progressMonitoring;
|
|
345
346
|
if (options.verbose && hasIntelligentFeatures && isAuthenticated) {
|
|
346
347
|
cliLogger.info('\n🧠 INTELLIGENT ORCHESTRATION MODE ENABLED!');
|
|
347
|
-
cliLogger.info('✨
|
|
348
|
+
cliLogger.info('✨ SnowCode will use advanced features:');
|
|
348
349
|
if (options.autoPermissions) {
|
|
349
350
|
cliLogger.info(' 🔐 Automatic permission escalation');
|
|
350
351
|
}
|
|
@@ -376,12 +377,12 @@ program
|
|
|
376
377
|
cliLogger.info('\n🔗 Live ServiceNow integration: ❌ Disabled');
|
|
377
378
|
}
|
|
378
379
|
}
|
|
379
|
-
// Try to execute
|
|
380
|
-
const success = await
|
|
380
|
+
// Try to execute SnowCode directly with the objective
|
|
381
|
+
const success = await executeSnowCode(objective);
|
|
381
382
|
if (success) {
|
|
382
383
|
if (options.verbose) {
|
|
383
|
-
cliLogger.info('✅
|
|
384
|
-
cliLogger.info('🤖
|
|
384
|
+
cliLogger.info('✅ SnowCode launched successfully!');
|
|
385
|
+
cliLogger.info('🤖 SnowCode is now executing your objective');
|
|
385
386
|
cliLogger.info(`💾 Monitor progress with session ID: ${sessionId}`);
|
|
386
387
|
if (isAuthenticated && options.autoDeploy) {
|
|
387
388
|
cliLogger.info('🚀 Real artifacts will be created in ServiceNow');
|
|
@@ -397,11 +398,11 @@ program
|
|
|
397
398
|
});
|
|
398
399
|
}
|
|
399
400
|
else {
|
|
400
|
-
cliLogger.warn('⚠️
|
|
401
|
-
cliLogger.info('\n📋 Please ensure
|
|
402
|
-
cliLogger.info(' npm install -g
|
|
403
|
-
cliLogger.info('\n💡 Or start
|
|
404
|
-
cliLogger.info(' 1. Run:
|
|
401
|
+
cliLogger.warn('⚠️ SnowCode CLI not found or failed to start');
|
|
402
|
+
cliLogger.info('\n📋 Please ensure SnowCode is installed:');
|
|
403
|
+
cliLogger.info(' npm install -g @groeimetai/snowcode');
|
|
404
|
+
cliLogger.info('\n💡 Or start SnowCode manually:');
|
|
405
|
+
cliLogger.info(' 1. Run: snowcode');
|
|
405
406
|
cliLogger.info(` 2. Enter objective: ${objective}`);
|
|
406
407
|
if (isAuthenticated && options.autoDeploy) {
|
|
407
408
|
cliLogger.info('\n🚀 Deployment Mode: Artifacts will be created in ServiceNow');
|
|
@@ -421,26 +422,26 @@ program
|
|
|
421
422
|
});
|
|
422
423
|
}
|
|
423
424
|
});
|
|
424
|
-
// Helper function to execute
|
|
425
|
-
async function
|
|
425
|
+
// Helper function to execute SnowCode directly with the objective
|
|
426
|
+
async function executeSnowCode(objective) {
|
|
426
427
|
try {
|
|
427
|
-
// Check if
|
|
428
|
+
// Check if SnowCode CLI is available
|
|
428
429
|
const { execSync } = require('child_process');
|
|
429
430
|
try {
|
|
430
|
-
execSync('which
|
|
431
|
+
execSync('which snowcode', { stdio: 'ignore' });
|
|
431
432
|
}
|
|
432
433
|
catch {
|
|
433
|
-
cliLogger.warn('⚠️
|
|
434
|
-
cliLogger.info('📋 Please install
|
|
434
|
+
cliLogger.warn('⚠️ SnowCode CLI not found in PATH');
|
|
435
|
+
cliLogger.info('📋 Please install SnowCode: npm install -g @groeimetai/snowcode');
|
|
435
436
|
return false;
|
|
436
437
|
}
|
|
437
|
-
// Check for
|
|
438
|
-
const
|
|
439
|
-
const
|
|
440
|
-
if (!
|
|
441
|
-
cliLogger.warn('⚠️
|
|
438
|
+
// Check for SnowCode config (.snowcode/snowcode.json created by init)
|
|
439
|
+
const snowcodeConfigPath = (0, path_1.join)(process.cwd(), '.snowcode', 'snowcode.json');
|
|
440
|
+
const hasSnowcodeConfig = (0, fs_2.existsSync)(snowcodeConfigPath);
|
|
441
|
+
if (!hasSnowcodeConfig) {
|
|
442
|
+
cliLogger.warn('⚠️ SnowCode configuration not found');
|
|
442
443
|
cliLogger.info('📋 Please run: snow-flow init');
|
|
443
|
-
cliLogger.info(' This will create .
|
|
444
|
+
cliLogger.info(' This will create .snowcode/snowcode.json with MCP servers configured');
|
|
444
445
|
return false;
|
|
445
446
|
}
|
|
446
447
|
// Check for .env file with required configuration
|
|
@@ -457,10 +458,10 @@ async function executeOpenCode(objective) {
|
|
|
457
458
|
// Debug output if enabled
|
|
458
459
|
if (process.env.SNOW_FLOW_DEBUG === 'true' || process.env.VERBOSE === 'true') {
|
|
459
460
|
cliLogger.info(`🔍 Working Directory: ${process.cwd()}`);
|
|
460
|
-
cliLogger.info(`🔍
|
|
461
|
+
cliLogger.info(`🔍 SnowCode Config: ${snowcodeConfigPath}`);
|
|
461
462
|
cliLogger.info(`🔍 Environment File: ${envPath}`);
|
|
462
463
|
}
|
|
463
|
-
// Write objective to temp file for
|
|
464
|
+
// Write objective to temp file for SnowCode to read
|
|
464
465
|
const { tmpdir } = await Promise.resolve().then(() => __importStar(require('os')));
|
|
465
466
|
const { writeFileSync, unlinkSync } = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
466
467
|
const tmpFile = (0, path_1.join)(tmpdir(), `snow-flow-objective-${Date.now()}.txt`);
|
|
@@ -468,29 +469,29 @@ async function executeOpenCode(objective) {
|
|
|
468
469
|
// Get default model from .env if available
|
|
469
470
|
const defaultModel = process.env.DEFAULT_MODEL;
|
|
470
471
|
const defaultProvider = process.env.DEFAULT_LLM_PROVIDER;
|
|
471
|
-
// Start
|
|
472
|
-
//
|
|
473
|
-
let
|
|
474
|
-
// If we have a default model, pass it to
|
|
472
|
+
// Start SnowCode with the objective and default model
|
|
473
|
+
// SnowCode will be started interactively with stdin redirect
|
|
474
|
+
let snowcodeCommand = `snowcode < "${tmpFile}"`;
|
|
475
|
+
// If we have a default model, pass it to SnowCode
|
|
475
476
|
if (defaultModel) {
|
|
476
|
-
|
|
477
|
+
snowcodeCommand = `snowcode --model "${defaultModel}" < "${tmpFile}"`;
|
|
477
478
|
}
|
|
478
|
-
// Spawn
|
|
479
|
-
//
|
|
480
|
-
// We pass the objective via stdin redirect (shell:
|
|
481
|
-
const
|
|
482
|
-
stdio: 'inherit', // All stdio inherited -
|
|
479
|
+
// Spawn SnowCode process - let it run fully interactively
|
|
480
|
+
// SnowCode is a TUI (Terminal User Interface) application that needs full terminal control
|
|
481
|
+
// We pass the objective via stdin redirect (shell: snowcode < tmpfile)
|
|
482
|
+
const snowcodeProcess = (0, child_process_1.spawn)('sh', ['-c', snowcodeCommand], {
|
|
483
|
+
stdio: 'inherit', // All stdio inherited - SnowCode can use TTY
|
|
483
484
|
cwd: process.cwd(),
|
|
484
485
|
env: {
|
|
485
486
|
...process.env,
|
|
486
|
-
// Ensure DEFAULT_MODEL is available to
|
|
487
|
+
// Ensure DEFAULT_MODEL is available to SnowCode
|
|
487
488
|
DEFAULT_MODEL: defaultModel || '',
|
|
488
489
|
DEFAULT_LLM_PROVIDER: defaultProvider || ''
|
|
489
490
|
}
|
|
490
491
|
});
|
|
491
492
|
// Set up process monitoring
|
|
492
493
|
return new Promise((resolve) => {
|
|
493
|
-
|
|
494
|
+
snowcodeProcess.on('close', async (code) => {
|
|
494
495
|
// Clean up temp file
|
|
495
496
|
try {
|
|
496
497
|
unlinkSync(tmpFile);
|
|
@@ -500,7 +501,7 @@ async function executeOpenCode(objective) {
|
|
|
500
501
|
}
|
|
501
502
|
resolve(code === 0);
|
|
502
503
|
});
|
|
503
|
-
|
|
504
|
+
snowcodeProcess.on('error', (error) => {
|
|
504
505
|
// Clean up temp file
|
|
505
506
|
try {
|
|
506
507
|
unlinkSync(tmpFile);
|
|
@@ -508,15 +509,15 @@ async function executeOpenCode(objective) {
|
|
|
508
509
|
catch (e) {
|
|
509
510
|
// Ignore cleanup errors
|
|
510
511
|
}
|
|
511
|
-
cliLogger.error(`❌ Failed to start
|
|
512
|
+
cliLogger.error(`❌ Failed to start SnowCode: ${error.message}`);
|
|
512
513
|
resolve(false);
|
|
513
514
|
});
|
|
514
515
|
// Set timeout (configurable via environment variable)
|
|
515
516
|
const timeoutMinutes = parseInt(process.env.SNOW_FLOW_TIMEOUT_MINUTES || '0');
|
|
516
517
|
if (timeoutMinutes > 0) {
|
|
517
518
|
setTimeout(() => {
|
|
518
|
-
cliLogger.warn(`⏱️
|
|
519
|
-
|
|
519
|
+
cliLogger.warn(`⏱️ SnowCode session timeout (${timeoutMinutes} minutes), terminating...`);
|
|
520
|
+
snowcodeProcess.kill('SIGTERM');
|
|
520
521
|
// Clean up temp file
|
|
521
522
|
try {
|
|
522
523
|
unlinkSync(tmpFile);
|
|
@@ -530,25 +531,25 @@ async function executeOpenCode(objective) {
|
|
|
530
531
|
});
|
|
531
532
|
}
|
|
532
533
|
catch (error) {
|
|
533
|
-
cliLogger.error('❌ Error launching
|
|
534
|
-
cliLogger.info('📋 Please start
|
|
534
|
+
cliLogger.error('❌ Error launching SnowCode:', error instanceof Error ? error.message : String(error));
|
|
535
|
+
cliLogger.info('📋 Please start SnowCode manually: snowcode');
|
|
535
536
|
return false;
|
|
536
537
|
}
|
|
537
538
|
}
|
|
538
|
-
// Real-time monitoring dashboard for
|
|
539
|
-
function startMonitoringDashboard(
|
|
539
|
+
// Real-time monitoring dashboard for SnowCode process
|
|
540
|
+
function startMonitoringDashboard(snowcodeProcess) {
|
|
540
541
|
let iterations = 0;
|
|
541
542
|
const startTime = Date.now();
|
|
542
543
|
// Show initial dashboard only once
|
|
543
544
|
cliLogger.info(`┌─────────────────────────────────────────────────────────────┐`);
|
|
544
545
|
cliLogger.info(`│ 🚀 Snow-Flow Dashboard v${version_js_1.VERSION} │`);
|
|
545
546
|
cliLogger.info(`├─────────────────────────────────────────────────────────────┤`);
|
|
546
|
-
cliLogger.info(`│ 🤖
|
|
547
|
-
cliLogger.info(`│ 📊 Process ID: ${
|
|
547
|
+
cliLogger.info(`│ 🤖 SnowCode Status: ✅ Starting │`);
|
|
548
|
+
cliLogger.info(`│ 📊 Process ID: ${snowcodeProcess.pid || 'N/A'} │`);
|
|
548
549
|
cliLogger.info(`│ ⏱️ Session Time: 00:00 │`);
|
|
549
550
|
cliLogger.info(`│ 🔄 Monitoring Cycles: 0 │`);
|
|
550
551
|
cliLogger.info('└─────────────────────────────────────────────────────────────┘');
|
|
551
|
-
// Silent monitoring - only log to file or memory, don't interfere with
|
|
552
|
+
// Silent monitoring - only log to file or memory, don't interfere with SnowCode UI
|
|
552
553
|
const monitoringInterval = setInterval(() => {
|
|
553
554
|
iterations++;
|
|
554
555
|
const uptime = Math.floor((Date.now() - startTime) / 1000);
|
|
@@ -1363,7 +1364,7 @@ program
|
|
|
1363
1364
|
cliLogger.info(` - Primary: ${sessionData.taskAnalysis.primaryAgent}`);
|
|
1364
1365
|
cliLogger.info(` - Supporting: ${sessionData.taskAnalysis.supportingAgents.join(', ')}`);
|
|
1365
1366
|
if (launchData && launchData.success) {
|
|
1366
|
-
cliLogger.info(`\n✅ Status:
|
|
1367
|
+
cliLogger.info(`\n✅ Status: SnowCode (or Claude Code) launched successfully`);
|
|
1367
1368
|
cliLogger.info(`🚀 Launched at: ${launchData.launched_at}`);
|
|
1368
1369
|
}
|
|
1369
1370
|
else if (errorData) {
|
|
@@ -1372,11 +1373,11 @@ program
|
|
|
1372
1373
|
cliLogger.error(`🕐 Failed at: ${errorData.failed_at}`);
|
|
1373
1374
|
}
|
|
1374
1375
|
else {
|
|
1375
|
-
cliLogger.info(`\n⏳ Status: Awaiting manual
|
|
1376
|
+
cliLogger.info(`\n⏳ Status: Awaiting manual SnowCode execution`);
|
|
1376
1377
|
}
|
|
1377
1378
|
cliLogger.info('\n💡 Tips:');
|
|
1378
|
-
cliLogger.info(' - Check
|
|
1379
|
-
cliLogger.info(' - Use Memory.get("swarm_session_' + sessionId + '") in
|
|
1379
|
+
cliLogger.info(' - Check SnowCode for real-time agent progress');
|
|
1380
|
+
cliLogger.info(' - Use Memory.get("swarm_session_' + sessionId + '") in SnowCode');
|
|
1380
1381
|
cliLogger.info(' - Monitor TodoRead for task completion status');
|
|
1381
1382
|
if (options.watch) {
|
|
1382
1383
|
cliLogger.info(`\n👀 Watching for updates every ${options.interval} seconds...`);
|
|
@@ -1387,7 +1388,7 @@ program
|
|
|
1387
1388
|
// Re-fetch session data to check for updates
|
|
1388
1389
|
const updatedSession = memorySystem.getLearning(`session_${sessionId}`);
|
|
1389
1390
|
if (updatedSession) {
|
|
1390
|
-
cliLogger.info(' Status: Active - Check
|
|
1391
|
+
cliLogger.info(' Status: Active - Check SnowCode for details');
|
|
1391
1392
|
}
|
|
1392
1393
|
}, parseInt(options.interval) * 1000);
|
|
1393
1394
|
// Handle graceful shutdown
|
|
@@ -1480,12 +1481,12 @@ program
|
|
|
1480
1481
|
console.log('│ 📋 Recent Activity: │');
|
|
1481
1482
|
console.log(`│ • ${new Date().toLocaleTimeString()} - System monitoring active │`);
|
|
1482
1483
|
cliLogger.info('└─────────────────────────────────────────────────────────────┘');
|
|
1483
|
-
// Check for active
|
|
1484
|
+
// Check for active SnowCode/Claude Code processes
|
|
1484
1485
|
try {
|
|
1485
1486
|
const { execSync } = require('child_process');
|
|
1486
|
-
const processes = execSync('ps aux | grep "claude\\|opencode" | grep -v grep', { encoding: 'utf8' }).toString();
|
|
1487
|
+
const processes = execSync('ps aux | grep "claude\\|opencode\\|snowcode" | grep -v grep', { encoding: 'utf8' }).toString();
|
|
1487
1488
|
if (processes.trim()) {
|
|
1488
|
-
cliLogger.info('\n🤖 Active
|
|
1489
|
+
cliLogger.info('\n🤖 Active SnowCode/Claude Code Processes:');
|
|
1489
1490
|
const lines = processes.trim().split('\n');
|
|
1490
1491
|
lines.forEach((line, index) => {
|
|
1491
1492
|
if (index < 3) { // Show max 3 processes
|
|
@@ -1576,43 +1577,92 @@ program
|
|
|
1576
1577
|
console.log('🔐 Creating environment configuration...');
|
|
1577
1578
|
await createEnvFile(targetDir, options.force);
|
|
1578
1579
|
// Create MCP configuration - always included now (SPARC is default)
|
|
1579
|
-
console.log('🔧 Setting up MCP servers for
|
|
1580
|
+
console.log('🔧 Setting up MCP servers for SnowCode (also works with Claude Code)...');
|
|
1580
1581
|
await createMCPConfig(targetDir, options.force);
|
|
1581
1582
|
// Copy CLAUDE.md file
|
|
1582
1583
|
console.log('📚 Creating documentation files...');
|
|
1583
1584
|
await copyCLAUDEmd(targetDir, options.force);
|
|
1584
1585
|
// Create README files
|
|
1585
1586
|
await createReadmeFiles(targetDir, options.force);
|
|
1586
|
-
// Copy
|
|
1587
|
-
await
|
|
1588
|
-
// Copy
|
|
1589
|
-
await
|
|
1587
|
+
// Copy snowcode-config.example.json
|
|
1588
|
+
await copySnowCodeConfig(targetDir, options.force);
|
|
1589
|
+
// Copy SnowCode themes
|
|
1590
|
+
await copySnowCodeThemes(targetDir, options.force);
|
|
1591
|
+
// Copy SnowCode package.json with snowcode-plugin
|
|
1592
|
+
console.log('📦 Configuring SnowCode plugin (snowcode fork)...');
|
|
1593
|
+
await copySnowCodePackageJson(targetDir, options.force);
|
|
1590
1594
|
// Copy MCP server management scripts
|
|
1591
1595
|
console.log('🔧 Setting up MCP server management scripts...');
|
|
1592
1596
|
await copyMCPServerScripts(targetDir, options.force);
|
|
1593
1597
|
console.log(chalk_1.default.green.bold('\n✅ Snow-Flow project initialized successfully!'));
|
|
1594
1598
|
console.log('\n📋 Created Snow-Flow configuration:');
|
|
1595
|
-
console.log(' ✓ .
|
|
1596
|
-
console.log(' ✓ .
|
|
1599
|
+
console.log(' ✓ .snowcode/ - SnowCode configuration with both MCP servers');
|
|
1600
|
+
console.log(' ✓ .snowcode/themes/ - ServiceNow custom theme for SnowCode');
|
|
1597
1601
|
console.log(' ✓ .claude/ - Claude Code MCP configuration (backward compatibility)');
|
|
1598
1602
|
console.log(' ✓ .mcp.json - 2 unified MCP servers (370 tools total)');
|
|
1599
|
-
console.log(' ✓ scripts/ - MCP server management and
|
|
1600
|
-
console.log(' ✓ AGENTS.md -
|
|
1603
|
+
console.log(' ✓ scripts/ - MCP server management and SnowCode launcher');
|
|
1604
|
+
console.log(' ✓ AGENTS.md - SnowCode primary instructions');
|
|
1601
1605
|
console.log(' ✓ CLAUDE.md - Claude Code compatibility');
|
|
1602
1606
|
console.log(' ✓ README.md - Complete capabilities documentation');
|
|
1603
|
-
console.log(' ✓
|
|
1607
|
+
console.log(' ✓ SNOWCODE-TROUBLESHOOTING.md - Troubleshooting guide');
|
|
1604
1608
|
console.log(' ✓ .snow-flow/ - Project workspace and memory');
|
|
1605
1609
|
if (!options.skipMcp) {
|
|
1606
|
-
// NOTE: MCP servers work with
|
|
1607
|
-
console.log(chalk_1.default.blue('\nℹ️ MCP servers configured for
|
|
1610
|
+
// NOTE: MCP servers work with SnowCode's native Task() system
|
|
1611
|
+
console.log(chalk_1.default.blue('\nℹ️ MCP servers configured for SnowCode (also compatible with Claude Code)'));
|
|
1608
1612
|
console.log(chalk_1.default.green('✅ 411 ServiceNow tools automatically available via 2 unified servers'));
|
|
1609
1613
|
console.log(chalk_1.default.blue('📋 SDK handles MCP server lifecycle automatically'));
|
|
1610
1614
|
// Verify MCP servers can actually start
|
|
1611
1615
|
console.log(chalk_1.default.dim('\n🔍 Verifying MCP server configuration...'));
|
|
1612
1616
|
await verifyMCPServers(targetDir);
|
|
1617
|
+
// Start MCP servers using the locally copied script
|
|
1618
|
+
console.log(chalk_1.default.blue('\n🚀 Starting MCP servers...'));
|
|
1619
|
+
try {
|
|
1620
|
+
const { execSync } = require('child_process');
|
|
1621
|
+
const path = require('path');
|
|
1622
|
+
const fs = require('fs');
|
|
1623
|
+
// Use the script that was copied to the project directory
|
|
1624
|
+
const localScriptPath = path.join(targetDir, 'scripts', 'mcp-server-manager.sh');
|
|
1625
|
+
// Check if the script exists locally
|
|
1626
|
+
if (!fs.existsSync(localScriptPath)) {
|
|
1627
|
+
throw new Error('MCP server manager script not found. Re-run snow-flow init if needed.');
|
|
1628
|
+
}
|
|
1629
|
+
// Make script executable
|
|
1630
|
+
try {
|
|
1631
|
+
fs.chmodSync(localScriptPath, '755');
|
|
1632
|
+
}
|
|
1633
|
+
catch (chmodError) {
|
|
1634
|
+
// Ignore chmod errors on Windows
|
|
1635
|
+
}
|
|
1636
|
+
// Execute and capture output
|
|
1637
|
+
const output = execSync(`bash "${localScriptPath}" start`, {
|
|
1638
|
+
cwd: targetDir,
|
|
1639
|
+
encoding: 'utf-8'
|
|
1640
|
+
});
|
|
1641
|
+
// Check if startup was successful
|
|
1642
|
+
if (output.includes('✓ MCP server started')) {
|
|
1643
|
+
console.log(chalk_1.default.green('✅ MCP servers started successfully'));
|
|
1644
|
+
const pidMatch = output.match(/PID: (\d+)/);
|
|
1645
|
+
if (pidMatch) {
|
|
1646
|
+
console.log(chalk_1.default.dim(` Server PID: ${pidMatch[1]}`));
|
|
1647
|
+
}
|
|
1648
|
+
console.log(chalk_1.default.dim(' Check status: ./scripts/mcp-server-manager.sh status'));
|
|
1649
|
+
console.log(chalk_1.default.dim(' View logs: ./scripts/mcp-server-manager.sh logs'));
|
|
1650
|
+
}
|
|
1651
|
+
else {
|
|
1652
|
+
console.log(chalk_1.default.yellow('⚠️ MCP server startup status unclear'));
|
|
1653
|
+
console.log(output);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
catch (error) {
|
|
1657
|
+
console.log(chalk_1.default.yellow('⚠️ MCP servers will start automatically when you launch SnowCode'));
|
|
1658
|
+
console.log(chalk_1.default.dim(' Or start manually: ./scripts/mcp-server-manager.sh start'));
|
|
1659
|
+
if (error.message.includes('No .env file found')) {
|
|
1660
|
+
console.log(chalk_1.default.dim(' 💡 Tip: Configure .env first, then run: ./scripts/mcp-server-manager.sh start'));
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1613
1663
|
}
|
|
1614
|
-
// Check and optionally install
|
|
1615
|
-
const configImported = await
|
|
1664
|
+
// Check and optionally install SnowCode
|
|
1665
|
+
const configImported = await checkAndInstallSnowCode();
|
|
1616
1666
|
console.log(chalk_1.default.blue.bold('\n🎯 Next steps:'));
|
|
1617
1667
|
console.log('1. Configure credentials: Edit ' + chalk_1.default.cyan('.env'));
|
|
1618
1668
|
console.log(' - Add your ServiceNow instance URL, username/password or OAuth credentials');
|
|
@@ -1620,10 +1670,10 @@ program
|
|
|
1620
1670
|
console.log(' - Authenticates with your LLM provider (Claude/OpenAI/Google/Ollama)');
|
|
1621
1671
|
console.log(' - Then authenticates with ServiceNow OAuth');
|
|
1622
1672
|
console.log(' - Your provider choice is automatically saved to .env');
|
|
1623
|
-
console.log('3. Start developing with
|
|
1673
|
+
console.log('3. Start developing with SnowCode: ' + chalk_1.default.cyan('./scripts/start-snowcode.sh'));
|
|
1624
1674
|
console.log(' - Smart launcher with pre-flight checks and MCP server management');
|
|
1625
1675
|
console.log(' - Or use swarm: ' + chalk_1.default.cyan('snow-flow swarm "create incident dashboard"'));
|
|
1626
|
-
console.log(' - Or launch
|
|
1676
|
+
console.log(' - Or launch SnowCode directly: ' + chalk_1.default.cyan('snowcode'));
|
|
1627
1677
|
console.log('\n📚 Documentation: ' + chalk_1.default.blue('https://github.com/groeimetai/snow-flow'));
|
|
1628
1678
|
console.log('💡 370+ ServiceNow tools • 2 MCP servers • Multi-LLM support');
|
|
1629
1679
|
// Force exit to prevent hanging
|
|
@@ -1654,7 +1704,7 @@ program
|
|
|
1654
1704
|
help Show this help
|
|
1655
1705
|
|
|
1656
1706
|
🎯 Example Usage:
|
|
1657
|
-
snow-flow init # Initialize project (auto-configures
|
|
1707
|
+
snow-flow init # Initialize project (auto-configures SnowCode)
|
|
1658
1708
|
snow-flow auth login # Authenticate (handles LLM + ServiceNow)
|
|
1659
1709
|
snow-flow auth status # Check authentication status
|
|
1660
1710
|
snow-flow swarm "create a widget for incident management"
|
|
@@ -1695,63 +1745,81 @@ program
|
|
|
1695
1745
|
`);
|
|
1696
1746
|
});
|
|
1697
1747
|
// Helper functions for init command
|
|
1698
|
-
// Check if
|
|
1699
|
-
async function
|
|
1748
|
+
// Check if SnowCode is installed, and offer to install it
|
|
1749
|
+
async function checkAndInstallSnowCode() {
|
|
1700
1750
|
const { execSync } = require('child_process');
|
|
1701
|
-
let
|
|
1751
|
+
let snowcodeInstalled = false;
|
|
1702
1752
|
try {
|
|
1703
|
-
// Check if
|
|
1704
|
-
execSync('which
|
|
1705
|
-
console.log(chalk_1.default.green('\n✅
|
|
1706
|
-
|
|
1753
|
+
// Check if snowcode is already installed
|
|
1754
|
+
execSync('which snowcode', { stdio: 'ignore' });
|
|
1755
|
+
console.log(chalk_1.default.green('\n✅ SnowCode is already installed!'));
|
|
1756
|
+
snowcodeInstalled = true;
|
|
1707
1757
|
}
|
|
1708
1758
|
catch {
|
|
1709
|
-
//
|
|
1710
|
-
console.log(chalk_1.default.yellow('\n⚠️
|
|
1711
|
-
console.log(chalk_1.default.blue('
|
|
1759
|
+
// SnowCode not installed
|
|
1760
|
+
console.log(chalk_1.default.yellow('\n⚠️ SnowCode is not installed'));
|
|
1761
|
+
console.log(chalk_1.default.blue('SnowCode is required to use Snow-Flow with any LLM provider'));
|
|
1712
1762
|
// Import inquirer dynamically
|
|
1713
1763
|
const inquirer = (await Promise.resolve().then(() => __importStar(require('inquirer')))).default;
|
|
1714
1764
|
const { shouldInstall } = await inquirer.prompt([
|
|
1715
1765
|
{
|
|
1716
1766
|
type: 'confirm',
|
|
1717
1767
|
name: 'shouldInstall',
|
|
1718
|
-
message: 'Would you like to install
|
|
1768
|
+
message: 'Would you like to install SnowCode now? (npm install -g @groeimetai/snowcode)',
|
|
1719
1769
|
default: true
|
|
1720
1770
|
}
|
|
1721
1771
|
]);
|
|
1722
1772
|
if (!shouldInstall) {
|
|
1723
|
-
console.log(chalk_1.default.yellow('\n⏭️ Skipping
|
|
1724
|
-
console.log(chalk_1.default.blue('You can install it later with: ') + chalk_1.default.cyan('npm install -g
|
|
1773
|
+
console.log(chalk_1.default.yellow('\n⏭️ Skipping SnowCode installation'));
|
|
1774
|
+
console.log(chalk_1.default.blue('You can install it later with: ') + chalk_1.default.cyan('npm install -g @groeimetai/snowcode'));
|
|
1725
1775
|
return false;
|
|
1726
1776
|
}
|
|
1727
|
-
// Install
|
|
1728
|
-
console.log(chalk_1.default.blue('\n📦 Installing
|
|
1777
|
+
// Install SnowCode
|
|
1778
|
+
console.log(chalk_1.default.blue('\n📦 Installing SnowCode globally...'));
|
|
1729
1779
|
console.log(chalk_1.default.dim('This may take a minute...'));
|
|
1730
1780
|
try {
|
|
1731
|
-
execSync('npm install -g
|
|
1732
|
-
console.log(chalk_1.default.green('\n✅
|
|
1733
|
-
|
|
1781
|
+
execSync('npm install -g @groeimetai/snowcode', { stdio: 'inherit' });
|
|
1782
|
+
console.log(chalk_1.default.green('\n✅ SnowCode installed successfully!'));
|
|
1783
|
+
snowcodeInstalled = true;
|
|
1734
1784
|
}
|
|
1735
1785
|
catch (error) {
|
|
1736
|
-
console.log(chalk_1.default.red('\n❌ Failed to install
|
|
1737
|
-
console.log(chalk_1.default.yellow('Please install it manually: ') + chalk_1.default.cyan('npm install -g
|
|
1786
|
+
console.log(chalk_1.default.red('\n❌ Failed to install SnowCode'));
|
|
1787
|
+
console.log(chalk_1.default.yellow('Please install it manually: ') + chalk_1.default.cyan('npm install -g @groeimetai/snowcode'));
|
|
1738
1788
|
return false;
|
|
1739
1789
|
}
|
|
1740
1790
|
}
|
|
1741
|
-
//
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
const
|
|
1791
|
+
// ALWAYS install SnowCode locally in the project directory with platform binaries
|
|
1792
|
+
console.log(chalk_1.default.blue('\n📦 Installing SnowCode locally (with platform binaries)...'));
|
|
1793
|
+
console.log(chalk_1.default.dim('Installing @groeimetai/snowcode@0.15.14-snow-flow-4...'));
|
|
1794
|
+
try {
|
|
1795
|
+
const projectDir = process.cwd();
|
|
1796
|
+
execSync('npm install @groeimetai/snowcode@0.15.14-snow-flow-4', {
|
|
1797
|
+
cwd: projectDir,
|
|
1798
|
+
stdio: 'inherit'
|
|
1799
|
+
});
|
|
1800
|
+
console.log(chalk_1.default.green('✅ SnowCode installed locally with platform binaries!'));
|
|
1801
|
+
console.log(chalk_1.default.dim(` Platform binary: opencode-${process.platform}-${process.arch}`));
|
|
1802
|
+
}
|
|
1803
|
+
catch (error) {
|
|
1804
|
+
console.log(chalk_1.default.red('\n❌ Failed to install SnowCode locally'));
|
|
1805
|
+
console.log(chalk_1.default.yellow('Please install it manually: ') + chalk_1.default.cyan('npm install @groeimetai/snowcode@0.15.14-snow-flow-4'));
|
|
1806
|
+
console.log(chalk_1.default.dim('This is required for the compiled binaries'));
|
|
1807
|
+
return false;
|
|
1808
|
+
}
|
|
1809
|
+
// If SnowCode is installed, copy config to .snowcode/ directory
|
|
1810
|
+
// SnowCode automatically detects config files in project root and .snowcode/ directory
|
|
1811
|
+
if (snowcodeInstalled) {
|
|
1812
|
+
const exampleConfigPath = (0, path_1.join)(process.cwd(), 'snowcode-config.example.json');
|
|
1813
|
+
const snowcodeConfigPath = (0, path_1.join)(process.cwd(), '.snowcode', 'config.json');
|
|
1746
1814
|
// Check if example config file exists
|
|
1747
1815
|
try {
|
|
1748
1816
|
await fs_1.promises.access(exampleConfigPath);
|
|
1749
|
-
console.log(chalk_1.default.blue('\n🔧 Setting up
|
|
1817
|
+
console.log(chalk_1.default.blue('\n🔧 Setting up SnowCode configuration...'));
|
|
1750
1818
|
try {
|
|
1751
|
-
// Copy example config to .
|
|
1819
|
+
// Copy example config to .snowcode/config.json for automatic detection
|
|
1752
1820
|
let configContent = await fs_1.promises.readFile(exampleConfigPath, 'utf-8');
|
|
1753
1821
|
// Ensure the config content has the correct cwd (in case it still has a placeholder)
|
|
1754
|
-
// This is a safety check - the placeholder should already be replaced by
|
|
1822
|
+
// This is a safety check - the placeholder should already be replaced by copySnowCodeConfig
|
|
1755
1823
|
if (configContent.includes('"/path/to/your/snow-flow/installation"')) {
|
|
1756
1824
|
console.log(chalk_1.default.yellow('⚠️ Config still contains placeholder, attempting to fix...'));
|
|
1757
1825
|
// Determine the snow-flow installation directory
|
|
@@ -1784,19 +1852,19 @@ async function checkAndInstallOpenCode() {
|
|
|
1784
1852
|
configContent = configContent.replace('"/path/to/your/snow-flow/installation"', `"${snowFlowRoot.replace(/\\/g, '/')}"`);
|
|
1785
1853
|
}
|
|
1786
1854
|
}
|
|
1787
|
-
await fs_1.promises.writeFile(
|
|
1788
|
-
console.log(chalk_1.default.green('✅
|
|
1789
|
-
console.log(chalk_1.default.blue('💡
|
|
1855
|
+
await fs_1.promises.writeFile(snowcodeConfigPath, configContent);
|
|
1856
|
+
console.log(chalk_1.default.green('✅ SnowCode configuration created at .snowcode/config.json'));
|
|
1857
|
+
console.log(chalk_1.default.blue('💡 SnowCode will automatically detect this configuration'));
|
|
1790
1858
|
return true; // Successfully configured
|
|
1791
1859
|
}
|
|
1792
1860
|
catch (error) {
|
|
1793
|
-
console.log(chalk_1.default.yellow('\n⚠️ Could not create
|
|
1794
|
-
console.log(chalk_1.default.blue('You can copy it manually: ') + chalk_1.default.cyan(`cp
|
|
1861
|
+
console.log(chalk_1.default.yellow('\n⚠️ Could not create SnowCode config'));
|
|
1862
|
+
console.log(chalk_1.default.blue('You can copy it manually: ') + chalk_1.default.cyan(`cp snowcode-config.example.json .snowcode/config.json`));
|
|
1795
1863
|
return false;
|
|
1796
1864
|
}
|
|
1797
1865
|
}
|
|
1798
1866
|
catch {
|
|
1799
|
-
console.log(chalk_1.default.yellow('\n⚠️
|
|
1867
|
+
console.log(chalk_1.default.yellow('\n⚠️ snowcode-config.example.json not found'));
|
|
1800
1868
|
console.log(chalk_1.default.blue('Config will be available after init completes'));
|
|
1801
1869
|
return false;
|
|
1802
1870
|
}
|
|
@@ -1857,7 +1925,7 @@ async function createReadmeFiles(targetDir, force = false) {
|
|
|
1857
1925
|
await fs_1.promises.writeFile((0, path_1.join)(targetDir, 'servicenow/README.md'), '# ServiceNow Artifacts\n\nThis directory contains generated ServiceNow development artifacts.');
|
|
1858
1926
|
}
|
|
1859
1927
|
// Helper functions
|
|
1860
|
-
async function
|
|
1928
|
+
async function copySnowCodeConfig(targetDir, force = false) {
|
|
1861
1929
|
try {
|
|
1862
1930
|
// Determine the snow-flow installation directory
|
|
1863
1931
|
let snowFlowRoot;
|
|
@@ -1892,14 +1960,14 @@ async function copyOpenCodeConfig(targetDir, force = false) {
|
|
|
1892
1960
|
throw new Error('Could not find snow-flow project root');
|
|
1893
1961
|
}
|
|
1894
1962
|
}
|
|
1895
|
-
// Try to find the
|
|
1963
|
+
// Try to find the snowcode-config.example.json
|
|
1896
1964
|
const sourceFiles = [
|
|
1897
|
-
(0, path_1.join)(snowFlowRoot, '
|
|
1898
|
-
(0, path_1.join)(__dirname, '..', '
|
|
1899
|
-
(0, path_1.join)(__dirname, '
|
|
1900
|
-
(0, path_1.join)(__dirname, '..', '..', '..', '
|
|
1901
|
-
(0, path_1.join)(__dirname, '..', '..', '..', '..', '
|
|
1902
|
-
(0, path_1.join)(process.cwd(), '
|
|
1965
|
+
(0, path_1.join)(snowFlowRoot, 'snowcode-config.example.json'),
|
|
1966
|
+
(0, path_1.join)(__dirname, '..', 'snowcode-config.example.json'),
|
|
1967
|
+
(0, path_1.join)(__dirname, 'snowcode-config.example.json'),
|
|
1968
|
+
(0, path_1.join)(__dirname, '..', '..', '..', 'snowcode-config.example.json'),
|
|
1969
|
+
(0, path_1.join)(__dirname, '..', '..', '..', '..', 'snowcode-config.example.json'),
|
|
1970
|
+
(0, path_1.join)(process.cwd(), 'snowcode-config.example.json')
|
|
1903
1971
|
];
|
|
1904
1972
|
let foundSource = false;
|
|
1905
1973
|
let configContent = '';
|
|
@@ -1907,7 +1975,7 @@ async function copyOpenCodeConfig(targetDir, force = false) {
|
|
|
1907
1975
|
try {
|
|
1908
1976
|
configContent = await fs_1.promises.readFile(sourcePath, 'utf8');
|
|
1909
1977
|
foundSource = true;
|
|
1910
|
-
console.log(`✅ Found
|
|
1978
|
+
console.log(`✅ Found snowcode-config.example.json at: ${sourcePath}`);
|
|
1911
1979
|
break;
|
|
1912
1980
|
}
|
|
1913
1981
|
catch {
|
|
@@ -1915,19 +1983,19 @@ async function copyOpenCodeConfig(targetDir, force = false) {
|
|
|
1915
1983
|
}
|
|
1916
1984
|
}
|
|
1917
1985
|
if (!foundSource) {
|
|
1918
|
-
console.log('⚠️ Could not find
|
|
1986
|
+
console.log('⚠️ Could not find snowcode-config.example.json source file');
|
|
1919
1987
|
return;
|
|
1920
1988
|
}
|
|
1921
1989
|
// Replace placeholders with actual snow-flow installation path
|
|
1922
1990
|
configContent = configContent.replace('"/path/to/your/snow-flow/installation"', `"${snowFlowRoot.replace(/\\/g, '/')}"`);
|
|
1923
|
-
const targetPath = (0, path_1.join)(targetDir, '
|
|
1991
|
+
const targetPath = (0, path_1.join)(targetDir, 'snowcode-config.example.json');
|
|
1924
1992
|
try {
|
|
1925
1993
|
await fs_1.promises.access(targetPath);
|
|
1926
1994
|
if (force) {
|
|
1927
|
-
console.log('⚠️
|
|
1995
|
+
console.log('⚠️ snowcode-config.example.json already exists, overwriting with --force flag');
|
|
1928
1996
|
}
|
|
1929
1997
|
else {
|
|
1930
|
-
console.log('✅
|
|
1998
|
+
console.log('✅ snowcode-config.example.json already exists');
|
|
1931
1999
|
return;
|
|
1932
2000
|
}
|
|
1933
2001
|
}
|
|
@@ -1935,15 +2003,15 @@ async function copyOpenCodeConfig(targetDir, force = false) {
|
|
|
1935
2003
|
// File doesn't exist, continue with creation
|
|
1936
2004
|
}
|
|
1937
2005
|
await fs_1.promises.writeFile(targetPath, configContent);
|
|
1938
|
-
console.log('✅ Created
|
|
2006
|
+
console.log('✅ Created snowcode-config.example.json with correct snow-flow path');
|
|
1939
2007
|
}
|
|
1940
2008
|
catch (error) {
|
|
1941
|
-
console.error('❌ Error copying
|
|
2009
|
+
console.error('❌ Error copying snowcode-config.example.json:', error);
|
|
1942
2010
|
}
|
|
1943
2011
|
}
|
|
1944
|
-
async function
|
|
2012
|
+
async function copySnowCodeThemes(targetDir, force = false) {
|
|
1945
2013
|
try {
|
|
1946
|
-
// Determine the snow-flow installation directory (same logic as
|
|
2014
|
+
// Determine the snow-flow installation directory (same logic as copySnowCodeConfig)
|
|
1947
2015
|
let snowFlowRoot;
|
|
1948
2016
|
const isGlobalInstall = __dirname.includes('node_modules/snow-flow') ||
|
|
1949
2017
|
__dirname.includes('node_modules/.pnpm') ||
|
|
@@ -1977,8 +2045,8 @@ async function copyOpenCodeThemes(targetDir, force = false) {
|
|
|
1977
2045
|
(0, path_1.join)(snowFlowRoot, 'themes'),
|
|
1978
2046
|
(0, path_1.join)(__dirname, '..', 'themes'),
|
|
1979
2047
|
(0, path_1.join)(__dirname, 'themes'),
|
|
1980
|
-
(0, path_1.join)(snowFlowRoot, '.
|
|
1981
|
-
(0, path_1.join)(__dirname, '..', '.
|
|
2048
|
+
(0, path_1.join)(snowFlowRoot, '.snowcode', 'themes'),
|
|
2049
|
+
(0, path_1.join)(__dirname, '..', '.snowcode', 'themes')
|
|
1982
2050
|
];
|
|
1983
2051
|
let themesSourceDir = null;
|
|
1984
2052
|
for (const sourcePath of themesSourcePaths) {
|
|
@@ -1996,8 +2064,8 @@ async function copyOpenCodeThemes(targetDir, force = false) {
|
|
|
1996
2064
|
console.log('⚠️ Could not find themes directory, skipping theme installation');
|
|
1997
2065
|
return;
|
|
1998
2066
|
}
|
|
1999
|
-
// Create target .
|
|
2000
|
-
const themesTargetDir = (0, path_1.join)(targetDir, '.
|
|
2067
|
+
// Create target .snowcode/themes directory
|
|
2068
|
+
const themesTargetDir = (0, path_1.join)(targetDir, '.snowcode', 'themes');
|
|
2001
2069
|
await fs_1.promises.mkdir(themesTargetDir, { recursive: true });
|
|
2002
2070
|
// Copy all theme files
|
|
2003
2071
|
const themeFiles = await fs_1.promises.readdir(themesSourceDir);
|
|
@@ -2029,11 +2097,86 @@ async function copyOpenCodeThemes(targetDir, force = false) {
|
|
|
2029
2097
|
}
|
|
2030
2098
|
}
|
|
2031
2099
|
if (copiedCount > 0) {
|
|
2032
|
-
console.log(`✅ Copied ${copiedCount}
|
|
2100
|
+
console.log(`✅ Copied ${copiedCount} SnowCode theme file(s) to .snowcode/themes/`);
|
|
2033
2101
|
}
|
|
2034
2102
|
}
|
|
2035
2103
|
catch (error) {
|
|
2036
|
-
console.error('❌ Error copying
|
|
2104
|
+
console.error('❌ Error copying SnowCode themes:', error);
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
async function copySnowCodePackageJson(targetDir, force = false) {
|
|
2108
|
+
try {
|
|
2109
|
+
// Determine the snow-flow installation directory
|
|
2110
|
+
let snowFlowRoot;
|
|
2111
|
+
const isGlobalInstall = __dirname.includes('node_modules/snow-flow') ||
|
|
2112
|
+
__dirname.includes('node_modules/.pnpm') ||
|
|
2113
|
+
__dirname.includes('npm/snow-flow');
|
|
2114
|
+
if (isGlobalInstall) {
|
|
2115
|
+
const parts = __dirname.split(/node_modules[\/\\]/);
|
|
2116
|
+
snowFlowRoot = parts[0] + 'node_modules/snow-flow';
|
|
2117
|
+
}
|
|
2118
|
+
else {
|
|
2119
|
+
let currentDir = __dirname;
|
|
2120
|
+
while (currentDir !== '/') {
|
|
2121
|
+
try {
|
|
2122
|
+
const packageJsonPath = (0, path_1.join)(currentDir, 'package.json');
|
|
2123
|
+
const packageJson = JSON.parse(await fs_1.promises.readFile(packageJsonPath, 'utf-8'));
|
|
2124
|
+
if (packageJson.name === 'snow-flow') {
|
|
2125
|
+
snowFlowRoot = currentDir;
|
|
2126
|
+
break;
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
catch {
|
|
2130
|
+
// Continue searching up
|
|
2131
|
+
}
|
|
2132
|
+
currentDir = (0, path_1.dirname)(currentDir);
|
|
2133
|
+
}
|
|
2134
|
+
if (!snowFlowRoot) {
|
|
2135
|
+
throw new Error('Could not find snow-flow project root');
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
// Find snowcode package.json template
|
|
2139
|
+
const templateSourcePaths = [
|
|
2140
|
+
(0, path_1.join)(snowFlowRoot, 'templates', 'snowcode-package.json'),
|
|
2141
|
+
(0, path_1.join)(__dirname, '..', 'templates', 'snowcode-package.json'),
|
|
2142
|
+
(0, path_1.join)(__dirname, 'templates', 'snowcode-package.json')
|
|
2143
|
+
];
|
|
2144
|
+
let templatePath = null;
|
|
2145
|
+
for (const sourcePath of templateSourcePaths) {
|
|
2146
|
+
try {
|
|
2147
|
+
await fs_1.promises.access(sourcePath);
|
|
2148
|
+
templatePath = sourcePath;
|
|
2149
|
+
break;
|
|
2150
|
+
}
|
|
2151
|
+
catch {
|
|
2152
|
+
// Continue to next path
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
if (!templatePath) {
|
|
2156
|
+
console.log('⚠️ SnowCode package.json template not found, SnowCode will use default plugin');
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
// Create .snowcode directory
|
|
2160
|
+
const snowcodeDir = (0, path_1.join)(targetDir, '.snowcode');
|
|
2161
|
+
await fs_1.promises.mkdir(snowcodeDir, { recursive: true });
|
|
2162
|
+
// Copy package.json template
|
|
2163
|
+
const targetPath = (0, path_1.join)(snowcodeDir, 'package.json');
|
|
2164
|
+
// Check if file already exists
|
|
2165
|
+
try {
|
|
2166
|
+
await fs_1.promises.access(targetPath);
|
|
2167
|
+
if (!force) {
|
|
2168
|
+
console.log('✅ .snowcode/package.json already exists (snowcode-plugin configured)');
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
catch {
|
|
2173
|
+
// File doesn't exist, we can create it
|
|
2174
|
+
}
|
|
2175
|
+
await fs_1.promises.copyFile(templatePath, targetPath);
|
|
2176
|
+
console.log('✅ Created .snowcode/package.json with @groeimetai/snowcode-plugin');
|
|
2177
|
+
}
|
|
2178
|
+
catch (error) {
|
|
2179
|
+
console.error('❌ Error copying SnowCode package.json:', error);
|
|
2037
2180
|
}
|
|
2038
2181
|
}
|
|
2039
2182
|
/**
|
|
@@ -2044,8 +2187,8 @@ async function verifyMCPServers(targetDir) {
|
|
|
2044
2187
|
const path = require('path');
|
|
2045
2188
|
const fs = require('fs').promises;
|
|
2046
2189
|
try {
|
|
2047
|
-
// Read
|
|
2048
|
-
const configPath = path.join(targetDir, '.
|
|
2190
|
+
// Read SnowCode configuration
|
|
2191
|
+
const configPath = path.join(targetDir, '.snowcode', 'snowcode.json');
|
|
2049
2192
|
const configContent = await fs.readFile(configPath, 'utf-8');
|
|
2050
2193
|
const config = JSON.parse(configContent);
|
|
2051
2194
|
if (!config.mcp) {
|
|
@@ -2064,7 +2207,11 @@ async function verifyMCPServers(targetDir) {
|
|
|
2064
2207
|
process.stdout.write(chalk_1.default.dim(` Testing ${serverName}... `));
|
|
2065
2208
|
try {
|
|
2066
2209
|
// Try to spawn the MCP server
|
|
2067
|
-
|
|
2210
|
+
// Handle both old format (command: string, args: array) and new format (command: array)
|
|
2211
|
+
const [cmd, ...args] = Array.isArray(serverConfig.command)
|
|
2212
|
+
? serverConfig.command
|
|
2213
|
+
: [serverConfig.command, ...(serverConfig.args || [])];
|
|
2214
|
+
const serverProcess = spawn(cmd, args, {
|
|
2068
2215
|
env: { ...process.env, ...serverConfig.env },
|
|
2069
2216
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
2070
2217
|
});
|
|
@@ -2099,7 +2246,8 @@ async function verifyMCPServers(targetDir) {
|
|
|
2099
2246
|
}
|
|
2100
2247
|
else if (error.includes('Cannot find module') || error.includes('ENOENT')) {
|
|
2101
2248
|
console.log(chalk_1.default.red('✗ (server file not found)'));
|
|
2102
|
-
|
|
2249
|
+
const serverPath = Array.isArray(serverConfig.command) ? serverConfig.command[1] : serverConfig.args?.[0];
|
|
2250
|
+
console.log(chalk_1.default.yellow(` Check: ${serverPath}`));
|
|
2103
2251
|
failCount++;
|
|
2104
2252
|
}
|
|
2105
2253
|
else if (error) {
|
|
@@ -2142,7 +2290,7 @@ async function verifyMCPServers(targetDir) {
|
|
|
2142
2290
|
}
|
|
2143
2291
|
catch (error) {
|
|
2144
2292
|
console.log(chalk_1.default.yellow(` ⚠️ Could not verify MCP servers: ${error.message}`));
|
|
2145
|
-
console.log(chalk_1.default.dim(' Servers will be tested when
|
|
2293
|
+
console.log(chalk_1.default.dim(' Servers will be tested when SnowCode starts'));
|
|
2146
2294
|
}
|
|
2147
2295
|
}
|
|
2148
2296
|
async function copyMCPServerScripts(targetDir, force = false) {
|
|
@@ -2204,7 +2352,7 @@ async function copyMCPServerScripts(targetDir, force = false) {
|
|
|
2204
2352
|
// Copy specific scripts
|
|
2205
2353
|
const scriptFiles = [
|
|
2206
2354
|
'mcp-server-manager.sh',
|
|
2207
|
-
'start-
|
|
2355
|
+
'start-snowcode.sh'
|
|
2208
2356
|
];
|
|
2209
2357
|
let copiedCount = 0;
|
|
2210
2358
|
for (const scriptFile of scriptFiles) {
|
|
@@ -2234,11 +2382,11 @@ async function copyMCPServerScripts(targetDir, force = false) {
|
|
|
2234
2382
|
console.log(`✅ Copied ${copiedCount} MCP server management script(s) to scripts/`);
|
|
2235
2383
|
console.log(`✅ Scripts are executable and ready to use`);
|
|
2236
2384
|
}
|
|
2237
|
-
// Also copy
|
|
2385
|
+
// Also copy SNOWCODE-TROUBLESHOOTING.md to project root
|
|
2238
2386
|
const troubleshootingSourcePaths = [
|
|
2239
|
-
(0, path_1.join)(snowFlowRoot, '
|
|
2240
|
-
(0, path_1.join)(__dirname, '..', '
|
|
2241
|
-
(0, path_1.join)(__dirname, '
|
|
2387
|
+
(0, path_1.join)(snowFlowRoot, 'SNOWCODE-TROUBLESHOOTING.md'),
|
|
2388
|
+
(0, path_1.join)(__dirname, '..', 'SNOWCODE-TROUBLESHOOTING.md'),
|
|
2389
|
+
(0, path_1.join)(__dirname, 'SNOWCODE-TROUBLESHOOTING.md')
|
|
2242
2390
|
];
|
|
2243
2391
|
let troubleshootingSourcePath = null;
|
|
2244
2392
|
for (const sourcePath of troubleshootingSourcePaths) {
|
|
@@ -2252,22 +2400,22 @@ async function copyMCPServerScripts(targetDir, force = false) {
|
|
|
2252
2400
|
}
|
|
2253
2401
|
}
|
|
2254
2402
|
if (troubleshootingSourcePath) {
|
|
2255
|
-
const targetPath = (0, path_1.join)(targetDir, '
|
|
2403
|
+
const targetPath = (0, path_1.join)(targetDir, 'SNOWCODE-TROUBLESHOOTING.md');
|
|
2256
2404
|
try {
|
|
2257
2405
|
await fs_1.promises.access(targetPath);
|
|
2258
2406
|
if (!force) {
|
|
2259
|
-
console.log(`✅
|
|
2407
|
+
console.log(`✅ SNOWCODE-TROUBLESHOOTING.md already exists`);
|
|
2260
2408
|
}
|
|
2261
2409
|
else {
|
|
2262
2410
|
const content = await fs_1.promises.readFile(troubleshootingSourcePath, 'utf8');
|
|
2263
2411
|
await fs_1.promises.writeFile(targetPath, content);
|
|
2264
|
-
console.log(`✅ Created
|
|
2412
|
+
console.log(`✅ Created SNOWCODE-TROUBLESHOOTING.md`);
|
|
2265
2413
|
}
|
|
2266
2414
|
}
|
|
2267
2415
|
catch {
|
|
2268
2416
|
const content = await fs_1.promises.readFile(troubleshootingSourcePath, 'utf8');
|
|
2269
2417
|
await fs_1.promises.writeFile(targetPath, content);
|
|
2270
|
-
console.log(`✅ Created
|
|
2418
|
+
console.log(`✅ Created SNOWCODE-TROUBLESHOOTING.md`);
|
|
2271
2419
|
}
|
|
2272
2420
|
}
|
|
2273
2421
|
}
|
|
@@ -2356,7 +2504,7 @@ async function copyCLAUDEmd(targetDir, force = false) {
|
|
|
2356
2504
|
await fs_1.promises.writeFile(claudeMdPath, claudeMdContent);
|
|
2357
2505
|
console.log('✅ Created CLAUDE.md (Primary instructions)');
|
|
2358
2506
|
}
|
|
2359
|
-
// Create AGENTS.md (identical copy for
|
|
2507
|
+
// Create AGENTS.md (identical copy for SnowCode compatibility)
|
|
2360
2508
|
const agentsMdPath = (0, path_1.join)(targetDir, 'AGENTS.md');
|
|
2361
2509
|
try {
|
|
2362
2510
|
await fs_1.promises.access(agentsMdPath);
|
|
@@ -2370,18 +2518,18 @@ async function copyCLAUDEmd(targetDir, force = false) {
|
|
|
2370
2518
|
}
|
|
2371
2519
|
catch {
|
|
2372
2520
|
await fs_1.promises.writeFile(agentsMdPath, agentsMdContent);
|
|
2373
|
-
console.log('✅ Created AGENTS.md (Identical copy for
|
|
2521
|
+
console.log('✅ Created AGENTS.md (Identical copy for SnowCode compatibility)');
|
|
2374
2522
|
}
|
|
2375
|
-
// Create .
|
|
2376
|
-
const
|
|
2377
|
-
const agentsDir = (0, path_1.join)(
|
|
2378
|
-
const modesDir = (0, path_1.join)(
|
|
2523
|
+
// Create .snowcode/ directory structure
|
|
2524
|
+
const snowcodeDir = (0, path_1.join)(targetDir, '.snowcode');
|
|
2525
|
+
const agentsDir = (0, path_1.join)(snowcodeDir, 'agent'); // Singular 'agent' as required by SnowCode
|
|
2526
|
+
const modesDir = (0, path_1.join)(snowcodeDir, 'modes');
|
|
2379
2527
|
try {
|
|
2380
|
-
await fs_1.promises.mkdir(
|
|
2528
|
+
await fs_1.promises.mkdir(snowcodeDir, { recursive: true });
|
|
2381
2529
|
await fs_1.promises.mkdir(agentsDir, { recursive: true });
|
|
2382
2530
|
await fs_1.promises.mkdir(modesDir, { recursive: true });
|
|
2383
|
-
console.log('✅ Created .
|
|
2384
|
-
// Copy agent files from .claude/ to .
|
|
2531
|
+
console.log('✅ Created .snowcode/ directory structure');
|
|
2532
|
+
// Copy agent files from .claude/ to .snowcode/agent/ (if they exist)
|
|
2385
2533
|
const sourceAgentsDir = (0, path_1.join)(__dirname, '..', '.claude', 'agents');
|
|
2386
2534
|
try {
|
|
2387
2535
|
const agentFiles = await fs_1.promises.readdir(sourceAgentsDir);
|
|
@@ -2393,68 +2541,85 @@ async function copyCLAUDEmd(targetDir, force = false) {
|
|
|
2393
2541
|
await fs_1.promises.writeFile(targetFile, content);
|
|
2394
2542
|
}
|
|
2395
2543
|
}
|
|
2396
|
-
console.log('✅ Copied agent configurations to .
|
|
2544
|
+
console.log('✅ Copied agent configurations to .snowcode/agent/');
|
|
2397
2545
|
}
|
|
2398
2546
|
catch (err) {
|
|
2399
|
-
// Silently continue - agent configs are in
|
|
2400
|
-
}
|
|
2401
|
-
// Create .
|
|
2402
|
-
//
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
},
|
|
2427
|
-
"snow-flow": {
|
|
2428
|
-
type: "local",
|
|
2429
|
-
command: "node",
|
|
2430
|
-
args: [(0, path_1.join)(distPath, "mcp/snow-flow-mcp.js")],
|
|
2431
|
-
env: {
|
|
2432
|
-
SNOW_FLOW_ENV: "production"
|
|
2433
|
-
},
|
|
2434
|
-
enabled: true,
|
|
2435
|
-
description: "Snow-Flow orchestration with 176+ tools: swarm coordination, agent spawning, memory, neural learning"
|
|
2547
|
+
// Silently continue - agent configs are in snowcode.json, not separate files
|
|
2548
|
+
}
|
|
2549
|
+
// Create .snowcode/snowcode.json by converting from .mcp.json.template
|
|
2550
|
+
// SINGLE SOURCE OF TRUTH: .mcp.json.template → both Claude and SnowCode formats
|
|
2551
|
+
// CRITICAL: SnowCode/OpenCode does NOT auto-expand ${...} variables
|
|
2552
|
+
// 🔧 Read actual environment values from .env file
|
|
2553
|
+
const envPath = (0, path_1.join)(targetDir, '.env');
|
|
2554
|
+
const envValues = {};
|
|
2555
|
+
try {
|
|
2556
|
+
const envContent = await fs_1.promises.readFile(envPath, 'utf-8');
|
|
2557
|
+
// Parse .env file (simple parser - handles KEY=VALUE lines)
|
|
2558
|
+
const lines = envContent.split('\n');
|
|
2559
|
+
for (var line of lines) {
|
|
2560
|
+
line = line.trim();
|
|
2561
|
+
// Skip comments and empty lines
|
|
2562
|
+
if (!line || line.startsWith('#'))
|
|
2563
|
+
continue;
|
|
2564
|
+
var equalIndex = line.indexOf('=');
|
|
2565
|
+
if (equalIndex > 0) {
|
|
2566
|
+
var key = line.substring(0, equalIndex).trim();
|
|
2567
|
+
var value = line.substring(equalIndex + 1).trim();
|
|
2568
|
+
// Remove quotes if present
|
|
2569
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
2570
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
2571
|
+
value = value.substring(1, value.length - 1);
|
|
2572
|
+
}
|
|
2573
|
+
envValues[key] = value;
|
|
2436
2574
|
}
|
|
2437
|
-
}
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
//
|
|
2452
|
-
const
|
|
2453
|
-
|
|
2454
|
-
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
catch (error) {
|
|
2578
|
+
console.log('⚠️ No .env file found - SnowCode config will use placeholder values');
|
|
2579
|
+
}
|
|
2580
|
+
// Helper function to get env value with proper URL formatting
|
|
2581
|
+
function getEnvValue(key, defaultValue = '') {
|
|
2582
|
+
var value = envValues[key] || process.env[key] || defaultValue;
|
|
2583
|
+
// Special handling for SNOW_INSTANCE - ensure it's a full URL
|
|
2584
|
+
if (key === 'SNOW_INSTANCE' && value && !value.startsWith('http')) {
|
|
2585
|
+
value = 'https://' + value.replace(/^https?:\/\//, '');
|
|
2586
|
+
}
|
|
2587
|
+
return value;
|
|
2588
|
+
}
|
|
2589
|
+
// Read .mcp.json.template (single source of truth for MCP servers)
|
|
2590
|
+
const mcpTemplatePath = (0, path_1.join)(snowFlowRoot, '.mcp.json.template');
|
|
2591
|
+
let mcpTemplateContent;
|
|
2592
|
+
try {
|
|
2593
|
+
mcpTemplateContent = await fs_1.promises.readFile(mcpTemplatePath, 'utf-8');
|
|
2594
|
+
}
|
|
2595
|
+
catch (error) {
|
|
2596
|
+
console.log('⚠️ Could not find .mcp.json.template');
|
|
2597
|
+
throw error;
|
|
2598
|
+
}
|
|
2599
|
+
// Replace placeholders with ACTUAL values from .env (not ${...} syntax!)
|
|
2600
|
+
const mcpConfigContent = mcpTemplateContent
|
|
2601
|
+
.replace(/{{PROJECT_ROOT}}/g, snowFlowRoot)
|
|
2602
|
+
.replace(/{{SNOW_INSTANCE}}/g, getEnvValue('SNOW_INSTANCE'))
|
|
2603
|
+
.replace(/{{SNOW_CLIENT_ID}}/g, getEnvValue('SNOW_CLIENT_ID'))
|
|
2604
|
+
.replace(/{{SNOW_CLIENT_SECRET}}/g, getEnvValue('SNOW_CLIENT_SECRET'))
|
|
2605
|
+
.replace(/{{SNOW_FLOW_ENV}}/g, getEnvValue('SNOW_FLOW_ENV', 'development'));
|
|
2606
|
+
const claudeConfig = JSON.parse(mcpConfigContent);
|
|
2607
|
+
// Convert Claude Desktop format to SnowCode format
|
|
2608
|
+
const snowcodeConfig = convertToSnowCodeFormat(claudeConfig);
|
|
2609
|
+
// Write both snowcode.json AND config.json (Claude uses config.json)
|
|
2610
|
+
const snowcodeConfigPath = (0, path_1.join)(snowcodeDir, 'snowcode.json');
|
|
2611
|
+
const configJsonPath = (0, path_1.join)(snowcodeDir, 'config.json');
|
|
2612
|
+
await fs_1.promises.writeFile(snowcodeConfigPath, JSON.stringify(snowcodeConfig, null, 2));
|
|
2613
|
+
await fs_1.promises.writeFile(configJsonPath, JSON.stringify(snowcodeConfig, null, 2));
|
|
2614
|
+
console.log('✅ Created .snowcode/snowcode.json (converted from .mcp.json.template → SnowCode format)');
|
|
2615
|
+
console.log('✅ Created .snowcode/config.json (SnowCode format, Claude compatibility)');
|
|
2616
|
+
// Also create AGENTS.md in .snowcode/
|
|
2617
|
+
const snowcodeAgentsMdPath = (0, path_1.join)(snowcodeDir, 'AGENTS.md');
|
|
2618
|
+
await fs_1.promises.writeFile(snowcodeAgentsMdPath, agentsMdContent);
|
|
2619
|
+
console.log('✅ Created .snowcode/AGENTS.md');
|
|
2455
2620
|
}
|
|
2456
2621
|
catch (error) {
|
|
2457
|
-
console.log('⚠️ Error creating .
|
|
2622
|
+
console.log('⚠️ Error creating .snowcode/ directory:', error instanceof Error ? error.message : String(error));
|
|
2458
2623
|
}
|
|
2459
2624
|
}
|
|
2460
2625
|
catch (error) {
|
|
@@ -2578,6 +2743,40 @@ async function appendToEnvFile(targetDir, content) {
|
|
|
2578
2743
|
const envFilePath = (0, path_1.join)(targetDir, '.env');
|
|
2579
2744
|
await fs_1.promises.appendFile(envFilePath, content);
|
|
2580
2745
|
}
|
|
2746
|
+
/**
|
|
2747
|
+
* Converts Claude Desktop MCP config format to SnowCode/OpenCode format
|
|
2748
|
+
* Single source of truth: .mcp.json.template → both .mcp.json and .snowcode/snowcode.json
|
|
2749
|
+
*/
|
|
2750
|
+
function convertToSnowCodeFormat(claudeConfig) {
|
|
2751
|
+
const snowcodeConfig = {
|
|
2752
|
+
"$schema": "https://opencode.ai/config.json",
|
|
2753
|
+
"name": "snow-flow",
|
|
2754
|
+
"description": "ServiceNow development with SnowCode and multi-LLM support",
|
|
2755
|
+
"mcp": {},
|
|
2756
|
+
"tools": {
|
|
2757
|
+
"enabled": true,
|
|
2758
|
+
"requireApproval": false
|
|
2759
|
+
},
|
|
2760
|
+
"instructions": [
|
|
2761
|
+
"AGENTS.md",
|
|
2762
|
+
"../CLAUDE.md",
|
|
2763
|
+
"../AGENTS.md"
|
|
2764
|
+
]
|
|
2765
|
+
};
|
|
2766
|
+
// Convert each server from Claude Desktop format to SnowCode format
|
|
2767
|
+
const servers = claudeConfig.servers || claudeConfig.mcpServers || {};
|
|
2768
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
2769
|
+
const s = server;
|
|
2770
|
+
snowcodeConfig.mcp[name] = {
|
|
2771
|
+
type: "local",
|
|
2772
|
+
command: s.args ? [s.command, ...s.args] : (Array.isArray(s.command) ? s.command : [s.command]),
|
|
2773
|
+
environment: s.env || s.environment || {},
|
|
2774
|
+
enabled: true,
|
|
2775
|
+
description: s.description || ""
|
|
2776
|
+
};
|
|
2777
|
+
}
|
|
2778
|
+
return snowcodeConfig;
|
|
2779
|
+
}
|
|
2581
2780
|
async function checkNeo4jAvailability() {
|
|
2582
2781
|
const { execSync } = require('child_process');
|
|
2583
2782
|
try {
|
|
@@ -2633,6 +2832,45 @@ async function createMCPConfig(targetDir, force = false) {
|
|
|
2633
2832
|
throw new Error('Could not find snow-flow project root');
|
|
2634
2833
|
}
|
|
2635
2834
|
}
|
|
2835
|
+
// 🔧 FIX: Read actual environment values from .env file
|
|
2836
|
+
// This solves the issue where SnowCode/Claude Code doesn't expand ${...} variables
|
|
2837
|
+
const envPath = (0, path_1.join)(targetDir, '.env');
|
|
2838
|
+
const envValues = {};
|
|
2839
|
+
try {
|
|
2840
|
+
const envContent = await fs_1.promises.readFile(envPath, 'utf-8');
|
|
2841
|
+
// Parse .env file (simple parser - handles KEY=VALUE lines)
|
|
2842
|
+
const lines = envContent.split('\n');
|
|
2843
|
+
for (var line of lines) {
|
|
2844
|
+
line = line.trim();
|
|
2845
|
+
// Skip comments and empty lines
|
|
2846
|
+
if (!line || line.startsWith('#'))
|
|
2847
|
+
continue;
|
|
2848
|
+
var equalIndex = line.indexOf('=');
|
|
2849
|
+
if (equalIndex > 0) {
|
|
2850
|
+
var key = line.substring(0, equalIndex).trim();
|
|
2851
|
+
var value = line.substring(equalIndex + 1).trim();
|
|
2852
|
+
// Remove quotes if present
|
|
2853
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
2854
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
2855
|
+
value = value.substring(1, value.length - 1);
|
|
2856
|
+
}
|
|
2857
|
+
envValues[key] = value;
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
catch (error) {
|
|
2862
|
+
console.log('⚠️ No .env file found - MCP config will use placeholder values');
|
|
2863
|
+
console.log(' Run "snow-flow auth login" after init to configure credentials');
|
|
2864
|
+
}
|
|
2865
|
+
// Helper function to get env value with proper URL formatting
|
|
2866
|
+
function getEnvValue(key, defaultValue = '') {
|
|
2867
|
+
var value = envValues[key] || process.env[key] || defaultValue;
|
|
2868
|
+
// Special handling for SNOW_INSTANCE - ensure it's a full URL
|
|
2869
|
+
if (key === 'SNOW_INSTANCE' && value && !value.startsWith('http')) {
|
|
2870
|
+
value = 'https://' + value.replace(/^https?:\/\//, '');
|
|
2871
|
+
}
|
|
2872
|
+
return value;
|
|
2873
|
+
}
|
|
2636
2874
|
// Read the template file
|
|
2637
2875
|
const templatePath = (0, path_1.join)(snowFlowRoot, '.mcp.json.template');
|
|
2638
2876
|
let templateContent;
|
|
@@ -2643,19 +2881,20 @@ async function createMCPConfig(targetDir, force = false) {
|
|
|
2643
2881
|
console.error('❌ Could not find .mcp.json.template file');
|
|
2644
2882
|
throw error;
|
|
2645
2883
|
}
|
|
2646
|
-
// Replace placeholders
|
|
2884
|
+
// Replace placeholders with ACTUAL values from .env (not ${...} syntax!)
|
|
2885
|
+
// This ensures SnowCode/Claude Code can use the MCP servers immediately
|
|
2647
2886
|
const distPath = (0, path_1.join)(snowFlowRoot, 'dist');
|
|
2648
2887
|
const mcpConfigContent = templateContent
|
|
2649
2888
|
.replace(/{{PROJECT_ROOT}}/g, snowFlowRoot)
|
|
2650
|
-
.replace(/{{SNOW_INSTANCE}}/g, '
|
|
2651
|
-
.replace(/{{SNOW_CLIENT_ID}}/g, '
|
|
2652
|
-
.replace(/{{SNOW_CLIENT_SECRET}}/g, '
|
|
2653
|
-
.replace(/{{SNOW_DEPLOYMENT_TIMEOUT}}/g, '
|
|
2654
|
-
.replace(/{{MCP_DEPLOYMENT_TIMEOUT}}/g, '
|
|
2655
|
-
.replace(/{{NEO4J_URI}}/g, '
|
|
2656
|
-
.replace(/{{NEO4J_USER}}/g, '
|
|
2657
|
-
.replace(/{{NEO4J_PASSWORD}}/g, '
|
|
2658
|
-
.replace(/{{SNOW_FLOW_ENV}}/g, '
|
|
2889
|
+
.replace(/{{SNOW_INSTANCE}}/g, getEnvValue('SNOW_INSTANCE'))
|
|
2890
|
+
.replace(/{{SNOW_CLIENT_ID}}/g, getEnvValue('SNOW_CLIENT_ID'))
|
|
2891
|
+
.replace(/{{SNOW_CLIENT_SECRET}}/g, getEnvValue('SNOW_CLIENT_SECRET'))
|
|
2892
|
+
.replace(/{{SNOW_DEPLOYMENT_TIMEOUT}}/g, getEnvValue('SNOW_DEPLOYMENT_TIMEOUT', '180000'))
|
|
2893
|
+
.replace(/{{MCP_DEPLOYMENT_TIMEOUT}}/g, getEnvValue('MCP_DEPLOYMENT_TIMEOUT', '180000'))
|
|
2894
|
+
.replace(/{{NEO4J_URI}}/g, getEnvValue('NEO4J_URI', ''))
|
|
2895
|
+
.replace(/{{NEO4J_USER}}/g, getEnvValue('NEO4J_USER', ''))
|
|
2896
|
+
.replace(/{{NEO4J_PASSWORD}}/g, getEnvValue('NEO4J_PASSWORD', ''))
|
|
2897
|
+
.replace(/{{SNOW_FLOW_ENV}}/g, getEnvValue('SNOW_FLOW_ENV', 'development'));
|
|
2659
2898
|
// Parse to ensure it's valid JSON
|
|
2660
2899
|
const mcpConfig = JSON.parse(mcpConfigContent);
|
|
2661
2900
|
// Keep the standard MCP structure that Claude Code expects
|
|
@@ -2912,6 +3151,44 @@ async function setupMCPConfig(targetDir, instanceUrl, clientId, clientSecret, fo
|
|
|
2912
3151
|
throw new Error('Could not find snow-flow project root');
|
|
2913
3152
|
}
|
|
2914
3153
|
}
|
|
3154
|
+
// 🔧 FIX: Read actual environment values from .env file
|
|
3155
|
+
// This solves the issue where SnowCode/Claude Code doesn't expand ${...} variables
|
|
3156
|
+
const envPath = (0, path_1.join)(targetDir, '.env');
|
|
3157
|
+
const envValues = {};
|
|
3158
|
+
try {
|
|
3159
|
+
const envContent = await fs_1.promises.readFile(envPath, 'utf-8');
|
|
3160
|
+
// Parse .env file (simple parser - handles KEY=VALUE lines)
|
|
3161
|
+
const lines = envContent.split('\n');
|
|
3162
|
+
for (var line of lines) {
|
|
3163
|
+
line = line.trim();
|
|
3164
|
+
// Skip comments and empty lines
|
|
3165
|
+
if (!line || line.startsWith('#'))
|
|
3166
|
+
continue;
|
|
3167
|
+
var equalIndex = line.indexOf('=');
|
|
3168
|
+
if (equalIndex > 0) {
|
|
3169
|
+
var key = line.substring(0, equalIndex).trim();
|
|
3170
|
+
var value = line.substring(equalIndex + 1).trim();
|
|
3171
|
+
// Remove quotes if present
|
|
3172
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
3173
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
3174
|
+
value = value.substring(1, value.length - 1);
|
|
3175
|
+
}
|
|
3176
|
+
envValues[key] = value;
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
catch (error) {
|
|
3181
|
+
// .env file doesn't exist yet - that's okay
|
|
3182
|
+
}
|
|
3183
|
+
// Helper function to get env value with proper URL formatting
|
|
3184
|
+
function getEnvValue(key, defaultValue = '') {
|
|
3185
|
+
var value = envValues[key] || process.env[key] || defaultValue;
|
|
3186
|
+
// Special handling for SNOW_INSTANCE - ensure it's a full URL
|
|
3187
|
+
if (key === 'SNOW_INSTANCE' && value && !value.startsWith('http')) {
|
|
3188
|
+
value = 'https://' + value.replace(/^https?:\/\//, '');
|
|
3189
|
+
}
|
|
3190
|
+
return value;
|
|
3191
|
+
}
|
|
2915
3192
|
// Read the template file
|
|
2916
3193
|
const templatePath = (0, path_1.join)(snowFlowRoot, '.mcp.json.template');
|
|
2917
3194
|
let templateContent;
|
|
@@ -2922,18 +3199,19 @@ async function setupMCPConfig(targetDir, instanceUrl, clientId, clientSecret, fo
|
|
|
2922
3199
|
console.error('❌ Could not find .mcp.json.template file');
|
|
2923
3200
|
throw error;
|
|
2924
3201
|
}
|
|
2925
|
-
// Replace placeholders
|
|
3202
|
+
// Replace placeholders with ACTUAL values from .env (not ${...} syntax!)
|
|
3203
|
+
// This ensures SnowCode/Claude Code can use the MCP servers immediately
|
|
2926
3204
|
const mcpConfigContent = templateContent
|
|
2927
3205
|
.replace(/{{PROJECT_ROOT}}/g, snowFlowRoot)
|
|
2928
|
-
.replace(/{{SNOW_INSTANCE}}/g, '
|
|
2929
|
-
.replace(/{{SNOW_CLIENT_ID}}/g, '
|
|
2930
|
-
.replace(/{{SNOW_CLIENT_SECRET}}/g, '
|
|
2931
|
-
.replace(/{{SNOW_DEPLOYMENT_TIMEOUT}}/g, '
|
|
2932
|
-
.replace(/{{MCP_DEPLOYMENT_TIMEOUT}}/g, '
|
|
2933
|
-
.replace(/{{NEO4J_URI}}/g, '
|
|
2934
|
-
.replace(/{{NEO4J_USER}}/g, '
|
|
2935
|
-
.replace(/{{NEO4J_PASSWORD}}/g, '
|
|
2936
|
-
.replace(/{{SNOW_FLOW_ENV}}/g, '
|
|
3206
|
+
.replace(/{{SNOW_INSTANCE}}/g, getEnvValue('SNOW_INSTANCE'))
|
|
3207
|
+
.replace(/{{SNOW_CLIENT_ID}}/g, getEnvValue('SNOW_CLIENT_ID'))
|
|
3208
|
+
.replace(/{{SNOW_CLIENT_SECRET}}/g, getEnvValue('SNOW_CLIENT_SECRET'))
|
|
3209
|
+
.replace(/{{SNOW_DEPLOYMENT_TIMEOUT}}/g, getEnvValue('SNOW_DEPLOYMENT_TIMEOUT', '180000'))
|
|
3210
|
+
.replace(/{{MCP_DEPLOYMENT_TIMEOUT}}/g, getEnvValue('MCP_DEPLOYMENT_TIMEOUT', '180000'))
|
|
3211
|
+
.replace(/{{NEO4J_URI}}/g, getEnvValue('NEO4J_URI', ''))
|
|
3212
|
+
.replace(/{{NEO4J_USER}}/g, getEnvValue('NEO4J_USER', ''))
|
|
3213
|
+
.replace(/{{NEO4J_PASSWORD}}/g, getEnvValue('NEO4J_PASSWORD', ''))
|
|
3214
|
+
.replace(/{{SNOW_FLOW_ENV}}/g, getEnvValue('SNOW_FLOW_ENV', 'development'));
|
|
2937
3215
|
// Parse to ensure it's valid JSON
|
|
2938
3216
|
const mcpConfig = JSON.parse(mcpConfigContent);
|
|
2939
3217
|
// Keep the standard MCP structure that Claude Code expects
|
|
@@ -2986,8 +3264,8 @@ program
|
|
|
2986
3264
|
console.log('\n📝 Updating MCP configuration...');
|
|
2987
3265
|
await setupMCPConfig(process.cwd(), instanceUrl, clientId, clientSecret, options.force || false);
|
|
2988
3266
|
console.log(chalk_1.default.green('\n✅ MCP configuration refreshed successfully!'));
|
|
2989
|
-
console.log('\n📢 IMPORTANT: Restart
|
|
2990
|
-
console.log(chalk_1.default.cyan('
|
|
3267
|
+
console.log('\n📢 IMPORTANT: Restart SnowCode (or Claude Code) to use the new configuration:');
|
|
3268
|
+
console.log(chalk_1.default.cyan(' SnowCode: snowcode'));
|
|
2991
3269
|
console.log(chalk_1.default.cyan(' Claude Code: claude --mcp-config .mcp.json'));
|
|
2992
3270
|
console.log('\n💡 The Local Development server now includes:');
|
|
2993
3271
|
console.log(' • Universal artifact detection via sys_metadata');
|
|
@@ -3018,16 +3296,16 @@ program
|
|
|
3018
3296
|
// MCP Server command with subcommands
|
|
3019
3297
|
program
|
|
3020
3298
|
.command('mcp <action>')
|
|
3021
|
-
.description('Manage ServiceNow MCP servers for
|
|
3299
|
+
.description('Manage ServiceNow MCP servers for SnowCode integration')
|
|
3022
3300
|
.option('--server <name>', 'Specific server name to manage')
|
|
3023
3301
|
.option('--port <port>', 'Port for MCP server (default: auto)')
|
|
3024
3302
|
.option('--host <host>', 'Host for MCP server (default: localhost)')
|
|
3025
3303
|
.action(async (action, options) => {
|
|
3026
|
-
// NOTE: MCP servers work with
|
|
3027
|
-
console.log(chalk_1.default.blue('ℹ️ MCP servers configured for
|
|
3304
|
+
// NOTE: MCP servers work with SnowCode's native Task() system
|
|
3305
|
+
console.log(chalk_1.default.blue('ℹ️ MCP servers configured for SnowCode (also compatible with Claude Code)'));
|
|
3028
3306
|
console.log(chalk_1.default.yellow('⚠️ Manual MCP commands are no longer needed'));
|
|
3029
|
-
console.log(chalk_1.default.green('✅
|
|
3030
|
-
console.log(chalk_1.default.blue('\n💡 Simply run your swarm commands -
|
|
3307
|
+
console.log(chalk_1.default.green('✅ SnowCode automatically handles all MCP server lifecycle'));
|
|
3308
|
+
console.log(chalk_1.default.blue('\n💡 Simply run your swarm commands - SnowCode handles the rest!'));
|
|
3031
3309
|
return;
|
|
3032
3310
|
});
|
|
3033
3311
|
// MCP action handlers
|
|
@@ -3052,9 +3330,9 @@ async function handleMCPStart(manager, options) {
|
|
|
3052
3330
|
const total = status.length;
|
|
3053
3331
|
console.log(`\n✅ Started ${running}/${total} MCP servers`);
|
|
3054
3332
|
if (running === total) {
|
|
3055
|
-
console.log('🎉 All MCP servers are now running and available in
|
|
3333
|
+
console.log('🎉 All MCP servers are now running and available in SnowCode!');
|
|
3056
3334
|
console.log('\n📋 Next steps:');
|
|
3057
|
-
console.log(' 1. Open
|
|
3335
|
+
console.log(' 1. Open SnowCode (or Claude Code)');
|
|
3058
3336
|
console.log(' 2. MCP tools will be automatically available');
|
|
3059
3337
|
console.log(' 3. Use snow_deploy_widget, snow_deploy_flow, etc.');
|
|
3060
3338
|
}
|
|
@@ -3133,7 +3411,7 @@ async function handleMCPStatus(manager, options) {
|
|
|
3133
3411
|
const total = servers.length;
|
|
3134
3412
|
console.log(`📈 Summary: ${running}/${total} servers running`);
|
|
3135
3413
|
if (running === total) {
|
|
3136
|
-
console.log('🎉 All MCP servers are operational and available in
|
|
3414
|
+
console.log('🎉 All MCP servers are operational and available in SnowCode (or Claude Code)!');
|
|
3137
3415
|
}
|
|
3138
3416
|
else if (running > 0) {
|
|
3139
3417
|
console.log('⚠️ Some servers are not running. Use "snow-flow mcp start" to start them.');
|
|
@@ -3243,22 +3521,22 @@ async function handleMCPDebug(options) {
|
|
|
3243
3521
|
console.log(` SNOW_INSTANCE: ${process.env.SNOW_INSTANCE ? '✅ Set' : '❌ Not set'}`);
|
|
3244
3522
|
console.log(` SNOW_CLIENT_ID: ${process.env.SNOW_CLIENT_ID ? '✅ Set' : '❌ Not set'}`);
|
|
3245
3523
|
console.log(` SNOW_CLIENT_SECRET: ${process.env.SNOW_CLIENT_SECRET ? '✅ Set' : '❌ Not set'}`);
|
|
3246
|
-
// Check
|
|
3247
|
-
console.log('\n🤖
|
|
3524
|
+
// Check SnowCode
|
|
3525
|
+
console.log('\n🤖 SnowCode:');
|
|
3248
3526
|
const { execSync } = require('child_process');
|
|
3249
3527
|
try {
|
|
3250
|
-
execSync('which
|
|
3251
|
-
console.log(' ✅
|
|
3528
|
+
execSync('which snowcode', { stdio: 'ignore' });
|
|
3529
|
+
console.log(' ✅ SnowCode CLI found');
|
|
3252
3530
|
}
|
|
3253
3531
|
catch {
|
|
3254
|
-
console.log(' ❌
|
|
3255
|
-
console.log(' 💡 Install with: npm install -g
|
|
3532
|
+
console.log(' ❌ SnowCode CLI not found in PATH');
|
|
3533
|
+
console.log(' 💡 Install with: npm install -g @groeimetai/snowcode');
|
|
3256
3534
|
}
|
|
3257
3535
|
console.log('\n💡 Tips:');
|
|
3258
|
-
console.log(' 1. Ensure
|
|
3536
|
+
console.log(' 1. Ensure SnowCode is configured: snowcode config import snowcode-config.example.json');
|
|
3259
3537
|
console.log(' 2. Check .env file has valid ServiceNow credentials and LLM API keys');
|
|
3260
3538
|
console.log(' 3. Start developing: snow-flow swarm "your objective"');
|
|
3261
|
-
console.log(' 4.
|
|
3539
|
+
console.log(' 4. SnowCode will automatically connect to Snow-Flow\'s MCP servers');
|
|
3262
3540
|
}
|
|
3263
3541
|
// SPARC Detailed Help Command - DISABLED (sparc-help.js file missing)
|
|
3264
3542
|
// program
|