diff --git a/apps/web/app/demo.tsx b/apps/web/app/demo.tsx index 38b99cf..cd12614 100644 --- a/apps/web/app/demo.tsx +++ b/apps/web/app/demo.tsx @@ -1,87 +1,334 @@ "use client"; import { useMemo, useState } from "react"; -import { buildTestRoutes, rankContextFiles, type RepoFile, type RepoMap } from "@aryam/fixmap-core/browser"; - -const sampleFiles = [ - sampleFile("src/auth/reset-password.ts", "password reset token email authentication", "code"), - sampleFile("src/auth/session.ts", "login session cookie authentication", "code"), - sampleFile("src/billing/create-invoice.ts", "billing payment invoice customer", "code"), - sampleFile("src/email/send-reset.ts", "send password reset email template", "code"), - sampleFile("test/auth/reset-password.test.ts", "password reset email token test", "code", true), - sampleFile(".github/workflows/ci.yml", "workflow test build pull request", "config"), - sampleFile("README.md", "installation guide documentation", "documentation") -]; +import { buildReportFromRepo, explainFile, verifyPlan } from "@aryam/fixmap-core/browser"; +import { sampleRepo, sampleRepoWithChanges, samplePaths } from "./sample-repo"; -const sampleRepo: RepoMap = { - root: "sample-repository", - files: sampleFiles, - packageScripts: [{ name: "test", command: "vitest run", packageDir: "" }], - changedFiles: [], - diffText: "", - packageManager: "npm", - diagnostics: [] -}; +type Stage = "plan" | "explain" | "verify"; const presets = [ - "Password reset emails fail", - "Invoices are created twice", - "Login sessions expire too early", - "Update the installation guide" + { + label: "Password reset emails never arrive", + note: "A symptom with no symbol. This is where a lexical ranker is weakest — watch what happens in the next preset." + }, + { + label: "sendMail throws and password reset emails never arrive", + note: "The same bug with one symbol named. The transport file climbs, and the reason says why: it defines sendMail." + }, + { + label: "TOKEN_TTL_MINUTES is ignored, reset links expire immediately", + note: "A named constant is the strongest anchor there is. The file that defines it wins outright." + }, + { + label: "Invoices are created twice for the same customer", + note: "A different subsystem, no overlap with the auth files, no drift into them." + }, + { + label: "make it better", + note: "No searchable anchor. FixMap reports nothing and says so, instead of ranking something plausible." + } +]; + +const scenarios = [ + { label: "Edited the build output", changed: ["dist/auth/reset-password.js"] }, + { label: "Shipped with no test", changed: ["src/email/transport.ts"] }, + { label: "Also touched billing", changed: ["src/email/transport.ts", "src/billing/invoice.ts"] }, + { + label: "Source and test together", + changed: ["src/auth/reset-password.ts", "test/auth/reset-password.test.ts"] + } ]; +const explainTargets = samplePaths; + export function Demo() { - const [task, setTask] = useState("Password reset emails fail"); - const result = useMemo(() => { - const ranked = rankContextFiles(sampleRepo, { issueText: task }, 4); - const routes = buildTestRoutes(sampleRepo, ranked.map((file) => file.path)); - return { ranked, routes }; - }, [task]); + const [task, setTask] = useState(presets[0]!.label); + const [stage, setStage] = useState("plan"); + const [explainTarget, setExplainTarget] = useState("dist/auth/reset-password.js"); + const [scenario, setScenario] = useState(0); + + const report = useMemo(() => buildReportFromRepo(sampleRepo, { issueText: task }), [task]); + const explanation = useMemo( + () => explainFile(sampleRepo, { issueText: task }, explainTarget), + [task, explainTarget] + ); + const verification = useMemo( + () => verifyPlan(report, sampleRepoWithChanges(scenarios[scenario]!.changed)), + [report, scenario] + ); + + const activePreset = presets.find((preset) => preset.label === task); + const command = { + plan: `fixmap plan --issue "${truncate(task)}"`, + explain: `fixmap plan --issue "${truncate(task)}" --explain ${explainTarget}`, + verify: `fixmap verify --report plan.json --diff main...HEAD` + }[stage]; return ( -
-
- -