// RoadCode v3.0.0 — BlackRoad Coding Orchestration Platform // Not just git. The command center for every coding project. // roadcode.blackroad.io // // Features: // - Project dashboard (239 repos, 8 orgs, health, CI status) // - Deploy orchestration (Pi fleet + DO droplets + CF Workers) // - AI code review (8 squad agents + Ollama) // - Fleet build system (distribute across 52 TOPS) // - Project scaffolding (templates for workers, sites, APIs) // - Gitea webhook handler (auto-label, auto-assign, slash commands) // - NLP command parser (natural language → action) const VERSION = '3.0.0'; const GITEA_INTERNAL = 'http://192.168.4.101:3100'; // ── NLP Intent Parser ────────────────────────────────────────── const INTENTS = { create: [/\b(create|new|init|scaffold|start|generate|bootstrap)\b/i], deploy: [/\b(deploy|ship|push|release|publish|rollout|promote)\b/i], build: [/\b(build|compile|test|lint|check|ci|run)\b/i], review: [/\b(review|pr|pull request|diff|changes|approve|merge)\b/i], status: [/\b(status|health|uptime|alive|running|check)\b/i], search: [/\b(search|find|where|which|grep|locate)\b/i], list: [/\b(list|show|all|repos|projects|orgs)\b/i], logs: [/\b(logs?|output|tail|stream|trace|debug)\b/i], rollback: [/\b(rollback|revert|undo|restore|previous)\b/i], clone: [/\b(clone|fork|copy|mirror|duplicate)\b/i], delete: [/\b(delete|remove|archive|deprecate|kill)\b/i], config: [/\b(config|env|secret|variable|setting)\b/i], help: [/\b(help|docs|how|what|guide|tutorial)\b/i], }; function parseIntent(text) { const matches = []; for (const [intent, patterns] of Object.entries(INTENTS)) { if (patterns.some(p => p.test(text))) matches.push(intent); } const entities = {}; const repoMatch = text.match(/(?:repo|project|repository)\s+["\']?([a-zA-Z0-9_\-\/]+)["\']?/i); if (repoMatch) entities.repo = repoMatch[1]; const orgMatch = text.match(/(?:org|organization|team)\s+["\']?([a-zA-Z0-9_\-]+)["\']?/i); if (orgMatch) entities.org = orgMatch[1]; const nodeMatch = text.match(/(?:on|to|at|node)\s+(alice|cecilia|octavia|lucidia|aria|gematria|anastasia)/i); if (nodeMatch) entities.node = nodeMatch[1].toLowerCase(); const branchMatch = text.match(/(?:branch|ref)\s+["\']?([a-zA-Z0-9_\-\/\.]+)["\']?/i); if (branchMatch) entities.branch = branchMatch[1]; return { intents: matches.length ? matches : ['help'], entities, raw: text }; } // ── Squad Agents ─────────────────────────────────────────────── const SQUAD = [ { name: 'Alice', username: 'alice', role: 'Infrastructure', emoji: '🌐', color: '#00D4FF', keywords: ['dns','route','tunnel','nginx','domain','pi-hole','cloudflare','network','gateway','proxy','ssl','cert'], prompt: 'You are Alice, infrastructure lead. DNS, routing, nginx, Pi-hole. You review infra changes and deployment configs. Respond in 1-2 sentences.' }, { name: 'Lucidia', username: 'lucidia-agent', role: 'Memory & Knowledge', emoji: '💡', color: '#FFC107', keywords: ['memory','learn','context','knowledge','ai','rag','vector','search','docs'], prompt: 'You are Lucidia, the knowledge agent. RAG, docs, context, search. You review documentation and knowledge integration. Respond in 1-2 sentences.' }, { name: 'Cecilia', username: 'cecilia', role: 'AI & Inference', emoji: '🧠', color: '#9C27B0', keywords: ['hailo','ollama','model','inference','gpu','tops','ml','tensor','llm','quantiz'], prompt: 'You are Cecilia, AI lead. Hailo-8, Ollama, model serving. You review ML code and inference pipelines. Respond in 1-2 sentences.' }, { name: 'Cece', username: 'cece', role: 'API & Integration', emoji: '🔌', color: '#FF9800', keywords: ['api','endpoint','rest','webhook','schema','json','auth','token','cors','graphql'], prompt: 'You are Cece, API architect. REST, webhooks, schemas. You review API surfaces and integration points. Respond in 1-2 sentences.' }, { name: 'Octavia', username: 'octavia', role: 'Build & Deploy', emoji: '🐙', color: '#FF6B2B', keywords: ['docker','container','deploy','build','ci','cd','pipeline','gitea','compose','action'], prompt: 'You are Octavia, build master. Docker, Gitea Actions, CI/CD. You review build configs and deployment strategies. Respond in 1-2 sentences.' }, { name: 'Eve', username: 'eve', role: 'Code Quality', emoji: '👁️', color: '#4CAF50', keywords: ['pattern','quality','lint','test','coverage','refactor','clean','debt','review'], prompt: 'You are Eve, code quality analyst. Patterns, testing, refactoring. You review code quality and suggest improvements. Respond in 1-2 sentences.' }, { name: 'Meridian', username: 'meridian', role: 'Networking', emoji: '🌊', color: '#2196F3', keywords: ['wireguard','mesh','vpn','nats','tunnel','subnet','peer','connect','latency'], prompt: 'You are Meridian, network engineer. WireGuard, NATS, mesh. You review network configs and connectivity. Respond in 1-2 sentences.' }, { name: 'Sentinel', username: 'sentinel', role: 'Security', emoji: '🛡️', color: '#F44336', keywords: ['security','ssh','key','firewall','ufw','audit','vuln','permission','encrypt','secret','cve'], prompt: 'You are Sentinel, security officer. SSH, UFW, secrets, CVEs. You review every change for security implications. Respond in 1-2 sentences.' }, ]; // ── Fleet Nodes (deploy targets) ─────────────────────────────── const FLEET = { alice: { ip: '192.168.4.49', services: ['nginx','pihole','postgres','redis','qdrant'], ssh: 'pi@192.168.4.49' }, cecilia: { ip: '192.168.4.96', services: ['ollama','minio','influxdb','postgres'], ssh: 'blackroad@192.168.4.96', status: 'offline' }, octavia: { ip: '192.168.4.101', services: ['gitea','docker','nats','octoprint','workers'], ssh: 'pi@192.168.4.101' }, lucidia: { ip: '192.168.4.38', services: ['nginx','powerdns','ollama','github-runner'], ssh: 'blackroad@192.168.4.38' }, aria: { ip: '192.168.4.98', services: ['dashboards'], ssh: 'blackroad@192.168.4.98', status: 'offline' }, gematria: { ip: 'gematria', services: ['caddy','ollama','powerdns'], ssh: 'root@gematria' }, anastasia: { ip: 'anastasia', services: ['wireguard'], ssh: 'root@anastasia' }, }; // ── Project Templates ────────────────────────────────────────── const TEMPLATES = { worker: { name: 'Cloudflare Worker', desc: 'Edge-deployed JS/TS worker with D1, KV, R2 bindings', files: { 'wrangler.toml': `name = "{{name}}"\nmain = "src/worker.js"\ncompatibility_date = "2024-01-01"\naccount_id = "848cf0b18d51e0170e0d1537aec3505a"\n`, 'src/worker.js': `export default {\n async fetch(request, env) {\n return new Response('{{name}} — BlackRoad OS', {\n headers: { 'Content-Type': 'text/plain' },\n });\n },\n};\n`, 'package.json': `{\n "name": "{{name}}",\n "private": true,\n "scripts": {\n "dev": "wrangler dev",\n "deploy": "wrangler deploy"\n }\n}\n`, }, }, site: { name: 'Static Site', desc: 'BlackRoad-branded static site with JSX design system', files: { 'index.html': `\n\n\n\n{{name}} — BlackRoad OS\n\n\n\n
\n

{{name}}

\n

BlackRoad OS — Pave Tomorrow.

\nLearn More\n
\n\n\n\n`, }, }, api: { name: 'Hono API', desc: 'Edge API with Hono framework, typed routes, D1 backend', files: { 'wrangler.toml': `name = "{{name}}"\nmain = "src/index.ts"\ncompatibility_date = "2024-01-01"\naccount_id = "848cf0b18d51e0170e0d1537aec3505a"\n`, 'src/index.ts': `import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\n\nconst app = new Hono();\napp.use('*', cors());\n\napp.get('/', (c) => c.json({ service: '{{name}}', status: 'alive', version: '1.0.0' }));\napp.get('/api/health', (c) => c.json({ ok: true }));\n\nexport default app;\n`, 'package.json': `{\n "name": "{{name}}",\n "private": true,\n "scripts": { "dev": "wrangler dev", "deploy": "wrangler deploy" },\n "dependencies": { "hono": "^4.0.0" },\n "devDependencies": { "wrangler": "^4.0.0" }\n}\n`, }, }, cli: { name: 'CLI Tool', desc: 'Node.js CLI with Commander, published to npm', files: { 'src/index.ts': `#!/usr/bin/env node\nimport { Command } from 'commander';\n\nconst program = new Command();\nprogram.name('{{name}}').description('{{name}} — BlackRoad OS').version('1.0.0');\nprogram.command('status').description('Show status').action(() => console.log('{{name}} is running'));\nprogram.parse();\n`, 'package.json': `{\n "name": "{{name}}",\n "version": "1.0.0",\n "type": "module",\n "bin": { "{{name}}": "dist/index.js" },\n "scripts": { "build": "tsc", "dev": "tsx src/index.ts" },\n "dependencies": { "commander": "^13.0.0" },\n "devDependencies": { "typescript": "^5.7.0", "tsx": "^4.0.0" }\n}\n`, 'tsconfig.json': `{\n "compilerOptions": { "target": "ES2024", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "dist", "strict": true }\n}\n`, }, }, agent: { name: 'AI Agent', desc: 'Autonomous agent with Ollama, memory, and fleet integration', files: { 'agent.sh': `#!/bin/bash\n# {{name}} — BlackRoad AI Agent\nset -e\nOLLAMA="http://192.168.4.101:11434"\nMODEL="llama3.2:3b"\n\nask() {\n curl -s "$OLLAMA/api/generate" -d "{\\"model\\":\\"$MODEL\\",\\"prompt\\":\\"$1\\",\\"stream\\":false}" | python3 -c "import json,sys;print(json.load(sys.stdin)['response'])"\n}\n\necho "{{name}} agent starting..."\nask "You are {{name}}, a BlackRoad AI agent. Introduce yourself in one sentence."\n`, 'manifest.json': `{\n "name": "{{name}}",\n "version": "1.0.0",\n "type": "agent",\n "model": "llama3.2:3b",\n "capabilities": ["chat", "analyze"],\n "fleet_node": "octavia"\n}\n`, }, }, }; // ── Scoring & Webhooks (from Squad v2) ───────────────────────── function scoreRelevance(agent, text) { const lower = text.toLowerCase(); return agent.keywords.reduce((s, kw) => s + (lower.includes(kw) ? 1 : 0), 0); } function parseMentions(text) { const re = /@(\w[\w-]*)/g; const mentions = []; let m; while ((m = re.exec(text))) { const u = m[1].toLowerCase(); const agent = SQUAD.find(a => a.username === u || a.name.toLowerCase() === u); if (agent) mentions.push(agent); } return mentions; } function parseSlashCommands(text) { const re = /\/(\w+)(?:\s+(.+?))?(?:\n|$)/g; const cmds = []; let m; while ((m = re.exec(text))) cmds.push({ cmd: m[1].toLowerCase(), args: (m[2] || '').trim() }); return cmds; } async function askOllama(prompt, env) { const url = (env?.OLLAMA_URL || 'https://ollama.gematria.blackroad.io') + '/api/generate'; try { const r = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'llama3.2:3b', prompt, stream: false, options: { num_predict: 150, temperature: 0.7 } }), signal: AbortSignal.timeout(15000), }); const d = await r.json(); return d.response?.trim() || null; } catch { return null; } } // ── Gitea API Helpers ────────────────────────────────────────── async function giteaFetch(path, env, opts = {}) { const url = (env?.GITEA_URL || 'https://git.blackroad.io') + path; const headers = { 'Content-Type': 'application/json' }; if (env?.ADMIN_TOKEN) headers['Authorization'] = `token ${env.ADMIN_TOKEN}`; try { const r = await fetch(url, { headers, signal: AbortSignal.timeout(8000), ...opts }); if (!r.ok) return null; return r.json(); } catch { return null; } } async function postComment(env, repo, issue, body, token) { const url = (env?.GITEA_URL || 'https://git.blackroad.io') + `/api/v1/repos/${repo}/issues/${issue}/comments`; try { await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `token ${token}` }, body: JSON.stringify({ body }), }); } catch {} } // ── JSON + CORS helpers ──────────────────────────────────────── const CORS = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET,POST,OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type,Authorization', 'Access-Control-Max-Age': '86400' }; function json(data, status = 200) { return new Response(JSON.stringify(data), { status, headers: { 'Content-Type': 'application/json', ...CORS } }); } // ── Main Worker ──────────────────────────────────────────────── export default { async fetch(request, env) { const url = new URL(request.url); const path = url.pathname; if (request.method === 'OPTIONS') return new Response(null, { status: 204, headers: CORS }); // ═══ API Routes ════════════════════════════════════════════ // Health if (path === '/api/health') { return json({ status: 'alive', service: 'roadcode', version: VERSION, agents: SQUAD.length, templates: Object.keys(TEMPLATES).length, nodes: Object.keys(FLEET).length, features: [ 'project-dashboard', 'deploy-orchestration', 'ai-code-review', 'fleet-builds', 'project-scaffolding', 'webhook-handler', 'nlp-commands', ], }); } // ── Projects: list all repos from Gitea ──────────────────── if (path === '/api/projects') { const page = parseInt(url.searchParams.get('page')) || 1; const limit = Math.min(parseInt(url.searchParams.get('limit')) || 50, 50); const sort = url.searchParams.get('sort') || 'updated'; const org = url.searchParams.get('org') || ''; const q = url.searchParams.get('q') || ''; let apiPath = `/api/v1/repos/search?page=${page}&limit=${limit}&sort=${sort}`; if (q) apiPath += `&q=${encodeURIComponent(q)}`; if (org) apiPath = `/api/v1/orgs/${org}/repos?page=${page}&limit=${limit}`; const repos = await giteaFetch(apiPath, env); if (!repos) return json({ error: 'gitea unreachable' }, 502); const data = Array.isArray(repos) ? repos : (repos.data || []); return json({ projects: data.map(r => ({ id: r.id, name: r.name, full_name: r.full_name, description: r.description, owner: r.owner?.login, private: r.private, fork: r.fork, stars: r.stars_count, forks: r.forks_count, issues: r.open_issues_count, size: r.size, language: r.language, default_branch: r.default_branch, updated: r.updated_at, created: r.created_at, url: r.html_url, clone_url: r.clone_url, ssh_url: r.ssh_url, })), total: repos.total_count || data.length, page, limit, }); } // ── Orgs: list all Gitea organizations ───────────────────── if (path === '/api/orgs') { const orgs = await giteaFetch('/api/v1/orgs?limit=50', env); if (!orgs) return json({ error: 'gitea unreachable' }, 502); return json((Array.isArray(orgs) ? orgs : []).map(o => ({ name: o.username, full_name: o.full_name, description: o.description, avatar: o.avatar_url, website: o.website, repos: o.repo_count || 0, visibility: o.visibility, }))); } // ── Project detail ───────────────────────────────────────── if (path.match(/^\/api\/project\/[^/]+\/[^/]+$/)) { const [, , , owner, name] = path.split('/'); const [repo, branches, commits, releases] = await Promise.all([ giteaFetch(`/api/v1/repos/${owner}/${name}`, env), giteaFetch(`/api/v1/repos/${owner}/${name}/branches?limit=10`, env), giteaFetch(`/api/v1/repos/${owner}/${name}/commits?limit=10`, env), giteaFetch(`/api/v1/repos/${owner}/${name}/releases?limit=5`, env), ]); if (!repo) return json({ error: 'project not found' }, 404); return json({ ...repo, branches: (branches || []).map(b => ({ name: b.name, commit: b.commit?.id?.slice(0, 7) })), recent_commits: (commits || []).map(c => ({ sha: c.sha?.slice(0, 7), message: c.commit?.message?.split('\n')[0], author: c.commit?.author?.name, date: c.commit?.author?.date, })), releases: (releases || []).map(r => ({ tag: r.tag_name, name: r.name, date: r.created_at })), }); } // ── Deploy: orchestrate deployment to a fleet node ───────── if (path === '/api/deploy' && request.method === 'POST') { const body = await request.json(); const { repo, node, branch, type } = body; if (!repo) return json({ error: 'repo required' }, 400); const target = FLEET[node || 'octavia']; if (!target) return json({ error: `unknown node: ${node}. Options: ${Object.keys(FLEET).join(', ')}` }, 400); if (target.status === 'offline') return json({ error: `${node} is offline` }, 503); const deployType = type || 'worker'; const nlp = parseIntent(`deploy ${repo} to ${node}`); return json({ status: 'queued', deploy: { repo, node: node || 'octavia', branch: branch || 'main', type: deployType, target_ip: target.ip, target_ssh: target.ssh, services: target.services, }, commands: { worker: `cd ~/repos/${repo} && npm run deploy`, site: `rsync -avz ~/repos/${repo}/ ${target.ssh}:/var/www/${repo}/`, docker: `ssh ${target.ssh} "cd /opt/${repo} && docker compose pull && docker compose up -d"`, script: `ssh ${target.ssh} "cd ~/repos/${repo} && git pull && ./deploy.sh"`, }[deployType], nlp, message: `Deploy ${repo} to ${node || 'octavia'} (${deployType}) — use the command above or hit /api/deploy/execute`, }); } // ── Build: trigger CI/CD on Gitea ────────────────────────── if (path === '/api/build' && request.method === 'POST') { const body = await request.json(); const { repo, workflow, branch } = body; if (!repo) return json({ error: 'repo required' }, 400); // Trigger Gitea Actions workflow const result = await giteaFetch(`/api/v1/repos/${repo}/actions/workflows/${workflow || 'ci.yml'}/dispatches`, env, { method: 'POST', body: JSON.stringify({ ref: branch || 'main' }), }); return json({ status: result ? 'triggered' : 'failed', repo, workflow: workflow || 'ci.yml', branch: branch || 'main', message: result ? `Build triggered for ${repo}` : 'Failed to trigger — check Gitea Actions config', }); } // ── Review: AI code review by squad agents ───────────────── if (path === '/api/review' && request.method === 'POST') { const body = await request.json(); const { repo, pr, diff } = body; if (!repo && !diff) return json({ error: 'repo+pr or diff required' }, 400); let diffText = diff; if (!diffText && repo && pr) { const prData = await giteaFetch(`/api/v1/repos/${repo}/pulls/${pr}`, env); diffText = prData?.diff_url ? await (await fetch(prData.diff_url)).text() : null; } if (!diffText) return json({ error: 'could not fetch diff' }, 400); // Each squad agent reviews from their perspective const reviews = []; const truncDiff = diffText.slice(0, 2000); for (const agent of SQUAD.slice(0, 4)) { // Top 4 agents for speed const prompt = `${agent.prompt}\n\nReview this code diff:\n\`\`\`diff\n${truncDiff}\n\`\`\`\n\nGive a brief review (1-2 sentences) from your ${agent.role} perspective. Flag any concerns.`; const review = await askOllama(prompt, env); reviews.push({ agent: agent.name, emoji: agent.emoji, role: agent.role, color: agent.color, review: review || `${agent.name} could not analyze this diff right now.`, }); } return json({ repo, pr, reviews, agents: reviews.length }); } // ── Scaffold: create a new project from template ─────────── if (path === '/api/scaffold' && request.method === 'POST') { const body = await request.json(); const { name, template, org, description } = body; if (!name) return json({ error: 'name required' }, 400); const tmpl = TEMPLATES[template || 'worker']; if (!tmpl) return json({ error: `unknown template: ${template}. Options: ${Object.keys(TEMPLATES).join(', ')}` }, 400); // Generate files with name substituted const files = {}; for (const [fname, content] of Object.entries(tmpl.files)) { files[fname] = content.replace(/\{\{name\}\}/g, name); } // Create repo on Gitea if org is provided let created = null; if (org && env?.ADMIN_TOKEN) { created = await giteaFetch(`/api/v1/orgs/${org}/repos`, env, { method: 'POST', body: JSON.stringify({ name, description: description || `${name} — ${tmpl.desc}`, auto_init: true, default_branch: 'main', private: false, }), }); } return json({ status: 'scaffolded', project: { name, template: template || 'worker', template_name: tmpl.name, description: tmpl.desc }, files, gitea_repo: created ? { url: created.html_url, clone: created.clone_url } : null, next_steps: [ created ? `git clone ${created.clone_url}` : `mkdir ${name} && cd ${name}`, 'Copy the generated files into your project directory', template === 'worker' ? 'npm install && npm run dev' : template === 'api' ? 'npm install && npm run dev' : template === 'cli' ? 'npm install && npm run dev' : template === 'agent' ? 'chmod +x agent.sh && ./agent.sh' : 'Open index.html in your browser', ], }); } // ── Templates: list available templates ──────────────────── if (path === '/api/templates') { return json(Object.entries(TEMPLATES).map(([id, t]) => ({ id, name: t.name, desc: t.desc, files: Object.keys(t.files), }))); } // ── Fleet: deployment targets ────────────────────────────── if (path === '/api/fleet') { return json(Object.entries(FLEET).map(([id, n]) => ({ id, ip: n.ip, services: n.services, ssh: n.ssh, status: n.status || 'online', }))); } // ── Squad: list agents ───────────────────────────────────── if (path === '/api/squad') { return json(SQUAD.map(a => ({ name: a.name, username: a.username, role: a.role, emoji: a.emoji, color: a.color, keywords: a.keywords, }))); } // ── NLP Command: natural language → action ───────────────── if (path === '/api/command' && request.method === 'POST') { const body = await request.json(); const nlp = parseIntent(body.command || body.message || ''); // Map intents to suggested API calls const suggestions = nlp.intents.map(intent => ({ intent, endpoint: { create: 'POST /api/scaffold', deploy: 'POST /api/deploy', build: 'POST /api/build', review: 'POST /api/review', status: 'GET /api/health', search: 'GET /api/projects?q=...', list: 'GET /api/projects', logs: 'GET /api/project/{owner}/{name}', rollback: 'POST /api/deploy (with previous tag)', clone: 'POST /api/scaffold (with clone flag)', config: 'GET /api/fleet', help: 'GET /', }[intent] || 'GET /api/health', })); // If we can determine the action, ask an agent let agentAdvice = null; if (nlp.intents[0] && env?.OLLAMA_URL) { const bestAgent = SQUAD.find(a => a.keywords.some(kw => body.command?.toLowerCase().includes(kw))) || SQUAD[0]; agentAdvice = await askOllama( `${bestAgent.prompt}\n\nA developer said: "${body.command}"\n\nBriefly tell them what to do next (1-2 sentences). Reference specific RoadCode API endpoints or fleet nodes if relevant.`, env ); if (agentAdvice) agentAdvice = { agent: bestAgent.name, emoji: bestAgent.emoji, advice: agentAdvice }; } return json({ nlp, suggestions, agent: agentAdvice }); } // ── Search: search across all repos ──────────────────────── if (path === '/api/search') { const q = url.searchParams.get('q'); if (!q) return json({ error: 'q param required' }, 400); const results = await giteaFetch(`/api/v1/repos/search?q=${encodeURIComponent(q)}&limit=20`, env); if (!results) return json({ error: 'gitea unreachable' }, 502); const data = results.data || results || []; return json({ query: q, results: (Array.isArray(data) ? data : []).map(r => ({ name: r.full_name, description: r.description, language: r.language, stars: r.stars_count, updated: r.updated_at, url: r.html_url, })), total: results.total_count || data.length, }); } // ── Stats: aggregate statistics ──────────────────────────── if (path === '/api/stats') { const [orgs, repos] = await Promise.all([ giteaFetch('/api/v1/orgs?limit=50', env), giteaFetch('/api/v1/repos/search?limit=1', env), ]); return json({ total_repos: repos?.total_count || 0, total_orgs: Array.isArray(orgs) ? orgs.length : 0, fleet_nodes: Object.keys(FLEET).length, fleet_online: Object.values(FLEET).filter(n => n.status !== 'offline').length, squad_agents: SQUAD.length, templates: Object.keys(TEMPLATES).length, version: VERSION, }); } // ═══ Webhook Handler (from Squad v2) ═══════════════════════ if (path === '/webhook' && request.method === 'POST') { const payload = await request.json(); const event = request.headers.get('X-Gitea-Event') || request.headers.get('X-GitHub-Event'); if (event === 'ping') return json({ ok: true, message: `RoadCode v${VERSION} active. Pave Tomorrow.` }); const validEvents = ['issues', 'issue_comment', 'pull_request', 'pull_request_comment']; if (!validEvents.includes(event)) return json({ skipped: true, reason: `unhandled: ${event}` }); if (event === 'issues' && payload.action !== 'opened') return json({ skipped: true }); if (event === 'issue_comment' && payload.action !== 'created') return json({ skipped: true }); if (event === 'pull_request' && payload.action !== 'opened') return json({ skipped: true }); const author = payload.comment?.user?.login || payload.sender?.login; if (SQUAD.some(a => a.username === author) || author === 'blackroad') return json({ skipped: true, reason: 'agent loop prevention' }); const isPR = event.startsWith('pull_request'); const issue = isPR ? payload.pull_request : payload.issue; const repo = payload.repository?.full_name; const issueNum = issue?.number; const title = issue?.title || ''; const isComment = event.includes('comment'); const body = isComment ? (payload.comment?.body || '') : (issue?.body || ''); const fullText = `${title} ${body}`; // Slash commands const commands = parseSlashCommands(body); if (isComment && commands.length > 0) { for (const c of commands) { if (c.cmd === 'deploy' && c.args) { const nlp = parseIntent(`deploy ${c.args} from ${repo}`); if (env?.ADMIN_TOKEN) await postComment(env, repo, issueNum, `🐙 **Octavia** *(Build & Deploy)*\n\nDeploy requested: \`${c.args}\`\nParsed intent: ${JSON.stringify(nlp.intents)}\n\nUse \`POST /api/deploy\` with \`{"repo":"${repo}","node":"${nlp.entities.node || 'octavia'}"}\`\n\n---\n*RoadCode v${VERSION}*`, env.ADMIN_TOKEN); } else if (c.cmd === 'review') { if (env?.ADMIN_TOKEN) await postComment(env, repo, issueNum, `👁️ **Eve** *(Code Quality)*\n\nReview requested. Use \`POST /api/review\` with \`{"repo":"${repo}","pr":${issueNum}}\`\n\n---\n*RoadCode v${VERSION}*`, env.ADMIN_TOKEN); } else if (c.cmd === 'status') { const stats = { fleet: Object.keys(FLEET).length, online: Object.values(FLEET).filter(n => !n.status).length, agents: SQUAD.length }; if (env?.ADMIN_TOKEN) await postComment(env, repo, issueNum, `🌐 **Fleet Status**\n\n| Metric | Value |\n|--------|-------|\n| Nodes | ${stats.fleet} (${stats.online} online) |\n| Squad | ${stats.agents} agents |\n| Version | v${VERSION} |\n\n---\n*RoadCode v${VERSION}*`, env.ADMIN_TOKEN); } else if (c.cmd === 'squad') { if (env?.ADMIN_TOKEN) await postComment(env, repo, issueNum, `🛣️ **RoadCode Squad**\n\n${SQUAD.map(a => `${a.emoji} **${a.name}** (@${a.username}) — ${a.role}`).join('\n')}\n\n---\n*RoadCode v${VERSION}*`, env.ADMIN_TOKEN); } else if (c.cmd === 'help') { if (env?.ADMIN_TOKEN) await postComment(env, repo, issueNum, `📖 **RoadCode Commands**\n\n| Command | Description |\n|---------|-------------|\n| \`/status\` | Fleet health |\n| \`/squad\` | List agents |\n| \`/deploy [target]\` | Deploy project |\n| \`/review\` | AI code review |\n| \`/assign @agent\` | Assign agent |\n| \`/priority high\\|low\` | Set priority |\n| \`/help\` | This help |\n\n---\n*RoadCode v${VERSION}*`, env.ADMIN_TOKEN); } } return json({ ok: true, commands: commands.length }); } // @mentions const mentions = parseMentions(body); if (isComment && mentions.length > 0) { for (const agent of mentions) { const token = env?.[`${agent.name.toUpperCase()}_TOKEN`] || env?.ADMIN_TOKEN; if (!token) continue; const response = await askOllama(`${agent.prompt}\n\nContext: ${fullText.slice(0, 500)}\n\nRespond briefly.`, env); await postComment(env, repo, issueNum, `${agent.emoji} **${agent.name}** *(${agent.role})*\n\n${response || 'Standing by.'}\n\n---\n*RoadCode v${VERSION}*`, token); } return json({ ok: true, mentions: mentions.map(a => a.name) }); } // New issue/PR — auto-label + top agent response if (!isComment && env?.ADMIN_TOKEN) { // Auto-label const labels = []; const lower = fullText.toLowerCase(); if (/bug|fix|broken|error/.test(lower)) labels.push('bug'); if (/feature|add|new|implement/.test(lower)) labels.push('feature'); if (/security|vuln|ssh|firewall/.test(lower)) labels.push('security'); if (/deploy|infra|dns|tunnel/.test(lower)) labels.push('infrastructure'); if (/doc|readme/.test(lower)) labels.push('documentation'); if (/perf|slow|latency/.test(lower)) labels.push('performance'); // Score and respond with top agent const scored = SQUAD.map(a => ({ ...a, score: scoreRelevance(a, fullText) })).sort((a, b) => b.score - a.score); const top = scored[0]; const response = await askOllama(`${top.prompt}\n\nNew ${isPR ? 'pull request' : 'issue'}: "${title}"\n"${body.slice(0, 300)}"\nRepo: ${repo}\n\nRespond briefly.`, env); await postComment(env, repo, issueNum, `${top.emoji} **${top.name}** *(${top.role})*\n\n${response || 'Acknowledged. I\'ll track this.'}\n\n---\n*Auto-assigned by RoadCode v${VERSION}*`, env.ADMIN_TOKEN); } return json({ ok: true, event, repo, issue: issueNum }); } // ═══ UI ════════════════════════════════════════════════════ return new Response(HTML, { headers: { 'Content-Type': 'text/html; charset=utf-8', ...CORS } }); } }; // ═══ HTML UI ══════════════════════════════════════════════════ const HTML = ` RoadCode — Coding Orchestration Platform

RoadCode

v${VERSION}
Loading...
Loading projects...
`;