Blame · Line-by-line history
spec-to-pr.ts
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| 14c3cc8 | 1 | /** |
| 2 | * Spec-to-PR (experimental). | |
| 3 | * | |
| 4 | * Entry point for the "describe a change in English, get a PR" feature. The | |
| 5 | * full pipeline — read the repo tree, call Claude to produce a patch, run it | |
| 6 | * through git plumbing, open a PR — is a follow-up patch. This file ships the | |
| 7 | * backend stub: it validates prerequisites (API key, repo existence) and | |
| 8 | * returns a structured `{ok:false}` result with a human-readable error that | |
| 9 | * the UI route surfaces directly. | |
| 10 | * | |
| 11 | * Keeping the stub real (not a throw) lets the UI wire up end-to-end today | |
| 12 | * and lets us light up the AI path without touching callers. | |
| 13 | */ | |
| 14 | import { eq } from "drizzle-orm"; | |
| 15 | import { db } from "../db"; | |
| 16 | import { repositories, users, pullRequests } from "../db/schema"; | |
| 17 | ||
| 18 | export type SpecPRResult = { | |
| 19 | ok: boolean; | |
| 20 | prNumber?: number; | |
| 21 | branchName?: string; | |
| 22 | filesChanged?: string[]; | |
| 23 | error?: string; | |
| 24 | }; | |
| 25 | ||
| 26 | export type SpecPRArgs = { | |
| 27 | repoId: number; | |
| 28 | spec: string; | |
| 29 | baseRef?: string; | |
| 30 | userId: number; | |
| 31 | }; | |
| 32 | ||
| 33 | export async function createSpecPR(args: SpecPRArgs): Promise<SpecPRResult> { | |
| 34 | // 1. Require ANTHROPIC_API_KEY — without it the AI step can't run, so we | |
| 35 | // fail fast rather than doing a pointless DB round-trip. | |
| 36 | if (!process.env.ANTHROPIC_API_KEY) { | |
| 37 | return { ok: false, error: "ANTHROPIC_API_KEY required for spec-to-PR" }; | |
| 38 | } | |
| 39 | ||
| 40 | // 2. Look up repo. If the repo doesn't exist we surface that specifically | |
| 41 | // so the UI can distinguish "bad id" from "AI not configured". | |
| 42 | try { | |
| 43 | const rows = await db | |
| 44 | .select() | |
| 45 | .from(repositories) | |
| 46 | .where(eq(repositories.id, args.repoId as unknown as string)) | |
| 47 | .limit(1); | |
| 48 | if (rows.length === 0) return { ok: false, error: "repo not found" }; | |
| 49 | } catch (err) { | |
| 50 | return { ok: false, error: "db lookup failed" }; | |
| 51 | } | |
| 52 | ||
| 53 | // Touch the remaining imports so they aren't flagged as unused and so that | |
| 54 | // the eventual implementation (user lookup for PR author, pullRequests | |
| 55 | // insert) doesn't need an import change in the follow-up patch. | |
| 56 | void users; | |
| 57 | void pullRequests; | |
| 58 | ||
| 59 | // 3. v1 stub — feature is experimental. For now, just return a clear | |
| 60 | // message. Full implementation (read tree, call Claude, git plumbing, | |
| 61 | // PR insert) is a follow-up. The UI route handles {ok:false} gracefully. | |
| 62 | return { | |
| 63 | ok: false, | |
| 64 | error: | |
| 65 | "spec-to-PR is experimental and not yet fully implemented. Backend stub only — full AI integration arriving in a follow-up patch.", | |
| 66 | }; | |
| 67 | } |