frontend / src /runtime.ts
delqhi's picture
Deploy frontend agent
5112d5b verified
Raw
History Blame Contribute Delete
4.85 kB
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;
}