refactor: Introduce centralized snapshot-based test project infrastructure with new CLI commands and improved storage structure#789
Conversation
🦋 Changeset detectedLatest commit: 08be363 The changes in this PR will be included in the next version bump. This PR includes changesets to release 21 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (6)
📝 WalkthroughWalkthroughAdds centralized snapshot-based test project infrastructure: new dev CLI commands (test-project and test), e2e-runner with discovery/runner, generation manifest and staleness checks, snapshot layout moved under baseplate/snapshots/, renames snapshotDirectory→baseplateDirectory, and new server actions for test-project lifecycle. Changes
Sequence Diagram(s)sequenceDiagram
participant User as CLI User
participant DevCLI as Dev CLI (test-project)
participant ServerAction as Server Action
participant Generator as Generator
participant Snapshot as Generation Manifest / Snapshot
participant Env as Environment Helper
User->>DevCLI: generate <test-name>
DevCLI->>ServerAction: invoke testProjectGenerateAction
ServerAction->>Generator: generate project output
Generator-->>ServerAction: generated output
ServerAction->>Snapshot: checkStaleness(outputDir)
alt not stale
ServerAction->>Snapshot: writeGenerationManifest(outputDir)
ServerAction-->>User: generation complete
else stale
ServerAction-->>User: error (stale) -> abort
end
User->>DevCLI: run-env <test-name>
DevCLI->>ServerAction: discover test definition
ServerAction->>Env: createEnvironmentHelpers + setupEnvironment
Env-->>User: environment ready (wait for signal)
User-->>Env: shutdown signal
Env->>Env: teardown
Env-->>User: environment stopped
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/project-builder-dev/src/commands/sync.ts (1)
25-27:⚠️ Potential issue | 🟡 MinorThe
--snapshotoption help text is misleading about what directory it expects.The CLI option describes "Apply diffs from snapshot directory", but it actually passes the value to
baseplateDirectory, which is documented as "Custom baseplate directory. Defaults topath.join(directory, 'baseplate')". These are different—the snapshot directory is derived from the baseplate directory, not the other way around.Update the help text to clarify: "Custom baseplate directory (defaults to
<project>/baseplate)" or rename the option to--baseplatefor consistency with the parameter name.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-dev/src/commands/sync.ts` around lines 25 - 27, The help text for the CLI option '--snapshot' is misleading because its value is passed into the baseplateDirectory parameter (used as "Custom baseplate directory" and defaulted to path.join(directory, 'baseplate')); either change the option name to '--baseplate <directory>' to match the parameter or update the help text to say "Custom baseplate directory (defaults to <project>/baseplate)" so it accurately documents baseplateDirectory; locate the option definition near the sync command where '--snapshot <directory>' is declared and update the flag name or the description to match the baseplateDirectory semantics.packages/project-builder-server/src/diff/snapshot/snapshot-utils.unit.test.ts (1)
188-204:⚠️ Potential issue | 🟠 MajorDon’t skip underscore round-trip cases; this hides a real path-mapping bug.
The skip branch accepts lossy conversion for filenames containing
_, which can mis-map snapshot diffs to incorrect paths. This should be asserted as a failing case and fixed inpackages/project-builder-server/src/diff/snapshot/snapshot-utils.tsrather than bypassed in tests.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-server/src/diff/snapshot/snapshot-utils.unit.test.ts` around lines 188 - 204, The test is skipping filenames with underscores which masks a real lossiness in pathToSafeDiffFilename / safeDiffFilenameToPath; remove the test skip and instead fix the conversion logic in snapshot-utils.ts so underscores round-trip. Update pathToSafeDiffFilename to escape or encode underscore characters in a reversible way (and escape whatever separator you use), and implement the complementary decoding in safeDiffFilenameToPath so safeDiffFilenameToPath(pathToSafeDiffFilename(x)) === x for inputs containing '_'; then re-enable the underscore cases in the unit test to assert the corrected behavior.packages/project-builder-server/src/actions/snapshot/snapshot-save.action.ts (1)
64-66:⚠️ Potential issue | 🟡 MinorWarning message should reflect all-app mode.
When
appis omitted, the current warning still says “this app”, which is misleading before an overwrite operation.✏️ Suggested fix
- logger.warn( - '⚠️ This will overwrite any existing snapshot for this app.', - ); + logger.warn( + `⚠️ This will overwrite any existing snapshot for ${app ? `app '${app}'` : 'all apps'}.`, + );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-server/src/actions/snapshot/snapshot-save.action.ts` around lines 64 - 66, The warning currently logged via logger.warn('⚠️ This will overwrite any existing snapshot for this app.') is misleading when the caller omits the app parameter; update the code in snapshot-save.action.ts (the place where logger.warn is called) to conditionally log a message based on the presence of the app variable: if app is provided log "⚠️ This will overwrite any existing snapshot for this app." otherwise log "⚠️ This will overwrite any existing snapshots for all apps." Ensure you reference the existing logger.warn call and the local parameter/variable named app when implementing this conditional message.
🧹 Nitpick comments (5)
packages/project-builder-server/src/diff/diff-project.ts (1)
149-153: Prefer shared baseplate-directory resolution over inline'baseplate'join.Line 149 hardcodes the baseplate root. If baseplate path resolution is centralized in other actions, this can drift and cause snapshot lookup mismatches later. Reuse the same resolver/helper used elsewhere for consistency.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-server/src/diff/diff-project.ts` around lines 149 - 153, Replace the hardcoded baseplateDirectory = path.join(project.directory, 'baseplate') with a call to the project’s centralized baseplate-directory resolver (the same helper used elsewhere) so snapshot resolution uses the canonical path; call that shared helper with project.directory to produce baseplateDirectory and then pass it into resolveSnapshotDirectory(projectBaseplateDir, app.name) (keep references to baseplateDirectory, project.directory, resolveSnapshotDirectory, and app.name to locate the change).packages/project-builder-dev/src/commands/snapshot.ts (1)
89-117: Keep CLI error handling/logging consistent across subcommands.
saveandshowdropped the localtry/catchpattern used inadd/remove. Wrap these actions similarly so failures are logged with command-specific context before rethrowing.Proposed consistency patch
- .action(async (project: string, app: string | undefined) => { + .action(async (project: string, app: string | undefined) => { + try { // Confirm with user before overwriting existing snapshot const target = app ?? 'all apps'; console.warn( `⚠️ This will overwrite any existing snapshot for ${target}.`, ); console.info( 'Use granular commands (snapshot add/remove) for safer updates.', ); const proceed: boolean = await confirm({ message: 'Are you sure you want to overwrite the existing snapshot?', default: false, }); if (!proceed) { logger.info('Aborted snapshot save.'); return; } const context = await createServiceActionContext(); await invokeServiceActionAsCli( snapshotSaveAction, { project, app, }, context, ); + } catch (error) { + logger.error('Failed to save snapshot:', error); + throw error; + } }); ... - .action(async (project: string, app: string) => { - const context = await createServiceActionContext(); + .action(async (project: string, app: string) => { + try { + const context = await createServiceActionContext(); await invokeServiceActionAsCli( snapshotShowAction, { project, app, }, context, ); + } catch (error) { + logger.error('Failed to show snapshot:', error); + throw error; + } });Also applies to: 123-134
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-dev/src/commands/snapshot.ts` around lines 89 - 117, The snapshot CLI handlers for "save" (where snapshotSaveAction and invokeServiceActionAsCli are called) and "show" need the same try/catch error handling used by "add"/"remove": wrap the async action body (after confirm and createServiceActionContext) in try { ... await invokeServiceActionAsCli(snapshotSaveAction, { project, app }, context) } catch (err) { logger.error(`Failed to save snapshot for project=${project} app=${app ?? 'all'}: ${err}`); throw err } — do the analogous try/catch/log in the "show" handler (referencing snapshotShowAction or the show handler) so failures are logged with command-specific context before rethrowing.packages/project-builder-server/src/actions/test-project/test-project-save.action.ts (1)
14-17: Avoid returning/compiling unusedappsinloadTestProjectContext.
compilePackages(...)is currently not consumed by this file’s save flow, so this can be trimmed (or explicitly documented as intentional validation) to reduce unnecessary work.Also applies to: 55-57, 81-87
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-server/src/actions/test-project/test-project-save.action.ts` around lines 14 - 17, The TestProjectContext currently includes and returns an unused apps array and calls compilePackages in loadTestProjectContext; remove the unused work by deleting the apps field from the TestProjectContext interface and stop invoking/returning compilePackages in loadTestProjectContext (or, if compilation is intentionally a validation step, add an explicit comment and keep only its side-effects), updating all references to apps in this file and removing the compilePackages(...) call sites so the save flow no longer performs unnecessary package compilation.packages/project-builder-dev/src/e2e-runner/runner.ts (1)
37-40: Avoid repeated plugin/version discovery inside each test run.Resolve
pluginsandcliVersiononce inrunTestsand pass them intorunTestto reduce repeated I/O and package lookup overhead.♻️ Suggested refactor
-async function runTest( +async function runTest( test: ProjectBuilderTest, testProjectsDir: string, outputDir: string, + shared: { plugins: Awaited<ReturnType<typeof discoverPlugins>>; cliVersion: string }, ): Promise<void> { @@ - const plugins = await discoverPlugins(process.cwd(), console); - const cliVersion = (await getPackageVersion(import.meta.dirname)) ?? '0.0.0'; + const { plugins, cliVersion } = shared; @@ export async function runTests(options: RunTestsOptions): Promise<void> { @@ + const plugins = await discoverPlugins(process.cwd(), console); + const cliVersion = (await getPackageVersion(import.meta.dirname)) ?? '0.0.0'; @@ - await runTest(test.content, testProjectsDir, outputDir); + await runTest(test.content, testProjectsDir, outputDir, { + plugins, + cliVersion, + });Also applies to: 86-94
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-dev/src/e2e-runner/runner.ts` around lines 37 - 40, Resolve plugins and cliVersion once in runTests by calling discoverPlugins(process.cwd(), console) and getPackageVersion(import.meta.dirname) at the start of runTests, store results in local variables (e.g., plugins and cliVersion), and pass them as parameters into runTest (and any calls to generateTestProject) instead of calling discoverPlugins/getPackageVersion inside runTest; update runTest signature and all internal uses to accept and use the passed plugins and cliVersion values to avoid repeated I/O and package lookups.packages/project-builder-dev/src/commands/test-project.ts (1)
197-198: Scope discovery to the requested test inrun-env.
run-env <test-name>currently imports every*.gen.tsbefore selecting one, so unrelated broken test defs can block this command.♻️ Suggested fix
- const tests = await discoverTests(testDefinitionsDir); + const tests = await discoverTests(testDefinitionsDir, testName);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-dev/src/commands/test-project.ts` around lines 197 - 198, The command currently calls discoverTests(testDefinitionsDir) which imports every *.gen.ts before filtering, so modify discovery to avoid importing unrelated files: update discoverTests (or add a new function, e.g., discoverTestByName) to accept an optional filter parameter (testName) and implement a two-step scan—first read filenames/AST or parse each file's exported metadata without executing the module, or map filenames to projectDirectory by reading the file contents to find the projectDirectory string—then only import the matching module(s). In test-project.ts replace the unconditional await discoverTests(testDefinitionsDir) + tests.find(...) with a call that passes the requested testName (from run-env) to the new/updated discovery function so only the target *.gen.ts is loaded and executed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/project-builder-dev/src/commands/snapshot.ts`:
- Around line 85-117: The save snapshot command currently always prompts before
overwriting; add a boolean CLI flag option('--force', 'Skip confirmation
prompt', false) to the command chain and update the .action signature to accept
the options parameter (e.g., .action(async (project: string, app: string |
undefined, options: { force?: boolean }) => { ... })). Inside the action, skip
calling confirm(...) when options.force is true (preserve the existing confirm
flow when false), and keep the existing calls to createServiceActionContext(),
invokeServiceActionAsCli(snapshotSaveAction, { project, app }, context), and
logger.info('Aborted snapshot save.') unchanged. Ensure the unique symbols
referenced are options.force, confirm, snapshotSaveAction,
invokeServiceActionAsCli, createServiceActionContext, and logger.
In `@packages/project-builder-dev/src/e2e-runner/discover-tests.ts`:
- Line 16: The glob passed to globby when building testFiles won't match files
in subdirectories; update the globby call in discover-tests.ts (the testFiles =
await globby(...) usage) to use a recursive pattern '**/*.gen.ts' instead of
'**.gen.ts' so nested files like src/tests/simple.gen.ts are discovered; modify
only the pattern string passed to globby and keep existing options intact.
In `@packages/project-builder-dev/src/e2e-runner/generation-manifest.ts`:
- Around line 106-129: The staleness check only looks for new or changed files
and ignores deletions; update the logic (in generation-manifest.ts around the
currentFiles mapping where collectFiles, hashFile, manifest.files and
FILE_HASH_CONCURRENCY are used) to compute deletedFiles by comparing
Object.keys(manifest.files) against the currentFiles list (or a Set of
currentFiles), add any missing manifest entries to deletedFiles, include
deletedFiles in the returned object, and ensure isStale becomes true if
deletedFiles.length > 0.
- Around line 98-104: The catch block that wraps readFile(manifestPath, 'utf-8')
and JSON.parse(...) is masking all errors; change it so only a missing file
(e.g., ENOENT) is treated as "not stale" and returns { isStale: false,
modifiedFiles: [], newFiles: [] }, while other errors (JSON.parse failures,
permission errors, etc.) are rethrown or bubbled up so callers can fail safely;
update the try/catch around readFile/JSON.parse in generation-manifest.ts
(referencing manifestPath, GenerationManifest, readFile, and the early return
shape) to inspect the error code and only swallow file-not-found, otherwise
throw the error.
In
`@packages/project-builder-server/src/actions/snapshot/snapshot-show.action.ts`:
- Line 1: The action hardcodes "project/baseplate" when building snapshot
filesystem paths; update SnapshotShowAction (in snapshot-show.action.ts) to use
the project's baseplateDirectory instead of the literal string: replace
occurrences that build paths like "project/baseplate" in functions/methods such
as snapshotShowAction and any local resolveSnapshotPath helper to compute paths
via path.join(project.path, project.baseplateDirectory, ...) or
path.resolve(project.root, project.baseplateDirectory, ...) (use the existing
project or ctx.project object and its baseplateDirectory property), and ensure
all four occurrences referenced (around the earlier path uses and the
check/report logic) are updated so missing-snapshot checks use the configured
baseplateDirectory.
In `@packages/project-builder-server/src/actions/sync/sync-project.action.ts`:
- Around line 20-25: The schema rename from snapshotDirectory to
baseplateDirectory will break callers; update the input handling for the sync
project action so both keys are accepted during migration: keep the existing zod
field baseplateDirectory but also accept the deprecated snapshotDirectory
(alias) and, if snapshotDirectory is provided, map/copy its value into
baseplateDirectory before any fallback resolution logic (the code that currently
reads baseplateDirectory and applies the fallback on missing value). Reference
the schema field baseplateDirectory and the old key snapshotDirectory and ensure
the resolution code that computes the final directory (the early fallback logic
currently triggered around the resolution step) uses the normalized
baseplateDirectory value.
In
`@packages/project-builder-server/src/diff/snapshot/apply-diff-to-generator-output.ts`:
- Around line 52-57: The check after reading the content file treats empty
string as missing; change the validation so an explicit file-not-found is
detected via the catch handler (handleFileNotFoundError) while allowing '' as a
valid value—i.e., keep the await readFile(contentFilePath,
'utf-8').catch(handleFileNotFoundError) but replace the truthy check on contents
with a test that distinguishes read failure (the error returned by
handleFileNotFoundError or undefined/null) from an empty string, and throw `new
Error(\`Content file not found: ${contentFilePath}\`)` only when the read
actually failed; locate this logic around the readFile call and the `contents`
variable in apply-diff-to-generator-output.ts.
In
`@packages/project-builder-server/src/diff/snapshot/create-snapshot-for-project.ts`:
- Around line 151-166: The compiled list from compilePackages(...) can include
non-app packages, so ensure appsToProcess only contains application packages:
after const apps = compilePackages(projectJson, context) filter that array
(e.g., const appsOnly = apps.filter(isApp)) where isApp checks the PackageEntry
marker for an application (package type/manifest flag used in your codebase),
then use appsOnly for the appName lookup and as the default list (replace uses
of apps with appsOnly when computing appsToProcess and validating appName). Also
add a clear error when appName is provided but matches a non-app package by
searching appsOnly rather than apps.
In `@packages/project-builder-server/src/diff/snapshot/snapshot-manifest.ts`:
- Around line 95-106: The current early-return when manifest.files.added
contains an entry with the same path prevents enriching an existing entry with
contentFile; update addAddedFile so it does not return immediately but instead
maps manifest.files.added and replaces the matching entry with one that includes
contentFile when provided (e.g., in the block that currently checks
manifest.files.added.some((entry) => entry.path === filePath), change behavior
to transform the existing entry to { path: filePath, ...(contentFile && {
contentFile }) } rather than returning manifest), ensuring new entries are still
appended when no match is found and preserving other manifest fields.
---
Outside diff comments:
In `@packages/project-builder-dev/src/commands/sync.ts`:
- Around line 25-27: The help text for the CLI option '--snapshot' is misleading
because its value is passed into the baseplateDirectory parameter (used as
"Custom baseplate directory" and defaulted to path.join(directory,
'baseplate')); either change the option name to '--baseplate <directory>' to
match the parameter or update the help text to say "Custom baseplate directory
(defaults to <project>/baseplate)" so it accurately documents
baseplateDirectory; locate the option definition near the sync command where
'--snapshot <directory>' is declared and update the flag name or the description
to match the baseplateDirectory semantics.
In
`@packages/project-builder-server/src/actions/snapshot/snapshot-save.action.ts`:
- Around line 64-66: The warning currently logged via logger.warn('⚠️ This will
overwrite any existing snapshot for this app.') is misleading when the caller
omits the app parameter; update the code in snapshot-save.action.ts (the place
where logger.warn is called) to conditionally log a message based on the
presence of the app variable: if app is provided log "⚠️ This will overwrite any
existing snapshot for this app." otherwise log "⚠️ This will overwrite any
existing snapshots for all apps." Ensure you reference the existing logger.warn
call and the local parameter/variable named app when implementing this
conditional message.
In
`@packages/project-builder-server/src/diff/snapshot/snapshot-utils.unit.test.ts`:
- Around line 188-204: The test is skipping filenames with underscores which
masks a real lossiness in pathToSafeDiffFilename / safeDiffFilenameToPath;
remove the test skip and instead fix the conversion logic in snapshot-utils.ts
so underscores round-trip. Update pathToSafeDiffFilename to escape or encode
underscore characters in a reversible way (and escape whatever separator you
use), and implement the complementary decoding in safeDiffFilenameToPath so
safeDiffFilenameToPath(pathToSafeDiffFilename(x)) === x for inputs containing
'_'; then re-enable the underscore cases in the unit test to assert the
corrected behavior.
---
Nitpick comments:
In `@packages/project-builder-dev/src/commands/snapshot.ts`:
- Around line 89-117: The snapshot CLI handlers for "save" (where
snapshotSaveAction and invokeServiceActionAsCli are called) and "show" need the
same try/catch error handling used by "add"/"remove": wrap the async action body
(after confirm and createServiceActionContext) in try { ... await
invokeServiceActionAsCli(snapshotSaveAction, { project, app }, context) } catch
(err) { logger.error(`Failed to save snapshot for project=${project} app=${app
?? 'all'}: ${err}`); throw err } — do the analogous try/catch/log in the "show"
handler (referencing snapshotShowAction or the show handler) so failures are
logged with command-specific context before rethrowing.
In `@packages/project-builder-dev/src/commands/test-project.ts`:
- Around line 197-198: The command currently calls
discoverTests(testDefinitionsDir) which imports every *.gen.ts before filtering,
so modify discovery to avoid importing unrelated files: update discoverTests (or
add a new function, e.g., discoverTestByName) to accept an optional filter
parameter (testName) and implement a two-step scan—first read filenames/AST or
parse each file's exported metadata without executing the module, or map
filenames to projectDirectory by reading the file contents to find the
projectDirectory string—then only import the matching module(s). In
test-project.ts replace the unconditional await
discoverTests(testDefinitionsDir) + tests.find(...) with a call that passes the
requested testName (from run-env) to the new/updated discovery function so only
the target *.gen.ts is loaded and executed.
In `@packages/project-builder-dev/src/e2e-runner/runner.ts`:
- Around line 37-40: Resolve plugins and cliVersion once in runTests by calling
discoverPlugins(process.cwd(), console) and
getPackageVersion(import.meta.dirname) at the start of runTests, store results
in local variables (e.g., plugins and cliVersion), and pass them as parameters
into runTest (and any calls to generateTestProject) instead of calling
discoverPlugins/getPackageVersion inside runTest; update runTest signature and
all internal uses to accept and use the passed plugins and cliVersion values to
avoid repeated I/O and package lookups.
In
`@packages/project-builder-server/src/actions/test-project/test-project-save.action.ts`:
- Around line 14-17: The TestProjectContext currently includes and returns an
unused apps array and calls compilePackages in loadTestProjectContext; remove
the unused work by deleting the apps field from the TestProjectContext interface
and stop invoking/returning compilePackages in loadTestProjectContext (or, if
compilation is intentionally a validation step, add an explicit comment and keep
only its side-effects), updating all references to apps in this file and
removing the compilePackages(...) call sites so the save flow no longer performs
unnecessary package compilation.
In `@packages/project-builder-server/src/diff/diff-project.ts`:
- Around line 149-153: Replace the hardcoded baseplateDirectory =
path.join(project.directory, 'baseplate') with a call to the project’s
centralized baseplate-directory resolver (the same helper used elsewhere) so
snapshot resolution uses the canonical path; call that shared helper with
project.directory to produce baseplateDirectory and then pass it into
resolveSnapshotDirectory(projectBaseplateDir, app.name) (keep references to
baseplateDirectory, project.directory, resolveSnapshotDirectory, and app.name to
locate the change).
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (197)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamltests/simple/.gitignoreis excluded by!tests/**tests/simple/.npmrcis excluded by!tests/**tests/simple/.prettierignoreis excluded by!tests/**tests/simple/.prettierrcis excluded by!tests/**tests/simple/README.mdis excluded by!tests/**tests/simple/apps/backend/.env.exampleis excluded by!tests/**tests/simple/apps/backend/.gitignoreis excluded by!tests/**tests/simple/apps/backend/.prettierignoreis excluded by!tests/**tests/simple/apps/backend/.prettierrcis excluded by!tests/**tests/simple/apps/backend/README.mdis excluded by!tests/**tests/simple/apps/backend/baseplate/file-id-map.jsonis excluded by!tests/**tests/simple/apps/backend/baseplate/generated/.env.exampleis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/.gitignoreis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/.prettierignoreis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/.prettierrcis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/README.mdis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/eslint.config.jsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/package.jsonis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/prisma.config.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/prisma/schema.prismais excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/index.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/instrument.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/blog/index.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/blog/schema/blog-post.object-type.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/blog/schema/blog-post.queries.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/graphql/index.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/graphql/scalars/date-time.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/graphql/scalars/date.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/graphql/scalars/json-object.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/graphql/scalars/json.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/graphql/scalars/uuid.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/modules/index.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/error-handler.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graceful-shutdown.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graphql/FieldWithInputPayloadPlugin/global-types.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graphql/FieldWithInputPayloadPlugin/index.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graphql/FieldWithInputPayloadPlugin/schema-builder.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graphql/FieldWithInputPayloadPlugin/types.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graphql/builder.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graphql/index.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graphql/strip-query-mutation-plugin.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graphql/use-graph-logger.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/graphql/use-sentry.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/health-check.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/plugins/request-context.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/prisma/seed.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/server.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/services/config.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/services/error-logger.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/services/logger.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/services/prisma.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/services/sentry.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/tests/helpers/db.test-helper.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/tests/helpers/logger.test-helper.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/tests/helpers/prisma.test-helper.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/tests/helpers/service-context.test-helper.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/tests/scripts/global-setup-prisma.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/app-modules.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/authorizers.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/define-operations.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/field-definitions.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/prisma-types.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/prisma-utils.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/relation-helpers.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/types.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/http-errors.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/request-service-context.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/service-context.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/string.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/src/utils/zod.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/tsconfig.jsonis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/baseplate/generated/vitest.config.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/backend/eslint.config.jsis excluded by!tests/**tests/simple/apps/backend/package.jsonis excluded by!tests/**tests/simple/apps/backend/prisma.config.tsis excluded by!tests/**tests/simple/apps/backend/prisma/migrations/migration_lock.tomlis excluded by!tests/**tests/simple/apps/backend/prisma/schema.prismais excluded by!tests/**tests/simple/apps/backend/schema.graphqlis excluded by!tests/**tests/simple/apps/backend/src/index.tsis excluded by!tests/**tests/simple/apps/backend/src/instrument.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/blog/index.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/blog/schema/blog-post.object-type.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/blog/schema/blog-post.queries.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/graphql/index.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/graphql/scalars/date-time.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/graphql/scalars/date.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/graphql/scalars/json-object.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/graphql/scalars/json.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/graphql/scalars/uuid.tsis excluded by!tests/**tests/simple/apps/backend/src/modules/index.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/error-handler.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graceful-shutdown.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graphql/FieldWithInputPayloadPlugin/global-types.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graphql/FieldWithInputPayloadPlugin/index.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graphql/FieldWithInputPayloadPlugin/schema-builder.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graphql/FieldWithInputPayloadPlugin/types.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graphql/builder.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graphql/index.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graphql/strip-query-mutation-plugin.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graphql/use-graph-logger.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/graphql/use-sentry.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/health-check.tsis excluded by!tests/**tests/simple/apps/backend/src/plugins/request-context.tsis excluded by!tests/**tests/simple/apps/backend/src/prisma/seed.tsis excluded by!tests/**tests/simple/apps/backend/src/server.tsis excluded by!tests/**tests/simple/apps/backend/src/services/config.tsis excluded by!tests/**tests/simple/apps/backend/src/services/error-logger.tsis excluded by!tests/**tests/simple/apps/backend/src/services/logger.tsis excluded by!tests/**tests/simple/apps/backend/src/services/prisma.tsis excluded by!tests/**tests/simple/apps/backend/src/services/sentry.tsis excluded by!tests/**tests/simple/apps/backend/src/tests/helpers/db.test-helper.tsis excluded by!tests/**tests/simple/apps/backend/src/tests/helpers/logger.test-helper.tsis excluded by!tests/**tests/simple/apps/backend/src/tests/helpers/prisma.test-helper.tsis excluded by!tests/**tests/simple/apps/backend/src/tests/helpers/service-context.test-helper.tsis excluded by!tests/**tests/simple/apps/backend/src/tests/scripts/global-setup-prisma.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/app-modules.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/authorizers.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/data-operations/define-operations.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/data-operations/field-definitions.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/data-operations/prisma-types.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/data-operations/prisma-utils.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/data-operations/relation-helpers.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/data-operations/types.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/http-errors.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/request-service-context.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/service-context.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/string.tsis excluded by!tests/**tests/simple/apps/backend/src/utils/zod.tsis excluded by!tests/**tests/simple/apps/backend/tsconfig.jsonis excluded by!tests/**tests/simple/apps/backend/vitest.config.tsis excluded by!tests/**tests/simple/apps/e2e/.gitignoreis excluded by!tests/**tests/simple/apps/e2e/.prettierignoreis excluded by!tests/**tests/simple/apps/e2e/.prettierrcis excluded by!tests/**tests/simple/apps/e2e/package.jsonis excluded by!tests/**tests/simple/apps/e2e/playwright.config.tsis excluded by!tests/**tests/simple/apps/e2e/tests/main.spec.tsis excluded by!tests/**tests/simple/apps/e2e/tsconfig.jsonis excluded by!tests/**tests/simple/apps/web/.env.developmentis excluded by!tests/**tests/simple/apps/web/.gitignoreis excluded by!tests/**tests/simple/apps/web/.prettierignoreis excluded by!tests/**tests/simple/apps/web/.prettierrcis excluded by!tests/**tests/simple/apps/web/README.mdis excluded by!tests/**tests/simple/apps/web/baseplate/file-id-map.jsonis excluded by!tests/**tests/simple/apps/web/baseplate/generated/.env.developmentis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/.gitignoreis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/.prettierignoreis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/.prettierrcis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/README.mdis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/eslint.config.jsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/graphql.config.tsis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/index.htmlis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/package.jsonis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/public/favicon.icois excluded by!**/*.ico,!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/app/app-apollo-provider.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/app/app.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/app/router.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/alert.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/async-boundary.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/badge.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/breadcrumb.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/button.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/calendar.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/card.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/checkbox-field.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/checkbox.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/circular-progress.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/combobox-field.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/combobox.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/command.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/confirm-dialog.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/date-picker-field.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/date-time-picker-field.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/dialog.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/dropdown.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/empty-display.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/error-boundary.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/error-display.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/errorable-loader.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/form-item.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/input-field.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/input.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/label.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/loader.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/multi-combobox-field.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/multi-combobox.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/navigation-menu.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/not-found-card.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/popover.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/scroll-area.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/select-field.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/select.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/separator.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/sheet.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/sidebar.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/skeleton.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**tests/simple/apps/web/baseplate/generated/src/components/ui/switch-field.tsxis excluded by!**/generated/**,!tests/**,!**/generated/**
📒 Files selected for processing (103)
.changeset/test-case-infrastructure.md.coderabbit.yaml.github/workflows/test-e2e.yml.gitignoreexamples/blog-with-auth/.baseplateignoreexamples/blog-with-auth/apps/backend/.baseplateignoreexamples/blog-with-auth/baseplate/snapshots/admin/diffs/package.json.diffexamples/blog-with-auth/baseplate/snapshots/admin/manifest.jsonexamples/blog-with-auth/baseplate/snapshots/backend/manifest.jsonexamples/blog-with-auth/baseplate/snapshots/root/manifest.jsonexamples/blog-with-auth/baseplate/snapshots/transactional/manifest.jsonexamples/todo-with-auth0/.baseplateignoreexamples/todo-with-auth0/apps/admin/.baseplateignoreexamples/todo-with-auth0/apps/backend/.baseplateignoreexamples/todo-with-auth0/apps/web/.baseplateignoreexamples/todo-with-auth0/baseplate/snapshots/admin/manifest.jsonexamples/todo-with-auth0/baseplate/snapshots/backend/manifest.jsonexamples/todo-with-auth0/baseplate/snapshots/root/manifest.jsonexamples/todo-with-auth0/baseplate/snapshots/web/manifest.jsonknip.config.jspackage.jsonpackages/core-generators/src/generators/node/prettier/prettier.generator.tspackages/project-builder-cli/src/commands/sync.tspackages/project-builder-dev/package.jsonpackages/project-builder-dev/src/commands/snapshot.tspackages/project-builder-dev/src/commands/sync.tspackages/project-builder-dev/src/commands/test-project.tspackages/project-builder-dev/src/commands/test.tspackages/project-builder-dev/src/e2e-runner/discover-tests.tspackages/project-builder-dev/src/e2e-runner/environment.tspackages/project-builder-dev/src/e2e-runner/errors.tspackages/project-builder-dev/src/e2e-runner/generation-manifest.tspackages/project-builder-dev/src/e2e-runner/index.tspackages/project-builder-dev/src/e2e-runner/runner.tspackages/project-builder-dev/src/e2e-runner/types.tspackages/project-builder-dev/src/e2e-runner/utils/kill-process-group.tspackages/project-builder-dev/src/e2e-runner/utils/ora.tspackages/project-builder-dev/src/e2e-runner/utils/process.tspackages/project-builder-dev/src/e2e-runner/utils/url.tspackages/project-builder-dev/src/e2e-runner/utils/wait-for-signal.tspackages/project-builder-dev/src/index.tspackages/project-builder-server/src/actions/index.tspackages/project-builder-server/src/actions/registry.tspackages/project-builder-server/src/actions/snapshot/snapshot-add.action.tspackages/project-builder-server/src/actions/snapshot/snapshot-remove.action.tspackages/project-builder-server/src/actions/snapshot/snapshot-save.action.tspackages/project-builder-server/src/actions/snapshot/snapshot-show.action.tspackages/project-builder-server/src/actions/sync/sync-project.action.tspackages/project-builder-server/src/actions/test-project/index.tspackages/project-builder-server/src/actions/test-project/test-project-generate.action.tspackages/project-builder-server/src/actions/test-project/test-project-init.action.tspackages/project-builder-server/src/actions/test-project/test-project-paths.tspackages/project-builder-server/src/actions/test-project/test-project-save.action.tspackages/project-builder-server/src/actions/utils/project-discovery.tspackages/project-builder-server/src/compiler/index.tspackages/project-builder-server/src/diff/diff-project.tspackages/project-builder-server/src/diff/snapshot/apply-diff-to-generator-output.tspackages/project-builder-server/src/diff/snapshot/apply-diff-to-generator-output.unit.test.tspackages/project-builder-server/src/diff/snapshot/create-snapshot-for-project.tspackages/project-builder-server/src/diff/snapshot/index.tspackages/project-builder-server/src/diff/snapshot/save-snapshot.tspackages/project-builder-server/src/diff/snapshot/save-snapshot.unit.test.tspackages/project-builder-server/src/diff/snapshot/snapshot-management.tspackages/project-builder-server/src/diff/snapshot/snapshot-manifest.tspackages/project-builder-server/src/diff/snapshot/snapshot-manifest.unit.test.tspackages/project-builder-server/src/diff/snapshot/snapshot-types.tspackages/project-builder-server/src/diff/snapshot/snapshot-utils.tspackages/project-builder-server/src/diff/snapshot/snapshot-utils.unit.test.tspackages/project-builder-server/src/index.tspackages/project-builder-server/src/plugins/node-plugin-store.tspackages/project-builder-server/src/project-definition/get-single-app-directory-for-project.tspackages/project-builder-server/src/project-definition/load-project-definition.tspackages/project-builder-server/src/sync/generate-for-directory.tspackages/project-builder-server/src/sync/sync-project.tspackages/project-builder-server/src/tests/helpers/generator-output.test-helper.tspackages/project-builder-test/.gitignorepackages/project-builder-test/eslint.config.jspackages/project-builder-test/package.jsonpackages/project-builder-test/src/commands/generate.tspackages/project-builder-test/src/commands/index.tspackages/project-builder-test/src/commands/run.tspackages/project-builder-test/src/commands/serve.tspackages/project-builder-test/src/commands/test.tspackages/project-builder-test/src/index.tspackages/project-builder-test/src/runner/runner.tspackages/project-builder-test/src/tests/simple.gen.tspackages/project-builder-test/src/utils/console.tspackages/project-builder-test/src/utils/directories.tspackages/project-builder-test/src/utils/resolve.tspackages/project-builder-test/src/utils/version.tspackages/project-builder-test/test-projects/simple/project-definition.jsonpackages/project-builder-test/test-projects/simple/snapshots/backend/diffs/prisma_migrations_20260302151454_initial_migration_migration.sql.diffpackages/project-builder-test/test-projects/simple/snapshots/backend/diffs/prisma_migrations_migration_lock.toml.diffpackages/project-builder-test/test-projects/simple/snapshots/backend/diffs/src_prisma_seed.ts.diffpackages/project-builder-test/test-projects/simple/snapshots/backend/manifest.jsonpackages/project-builder-test/test-projects/simple/snapshots/root/diffs/pnpm-lock.yaml.diffpackages/project-builder-test/test-projects/simple/snapshots/root/manifest.jsonpackages/project-builder-test/test-projects/simple/snapshots/web/manifest.jsonpackages/project-builder-test/turbo.jsonpackages/sync/src/output/post-write-commands/run-commands.tspackages/sync/src/utils/ignore-patterns.tspackages/sync/src/utils/ignore-patterns.unit.test.tsscripts/run-all.sh
💤 Files with no reviewable changes (15)
- packages/project-builder-cli/src/commands/sync.ts
- packages/project-builder-test/src/commands/run.ts
- packages/project-builder-test/src/commands/test.ts
- packages/project-builder-test/src/index.ts
- packages/project-builder-test/src/utils/resolve.ts
- packages/project-builder-test/src/utils/console.ts
- packages/project-builder-test/src/utils/directories.ts
- packages/project-builder-server/src/project-definition/get-single-app-directory-for-project.ts
- packages/project-builder-test/src/commands/index.ts
- packages/project-builder-test/src/commands/generate.ts
- packages/sync/src/utils/ignore-patterns.ts
- packages/project-builder-test/turbo.json
- packages/project-builder-test/src/runner/runner.ts
- packages/project-builder-test/src/commands/serve.ts
- packages/project-builder-test/src/utils/version.ts
| baseplateDirectory: z | ||
| .string() | ||
| .optional() | ||
| .describe('Directory containing snapshot to use when generating.'), | ||
| .describe( | ||
| 'Custom baseplate directory for snapshot resolution. Defaults to <projectDirectory>/baseplate.', | ||
| ), |
There was a problem hiding this comment.
Backward-compatibility regression risk in renamed input field.
On Line 20 and Line 57, replacing snapshotDirectory with baseplateDirectory without alias handling can silently break older callers (unknown keys are ignored by default), and Line 92 then uses fallback resolution unintentionally.
💡 Migration-safe fix (support deprecated alias during transition)
const syncProjectInputSchema = z.object({
project: z.string().describe('The name or ID of the project to sync.'),
@@
baseplateDirectory: z
.string()
.optional()
.describe(
'Custom baseplate directory for snapshot resolution. Defaults to <projectDirectory>/baseplate.',
),
+ snapshotDirectory: z
+ .string()
+ .optional()
+ .describe('DEPRECATED: use baseplateDirectory.'),
packages: z
.array(z.string())
.optional()
.describe('Only sync specific packages by name.'),
});
@@
const {
project: projectId,
overwrite,
skipCommands,
baseplateDirectory,
+ snapshotDirectory,
packages,
} = input;
+ const resolvedBaseplateDirectory =
+ baseplateDirectory ?? snapshotDirectory;
@@
- baseplateDirectory,
+ baseplateDirectory: resolvedBaseplateDirectory,Also applies to: 57-57, 92-92
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/project-builder-server/src/actions/sync/sync-project.action.ts`
around lines 20 - 25, The schema rename from snapshotDirectory to
baseplateDirectory will break callers; update the input handling for the sync
project action so both keys are accepted during migration: keep the existing zod
field baseplateDirectory but also accept the deprecated snapshotDirectory
(alias) and, if snapshotDirectory is provided, map/copy its value into
baseplateDirectory before any fallback resolution logic (the code that currently
reads baseplateDirectory and applies the fallback on missing value). Reference
the schema field baseplateDirectory and the old key snapshotDirectory and ensure
the resolution code that computes the final directory (the early fallback logic
currently triggered around the resolution step) uses the normalized
baseplateDirectory value.
| logger.info('Compiling applications...'); | ||
| const apps = compilePackages(projectJson, context); | ||
|
|
||
| // Filter apps if specified | ||
| const app = apps.find((app) => appName === app.name); | ||
|
|
||
| if (!app) { | ||
| throw new Error( | ||
| `No applications found named ${appName}. Available apps: ${apps.map((a) => a.name).join(', ')}`, | ||
| ); | ||
| let appsToProcess: PackageEntry[]; | ||
|
|
||
| if (appName) { | ||
| const app = apps.find((a) => appName === a.name); | ||
| if (!app) { | ||
| throw new Error( | ||
| `No applications found named ${appName}. Available apps: ${apps.map((a) => a.name).join(', ')}`, | ||
| ); | ||
| } | ||
| appsToProcess = [app]; | ||
| } else { | ||
| appsToProcess = apps; | ||
| } |
There was a problem hiding this comment.
App selection currently includes non-app packages.
appsToProcess is derived from compilePackages(...), which includes more than apps. In all-app mode this can create snapshots for root/libs, and in single-app mode a non-app name can be selected.
🐛 Suggested fix
- const apps = compilePackages(projectJson, context);
+ const packages = compilePackages(projectJson, context);
+ const appNameSet = new Set(projectJson.apps.map((a) => a.name));
+ const apps = packages.filter((pkg) => appNameSet.has(pkg.name));
@@
- const app = apps.find((a) => appName === a.name);
+ const app = apps.find((a) => appName === a.name);
if (!app) {
throw new Error(
`No applications found named ${appName}. Available apps: ${apps.map((a) => a.name).join(', ')}`,
);
}
appsToProcess = [app];
} else {
appsToProcess = apps;
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@packages/project-builder-server/src/diff/snapshot/create-snapshot-for-project.ts`
around lines 151 - 166, The compiled list from compilePackages(...) can include
non-app packages, so ensure appsToProcess only contains application packages:
after const apps = compilePackages(projectJson, context) filter that array
(e.g., const appsOnly = apps.filter(isApp)) where isApp checks the PackageEntry
marker for an application (package type/manifest flag used in your codebase),
then use appsOnly for the appName lookup and as the default list (replace uses
of apps with appsOnly when computing appsToProcess and validating appName). Also
add a clear error when appName is provided but matches a non-app package by
searching appsOnly rather than apps.
| if (manifest.files.added.some((entry) => entry.path === filePath)) { | ||
| return manifest; | ||
| } | ||
|
|
||
| return { | ||
| ...manifest, | ||
| files: { | ||
| ...manifest.files, | ||
| added: [...manifest.files.added, filePath], | ||
| added: [ | ||
| ...manifest.files.added.filter((entry) => entry.path !== filePath), | ||
| { path: filePath, ...(contentFile && { contentFile }) }, | ||
| ], |
There was a problem hiding this comment.
Allow addAddedFile to upgrade an existing entry with contentFile.
Current duplicate handling returns early, so a later call cannot enrich { path } into { path, contentFile }. That can leave incomplete metadata in the manifest.
Proposed fix
function addAddedFile(
manifest: SnapshotManifest,
filePath: string,
contentFile?: string,
): SnapshotManifest {
- if (manifest.files.added.some((entry) => entry.path === filePath)) {
- return manifest;
- }
+ const existing = manifest.files.added.find((entry) => entry.path === filePath);
+ if (existing) {
+ if (!contentFile || existing.contentFile === contentFile) {
+ return manifest;
+ }
+ return {
+ ...manifest,
+ files: {
+ ...manifest.files,
+ added: manifest.files.added.map((entry) =>
+ entry.path === filePath ? { ...entry, contentFile } : entry,
+ ),
+ },
+ };
+ }
return {
...manifest,
files: {
...manifest.files,
added: [
- ...manifest.files.added.filter((entry) => entry.path !== filePath),
{ path: filePath, ...(contentFile && { contentFile }) },
+ ...manifest.files.added,
],
},
};
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (manifest.files.added.some((entry) => entry.path === filePath)) { | |
| return manifest; | |
| } | |
| return { | |
| ...manifest, | |
| files: { | |
| ...manifest.files, | |
| added: [...manifest.files.added, filePath], | |
| added: [ | |
| ...manifest.files.added.filter((entry) => entry.path !== filePath), | |
| { path: filePath, ...(contentFile && { contentFile }) }, | |
| ], | |
| function addAddedFile( | |
| manifest: SnapshotManifest, | |
| filePath: string, | |
| contentFile?: string, | |
| ): SnapshotManifest { | |
| const existing = manifest.files.added.find((entry) => entry.path === filePath); | |
| if (existing) { | |
| if (!contentFile || existing.contentFile === contentFile) { | |
| return manifest; | |
| } | |
| return { | |
| ...manifest, | |
| files: { | |
| ...manifest.files, | |
| added: manifest.files.added.map((entry) => | |
| entry.path === filePath ? { ...entry, contentFile } : entry, | |
| ), | |
| }, | |
| }; | |
| } | |
| return { | |
| ...manifest, | |
| files: { | |
| ...manifest.files, | |
| added: [ | |
| { path: filePath, ...(contentFile && { contentFile }) }, | |
| ...manifest.files.added, | |
| ], | |
| }, | |
| }; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/project-builder-server/src/diff/snapshot/snapshot-manifest.ts`
around lines 95 - 106, The current early-return when manifest.files.added
contains an entry with the same path prevents enriching an existing entry with
contentFile; update addAddedFile so it does not return immediately but instead
maps manifest.files.added and replaces the matching entry with one that includes
contentFile when provided (e.g., in the block that currently checks
manifest.files.added.some((entry) => entry.path === filePath), change behavior
to transform the existing entry to { path: filePath, ...(contentFile && {
contentFile }) } rather than returning manifest), ensuring new entries are still
appended when no match is found and preserving other manifest fields.
Summary by CodeRabbit
New Features
Improvements
Chores