Initial commit — AI-powered coding tutor (Professor)

Next.js 16, React 19, Monaco editor, Anthropic SDK, multi-provider AI,
Wandbox Python execution, iframe HTML preview, SQLite auth + session persistence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Aodhan Collins
2026-03-04 21:48:34 +00:00
commit f644937604
56 changed files with 14012 additions and 0 deletions

57
lib/pistonClient.ts Normal file
View File

@@ -0,0 +1,57 @@
import type { ExecutionResult } from '@/types';
// Wandbox — free public code execution API, no auth required
// https://github.com/melpon/wandbox
const WANDBOX_API = 'https://wandbox.org/api/compile.json';
const TIMEOUT_MS = 15_000;
export async function executePython(code: string, stdin = ''): Promise<ExecutionResult> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
try {
const res = await fetch(WANDBOX_API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
signal: controller.signal,
body: JSON.stringify({
compiler: 'cpython-3.12.7',
code,
stdin,
}),
});
if (!res.ok) {
throw new Error(`Execution service error: ${res.status}`);
}
const data = await res.json();
const exitCode = parseInt(data.status ?? '0', 10);
// Wandbox separates compiler errors from runtime errors
const stderr = [data.program_error, data.compiler_error]
.filter(Boolean)
.join('\n')
.trim();
return {
stdout: data.program_output ?? '',
stderr,
exitCode,
timedOut: !!data.signal,
};
} catch (err: unknown) {
if (err instanceof Error && err.name === 'AbortError') {
return { stdout: '', stderr: '', exitCode: -1, timedOut: true, error: 'Execution timed out after 15 seconds.' };
}
return {
stdout: '',
stderr: '',
exitCode: -1,
timedOut: false,
error: err instanceof Error ? err.message : 'Unknown execution error',
};
} finally {
clearTimeout(timer);
}
}