diff --git a/scripts/check-code-health.mjs b/scripts/check-code-health.mjs index 512f4a6..ce3890f 100644 --- a/scripts/check-code-health.mjs +++ b/scripts/check-code-health.mjs @@ -28,11 +28,11 @@ const baselines = { unlisted: 0, unresolved: 0, }, - complexity: { violations: 35, maxCcn: 56, maxLength: 397, maxParams: 17 }, + complexity: { violations: 34, maxCcn: 56, maxLength: 397, maxParams: 17 }, duplication: { - clones: 34, - duplicatedLines: 532, - percentage: 2.698452954603094, + clones: 27, + duplicatedLines: 369, + percentage: 1.8774, }, suppressions: 8, dependencies: { critical: 0, highIds: 0, highFindings: 0 }, diff --git a/scripts/seed-popular.ts b/scripts/seed-popular.ts index 5385a83..e3870e2 100644 --- a/scripts/seed-popular.ts +++ b/scripts/seed-popular.ts @@ -36,7 +36,7 @@ import type { DbClient as Client, InStatement } from '../src/db/client'; import { createD1RestClientFromEnv } from '../src/db/rest-client'; import { isRetryableDbError } from '../src/lib/db-retry'; -import { buildRepoEmbeddingText, generateEmbeddings, textHash } from '../src/lib/embeddings'; +import { buildEmbeddingFromRow, generateEmbeddings } from '../src/lib/embeddings'; import { enumeratePopularCatalog, GITHUB_SEARCH_PAGE_SIZE, @@ -277,22 +277,7 @@ async function embedPending(db: Client, limit: number): Promise { const toEmbed: { id: number; text: string; hash: string }[] = []; for (const row of pending.rows) { - const text = buildRepoEmbeddingText({ - full_name: row.full_name as string, - description: row.description as string | null, - language: row.language as string | null, - topics: row.topics as string, - ai: row.summary - ? { - summary: row.summary as string, - category: row.category as string, - subcategories: row.subcategories as string, - use_cases: row.use_cases as string, - keywords: row.keywords as string, - } - : null, - }); - const hash = textHash(text); + const { text, hash } = buildEmbeddingFromRow(row); if (row.text_hash !== hash) { toEmbed.push({ id: row.id as number, text, hash }); } diff --git a/src/app/api/internal/embed-pending/route.ts b/src/app/api/internal/embed-pending/route.ts index 0acb523..9d99b35 100644 --- a/src/app/api/internal/embed-pending/route.ts +++ b/src/app/api/internal/embed-pending/route.ts @@ -2,7 +2,7 @@ import type { InStatement } from '@/db/client'; import { NextResponse } from 'next/server'; import { db } from '@/db'; -import { buildRepoEmbeddingText, generateEmbeddings, textHash } from '@/lib/embeddings'; +import { buildEmbeddingFromRow, generateEmbeddings } from '@/lib/embeddings'; import { hasValidOperatorToken } from '@/lib/operator-auth'; import { repoVectors } from '@/lib/repo-vectors'; @@ -77,22 +77,7 @@ export async function POST(request: Request) { const pending: { id: number; text: string; hash: string }[] = []; for (const row of repos.rows) { - const text = buildRepoEmbeddingText({ - full_name: row.full_name as string, - description: row.description as string | null, - language: row.language as string | null, - topics: row.topics as string, - ai: row.summary - ? { - summary: row.summary as string, - category: row.category as string, - subcategories: row.subcategories as string, - use_cases: row.use_cases as string, - keywords: row.keywords as string, - } - : null, - }); - const hash = textHash(text); + const { text, hash } = buildEmbeddingFromRow(row); if (row.text_hash !== hash) { pending.push({ id: row.id as number, text, hash }); } diff --git a/src/app/api/repos/[repoId]/route.ts b/src/app/api/repos/[repoId]/route.ts index d2f741d..be21201 100644 --- a/src/app/api/repos/[repoId]/route.ts +++ b/src/app/api/repos/[repoId]/route.ts @@ -2,22 +2,7 @@ import { type NextRequest, NextResponse } from 'next/server'; import { db } from '@/db'; -import { resolveRepoId } from '../resolve'; - -interface GitHubRepoResponse { - id: number; - name: string; - full_name: string; - owner: { login: string; avatar_url: string }; - html_url: string; - description: string | null; - language: string | null; - stargazers_count: number; - archived?: boolean; - topics?: string[]; - created_at: string; - updated_at: string; -} +import { type GitHubRepoResponse, resolveRepoId, upsertRepoFromGitHub } from '../resolve'; export async function GET( request: NextRequest, @@ -82,33 +67,7 @@ export async function GET( const gh = (await ghRes.json()) as GitHubRepoResponse; - await db.execute({ - sql: `INSERT INTO repos (id, name, full_name, owner_login, owner_avatar, html_url, - description, language, stargazers_count, archived, topics, repo_created_at, repo_updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ON CONFLICT(id) DO UPDATE SET - name = excluded.name, full_name = excluded.full_name, - owner_login = excluded.owner_login, owner_avatar = excluded.owner_avatar, - html_url = excluded.html_url, description = excluded.description, - language = excluded.language, stargazers_count = excluded.stargazers_count, - archived = excluded.archived, topics = excluded.topics, repo_created_at = excluded.repo_created_at, - repo_updated_at = excluded.repo_updated_at`, - args: [ - gh.id, - gh.name, - gh.full_name, - gh.owner.login, - gh.owner.avatar_url, - gh.html_url, - gh.description ?? null, - gh.language ?? null, - gh.stargazers_count, - gh.archived ? 1 : 0, - JSON.stringify(gh.topics ?? []), - gh.created_at, - gh.updated_at, - ], - }); + await upsertRepoFromGitHub(gh); repoResult = await db.execute({ sql: 'SELECT * FROM repos WHERE id = ?', diff --git a/src/app/api/repos/resolve.ts b/src/app/api/repos/resolve.ts index 6cb1fcc..1b32903 100644 --- a/src/app/api/repos/resolve.ts +++ b/src/app/api/repos/resolve.ts @@ -1,6 +1,6 @@ import { db } from '@/db'; -interface GitHubRepoResponse { +export interface GitHubRepoResponse { id: number; name: string; full_name: string; @@ -15,6 +15,42 @@ interface GitHubRepoResponse { updated_at: string; } +const REPO_UPSERT_SQL = `INSERT INTO repos (id, name, full_name, owner_login, owner_avatar, html_url, + description, language, stargazers_count, archived, topics, repo_created_at, repo_updated_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(id) DO UPDATE SET + name = excluded.name, full_name = excluded.full_name, + owner_login = excluded.owner_login, owner_avatar = excluded.owner_avatar, + html_url = excluded.html_url, description = excluded.description, + language = excluded.language, stargazers_count = excluded.stargazers_count, + archived = excluded.archived, topics = excluded.topics, repo_created_at = excluded.repo_created_at, + repo_updated_at = excluded.repo_updated_at`; + +/** + * Upsert a GitHub repo row into D1. Shared by resolveRepoId and the + * [repoId] GET route so the INSERT/ON CONFLICT shape stays in one place. + */ +export async function upsertRepoFromGitHub(gh: GitHubRepoResponse): Promise { + await db.execute({ + sql: REPO_UPSERT_SQL, + args: [ + gh.id, + gh.name, + gh.full_name, + gh.owner.login, + gh.owner.avatar_url, + gh.html_url, + gh.description ?? null, + gh.language ?? null, + gh.stargazers_count, + gh.archived ? 1 : 0, + JSON.stringify(gh.topics ?? []), + gh.created_at, + gh.updated_at, + ], + }); +} + /** * Resolve owner/repo slug to a numeric repo ID. * If the repo isn't in our DB yet, fetches from GitHub and inserts it. @@ -42,33 +78,7 @@ export async function resolveRepoId(owner: string, repo: string): Promise -
- - - - -
- -
- - -
-
- {Array.from({ length: 6 }).map((_, i) => ( -
-
- - -
- - -
-
- - -
-
-
- ))} -
-
-
- - ); -} - export default function DiscoverClient({ initialData, initialUrl, diff --git a/src/app/discover/error.tsx b/src/app/discover/error.tsx index 6ebb9ba..ca6519c 100644 --- a/src/app/discover/error.tsx +++ b/src/app/discover/error.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; +import { ErrorActions } from '@/components/error-actions'; import { captureError } from '@/lib/foundry-monitoring'; export default function DiscoverError({ @@ -23,18 +24,7 @@ export default function DiscoverError({

Something went wrong while loading the discover feed — try again.

-
- - -
- {error.digest ?

Reference: {error.digest}

: null} + ); diff --git a/src/app/error.tsx b/src/app/error.tsx index 1c9c424..7613112 100644 --- a/src/app/error.tsx +++ b/src/app/error.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; +import { ErrorActions } from '@/components/error-actions'; import { captureError } from '@/lib/foundry-monitoring'; export default function Error({ @@ -25,18 +26,7 @@ export default function Error({ An unexpected error occurred on our end. Your data is safe — try again, and if it keeps happening, come back in a few minutes.

-
- - -
- {error.digest ?

Reference: {error.digest}

: null} + ); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2fcb9ff..f4fb1d6 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -72,8 +72,9 @@ export default function RootLayout({ {/* fleet-jsonld:start (generated by apply-agent-surfaces; edit registry, not this) */}