import { CONTEXT_KINDS, contextPathForKind, MAX_CONTEXT_DOCUMENT_CHARACTERS, type PreparedPublicGitSource, type PublicGitImportResult, type RepositoryContextDocument, } from "@code/primitives/project"; const GITHUB_HOST = "github.com"; const REQUEST_HEADERS = { Accept: "application/vnd.github+json", "User-Agent": "zopu-project-importer", } as const; const candidatePaths = { agents: ["AGENTS.md"], business: ["business.md", "docs/business.md"], design: ["design.md", "docs/design.md"], product: ["product.md", "docs/product.md"], readme: ["README.md", "README", "readme.md"], tech: ["tech.md", "docs/tech.md"], } as const; const encodePath = (path: string) => path .split("/") .map((segment) => encodeURIComponent(segment)) .join("/"); const fetchTextCandidate = async ( repositoryPath: string, branch: string, path: string ): Promise => { const url = `https://raw.githubusercontent.com/${encodePath(repositoryPath)}/${encodePath(branch)}/${encodePath(path)}`; const response = await fetch(url, { headers: REQUEST_HEADERS }); if (response.status === 404) { return null; } if (!response.ok) { throw new Error(`GitHub returned ${response.status} for ${path}`); } const content = await response.text(); if (content.trim().length === 0) { return null; } if (content.length > MAX_CONTEXT_DOCUMENT_CHARACTERS) { throw new Error(`${path} exceeds the 200000 character import limit`); } return content; }; const fetchContextDocument = async ( source: PreparedPublicGitSource, branch: string, kind: (typeof CONTEXT_KINDS)[number] ): Promise => { for (const candidate of candidatePaths[kind]) { const content = await fetchTextCandidate( source.repositoryPath, branch, candidate ); if (content) { return { content, kind, path: contextPathForKind(kind), }; } } return null; }; const readDefaultBranch = async ( source: PreparedPublicGitSource ): Promise => { if (source.host !== GITHUB_HOST) { throw new Error("Repository import currently supports public GitHub URLs"); } const response = await fetch( `https://api.github.com/repos/${encodePath(source.repositoryPath)}`, { headers: REQUEST_HEADERS } ); if (!response.ok) { throw new Error( response.status === 404 ? "Public GitHub repository not found" : `GitHub returned ${response.status} while reading the repository` ); } const metadata = (await response.json()) as { default_branch?: unknown }; if ( typeof metadata.default_branch !== "string" || metadata.default_branch.length === 0 ) { throw new Error("GitHub did not return a default branch"); } return metadata.default_branch; }; export const inspectPublicGit = async ( source: PreparedPublicGitSource ): Promise => { const defaultBranch = await readDefaultBranch(source); const candidates = await Promise.all( CONTEXT_KINDS.map((kind) => fetchContextDocument(source, defaultBranch, kind) ) ); const documents = candidates.filter( (document): document is RepositoryContextDocument => document !== null ); return { defaultBranch, documents, warnings: CONTEXT_KINDS.filter( (kind) => !documents.some((document) => document.kind === kind) ).map((kind) => ({ message: "Canonical context file was not found in the repository", path: contextPathForKind(kind), })), }; };