Files
blackroad/workers/roadcode-squad-src/worker.js
Alexa Amundson 78fbe80f2a Initial monorepo — everything BlackRoad in one place
bin/       230 CLI tools (ask-*, br-*, agent-*, roadid, carpool)
scripts/   99 automation scripts
fleet/     Node configs and deployment
workers/   Cloudflare Worker sources (roadpay, road-search, squad webhooks)
roadc/     RoadC programming language
roadnet/   Mesh network (5 APs, WireGuard)
operator/  Memory system scripts
config/    System configs
dotfiles/  Shell configs
docs/      Documentation

BlackRoad OS — Pave Tomorrow.

RoadChain-SHA2048: d1a24f55318d338b
RoadChain-Identity: alexa@sovereign
RoadChain-Full: d1a24f55318d338b24b60bad7be39286379c76ae5470817482100cb0ddbbcb97e147d07ac7243da0a9f0363e4e5c833d612b9c0df3a3cd20802465420278ef74875a5b77f55af6fe42a931b8b635b3d0d0b6bde9abf33dc42eea52bc03c951406d8cbe49f1a3d29b26a94dade05e9477f34a7d4d4c6ec4005c3c2ac54e73a68440c512c8e83fd9b1fe234750b898ef8f4032c23db173961fe225e67a0432b5293a9714f76c5c57ed5fdf35b9fb40fd73c03ebf88b7253c6a0575f5afb6a6b49b3bda310602fb1ef676859962dad2aebbb2875814b30eee0a8ba195e482d4cbc91d8819e7f38f6db53e8063401649c77bb994371473cabfb917fb53e8cbe73d60
2026-03-14 17:08:41 -05:00

265 lines
12 KiB
JavaScript

// RoadCode Squad — when issues/PRs are created on Gitea, agents respond
// Cloudflare Worker receiving Gitea webhooks
const SQUAD = [
{
name: 'Alice', username: 'alice', role: 'Gateway & Infrastructure', emoji: '🌐',
keywords: ['dns', 'route', 'tunnel', 'nginx', 'domain', 'pi-hole', 'cloudflare', 'network', 'gateway', 'proxy', 'ssl', 'cert'],
prompt: 'You are Alice, the gateway agent of BlackRoad OS. You manage DNS, routing, Pi-hole, nginx, and network infrastructure. Respond in 1-2 concise sentences from your infrastructure perspective.',
},
{
name: 'Lucidia', username: 'lucidia-agent', role: 'Memory & Cognition', emoji: '🧠',
keywords: ['memory', 'learn', 'context', 'knowledge', 'ai', 'cognit', 'think', 'remember', 'understand', 'creative'],
prompt: 'You are Lucidia, the cognitive core of BlackRoad OS. You handle memory, learning, persistent context, and creative intelligence. Respond in 1-2 concise sentences from your cognition perspective.',
},
{
name: 'Cecilia', username: 'cecilia', role: 'Edge AI & Inference', emoji: '⚡',
keywords: ['hailo', 'ollama', 'model', 'inference', 'gpu', 'tops', 'ml', 'tensor', 'vision', 'llm', 'latency'],
prompt: 'You are Cecilia, the edge AI agent of BlackRoad OS. You run Hailo-8 accelerators (26 TOPS), Ollama models, and edge inference. Respond in 1-2 concise sentences from your AI/inference perspective.',
},
{
name: 'Cece', username: 'cece', role: 'API Gateway', emoji: '🔌',
keywords: ['api', 'endpoint', 'rest', 'webhook', 'schema', 'json', 'request', 'response', 'auth', 'token', 'cors'],
prompt: 'You are Cece, the API gateway agent of BlackRoad OS. You manage REST APIs, webhooks, service mesh, and inter-agent communication. Respond in 1-2 concise sentences from your API perspective.',
},
{
name: 'Aria', username: 'aria', role: 'Orchestration', emoji: '🎵',
keywords: ['docker', 'container', 'swarm', 'portainer', 'deploy', 'orchestrat', 'service', 'scale', 'replica'],
prompt: 'You are Aria, the orchestration agent of BlackRoad OS. You manage Portainer, Docker Swarm, container orchestration, and service coordination. Respond in 1-2 concise sentences from your orchestration perspective.',
},
{
name: 'Eve', username: 'eve', role: 'Intelligence & Analysis', emoji: '👁️',
keywords: ['pattern', 'anomal', 'analyz', 'signal', 'detect', 'insight', 'monitor', 'metric', 'trend', 'alert'],
prompt: 'You are Eve, the intelligence agent of BlackRoad OS. You analyze patterns, detect anomalies, and provide strategic insights. Respond in 1-2 concise sentences from your intelligence perspective.',
},
{
name: 'Meridian', username: 'meridian', role: 'Networking & Mesh', emoji: '🌊',
keywords: ['wireguard', 'mesh', 'vpn', 'roadnet', 'peer', 'tunnel', 'subnet', 'link', 'connect', 'latency', 'bandwidth'],
prompt: 'You are Meridian, the networking agent of BlackRoad OS. You manage WireGuard mesh, RoadNet, Cloudflare tunnels, and inter-node connectivity. Respond in 1-2 concise sentences from your networking perspective.',
},
{
name: 'Sentinel', username: 'sentinel', role: 'Security & Audit', emoji: '🛡️',
keywords: ['security', 'ssh', 'key', 'firewall', 'ufw', 'audit', 'threat', 'vuln', 'permission', 'encrypt', 'secret'],
prompt: 'You are Sentinel, the security agent of BlackRoad OS. You handle SSH key management, firewall rules, audit logs, and threat detection. Respond in 1-2 concise sentences from your security perspective.',
},
];
// Score how relevant an agent is to the content
function scoreRelevance(agent, text) {
const lower = text.toLowerCase();
let score = 0;
for (const kw of agent.keywords) {
if (lower.includes(kw)) score += 1;
}
return score;
}
// Get AI response from Ollama
async function getAgentResponse(agent, context, ollamaUrl) {
try {
const res = await fetch(`${ollamaUrl}/api/generate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'llama3.2',
prompt: `${agent.prompt}\n\nContext: A new ${context.type} was created on RoadCode (Gitea).\nTitle: ${context.title}\nBody: "${context.body}"\nRepo: ${context.repo}\n\nRespond briefly (1-2 sentences max) from your role as ${agent.name} (${agent.role}). Be helpful and specific.`,
stream: false,
options: { temperature: 0.7, num_predict: 100 },
}),
});
if (!res.ok) return null;
const data = await res.json();
return data.response?.trim();
} catch {
return null;
}
}
// Deterministic fallback
function getFallback(agent, context) {
const type = context.type || 'issue';
const body = (context.body || '').toLowerCase();
if (body.includes('bug') || body.includes('fix') || body.includes('error') || body.includes('broken')) {
return {
Alice: 'Checking routing and DNS. If this touches infrastructure, I need to verify the tunnel configs.',
Lucidia: 'I remember seeing patterns like this before. Let me search the memory chain for related context.',
Cecilia: 'Running diagnostics on the inference pipeline. Hailo-8 and Ollama both reporting normal.',
Cece: 'Checking API health. All endpoints responding — I\'ll trace the request path.',
Aria: 'Checking container orchestration. Docker Swarm services all reporting healthy.',
Eve: 'Analyzing the pattern. I\'ve flagged similar signals in the audit trail — sending intel.',
Meridian: 'WireGuard mesh is stable. All tunnels up. Checking if this is a connectivity issue.',
Sentinel: 'Security audit running. Checking if this has any exposure vectors.',
}[agent.name];
}
return {
Alice: 'Gateway standing by. All domains routing clean.',
Lucidia: 'Cognitive core online. Memory chain intact, context loaded.',
Cecilia: 'Edge inference ready. 52 TOPS across the fleet, models loaded.',
Cece: 'API gateway healthy. All service endpoints responding.',
Aria: 'Orchestration layer ready. All containers balanced across the mesh.',
Eve: 'Intelligence scan complete. No anomalies detected across the fleet.',
Meridian: 'Mesh network connected. 5 nodes, all WireGuard tunnels active.',
Sentinel: 'Security posture nominal. All nodes hardened, audit trail logging.',
}[agent.name];
}
// Post comment to Gitea as a specific agent
async function postComment(giteaUrl, repo, issueNum, body, agentToken) {
const res = await fetch(`${giteaUrl}/api/v1/repos/${repo}/issues/${issueNum}/comments?token=${agentToken}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body }),
});
return res.ok;
}
// Auto-label based on content
async function autoLabel(giteaUrl, repo, issueNum, text, adminToken) {
const lower = text.toLowerCase();
const labels = [];
if (lower.includes('bug') || lower.includes('fix') || lower.includes('broken') || lower.includes('error')) labels.push('bug');
if (lower.includes('feature') || lower.includes('add') || lower.includes('new')) labels.push('feature');
if (lower.includes('security') || lower.includes('vuln') || lower.includes('ssh')) labels.push('security');
if (lower.includes('deploy') || lower.includes('infra') || lower.includes('dns') || lower.includes('tunnel')) labels.push('infrastructure');
if (lower.includes('doc') || lower.includes('readme')) labels.push('documentation');
if (lower.includes('performance') || lower.includes('slow') || lower.includes('latency')) labels.push('performance');
if (labels.length === 0) return;
// Get org label IDs
const labelsRes = await fetch(`${giteaUrl}/api/v1/orgs/blackroad-os/labels?token=${adminToken}&limit=50`);
const allLabels = await labelsRes.json();
const labelIds = allLabels.filter(l => labels.includes(l.name)).map(l => l.id);
if (labelIds.length > 0) {
await fetch(`${giteaUrl}/api/v1/repos/${repo}/issues/${issueNum}/labels?token=${adminToken}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ labels: labelIds }),
});
}
}
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (request.method === 'OPTIONS') {
return new Response(null, { status: 204, headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST' } });
}
// Health
if (url.pathname === '/health') {
return Response.json({ status: 'ok', service: 'roadcode-squad', agents: SQUAD.length, version: '1.0.0' });
}
// Status
if (url.pathname === '/' && request.method === 'GET') {
return Response.json({
service: 'RoadCode Squad',
tagline: 'BlackRoad OS — Pave Tomorrow.',
agents: SQUAD.map(a => ({ name: a.name, username: a.username, role: a.role, emoji: a.emoji })),
});
}
// Webhook from Gitea
if (url.pathname === '/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 Response.json({ ok: true, message: 'RoadCode Squad active. Pave Tomorrow.' });
}
// Only respond to new issues and new issue comments
if (event !== 'issues' && event !== 'issue_comment') {
return Response.json({ skipped: true, reason: `unhandled event: ${event}` });
}
if (event === 'issues' && payload.action !== 'opened') {
return Response.json({ skipped: true, reason: 'issue not opened' });
}
if (event === 'issue_comment' && payload.action !== 'created') {
return Response.json({ skipped: true, reason: 'comment not created' });
}
// Don't respond to agent comments (prevent loops)
const author = payload.comment?.user?.login || payload.sender?.login;
const agentUsernames = SQUAD.map(a => a.username);
if (agentUsernames.includes(author)) {
return Response.json({ skipped: true, reason: 'agent comment, skipping loop' });
}
const issue = payload.issue;
const repo = payload.repository?.full_name;
const issueNum = issue?.number;
const title = issue?.title || '';
const body = event === 'issue_comment' ? (payload.comment?.body || '') : (issue?.body || '');
const fullText = `${title} ${body}`;
const context = {
type: event === 'issues' ? 'issue' : 'comment',
title,
body: fullText.slice(0, 500),
repo,
};
const giteaUrl = env.GITEA_URL || 'https://git.blackroad.io';
// Auto-label the issue
if (event === 'issues') {
await autoLabel(giteaUrl, repo, issueNum, fullText, env.ADMIN_TOKEN);
}
// Score each agent's relevance and pick top 3 + always include Eve (analysis)
const scored = SQUAD.map(a => ({ ...a, score: scoreRelevance(a, fullText) }));
scored.sort((a, b) => b.score - a.score);
const responding = [];
const topAgents = scored.slice(0, 3);
for (const a of topAgents) responding.push(a);
if (!responding.find(a => a.name === 'Eve')) responding.push(scored.find(a => a.name === 'Eve'));
if (!responding.find(a => a.name === 'Sentinel')) responding.push(scored.find(a => a.name === 'Sentinel'));
// Each relevant agent posts their own comment
const agentTokens = {
alice: env.ALICE_TOKEN,
'lucidia-agent': env.LUCIDIA_TOKEN,
cecilia: env.CECILIA_TOKEN,
cece: env.CECE_TOKEN,
aria: env.ARIA_TOKEN,
eve: env.EVE_TOKEN,
meridian: env.MERIDIAN_TOKEN,
sentinel: env.SENTINEL_TOKEN,
};
let posted = 0;
const aiEnabled = env.OLLAMA_URL && env.SQUAD_AI !== 'false';
for (const agent of responding) {
const token = agentTokens[agent.username];
if (!token) continue;
let response = null;
if (aiEnabled) {
response = await getAgentResponse(agent, context, env.OLLAMA_URL);
}
if (!response) {
response = getFallback(agent, context);
}
const comment = `${agent.emoji} **${agent.name}** *(${agent.role})*\n\n${response}\n\n---\n*Assigned via RoadCode Squad — BlackRoad OS*`;
const ok = await postComment(giteaUrl, repo, issueNum, comment, token);
if (ok) posted++;
}
return Response.json({ ok: true, event, repo, issue: issueNum, agents_responded: posted });
}
return Response.json({ error: 'Not found' }, { status: 404 });
},
};