#!/usr/bin/env node /** * sync-server.js — runs inside the Theia container on port 3001 * Called by vibn-agent-runner after an agent session auto-commits to Gitea. * Triggers git pull (or clone) so "Open in Theia" immediately shows new files. * * POST /sync { repo: "mark/sportsy" } * GET /health */ const http = require('http'); const { execSync } = require('child_process'); const WORKSPACE = '/home/project'; const GITEA_BASE = process.env.GITEA_API_URL || 'https://git.vibnai.com'; const GITEA_TOKEN = process.env.GITEA_TOKEN || process.env.GITEA_API_TOKEN || ''; const PORT = 3001; const server = http.createServer((req, res) => { res.setHeader('Content-Type', 'application/json'); if (req.url === '/health' && req.method === 'GET') { res.writeHead(200).end(JSON.stringify({ ok: true, workspace: WORKSPACE })); return; } if (req.url === '/sync' && req.method === 'POST') { let body = ''; req.on('data', d => { body += d; }); req.on('end', () => { try { const { repo } = JSON.parse(body || '{}'); if (!repo || !/^[\w.-]+\/[\w.-]+$/.test(repo)) { res.writeHead(400).end(JSON.stringify({ error: 'invalid repo' })); return; } const repoName = repo.split('/').pop(); const cloneDir = `${WORKSPACE}/${repoName}`; const authedUrl = GITEA_BASE.replace('https://', `https://vibn:${GITEA_TOKEN}@`) + `/${repo}.git`; let action; try { if (require('fs').existsSync(`${cloneDir}/.git`)) { execSync(`git -C "${cloneDir}" fetch --depth=50 origin main 2>&1`, { timeout: 30000 }); execSync(`git -C "${cloneDir}" reset --hard origin/main 2>&1`, { timeout: 10000 }); action = 'pulled'; } else { execSync(`git clone --depth=50 "${authedUrl}" "${cloneDir}" 2>&1`, { timeout: 60000 }); action = 'cloned'; } } catch (gitErr) { console.error('[sync-server] git error:', gitErr.message); res.writeHead(500).end(JSON.stringify({ ok: false, error: gitErr.message })); return; } console.log(`[sync-server] ${action} ${repo} -> ${cloneDir}`); res.writeHead(200).end(JSON.stringify({ ok: true, action, repo, path: cloneDir })); } catch (err) { console.error('[sync-server] error:', err.message); res.writeHead(500).end(JSON.stringify({ ok: false, error: err.message })); } }); return; } res.writeHead(404).end(JSON.stringify({ error: 'not found' })); }); server.listen(PORT, '0.0.0.0', () => { console.log(`[sync-server] Listening on :${PORT} - workspace: ${WORKSPACE}`); });