From 611629e7cae95df985c2e605aa4c1df0a400e70a Mon Sep 17 00:00:00 2001 From: Mohith Gajjela <109003762+Mohith26@users.noreply.github.com> Date: Tue, 28 Jul 2026 13:10:17 -0500 Subject: [PATCH 1/2] fix(eve): resolve parent package tsconfig path aliases in dev runtime snapshots A withEve agent whose root is a bare directory inside a Next.js app (no package.json/tsconfig.json of its own) bundles fine in production because authored-module bundling walks up to the owning package and passes its tsconfig path aliases to rolldown. Dev runtime snapshots broke that in two ways: the snapshot plan only scanned the app root itself for tsconfigs, so the owning package's tsconfig and alias-target sources were never copied, and the copy step synthesized a package.json at the snapshot agent root, moving the package boundary below the owning package so the parent tsconfig stayed invisible to the bundler. Mirror the dependency-declaration walk-up (vercel/eve#1151) for tsconfig discovery: resolve tsconfigs from the nearest owning package as well, copy that package into the snapshot when its tsconfig declares path aliases, and only generate a synthetic runtime package.json when no owning package.json exists at or above the runtime app root inside the snapshot. Fixes #1242 --- .../nitro/dev-runtime-source-snapshot-copy.ts | 61 ++++- ...-runtime-source-snapshot-tsconfig-paths.ts | 204 ++++++++++++++++ .../nitro/dev-runtime-source-snapshot.ts | 218 ++++-------------- 3 files changed, 304 insertions(+), 179 deletions(-) create mode 100644 packages/eve/src/internal/nitro/dev-runtime-source-snapshot-tsconfig-paths.ts diff --git a/packages/eve/src/internal/nitro/dev-runtime-source-snapshot-copy.ts b/packages/eve/src/internal/nitro/dev-runtime-source-snapshot-copy.ts index 9e4975606..844fb02fa 100644 --- a/packages/eve/src/internal/nitro/dev-runtime-source-snapshot-copy.ts +++ b/packages/eve/src/internal/nitro/dev-runtime-source-snapshot-copy.ts @@ -99,6 +99,20 @@ async function copySnapshotDirectory(input: { continue; } + // `cp` refuses to copy a directory that contains its own destination, + // even when the filter excludes that subtree. A copy root above the app + // root (an owning package with tsconfig path aliases, vercel/eve#1242) + // contains the snapshot inside the app root's `.eve` directory, so + // recurse manually until the skipped `.eve` subtree is filtered out. + if (entry.isDirectory() && isPathInsideOrEqual(input.plan.snapshotRoot, sourcePath)) { + await copySnapshotDirectory({ + plan: input.plan, + sourcePath, + targetPath: join(input.targetPath, entry.name), + }); + continue; + } + await cp(sourcePath, join(input.targetPath, entry.name), { filter: (source) => !shouldSkipSnapshotSource(input.plan, source), mode: SNAPSHOT_COPY_MODE, @@ -310,12 +324,18 @@ async function createSnapshotDependencyMounts(plan: DevelopmentSourceSnapshotPla } async function ensureRuntimePackageJson(plan: DevelopmentSourceSnapshotPlan): Promise { - const runtimePackageJsonPath = join(plan.runtimeAppRoot, "package.json"); - - if (existsSync(runtimePackageJsonPath)) { + // A synthetic package.json below an owning package that made it into the + // snapshot would move the package boundary that authored-module bundling + // (`resolveAuthoredPackageRoot`) and Node resolution walk up to, hiding the + // owning package's tsconfig path aliases (vercel/eve#1242). Only generate + // one when the snapshot carries no owning package.json at or above the + // runtime app root. + if (findNearestSnapshotPackageJsonPath(plan) !== undefined) { return; } + const runtimePackageJsonPath = join(plan.runtimeAppRoot, "package.json"); + await mkdir(plan.runtimeAppRoot, { recursive: true }); await writeFile( runtimePackageJsonPath, @@ -333,11 +353,9 @@ async function ensureRuntimePackageJson(plan: DevelopmentSourceSnapshotPlan): Pr async function validateDevelopmentSourceSnapshot( plan: DevelopmentSourceSnapshotPlan, ): Promise { - const runtimePackageJsonPath = join(plan.runtimeAppRoot, "package.json"); - - if (!existsSync(runtimePackageJsonPath)) { + if (findNearestSnapshotPackageJsonPath(plan) === undefined) { throw new DevelopmentRuntimeSourceSnapshotError( - `Development runtime source snapshot is missing the runtime app package.json at "${runtimePackageJsonPath}".`, + `Development runtime source snapshot is missing a package.json at or above the runtime app root "${plan.runtimeAppRoot}".`, ); } @@ -378,6 +396,35 @@ async function validateSnapshotTsConfigExtends(configPath: string): Promise { + let currentDirectory = resolve(path); + + try { + const stats = await lstat(currentDirectory); + + if (!stats.isDirectory()) { + currentDirectory = dirname(currentDirectory); + } + } catch { + currentDirectory = dirname(currentDirectory); + } + + while (isAuthoredSourcePath(currentDirectory, sourceRoot)) { + if (existsSync(join(currentDirectory, "package.json"))) { + return currentDirectory; + } + + const parentDirectory = dirname(currentDirectory); + + if (parentDirectory === currentDirectory) { + return undefined; + } + + currentDirectory = parentDirectory; + } + + return undefined; +} + +/** Returns whether a tsconfig/jsconfig file declares at least one `paths` alias. */ +export async function tsConfigDefinesPathAliases(configPath: string): Promise { + const source = await readTextFileIfExists(configPath); + + if (source === undefined) { + return false; + } + + const parsedConfig = parseTsConfigObject(source); + const compilerOptions = isObjectRecord(parsedConfig?.compilerOptions) + ? parsedConfig.compilerOptions + : undefined; + const paths = isObjectRecord(compilerOptions?.paths) ? compilerOptions.paths : undefined; + + return paths !== undefined && Object.keys(paths).length > 0; +} + +/** + * Resolves the local source roots a tsconfig's `paths` aliases can target so + * a development source snapshot includes them. + */ +export async function resolveLocalTsConfigPathTargetRoots(input: { + readonly configPath: string; + readonly sourceRoot: string; +}): Promise { + const source = await readTextFileIfExists(input.configPath); + + if (source === undefined) { + return []; + } + + const parsedConfig = parseTsConfigObject(source); + const compilerOptions = isObjectRecord(parsedConfig?.compilerOptions) + ? parsedConfig.compilerOptions + : undefined; + const paths = isObjectRecord(compilerOptions?.paths) ? compilerOptions.paths : undefined; + + if (compilerOptions === undefined || paths === undefined) { + return []; + } + + const baseDirectory = + typeof compilerOptions.baseUrl === "string" + ? resolve(dirname(input.configPath), compilerOptions.baseUrl) + : dirname(input.configPath); + const localRoots = new Set(); + + for (const targets of Object.values(paths)) { + if (!Array.isArray(targets)) { + continue; + } + + for (const target of targets) { + if (typeof target !== "string" || target.length === 0) { + continue; + } + + const localRoot = await resolveLocalTsConfigPathTargetRoot({ + baseDirectory, + sourceRoot: input.sourceRoot, + target, + }); + + if (localRoot !== undefined) { + localRoots.add(localRoot); + } + } + } + + return [...localRoots].sort((left, right) => left.localeCompare(right)); +} + +async function resolveLocalTsConfigPathTargetRoot(input: { + readonly baseDirectory: string; + readonly sourceRoot: string; + readonly target: string; +}): Promise { + const hasWildcard = input.target.includes("*"); + const targetPrefix = hasWildcard + ? input.target.slice(0, input.target.indexOf("*")) + : input.target; + + if (targetPrefix.length === 0 || targetPrefix === "." || targetPrefix === "./") { + return undefined; + } + + const resolvedTarget = resolve(input.baseDirectory, targetPrefix); + + if (!isAuthoredSourcePath(resolvedTarget, input.sourceRoot)) { + return undefined; + } + + const existingTarget = await resolveExistingPathOrAncestor({ + path: resolvedTarget, + stopDirectory: input.sourceRoot, + }); + + if (existingTarget === undefined) { + return undefined; + } + + const packageRoot = await resolveNearestPackageRoot(existingTarget, input.sourceRoot); + + if (packageRoot !== undefined && packageRoot !== input.sourceRoot) { + return packageRoot; + } + + if (hasWildcard) { + return undefined; + } + + return existingTarget === input.sourceRoot ? undefined : existingTarget; +} + +async function resolveExistingPathOrAncestor(input: { + readonly path: string; + readonly stopDirectory: string; +}): Promise { + let currentPath = resolve(input.path); + + while (isAuthoredSourcePath(currentPath, input.stopDirectory)) { + if (existsSync(currentPath)) { + return currentPath; + } + + const parentPath = dirname(currentPath); + + if (parentPath === currentPath) { + return undefined; + } + + currentPath = parentPath; + } + + return undefined; +} + +function isObjectRecord(value: unknown): value is Record { + return value !== null && typeof value === "object" && !Array.isArray(value); +} diff --git a/packages/eve/src/internal/nitro/dev-runtime-source-snapshot.ts b/packages/eve/src/internal/nitro/dev-runtime-source-snapshot.ts index 2421563fb..8650aef0f 100644 --- a/packages/eve/src/internal/nitro/dev-runtime-source-snapshot.ts +++ b/packages/eve/src/internal/nitro/dev-runtime-source-snapshot.ts @@ -1,12 +1,20 @@ import { existsSync, readFileSync } from "node:fs"; import { lstat, readlink, realpath } from "node:fs/promises"; -import { dirname, join, relative, resolve, sep } from "node:path"; +import { dirname, join, relative, resolve } from "node:path"; import { - parseTsConfigObject, readTextFileIfExists, resolveTsConfigDependencyPaths, } from "#internal/application/tsconfig-dependencies.js"; +import { + isAuthoredSourcePath, + isPathInsideOrEqual, + resolveLocalTsConfigPathTargetRoots, + resolveNearestPackageRoot, + tsConfigDefinesPathAliases, +} from "#internal/nitro/dev-runtime-source-snapshot-tsconfig-paths.js"; + +export { isAuthoredSourcePath } from "#internal/nitro/dev-runtime-source-snapshot-tsconfig-paths.js"; export const DEV_RUNTIME_SOURCE_DIRECTORY = "source"; @@ -204,7 +212,36 @@ async function addTsConfigDependenciesForRoot( state: SnapshotPlanState, packageRoot: string, ): Promise { - const tsconfigPaths = await resolveTsConfigDependencyPaths(packageRoot); + await addTsConfigDependenciesForConfigRoot(state, packageRoot); + + // An app root without its own `package.json` (a bare `withEve` agent + // directory) is bundled with the nearest owning package's tsconfig in + // production, so its path aliases must resolve inside the snapshot too + // (vercel/eve#1242). + const declarationRoot = resolveDependencyDeclarationRoot(packageRoot, state.sourceRoot); + + if (declarationRoot === packageRoot) { + return; + } + + const declaresPathAliases = await addTsConfigDependenciesForConfigRoot(state, declarationRoot); + + // Alias targets such as `"@/*": ["./*"]` resolve against the owning + // package root, so that whole package must be part of the snapshot for + // dev bundling to match production resolution (vercel/eve#1242). The + // source root itself is never copied wholesale, matching + // `resolveLocalTsConfigPathTargetRoot`. + if (declaresPathAliases && declarationRoot !== state.sourceRoot) { + enqueueLocalRoot(state, declarationRoot); + } +} + +async function addTsConfigDependenciesForConfigRoot( + state: SnapshotPlanState, + configRoot: string, +): Promise { + const tsconfigPaths = await resolveTsConfigDependencyPaths(configRoot); + let declaresPathAliases = false; for (const tsconfigPath of tsconfigPaths) { if (!isPathInsideOrEqual(tsconfigPath, state.sourceRoot)) { @@ -214,6 +251,10 @@ async function addTsConfigDependenciesForRoot( state.tsconfigPaths.add(tsconfigPath); state.copyFiles.add(tsconfigPath); + if (await tsConfigDefinesPathAliases(tsconfigPath)) { + declaresPathAliases = true; + } + for (const localRoot of await resolveLocalTsConfigPathTargetRoots({ configPath: tsconfigPath, sourceRoot: state.sourceRoot, @@ -221,6 +262,8 @@ async function addTsConfigDependenciesForRoot( enqueueLocalRoot(state, localRoot); } } + + return declaresPathAliases; } async function addDependencyMountsForRoot( @@ -450,155 +493,6 @@ async function readPackageDependencyNames(packageRoot: string): Promise left.localeCompare(right)); } -async function resolveLocalTsConfigPathTargetRoots(input: { - readonly configPath: string; - readonly sourceRoot: string; -}): Promise { - const source = await readTextFileIfExists(input.configPath); - - if (source === undefined) { - return []; - } - - const parsedConfig = parseTsConfigObject(source); - const compilerOptions = isObjectRecord(parsedConfig?.compilerOptions) - ? parsedConfig.compilerOptions - : undefined; - const paths = isObjectRecord(compilerOptions?.paths) ? compilerOptions.paths : undefined; - - if (compilerOptions === undefined || paths === undefined) { - return []; - } - - const baseDirectory = - typeof compilerOptions.baseUrl === "string" - ? resolve(dirname(input.configPath), compilerOptions.baseUrl) - : dirname(input.configPath); - const localRoots = new Set(); - - for (const targets of Object.values(paths)) { - if (!Array.isArray(targets)) { - continue; - } - - for (const target of targets) { - if (typeof target !== "string" || target.length === 0) { - continue; - } - - const localRoot = await resolveLocalTsConfigPathTargetRoot({ - baseDirectory, - sourceRoot: input.sourceRoot, - target, - }); - - if (localRoot !== undefined) { - localRoots.add(localRoot); - } - } - } - - return [...localRoots].sort((left, right) => left.localeCompare(right)); -} - -async function resolveLocalTsConfigPathTargetRoot(input: { - readonly baseDirectory: string; - readonly sourceRoot: string; - readonly target: string; -}): Promise { - const hasWildcard = input.target.includes("*"); - const targetPrefix = hasWildcard - ? input.target.slice(0, input.target.indexOf("*")) - : input.target; - - if (targetPrefix.length === 0 || targetPrefix === "." || targetPrefix === "./") { - return undefined; - } - - const resolvedTarget = resolve(input.baseDirectory, targetPrefix); - - if (!isAuthoredSourcePath(resolvedTarget, input.sourceRoot)) { - return undefined; - } - - const existingTarget = await resolveExistingPathOrAncestor({ - path: resolvedTarget, - stopDirectory: input.sourceRoot, - }); - - if (existingTarget === undefined) { - return undefined; - } - - const packageRoot = await resolveNearestPackageRoot(existingTarget, input.sourceRoot); - - if (packageRoot !== undefined && packageRoot !== input.sourceRoot) { - return packageRoot; - } - - if (hasWildcard) { - return undefined; - } - - return existingTarget === input.sourceRoot ? undefined : existingTarget; -} - -async function resolveExistingPathOrAncestor(input: { - readonly path: string; - readonly stopDirectory: string; -}): Promise { - let currentPath = resolve(input.path); - - while (isAuthoredSourcePath(currentPath, input.stopDirectory)) { - if (existsSync(currentPath)) { - return currentPath; - } - - const parentPath = dirname(currentPath); - - if (parentPath === currentPath) { - return undefined; - } - - currentPath = parentPath; - } - - return undefined; -} - -async function resolveNearestPackageRoot( - path: string, - sourceRoot: string, -): Promise { - let currentDirectory = resolve(path); - - try { - const stats = await lstat(currentDirectory); - - if (!stats.isDirectory()) { - currentDirectory = dirname(currentDirectory); - } - } catch { - currentDirectory = dirname(currentDirectory); - } - - while (isAuthoredSourcePath(currentDirectory, sourceRoot)) { - if (existsSync(join(currentDirectory, "package.json"))) { - return currentDirectory; - } - - const parentDirectory = dirname(currentDirectory); - - if (parentDirectory === currentDirectory) { - return undefined; - } - - currentDirectory = parentDirectory; - } - - return undefined; -} - function normalizeCopyRoots(copyRoots: readonly string[]): string[] { const sortedRoots = [...new Set(copyRoots.map((path) => resolve(path)))].sort((left, right) => { const lengthDifference = left.length - right.length; @@ -674,26 +568,6 @@ function toSnapshotPath(input: { return join(input.snapshotSourceRoot, relative(input.sourceRoot, input.sourcePath)); } -function isPathInsideOrEqual(path: string, directory: string): boolean { - const resolvedPath = resolve(path); - const resolvedDirectory = resolve(directory); - - return ( - resolvedPath === resolvedDirectory || resolvedPath.startsWith(`${resolvedDirectory}${sep}`) - ); -} - -/** Returns whether a path is authored workspace source rather than installed dependency data. */ -export function isAuthoredSourcePath(path: string, sourceRoot: string): boolean { - if (!isPathInsideOrEqual(path, sourceRoot)) { - return false; - } - - const relativePath = relative(sourceRoot, path); - - return !relativePath.split(/[\\/]/).includes("node_modules"); -} - function isObjectRecord(value: unknown): value is Record { return value !== null && typeof value === "object" && !Array.isArray(value); } From 1ee0da0d8687f9f5f0a7d2fb62325ed2569a90a3 Mon Sep 17 00:00:00 2001 From: Mohith Gajjela <109003762+Mohith26@users.noreply.github.com> Date: Tue, 28 Jul 2026 13:12:45 -0500 Subject: [PATCH 2/2] test(eve): cover parent package tsconfig path aliases in dev runtime snapshots Regression coverage for vercel/eve#1242: a bare withEve agent directory whose imports use the parent Next.js package's tsconfig path aliases must keep resolving from dev runtime snapshots. One test asserts the snapshot carries the owning package's tsconfig, alias-target sources, and package boundary (no synthetic package.json below it) and that the authored module loader resolves the alias from the snapshot; the second reproduces the issue end-to-end by hydrating a materialized dev generation whose agent module imports parent application code through an alias. --- .../dev-runtime-artifacts.integration.test.ts | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/packages/eve/src/internal/nitro/dev-runtime-artifacts.integration.test.ts b/packages/eve/src/internal/nitro/dev-runtime-artifacts.integration.test.ts index 480d7bff9..2928f3e86 100644 --- a/packages/eve/src/internal/nitro/dev-runtime-artifacts.integration.test.ts +++ b/packages/eve/src/internal/nitro/dev-runtime-artifacts.integration.test.ts @@ -408,6 +408,179 @@ describe("development runtime artifact snapshots", () => { expect(acceptableMountLocations.some((location) => existsSync(location))).toBe(true); }); + // https://github.com/vercel/eve/issues/1242 — withEve bare-agent-dir + // expression: the agent root has no package.json or tsconfig.json of its + // own; the parent Next.js-style package owns both, and its tsconfig path + // aliases must keep resolving from dev runtime snapshots exactly like in + // production builds. + it("resolves parent package tsconfig path aliases from dev runtime snapshots", async () => { + const workspaceRoot = await createScratchDirectory("eve-dev-runtime-parent-tsconfig-paths-"); + const hostRoot = join(workspaceRoot, "apps", "nextjs"); + const appRoot = join(hostRoot, "agents", "app-agent"); + const compileDirectoryPath = join(appRoot, ".eve", "compile"); + + await mkdir(join(appRoot, "tools"), { recursive: true }); + await mkdir(join(hostRoot, "lib"), { recursive: true }); + await mkdir(compileDirectoryPath, { recursive: true }); + await writeFile(join(workspaceRoot, "pnpm-workspace.yaml"), "packages:\n - apps/*\n"); + await writeFile(join(workspaceRoot, "package.json"), '{"type":"module"}\n'); + await writeFile(join(hostRoot, "package.json"), '{"name":"nextjs-host","type":"module"}\n'); + await writeFile( + join(hostRoot, "tsconfig.json"), + `${JSON.stringify( + { + compilerOptions: { + baseUrl: ".", + paths: { + "@/*": ["./*"], + }, + }, + }, + null, + 2, + )}\n`, + ); + await writeFile( + join(hostRoot, "lib", "utils.ts"), + 'export const findFirstOrUndefined = "parent-lib-utils";\n', + ); + await writeFile( + join(appRoot, "tools", "query-data.ts"), + [ + 'import { findFirstOrUndefined } from "@/lib/utils";', + "", + "export const resolved = findFirstOrUndefined;", + "", + ].join("\n"), + ); + await writeFile( + join(compileDirectoryPath, "compiled-agent-manifest.json"), + `${JSON.stringify({ agentRoot: appRoot, appRoot }, null, 2)}\n`, + ); + + const snapshot = await stageDevelopmentRuntimeArtifactsSnapshot({ + paths: { compileDirectoryPath }, + project: { appRoot }, + } as CompileAgentResult); + const snapshotHostRoot = join(snapshot.snapshotSourceRoot, "apps", "nextjs"); + + // The owning package's tsconfig and alias-target sources are part of the + // snapshot. + expect(existsSync(join(snapshotHostRoot, "tsconfig.json"))).toBe(true); + expect(existsSync(join(snapshotHostRoot, "lib", "utils.ts"))).toBe(true); + // No synthetic package.json shadows the owning package boundary that + // production bundling resolves the tsconfig through. + expect(existsSync(join(snapshotHostRoot, "package.json"))).toBe(true); + expect(existsSync(join(snapshot.runtimeAppRoot, "package.json"))).toBe(false); + + const moduleNamespace = await loadAuthoredModuleNamespace( + join(snapshot.runtimeAppRoot, "tools", "query-data.ts"), + ); + + expect(moduleNamespace.resolved).toBe("parent-lib-utils"); + }); + + // https://github.com/vercel/eve/issues/1242 — end-to-end expression: the + // materialized dev generation must hydrate an agent module that imports + // parent application code through the parent tsconfig's path aliases. + it("hydrates parent tsconfig alias imports from materialized dev generations", async () => { + const workspaceRoot = await createScratchDirectory("eve-dev-runtime-parent-alias-hydrate-"); + const hostRoot = join(workspaceRoot, "apps", "nextjs"); + const appRoot = join(hostRoot, "agents", "app-agent"); + const compileDirectoryPath = join(appRoot, ".eve", "compile"); + const manifestPath = join(compileDirectoryPath, "compiled-agent-manifest.json"); + const moduleMapPath = join(compileDirectoryPath, "module-map.mjs"); + + await mkdir(appRoot, { recursive: true }); + await mkdir(join(hostRoot, "lib"), { recursive: true }); + await mkdir(compileDirectoryPath, { recursive: true }); + await writeFile(join(workspaceRoot, "pnpm-workspace.yaml"), "packages:\n - apps/*\n"); + await writeFile(join(workspaceRoot, "package.json"), '{"type":"module"}\n'); + await writeFile(join(hostRoot, "package.json"), '{"name":"nextjs-host","type":"module"}\n'); + await writeFile( + join(hostRoot, "tsconfig.json"), + `${JSON.stringify( + { + compilerOptions: { + baseUrl: ".", + paths: { + "@/*": ["./*"], + }, + }, + }, + null, + 2, + )}\n`, + ); + await writeFile( + join(hostRoot, "lib", "auth.ts"), + 'export const eveAuth = "parent-auth-config";\n', + ); + await writeFile( + join(appRoot, "agent.ts"), + [ + 'import { eveAuth } from "@/lib/auth";', + "", + "export const routed = `router:${eveAuth}`;", + "", + ].join("\n"), + ); + + const manifest = createCompiledAgentManifest({ + agentRoot: appRoot, + appRoot, + config: { + model: { + id: "openai/gpt-5.4-mini", + routing: { + kind: "gateway", + target: "openai/gpt-5.4-mini", + }, + }, + name: "Parent Alias Agent", + source: { + logicalPath: "agent.ts", + sourceId: "agent.ts", + sourceKind: "module", + }, + }, + instructions: { + logicalPath: "instructions.md", + markdown: "Use the routed model.", + name: "instructions", + sourceId: "instructions.md", + sourceKind: "markdown", + }, + }); + + await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); + await writeFile( + moduleMapPath, + createCompiledModuleMapSource({ + manifest, + moduleMapPath, + }), + ); + + await publishDevelopmentGeneration({ + paths: { compileDirectoryPath }, + project: { appRoot }, + } as CompileAgentResult); + + await withRuntimeSession(createRuntimeSession("parent-alias-imports-regression"), async () => { + const bundle = await getCompiledRuntimeAgentBundle({ + compiledArtifactsSource: resolveNitroCompiledArtifactsSource( + createDevelopmentNitroArtifactsConfig({ appRoot }), + ), + }); + const agentModule = bundle.moduleMap.nodes[ROOT_COMPILED_AGENT_NODE_ID]?.modules["agent.ts"]; + + expect(agentModule).toMatchObject({ + routed: "router:parent-auth-config", + }); + }); + }); + it("stops copying at nested git repository boundaries", async () => { const appRoot = await createScratchDirectory("eve-dev-runtime-nested-git-"); const agentRoot = join(appRoot, "agent");