diff --git a/app/api/scan-repo/route.ts b/app/api/scan-repo/route.ts index e0d4513..9987296 100644 --- a/app/api/scan-repo/route.ts +++ b/app/api/scan-repo/route.ts @@ -6,9 +6,10 @@ import type { RepoScanSummary, RepoStructureSummary, } from "@/types/repo-scan" -import { collectConventionValues, normalizeConventionValue } from "@/lib/convention-values" +import { loadStackQuestionMetadata, normalizeConventionValue } from "@/lib/question-metadata" import { loadStackConventions } from "@/lib/conventions" import { inferStackFromScan } from "@/lib/scan-to-wizard" +import { stackQuestion } from "@/lib/wizard-config" const GITHUB_API_BASE_URL = "https://api.github.com" const GITHUB_HOSTNAMES = new Set(["github.com", "www.github.com"]) @@ -302,10 +303,10 @@ const getTestingConventionValues = async (stackId: string): Promise answer.value === detectedStack) ?? null + const stackSupported = matchedStackAnswer + ? matchedStackAnswer.disabled !== true && matchedStackAnswer.enabled !== false + : false + const stackLabel = matchedStackAnswer?.label ?? null summary.conventions = { stack: detectedStack, + stackLabel, + isSupported: stackSupported, hasCustomConventions: hasStackFile, structureRelevant: conventions.structureRelevant, } diff --git a/app/existing/[repoUrl]/repo-scan-client.tsx b/app/existing/[repoUrl]/repo-scan-client.tsx index 1c1b85a..e66989e 100644 --- a/app/existing/[repoUrl]/repo-scan-client.tsx +++ b/app/existing/[repoUrl]/repo-scan-client.tsx @@ -18,6 +18,7 @@ import type { GeneratedFileResult } from "@/types/output" const buildQuery = (url: string) => `/api/scan-repo?url=${encodeURIComponent(url)}` const CONVENTIONS_DOC_URL = process.env.NEXT_PUBLIC_CONVENTIONS_URL ?? "https://github.com/devcontext-ai/devcontext/tree/main/conventions" +const STACKS_DATA_DOC_URL = "https://github.com/spivx/devcontext/blob/main/data/stacks.json" const formatList = (values: string[]) => (values.length > 0 ? values.join(", ") : "Not detected") @@ -127,6 +128,11 @@ export default function RepoScanClient({ initialRepoUrl }: RepoScanClientProps) } const warnings = scanResult?.warnings ?? [] + const stackMeta = scanResult?.conventions ?? null + const detectedStackId = stackMeta?.stack ?? null + const detectedStackLabel = stackMeta?.stackLabel ?? detectedStackId ?? "Not detected" + const stackIsSupported = stackMeta?.isSupported ?? false + const showUnsupportedStackNotice = Boolean(detectedStackId) && !stackIsSupported const repoSlug = repoUrlForScan ? toSlug(repoUrlForScan) : null const promptVisible = Boolean(repoUrlForScan && !hasConfirmed && !isLoading && !scanResult && !error) const canRetry = hasConfirmed && !isLoading @@ -138,7 +144,7 @@ export default function RepoScanClient({ initialRepoUrl }: RepoScanClientProps) const [generatedFile, setGeneratedFile] = useState(null) const handleGenerate = useCallback(async (fileId: string) => { - if (!scanResult) return + if (!scanResult || scanResult.conventions?.isSupported === false) return setIsGeneratingMap((prev) => ({ ...prev, [fileId]: true })) setGeneratedFile(null) try { @@ -228,7 +234,22 @@ export default function RepoScanClient({ initialRepoUrl }: RepoScanClientProps)

- {scanResult.conventions && !scanResult.conventions.hasCustomConventions ? ( +
+
+
+

{detectedStackLabel}

+ {detectedStackId && detectedStackLabel !== detectedStackId ? ( +

+ Stack ID: {detectedStackId} +

+ ) : null} + {showUnsupportedStackNotice ? ( +

Not yet supported

+ ) : null} +
+ {!showUnsupportedStackNotice && scanResult.conventions && !scanResult.conventions.hasCustomConventions ? (
@@ -250,107 +271,138 @@ export default function RepoScanClient({ initialRepoUrl }: RepoScanClientProps)
) : null} -
-
-
-

- {scanResult.language ?? "Not detected"} -

- {scanResult.languages.length > 1 ? ( -

- Also spotted: {scanResult.languages.slice(1).join(", ")} -

- ) : null} -
-
-
-
-

{scanResult.defaultBranch}

-
-
-
-
-

Frameworks

-

{formatList(scanResult.frameworks)}

-
-
-

Tooling

-

{formatList(scanResult.tooling)}

-
-
-

Testing

-

{formatList(scanResult.testing)}

-
-
-

Structure hints

-
    - {structureEntries.map(({ key, value }) => ( -
  • - {key} - - {value ? "Present" : "Missing"} - -
  • - ))} -
-
-
-
-
-

Generate instructions

-

- Choose the file you need—each one opens an Instructions ready preview powered by this scan. -

-
-
- {fileOptions.map((file) => { - const busy = Boolean(isGeneratingMap[file.id]) - return ( - - ) - })} -
+ {!showUnsupportedStackNotice ? ( + <> +
+
+
+

+ {scanResult.language ?? "Not detected"} +

+ {scanResult.languages.length > 1 ? ( +

+ Also spotted: {scanResult.languages.slice(1).join(", ")} +

+ ) : null} +
+
+
+
+

{scanResult.defaultBranch}

+
+ + ) : null}
- {warnings.length > 0 ? ( -
-
-