diff --git a/app/api/projects/create/route.ts b/app/api/projects/create/route.ts index 0cb4ec1..48dae04 100644 --- a/app/api/projects/create/route.ts +++ b/app/api/projects/create/route.ts @@ -3,7 +3,7 @@ import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth/authOptions'; import { query } from '@/lib/db-postgres'; import { randomUUID } from 'crypto'; -import { createRepo, createWebhook, GITEA_ADMIN_USER_EXPORT } from '@/lib/gitea'; +import { createRepo, createWebhook, getRepo, listWebhooks, GITEA_ADMIN_USER_EXPORT } from '@/lib/gitea'; import { provisionTheiaWorkspace } from '@/lib/cloud-run-workspace'; import type { ProjectPhaseData, ProjectPhaseScores } from '@/lib/types/project-artifacts'; @@ -67,23 +67,45 @@ export async function POST(request: Request) { try { const repoName = slug; // e.g. "taskmaster" - const repo = await createRepo(repoName, { - description: `${projectName} — managed by Vibn`, - private: true, - auto_init: true, - }); + let repo; + + try { + repo = await createRepo(repoName, { + description: `${projectName} — managed by Vibn`, + private: true, + auto_init: true, + }); + console.log(`[API] Gitea repo created: ${GITEA_ADMIN_USER}/${repoName}`); + } catch (createErr) { + const msg = createErr instanceof Error ? createErr.message : String(createErr); + // 409 = repo already exists — link to it instead of failing + if (msg.includes('409')) { + console.log(`[API] Gitea repo already exists, linking to ${GITEA_ADMIN_USER}/${repoName}`); + repo = await getRepo(GITEA_ADMIN_USER, repoName); + if (!repo) throw new Error(`Repo ${repoName} exists but could not be fetched`); + } else { + throw createErr; + } + } giteaRepo = repo.full_name; // e.g. "mark/taskmaster" giteaRepoUrl = repo.html_url; // e.g. "https://git.vibnai.com/mark/taskmaster" giteaCloneUrl = repo.clone_url; giteaSshUrl = repo.ssh_url; - // 2. Register webhook on the repo pointing back to Vibn + // Register webhook — skip if one already points to this project const webhookUrl = `${APP_URL}/api/webhooks/gitea?projectId=${projectId}`; - const hook = await createWebhook(GITEA_ADMIN_USER, repoName, webhookUrl, GITEA_WEBHOOK_SECRET); - giteaWebhookId = hook.id; + const existingHooks = await listWebhooks(GITEA_ADMIN_USER, repoName).catch(() => []); + const alreadyHooked = existingHooks.some(h => h.config.url.includes(projectId)); - console.log(`[API] Gitea repo created: ${giteaRepo}, webhook: ${giteaWebhookId}`); + if (!alreadyHooked) { + const hook = await createWebhook(GITEA_ADMIN_USER, repoName, webhookUrl, GITEA_WEBHOOK_SECRET); + giteaWebhookId = hook.id; + console.log(`[API] Webhook registered: ${giteaRepo}, id: ${giteaWebhookId}`); + } else { + giteaWebhookId = existingHooks.find(h => h.config.url.includes(projectId))?.id ?? null; + console.log(`[API] Webhook already exists for ${giteaRepo}`); + } } catch (err) { // Non-fatal — log and continue. Project is still created. giteaError = err instanceof Error ? err.message : String(err);