Not-for / server.js
senkulucca8's picture
Update server.js
8d37ed8 verified
Raw
History Blame Contribute Delete
6.55 kB
const express = require('express');
const cors = require('cors');
const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
const { v4: uuidv4 } = require('uuid');
const app = express();
app.use(cors());
app.use(express.json());
// Security Check Middleware
app.use((req, res, next) => {
const clientToken = req.headers['x-custom-app-token'];
const serverToken = process.env.MY_APP_TOKEN || 'ayon_custom_token_1234';
if (clientToken !== serverToken) {
return res.status(403).json({ success: false, error: "Access Denied!" });
}
next();
});
// ১. আসল স্কিল ফোল্ডারটা খুঁজে বের করার ফাংশন
const findTargetFolder = (dir) => {
if (!fs.existsSync(dir)) return null;
const list = fs.readdirSync(dir);
for (let file of list) {
const fullPath = path.join(dir, file);
const stat = fs.statSync(fullPath);
if (stat && stat.isDirectory()) {
const ignoreDirs = ['node_modules', '.npm', '.cache'];
if (!ignoreDirs.includes(file)) {
const found = findTargetFolder(fullPath);
if (found) return found;
}
} else if (file.toLowerCase() === 'skill.md') {
return dir;
}
}
return null;
};
// ২. পুরো ফোল্ডার স্ক্যান করে JSON Tree বানানোর ফাংশন (মেইন ফোল্ডারের নামসহ)
const buildFolderTree = (currentDir, rootDir) => {
let folderData = [];
if (!fs.existsSync(currentDir)) return folderData;
// অয়নের লজিক: মেইন ফোল্ডারের নামটা বের করে নেওয়া (যেমন: stitch-design)
const rootFolderName = path.basename(rootDir);
const list = fs.readdirSync(currentDir);
list.forEach(file => {
const fullPath = path.join(currentDir, file);
const stat = fs.statSync(fullPath);
if (stat && stat.isDirectory()) {
const subFolderData = buildFolderTree(fullPath, rootDir);
folderData = folderData.concat(subFolderData);
} else {
const fileName = file.toLowerCase();
if (fileName.endsWith('.md') && fileName !== 'readme.md') {
const content = fs.readFileSync(fullPath, 'utf-8');
// রিলেটিভ পাথ বের করে তার আগে মেইন ফোল্ডারের নাম জোড়া দেওয়া হচ্ছে
const relativePath = path.relative(rootDir, fullPath);
// উইন্ডোজ এবং লিনাক্স সব জায়গায় ঠিকঠাক কাজ করার জন্য স্লাশ (/) ঠিক করা হচ্ছে
const finalPath = rootFolderName + '/' + relativePath.replace(/\\/g, '/');
folderData.push({
name: file,
path: finalPath, // এখন পাথ হবে: "stitch-design/SKILL.md"
content: content
});
}
}
});
return folderData;
};
app.post('/run-skill', (req, res) => {
let command = req.body.command || '';
command = command.replace(/^npx\s+/ig, '').trim();
command = 'npx ' + command;
const sessionID = req.headers['x-session-id'] || uuidv4();
const workDir = path.join(__dirname, 'tmp', sessionID);
console.log(`\n========================================`);
console.log(`🟢 [API Request] Session: ${sessionID}`);
console.log(`💻 [Command] ${command}`);
fs.mkdirSync(workDir, { recursive: true });
let isFinished = false;
const childProcess = spawn(command, {
cwd: workDir,
shell: true,
env: { ...process.env, HOME: workDir, USERPROFILE: workDir }
});
let rawOutput = "";
childProcess.stdout.on('data', (data) => rawOutput += data.toString());
childProcess.stderr.on('data', (data) => rawOutput += data.toString());
const timeoutId = setTimeout(() => {
if (!isFinished) {
console.log(`⏱️ [Timeout] Killing process...`);
childProcess.kill('SIGKILL');
}
}, 120000);
childProcess.on('close', (code) => {
isFinished = true;
clearTimeout(timeoutId);
if (code === 0) {
const targetFolder = findTargetFolder(workDir);
if (targetFolder) {
console.log(`🎯 [Target Locked] Found Folder: ${targetFolder}`);
try {
const folderTree = buildFolderTree(targetFolder, targetFolder);
console.log(`🚀 [Sending Data] Sending JSON with ${folderTree.length} files...`);
res.json({
success: true,
type: "folder_tree",
total_files: folderTree.length,
files: folderTree,
session_id: sessionID
});
} catch (err) {
console.log(`❌ [Read Error] ${err.message}`);
res.status(500).json({ success: false, error: "Failed to read folder contents." });
}
} else {
console.log(`⚠️ [Warning] Valid skill folder not found.`);
res.status(404).json({ success: false, error: "Skill Folder not found." });
}
} else {
console.log(`❌ [Failed] Process ended with code: ${code}`);
res.status(500).json({ success: false, error: "Execution failed.", logs: rawOutput });
}
if (fs.existsSync(workDir)) {
fs.rmSync(workDir, { recursive: true, force: true });
console.log(`🧹 [Cleanup] Cache deleted.`);
}
console.log(`========================================\n`);
});
childProcess.on('error', (err) => {
isFinished = true;
clearTimeout(timeoutId);
res.status(500).json({ success: false, error: err.message });
if (fs.existsSync(workDir)) fs.rmSync(workDir, { recursive: true, force: true });
});
});
const PORT = process.env.PORT || 7860;
app.listen(PORT, () => {
console.log(`🚀 Modern API Server running on port ${PORT}`);
});