| import { exec, execFile } from 'node:child_process'; |
| import { mkdir, readFile, writeFile } from 'node:fs/promises'; |
| import { dirname, join, resolve } from 'node:path'; |
| import { homedir } from 'node:os'; |
| import { fileURLToPath } from 'node:url'; |
| import { promisify } from 'node:util'; |
| import { getFrontendDualDbRoutingStatus } from './supabase.js'; |
|
|
| 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'); |
| const DEFAULT_STATE_PATH = join(homedir(), '.config', 'sin', 'sin-frontend', 'onboarding-state.json'); |
|
|
| type OnboardingState = { |
| ownerEmail?: string; |
| notes?: string; |
| updatedAt?: string; |
| }; |
|
|
| export type TemplateAgentAction = |
| | { action: 'agent.help' } |
| | { action: 'sin.frontend.health' } |
| | { action: 'sin.frontend.onboarding.status' } |
| | { action: 'sin.frontend.onboarding.save'; ownerEmail?: string; notes?: string; confirm?: boolean } |
| | { action: 'sin.frontend.code.generate'; prompt: string; contextDir?: string } |
| | { action: 'sin.frontend.code.review'; targetDir: string }; |
|
|
| export type FrontendAgentAction = TemplateAgentAction; |
|
|
| export async function executeTemplateAgentAction(action: TemplateAgentAction): Promise<unknown> { |
| switch (action.action) { |
| case 'agent.help': |
| return buildHelpPayload(); |
| case 'sin.frontend.health': |
| return { |
| ok: true, |
| agent: 'sin-code-frontend', |
| primaryModel: 'google/antigravity-gemini-3.1-pro', |
| fallbackModel: 'opencode/nemotron-3-super-free', |
| team: 'Team - Coding', |
| status: 'Elite Coder Runtime Online', |
| dualDb: getFrontendDualDbRoutingStatus(), |
| }; |
| case 'sin.frontend.onboarding.status': |
| return { |
| ok: true, |
| statePath: DEFAULT_STATE_PATH, |
| state: await readState(), |
| }; |
| case 'sin.frontend.onboarding.save': |
| if (!action.confirm) { |
| throw new Error('input_required:confirm=true required'); |
| } |
| return { |
| ok: true, |
| statePath: DEFAULT_STATE_PATH, |
| state: await writeState({ |
| ownerEmail: clean(action.ownerEmail), |
| notes: clean(action.notes), |
| updatedAt: new Date().toISOString(), |
| }), |
| }; |
| case 'sin.frontend.code.generate': |
| return await executeOpenCode(action.prompt, action.contextDir); |
| case 'sin.frontend.code.review': |
| return await executeOpenCode( |
| `Review ${action.targetDir} according to multi-billion dollar Google Workspace level Alpha standards.`, |
| action.targetDir, |
| ); |
| } |
| } |
|
|
| export const executeFrontendAgentAction = executeTemplateAgentAction; |
|
|
| 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', 'google/antigravity-gemini-3.1-pro', '--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 Coder Execution Failed: ${error.message}`); |
| } |
| } |
|
|
| function buildHelpPayload() { |
| return { |
| ok: true, |
| agent: 'sin-code-frontend', |
| mandate: 'CEO Elite Master Boss Coder for multi-billion dollar Alpha frontends.', |
| actions: [ |
| 'sin.frontend.health', |
| 'sin.frontend.onboarding.status', |
| 'sin.frontend.onboarding.save', |
| 'sin.frontend.code.generate', |
| 'sin.frontend.code.review', |
| ], |
| }; |
| } |
|
|
| async function readState(): Promise<OnboardingState | null> { |
| try { |
| return JSON.parse(await readFile(DEFAULT_STATE_PATH, 'utf8')) as OnboardingState; |
| } catch { |
| return null; |
| } |
| } |
|
|
| async function writeState(state: OnboardingState) { |
| await mkdir(dirname(DEFAULT_STATE_PATH), { recursive: true }); |
| await writeFile(DEFAULT_STATE_PATH, `${JSON.stringify(state, null, 2)}\n`, 'utf8'); |
| return state; |
| } |
|
|
| function clean(value: string | undefined) { |
| const normalized = String(value || '').trim(); |
| return normalized || undefined; |
| } |
|
|