File size: 2,918 Bytes
3c7404b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import { exec, execFile } from 'node:child_process';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { promisify } from 'node:util';

const execAsync = promisify(exec);
const execFileAsync = promisify(execFile);
const AGENT_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
const HF_PULL_SCRIPT = resolve(AGENT_ROOT, 'scripts', 'hf_pull_script.py');
const RUN_OPENCODE_SCRIPT = resolve(AGENT_ROOT, 'scripts', 'run_opencode.py');

export type BackendAgentAction =
  | { action: 'agent.help' }
  | { action: 'sin.backend.health' }
  | { action: 'sin.backend.code.generate'; prompt: string; contextDir?: string }
  | { action: 'sin.backend.code.review'; targetDir: string };

export async function executeBackendAgentAction(action: BackendAgentAction): Promise<unknown> {
  switch (action.action) {
    case 'agent.help':
      return {
        ok: true,
        agent: 'sin-backend',
        mandate: 'CEO Elite Architect for 2026 Supabase + A2A Micro-Agent backends.',
        actions: ['sin.backend.health', 'sin.backend.code.generate', 'sin.backend.code.review'],
      };
    
    case 'sin.backend.health':
      return {
        ok: true,
        agent: 'sin-backend',
        primaryModel: 'opencode/qwen3.6-plus-free',
        fallbackModel: 'opencode/nemotron-3-super-free',
        team: 'Team - Coding',
        status: 'Elite 2026 Backend Architect Online',
      };
      
    case 'sin.backend.code.generate':
      return await executeOpenCode(action.prompt, action.contextDir);
      
    case 'sin.backend.code.review':
      return await executeOpenCode(`Review the backend in ${action.targetDir} according to 2026 A2A and Supabase-native architectural standards. Forbid monolithic REST APIs.`, action.targetDir);
  }
}

async function executeOpenCode(prompt: string, dir?: string) {
  await execFileAsync('python3', [HF_PULL_SCRIPT], { cwd: AGENT_ROOT }).catch(() => {
    console.warn('Rotator token pull failed, using cached auth if available');
  });
  
  const options = dir ? { cwd: dir } : {};
  
  try {
    const { stdout } = await execFileAsync('python3', [RUN_OPENCODE_SCRIPT, '--model', 'opencode/qwen3.6-plus-free', '--agent', 'sin-executor-solo', '--cwd', dir || AGENT_ROOT, '--timeout-sec', '900', '--prompt', prompt], { cwd: AGENT_ROOT });
    const result = JSON.parse(stdout) as { ok: boolean; stdout: string; stderr: string; timeout: boolean; returncode: number };
    if (!result.ok) {
      throw new Error(result.timeout ? `${result.stderr || result.stdout || 'opencode_timeout'}\nagent_timeout:900s` : (result.stderr || result.stdout || `opencode_returncode_${result.returncode}`));
    }
    return {
      ok: true,
      expertAnalysis: result.stdout,
      warnings: result.stderr || undefined,
    };
  } catch (error: any) {
    throw new Error(`Master Architect Execution Failed: ${error.message}`);
  }
}