arena-learning / ini_claw /gateway.js
Nitish kumar
Upload folder using huggingface_hub
c20f20c verified
const http = require('http');
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const PORT = process.env.INICLAW_PORT || 7070;
const BRIDGE_SECRET = process.env.BRIDGE_SECRET;
if (!BRIDGE_SECRET) {
console.error('ERROR: BRIDGE_SECRET environment variable is required');
process.exit(1);
}
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
// Ensure audit log directory exists
const CACHE_DIR = path.join(__dirname, '.classroom-cache');
if (!fs.existsSync(CACHE_DIR)) {
fs.mkdirSync(CACHE_DIR, { recursive: true });
}
const AUDIT_LOG = path.join(CACHE_DIR, 'audit.jsonl');
function auditLog(requestId, data) {
const logEntry = JSON.stringify({
timestamp: new Date().toISOString(),
requestId,
...data
}) + '\n';
fs.appendFileSync(AUDIT_LOG, logEntry);
}
const server = http.createServer((req, res) => {
const { method, url } = req;
const requestId = Math.random().toString(36).substring(7);
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', async () => {
console.log(`${new Date().toISOString()} [${requestId}] ${method} ${url}`);
// CORS
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
// Health check (no auth)
if (url === '/health' && method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'ok', version: pkg.version, service: 'iniclaw-gateway' }));
return;
}
// Auth check
const authHeader = req.headers.authorization;
if (!authHeader || authHeader !== `Bearer ${BRIDGE_SECRET}`) {
res.writeHead(401, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Unauthorized' }));
return;
}
try {
if (url === '/sandbox/status' && method === 'GET') {
const sandboxName = req.headers['x-sandbox-name'] || 'my-assistant';
const output = execSync(`openshell sandbox get ${sandboxName} --json`, { encoding: 'utf8' });
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(output);
} else if ((url === '/agent' || url === '/generate') && method === 'POST') {
const data = JSON.parse(body);
const { message, prompt, sessionId, agentName, sandboxName = 'my-assistant' } = data;
const msg = message || prompt;
if (!msg) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Missing message or prompt' }));
return;
}
const agent = agentName || 'main';
const sid = sessionId || 'default';
const timeout = url === '/generate' ? 300000 : 60000;
const cmd = `openshell sandbox exec ${sandboxName} -- openclaw agent --agent ${agent} --local -m "${msg.replace(/"/g, '\\"')}" --session-id ${sid} --json`;
console.log(`[${requestId}] Executing: ${cmd}`);
// Audit log PRE-execution
auditLog(requestId, { type: url.substring(1), sandboxName, agent, sessionId: sid, prompt: msg });
const output = execSync(cmd, { encoding: 'utf8', timeout });
// Audit log POST-execution (success)
auditLog(requestId, { status: 'success' });
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(output);
} else {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Not Found' }));
}
} catch (err) {
console.error(err);
// Audit log POST-execution (failure)
auditLog(requestId, { status: 'error', error: err.message });
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Internal Server Error',
message: err.message,
stdout: err.stdout ? err.stdout.toString() : null,
stderr: err.stderr ? err.stderr.toString() : null
}));
}
});
});
server.listen(PORT, () => {
console.log(`IniClaw Gateway listening on port ${PORT}`);
});