diff --git a/src/index.ts b/src/index.ts index 59d9471..e958f44 100644 --- a/src/index.ts +++ b/src/index.ts @@ -41,6 +41,7 @@ const server = new Server( { capabilities: { tools: {}, + logging: {}, }, } ); @@ -197,10 +198,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { try { switch (name) { case "aztec_sync_repos": { + const log = (message: string, level: string = "info") => { + server.sendLoggingMessage({ + level: level as "info" | "debug" | "warning" | "error", + logger: "aztec-sync", + data: message, + }).catch(() => {}); + }; const result = await syncRepos({ version: args?.version as string | undefined, force: args?.force as boolean | undefined, repos: args?.repos as string[] | undefined, + log, }); return { content: [ diff --git a/src/tools/search.ts b/src/tools/search.ts index 380dc53..dd328eb 100644 --- a/src/tools/search.ts +++ b/src/tools/search.ts @@ -73,12 +73,12 @@ export function searchAztecDocs(options: { } { const { query, section, maxResults = 20 } = options; - if (!isRepoCloned("aztec-packages")) { + if (!isRepoCloned("aztec-packages-docs")) { return { success: false, results: [], message: - "aztec-packages is not cloned. Run aztec_sync_repos first to get documentation.", + "aztec-packages-docs is not cloned. Run aztec_sync_repos first to get documentation.", }; } diff --git a/src/tools/sync.ts b/src/tools/sync.ts index a8d0a68..1f99980 100644 --- a/src/tools/sync.ts +++ b/src/tools/sync.ts @@ -3,7 +3,7 @@ */ import { AZTEC_REPOS, getAztecRepos, DEFAULT_AZTEC_VERSION, RepoConfig } from "../repos/config.js"; -import { cloneRepo, getReposStatus, getNoirCommitFromAztec, REPOS_DIR } from "../utils/git.js"; +import { cloneRepo, getReposStatus, getNoirCommitFromAztec, REPOS_DIR, Logger } from "../utils/git.js"; export interface SyncResult { success: boolean; @@ -24,8 +24,9 @@ export async function syncRepos(options: { force?: boolean; repos?: string[]; version?: string; + log?: Logger; }): Promise { - const { force = false, repos: repoNames, version } = options; + const { force = false, repos: repoNames, version, log } = options; // Get repos configured for the specified version const configuredRepos = version ? getAztecRepos(version) : AZTEC_REPOS; @@ -45,13 +46,40 @@ export async function syncRepos(options: { }; } + // Generate synthetic repo configs from sparsePathOverrides + const syntheticRepos: RepoConfig[] = []; + for (const repo of reposToSync) { + if (repo.sparsePathOverrides) { + for (const override of repo.sparsePathOverrides) { + syntheticRepos.push({ + name: `${repo.name}-docs`, + url: repo.url, + branch: override.branch, + sparse: override.paths, + description: `${repo.description} (docs from ${override.branch})`, + }); + } + } + } + + // Include synthetic repos in total count + const totalRepos = reposToSync.length + syntheticRepos.length; + log?.(`Starting sync: ${totalRepos} repos, version=${effectiveVersion}, force=${force}`, "info"); + const results: SyncResult["repos"] = []; - async function syncRepo(config: RepoConfig, statusTransform?: (s: string) => string): Promise { + async function syncRepo( + config: RepoConfig, + index: number, + total: number, + statusTransform?: (s: string) => string, + ): Promise { + log?.(`Syncing ${index}/${total}: ${config.name}`, "info"); try { - const status = await cloneRepo(config, force); + const status = log ? await cloneRepo(config, force, log) : await cloneRepo(config, force); results.push({ name: config.name, status: statusTransform ? statusTransform(status) : status }); } catch (error) { + log?.(`${config.name}: Failed: ${error instanceof Error ? error.message : String(error)}`, "error"); results.push({ name: config.name, status: `Error: ${error instanceof Error ? error.message : String(error)}`, @@ -59,43 +87,58 @@ export async function syncRepos(options: { } } - // Sort repos so aztec-packages is cloned first (needed to determine Noir version) + // Clone aztec-packages first (blocking - needed to determine Noir version) const aztecPackages = reposToSync.find((r) => r.name === "aztec-packages"); - const noirRepos = reposToSync.filter((r) => r.url.includes("noir-lang")); - const otherRepos = reposToSync.filter( - (r) => r.name !== "aztec-packages" && !r.url.includes("noir-lang") - ); - - // Clone aztec-packages first if present + let nextIndex = 1; if (aztecPackages) { - await syncRepo(aztecPackages); + await syncRepo(aztecPackages, nextIndex++, totalRepos); } // Get the Noir commit from aztec-packages (if available) const noirCommit = await getNoirCommitFromAztec(); + if (noirCommit) { + log?.(`Resolved Noir commit from aztec-packages: ${noirCommit.substring(0, 7)}`, "info"); + } + + // Build list of all remaining repos to clone in parallel + const parallelBatch: { config: RepoConfig; index: number; statusTransform?: (s: string) => string }[] = []; + + const noirRepos = reposToSync.filter((r) => r.url.includes("noir-lang")); + const otherRepos = reposToSync.filter( + (r) => r.name !== "aztec-packages" && !r.url.includes("noir-lang") + ); - // Clone Noir repos with the commit from aztec-packages for (const config of noirRepos) { const useAztecCommit = config.name === "noir" && noirCommit; const noirConfig: RepoConfig = useAztecCommit ? { ...config, commit: noirCommit, branch: undefined } : config; - - await syncRepo( - noirConfig, - useAztecCommit ? (s) => s.replace("(commit", "(commit from aztec-packages") : undefined - ); + parallelBatch.push({ + config: noirConfig, + index: nextIndex++, + statusTransform: useAztecCommit ? (s) => s.replace("(commit", "(commit from aztec-packages") : undefined, + }); } - // Clone other repos for (const config of otherRepos) { - await syncRepo(config); + parallelBatch.push({ config, index: nextIndex++ }); } + for (const config of syntheticRepos) { + parallelBatch.push({ config, index: nextIndex++ }); + } + + // Clone all remaining repos in parallel + await Promise.all( + parallelBatch.map((item) => syncRepo(item.config, item.index, totalRepos, item.statusTransform)) + ); + const allSuccess = results.every( (r) => !r.status.toLowerCase().includes("error") ); + log?.(`Sync complete: ${results.length} repos, ${allSuccess ? "all succeeded" : "some failed"}`, "info"); + return { success: allSuccess, message: allSuccess diff --git a/src/utils/git.ts b/src/utils/git.ts index 3cc7c13..72ada50 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -8,6 +8,8 @@ import { join } from "path"; import { homedir } from "os"; import { RepoConfig } from "../repos/config.js"; +export type Logger = (message: string, level?: "info" | "debug" | "warning" | "error") => void; + /** Base directory for cloned repos */ export const REPOS_DIR = join( process.env.AZTEC_MCP_REPOS_DIR || join(homedir(), ".aztec-mcp"), @@ -41,7 +43,8 @@ export function isRepoCloned(repoName: string): boolean { */ export async function cloneRepo( config: RepoConfig, - force: boolean = false + force: boolean = false, + log?: Logger ): Promise { ensureReposDir(); const repoPath = getRepoPath(config.name); @@ -51,21 +54,36 @@ export async function cloneRepo( // Remove existing if force is set or version changed if ((force || versionMismatch) && existsSync(repoPath)) { + log?.(`${config.name}: Removing existing clone (force=${force}, versionMismatch=${versionMismatch})`, "debug"); rmSync(repoPath, { recursive: true, force: true }); } - // If already cloned and version matches, just update + // If already cloned and version matches, skip or update if (isRepoCloned(config.name)) { - return await updateRepo(config.name); + if (config.tag || config.commit) { + log?.(`${config.name}: Already cloned at correct ${config.tag ? "tag" : "commit"}, skipping`, "debug"); + return `${config.name} already at ${config.commit || config.tag}`; + } + log?.(`${config.name}: Already cloned, updating`, "debug"); + return await updateRepo(config.name, log); } - const git: SimpleGit = simpleGit(); - // Determine ref to checkout: commit > tag > branch const ref = config.commit || config.tag || config.branch || "default"; const refType = config.commit ? "commit" : config.tag ? "tag" : "branch"; + const isSparse = config.sparse && config.sparse.length > 0; - if (config.sparse && config.sparse.length > 0) { + log?.(`${config.name}: Cloning @ ${ref} (${refType}${isSparse ? ", sparse" : ""})`, "info"); + + const progressHandler = log + ? (data: { method: string; stage: string; progress: number }) => { + log(`${config.name}: ${data.method} ${data.stage} ${data.progress}%`, "debug"); + } + : undefined; + + const git: SimpleGit = simpleGit({ progress: progressHandler }); + + if (isSparse) { // Clone with sparse checkout for large repos if (config.commit) { // For commits, we need full history to fetch the commit @@ -75,10 +93,13 @@ export async function cloneRepo( "--no-checkout", ]); - const repoGit = simpleGit(repoPath); + const repoGit = simpleGit({ baseDir: repoPath, progress: progressHandler }); await repoGit.raw(["config", "gc.auto", "0"]); - await repoGit.raw(["sparse-checkout", "set", ...config.sparse]); + log?.(`${config.name}: Setting sparse checkout paths: ${config.sparse!.join(", ")}`, "debug"); + await repoGit.raw(["sparse-checkout", "set", ...config.sparse!]); + log?.(`${config.name}: Fetching commit ${config.commit.substring(0, 7)}`, "info"); await repoGit.fetch(["origin", config.commit]); + log?.(`${config.name}: Checking out commit`, "debug"); await repoGit.checkout(config.commit); } else if (config.tag) { await git.clone(config.url, repoPath, [ @@ -87,29 +108,14 @@ export async function cloneRepo( "--no-checkout", ]); - const repoGit = simpleGit(repoPath); + const repoGit = simpleGit({ baseDir: repoPath, progress: progressHandler }); await repoGit.raw(["config", "gc.auto", "0"]); - await repoGit.raw(["sparse-checkout", "set", ...config.sparse]); + log?.(`${config.name}: Setting sparse checkout paths: ${config.sparse!.join(", ")}`, "debug"); + await repoGit.raw(["sparse-checkout", "set", ...config.sparse!]); + log?.(`${config.name}: Fetching tag ${config.tag}`, "info"); await repoGit.fetch(["--depth=1", "origin", `refs/tags/${config.tag}:refs/tags/${config.tag}`]); + log?.(`${config.name}: Checking out tag`, "debug"); await repoGit.checkout(config.tag); - - // Apply sparse path overrides from different branches - if (config.sparsePathOverrides) { - for (const override of config.sparsePathOverrides) { - await repoGit.fetch(["--depth=1", "origin", override.branch]); - try { - await repoGit.checkout([`origin/${override.branch}`, "--", ...override.paths]); - } catch (error) { - const repoBase = config.url.replace(/\.git$/, ""); - const parentDirs = [...new Set(override.paths.map((p) => p.split("/").slice(0, -1).join("/")))]; - const browseLinks = parentDirs.map((d) => `${repoBase}/tree/${override.branch}/${d}`); - throw new Error( - `sparsePathOverrides failed for branch "${override.branch}": could not checkout paths [${override.paths.join(", ")}]. ` + - `Check the actual folder names at: ${browseLinks.join(" , ")}`, - ); - } - } - } } else { await git.clone(config.url, repoPath, [ "--filter=blob:none", @@ -118,25 +124,31 @@ export async function cloneRepo( ...(config.branch ? ["-b", config.branch] : []), ]); - const repoGit = simpleGit(repoPath); + const repoGit = simpleGit({ baseDir: repoPath, progress: progressHandler }); await repoGit.raw(["config", "gc.auto", "0"]); - await repoGit.raw(["sparse-checkout", "set", ...config.sparse]); + log?.(`${config.name}: Setting sparse checkout paths: ${config.sparse!.join(", ")}`, "debug"); + await repoGit.raw(["sparse-checkout", "set", ...config.sparse!]); } - return `Cloned ${config.name} @ ${ref} (${refType}, sparse: ${config.sparse.join(", ")})`; + log?.(`${config.name}: Clone complete`, "info"); + return `Cloned ${config.name} @ ${ref} (${refType}, sparse: ${config.sparse!.join(", ")})`; } else { // Clone for smaller repos if (config.commit) { // For commits, clone and checkout specific commit await git.clone(config.url, repoPath, ["--no-checkout"]); - const repoGit = simpleGit(repoPath); + const repoGit = simpleGit({ baseDir: repoPath, progress: progressHandler }); + log?.(`${config.name}: Fetching commit ${config.commit.substring(0, 7)}`, "info"); await repoGit.fetch(["origin", config.commit]); + log?.(`${config.name}: Checking out commit`, "debug"); await repoGit.checkout(config.commit); } else if (config.tag) { // Clone and checkout tag await git.clone(config.url, repoPath, ["--no-checkout"]); - const repoGit = simpleGit(repoPath); + const repoGit = simpleGit({ baseDir: repoPath, progress: progressHandler }); + log?.(`${config.name}: Fetching tag ${config.tag}`, "info"); await repoGit.fetch(["--depth=1", "origin", `refs/tags/${config.tag}:refs/tags/${config.tag}`]); + log?.(`${config.name}: Checking out tag`, "debug"); await repoGit.checkout(config.tag); } else { await git.clone(config.url, repoPath, [ @@ -145,6 +157,7 @@ export async function cloneRepo( ]); } + log?.(`${config.name}: Clone complete`, "info"); return `Cloned ${config.name} @ ${ref} (${refType})`; } } @@ -152,25 +165,30 @@ export async function cloneRepo( /** * Update an existing repository */ -export async function updateRepo(repoName: string): Promise { +export async function updateRepo(repoName: string, log?: Logger): Promise { const repoPath = getRepoPath(repoName); if (!isRepoCloned(repoName)) { throw new Error(`Repository ${repoName} is not cloned`); } + log?.(`${repoName}: Updating`, "info"); const git = simpleGit(repoPath); try { await git.fetch(["--depth=1"]); await git.reset(["--hard", "origin/HEAD"]); + log?.(`${repoName}: Update complete`, "info"); return `Updated ${repoName}`; } catch (error) { + log?.(`${repoName}: Fetch failed, trying pull`, "warning"); // If fetch fails, try a simple pull try { await git.pull(); + log?.(`${repoName}: Pull complete`, "info"); return `Updated ${repoName}`; } catch (pullError) { + log?.(`${repoName}: Update failed: ${pullError}`, "error"); return `Failed to update ${repoName}: ${pullError}`; } } diff --git a/src/utils/search.ts b/src/utils/search.ts index 0840c1c..3b10bb6 100644 --- a/src/utils/search.ts +++ b/src/utils/search.ts @@ -81,19 +81,26 @@ export function searchDocs( ): SearchResult[] { const { section, maxResults = 30 } = options; - // Determine search path based on section + // Search versioned docs under developer_versioned_docs, narrowing by section if possible let repo: string | undefined; - if (section) { - const docsPath = join(REPOS_DIR, "aztec-packages", "docs", "docs", section); - if (existsSync(docsPath)) { - // Search within the specific section by using a narrowed path - repo = `aztec-packages/docs/docs/${section}`; + const versionedDocsGlob = join(REPOS_DIR, "aztec-packages-docs", "docs", "developer_versioned_docs"); + const versionDirs = existsSync(versionedDocsGlob) ? globbySync("version-*", { cwd: versionedDocsGlob, onlyDirectories: true }) : []; + const versionDir = versionDirs[0]; + + if (section && versionDir) { + const sectionPath = join(versionedDocsGlob, versionDir, section); + if (existsSync(sectionPath)) { + repo = `aztec-packages-docs/docs/developer_versioned_docs/${versionDir}/${section}`; } } + if (!repo && versionDir) { + repo = `aztec-packages-docs/docs/developer_versioned_docs/${versionDir}`; + } + return searchCode(query, { filePattern: "*.{md,mdx}", - repo: repo || "aztec-packages", + repo: repo || "aztec-packages-docs", maxResults, }); } diff --git a/tests/tools/search.test.ts b/tests/tools/search.test.ts index 1d28a90..8895c4a 100644 --- a/tests/tools/search.test.ts +++ b/tests/tools/search.test.ts @@ -97,11 +97,11 @@ describe("searchAztecCode", () => { }); describe("searchAztecDocs", () => { - it("returns failure when aztec-packages not cloned", () => { + it("returns failure when aztec-packages-docs not cloned", () => { mockIsRepoCloned.mockReturnValue(false); const result = searchAztecDocs({ query: "tutorial" }); expect(result.success).toBe(false); - expect(result.message).toContain("aztec-packages is not cloned"); + expect(result.message).toContain("aztec-packages-docs is not cloned"); }); it("delegates to searchDocs with correct options", () => { diff --git a/tests/tools/sync.test.ts b/tests/tools/sync.test.ts index 6788421..7bcc37f 100644 --- a/tests/tools/sync.test.ts +++ b/tests/tools/sync.test.ts @@ -10,6 +10,13 @@ vi.mock("../../src/repos/config.js", () => ({ name: "aztec-packages", url: "https://github.com/AztecProtocol/aztec-packages", tag: "v1.0.0", + sparse: ["noir-projects/aztec-nr", "yarn-project"], + sparsePathOverrides: [ + { + paths: ["docs/developer_versioned_docs/version-v1.0.0", "docs/static/api"], + branch: "next", + }, + ], description: "Main repo", }, { @@ -42,6 +49,12 @@ vi.mock("../../src/repos/config.js", () => ({ name: "aztec-packages", url: "https://github.com/AztecProtocol/aztec-packages", tag: version, + sparsePathOverrides: [ + { + paths: ["docs/developer_versioned_docs/version-" + version], + branch: "next", + }, + ], description: "Main repo", }, { @@ -88,11 +101,13 @@ describe("syncRepos", () => { await syncRepos({}); - // aztec-packages should be first + // aztec-packages should be first (blocking clone) expect(callOrder[0]).toBe("aztec-packages"); // noir repos should come after aztec-packages const noirIndex = callOrder.indexOf("noir"); expect(noirIndex).toBeGreaterThan(0); + // synthetic docs repo should be included + expect(callOrder).toContain("aztec-packages-docs"); }); it("extracts noir commit from aztec-packages and applies it", async () => { @@ -112,8 +127,8 @@ describe("syncRepos", () => { it("uses AZTEC_REPOS when no version specified", async () => { await syncRepos({}); - // Should clone repos from AZTEC_REPOS (5 repos) - expect(mockCloneRepo).toHaveBeenCalledTimes(5); + // Should clone repos from AZTEC_REPOS (5 repos + 1 synthetic docs repo) + expect(mockCloneRepo).toHaveBeenCalledTimes(6); expect(mockGetAztecRepos).not.toHaveBeenCalled(); }); @@ -126,8 +141,13 @@ describe("syncRepos", () => { it("filters to specific repos when repos option provided", async () => { await syncRepos({ repos: ["aztec-packages"] }); - expect(mockCloneRepo).toHaveBeenCalledTimes(1); + // aztec-packages + synthetic aztec-packages-docs + expect(mockCloneRepo).toHaveBeenCalledTimes(2); expect(mockCloneRepo.mock.calls[0][0].name).toBe("aztec-packages"); + const docsCall = mockCloneRepo.mock.calls.find((c: any[]) => c[0].name === "aztec-packages-docs"); + expect(docsCall).toBeDefined(); + expect(docsCall![0].branch).toBe("next"); + expect(docsCall![0].sparse).toEqual(["docs/developer_versioned_docs/version-v1.0.0", "docs/static/api"]); }); it("returns success:false when no repos match filter", async () => { diff --git a/tests/utils/git.test.ts b/tests/utils/git.test.ts index 4f5175f..9485c18 100644 --- a/tests/utils/git.test.ts +++ b/tests/utils/git.test.ts @@ -147,80 +147,6 @@ describe("cloneRepo", () => { expect(mockGitInstance.checkout).toHaveBeenCalledWith("v1.0.0"); }); - it("sparse + tag + sparsePathOverrides: fetches override branch and checks out paths", async () => { - const overrideConfig: RepoConfig = { - ...sparseConfig, - sparsePathOverrides: [ - { - paths: [ - "docs/developer_versioned_docs/version-v1.0.0", - "docs/static/api", - ], - branch: "next", - }, - ], - }; - mockExistsSync.mockReturnValue(false); - mockGitInstance.clone.mockResolvedValue(undefined); - mockGitInstance.raw.mockResolvedValue(undefined); - mockGitInstance.fetch.mockResolvedValue(undefined); - mockGitInstance.checkout.mockResolvedValue(undefined); - - const result = await cloneRepo(overrideConfig); - expect(result).toContain("Cloned aztec-packages"); - - // Normal tag checkout happens first - expect(mockGitInstance.checkout).toHaveBeenCalledWith("v1.0.0"); - - // Then override: fetch the branch and checkout paths from it - expect(mockGitInstance.fetch).toHaveBeenCalledWith([ - "--depth=1", - "origin", - "next", - ]); - expect(mockGitInstance.checkout).toHaveBeenCalledWith([ - "origin/next", - "--", - "docs/developer_versioned_docs/version-v1.0.0", - "docs/static/api", - ]); - }); - - it("sparse + tag + sparsePathOverrides: throws descriptive error with GitHub links on failure", async () => { - const overrideConfig: RepoConfig = { - ...sparseConfig, - sparsePathOverrides: [ - { - paths: [ - "docs/developer_versioned_docs/version-v1.0.0", - "docs/static/aztec-nr-api/devnet", - "docs/static/typescript-api/devnet", - ], - branch: "next", - }, - ], - }; - mockExistsSync.mockReturnValue(false); - mockGitInstance.clone.mockResolvedValue(undefined); - mockGitInstance.raw.mockResolvedValue(undefined); - mockGitInstance.fetch.mockResolvedValue(undefined); - // Tag checkout succeeds, override checkout fails - mockGitInstance.checkout - .mockResolvedValueOnce(undefined) // tag checkout - .mockRejectedValueOnce(new Error("pathspec did not match")); - - try { - await cloneRepo(overrideConfig); - expect.unreachable("should have thrown"); - } catch (e: any) { - expect(e.message).toMatch(/sparsePathOverrides failed for branch "next"/); - expect(e.message).toContain("docs/developer_versioned_docs/version-v1.0.0"); - expect(e.message).toContain("https://github.com/AztecProtocol/aztec-packages/tree/next/docs/developer_versioned_docs"); - expect(e.message).toContain("https://github.com/AztecProtocol/aztec-packages/tree/next/docs/static/aztec-nr-api"); - expect(e.message).toContain("https://github.com/AztecProtocol/aztec-packages/tree/next/docs/static/typescript-api"); - } - }); - it("sparse + commit: clones with sparse flags, fetches commit", async () => { const commitConfig: RepoConfig = { ...sparseConfig, @@ -303,18 +229,17 @@ describe("cloneRepo", () => { ); }); - it("already cloned + version match delegates to updateRepo", async () => { + it("already cloned + version match skips update for tag-pinned repos", async () => { // needsReclone: isRepoCloned returns true, tag matches mockExistsSync.mockReturnValue(true); // getRepoTag needs git.raw to return the tag mockGitInstance.raw.mockResolvedValue("v1.0.0\n"); - // isRepoCloned returns true -> delegates to updateRepo - // updateRepo does fetch + reset - mockGitInstance.fetch.mockResolvedValue(undefined); - mockGitInstance.reset.mockResolvedValue(undefined); const result = await cloneRepo(sparseConfig); - expect(result).toContain("Updated"); + expect(result).toContain("already at v1.0.0"); + // Should NOT call fetch/reset (updateRepo not invoked) + expect(mockGitInstance.fetch).not.toHaveBeenCalled(); + expect(mockGitInstance.reset).not.toHaveBeenCalled(); }); }); diff --git a/tests/utils/search.test.ts b/tests/utils/search.test.ts index f0aea1e..e87905e 100644 --- a/tests/utils/search.test.ts +++ b/tests/utils/search.test.ts @@ -236,15 +236,16 @@ describe("searchDocs", () => { it("narrows path when section exists", () => { mockExistsSync.mockReturnValue(true); + mockGlobbySync.mockReturnValue(["version-v1.0.0"] as any); mockExecSync.mockReturnValue(""); searchDocs("tutorial", { section: "tutorials" }); const call = mockExecSync.mock.calls[0][0] as string; - expect(call).toContain("aztec-packages/docs/docs/tutorials"); + expect(call).toContain("aztec-packages-docs/docs/developer_versioned_docs/version-v1.0.0/tutorials"); }); - it("falls back to aztec-packages when section doesn't exist", () => { + it("falls back to aztec-packages-docs when section doesn't exist", () => { // existsSync: first call for section path returns false, second for search path returns true mockExistsSync .mockReturnValueOnce(false) // section path doesn't exist @@ -254,8 +255,8 @@ describe("searchDocs", () => { searchDocs("tutorial", { section: "nonexistent" }); const call = mockExecSync.mock.calls[0][0] as string; - // Should search in aztec-packages, not the nonexistent section - expect(call).toContain("/fake/repos/aztec-packages"); + // Should search in aztec-packages-docs, not the nonexistent section + expect(call).toContain("/fake/repos/aztec-packages-docs"); }); });