feat: Add snapshot management command#619
Conversation
🦋 Changeset detectedLatest commit: 8d08df0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 17 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 |
WalkthroughThis change introduces a structured directory snapshot system to the project builder, enhancing the Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI
participant DiffUtils
participant SnapshotMgr
participant FileSystem
User->>CLI: Run `baseplate diff`
CLI->>DiffUtils: scanWorkingDirectory()
DiffUtils->>FileSystem: List files (globby)
DiffUtils->>FileSystem: Read generated & working files
DiffUtils->>CLI: Report added, modified, deleted files
User->>CLI: Run `baseplate snapshot save`
CLI->>SnapshotMgr: createSnapshotForProject()
SnapshotMgr->>DiffUtils: compareFiles()
DiffUtils->>FileSystem: Read files
SnapshotMgr->>FileSystem: Write snapshot manifest & diffs
User->>CLI: Run `baseplate sync --overwrite --snapshot`
CLI->>SnapshotMgr: Load snapshot
CLI->>DiffUtils: Apply snapshot to generator output
DiffUtils->>FileSystem: Write files (with snapshot diffs applied)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (8)
packages/project-builder-server/package.json (1)
69-69: Consider replacingglobbywith Node 22’s built-in globbing
globbyis great, but Node 22 already exposesfs.glob/fs.globSync, which removes this extra dependency (≈160 KB install, transitive deps, audit surface).If you don’t rely on advanced
globbyoptions (streaming, gitignore, etc.) a native replacement would:
- reduce cold-start and install time
- eliminate one supply-chain risk
Otherwise add a comment explaining the feature gap that requires
globby.Let me know if you want a PoC patch.
packages/project-builder-cli/src/commands/diff.ts (1)
17-17: Minor wording nitIf you want a trailing period for consistency with other commands:
-'Show diff between generated output and current working directory' +'Show diff between generated output and current working directory.'Totally optional.
packages/project-builder-server/src/project-definition/get-single-app-directory-for-project.ts (1)
1-28: Well-implemented utility function with minor naming suggestion.The function is well-structured with proper error handling, TypeScript types, and JSDoc documentation. It correctly uses
AppUtils.getAppDirectory()for consistency with the broader refactoring.Consider renaming
matchedAppstomatchedAppsincefind()returns a single app or undefined:- const matchedApps = projectDefinition.apps.find((a) => a.name === app); + const matchedApp = projectDefinition.apps.find((a) => a.name === app); - if (!matchedApps) { + if (!matchedApp) { - return path.join(projectDirectory, AppUtils.getAppDirectory(matchedApps)); + return path.join(projectDirectory, AppUtils.getAppDirectory(matchedApp));Also, the JSDoc comment mentions throwing an error for "more than one apps matching the name", but the implementation would return the first match. Consider updating the comment if multiple matches are acceptable.
packages/project-builder-server/src/diff/snapshot/apply-diff-to-generator-output.ts (1)
35-42: Consider immutable update pattern for file contents.The current implementation directly mutates
fileData.contents, which could lead to unexpected side effects since it modifies the original FileData object.- fileData.contents = newContents; + generatorFiles.set(fileEntry.path, { + ...fileData, + contents: newContents, + });packages/project-builder-server/src/project-definition/load-project-definition.ts (1)
47-49: Consider safer type handling for parsed JSON.The type assertion
as ProjectDefinitionon line 48 could be unsafe if the JSON structure doesn't match expectations. TherunSchemaMigrationsfunction should handle validation, but it's worth ensuring this is robust.Consider adding explicit validation or letting the migration function handle any type mismatches:
- const { migratedDefinition, appliedMigrations } = runSchemaMigrations( - projectJson as ProjectDefinition, - ); + const { migratedDefinition, appliedMigrations } = runSchemaMigrations( + projectJson as ProjectDefinition, // Migration function validates structure + );packages/project-builder-server/src/diff/snapshot/snapshot-utils.ts (1)
20-29: Note the limitation with underscore handling.The implementation is correct for path separators, but original filenames containing underscores will be converted to path separators during round-trip conversion. This limitation is acknowledged in the tests, but consider documenting it in the function comment for clarity.
/** * Converts a safe diff filename back to the original file path * Example: "src_components_button.tsx.diff" -> "src/components/button.tsx" + * Note: Original underscores in filenames will be converted to path separators */packages/project-builder-server/src/diff/diff-utils.ts (1)
80-104: Consider adding error handling for globby operations.The function implementation is good, but consider wrapping the globby call in try-catch for better error handling.
export async function scanWorkingDirectory( directory: string, globPatterns?: string[], ignoreInstance?: ignore.Ignore, ): Promise<string[]> { // Create glob pattern to match all files const patterns = globPatterns && globPatterns.length > 0 ? globPatterns : ['**/*']; - const files = await globby(patterns, { - cwd: directory, - onlyFiles: true, - fs: fsAdapter, - gitignore: true, - absolute: false, // Return relative paths - }); + try { + const files = await globby(patterns, { + cwd: directory, + onlyFiles: true, + fs: fsAdapter, + gitignore: true, + absolute: false, // Return relative paths + }); + + // Filter files using ignore patterns and glob patterns + return files.filter((filePath) => + shouldIncludeFile(filePath, globPatterns, ignoreInstance), + ); + } catch (error) { + throw new Error(`Failed to scan directory: ${error instanceof Error ? error.message : String(error)}`); + } - - // Filter files using ignore patterns and glob patterns - return files.filter((filePath) => - shouldIncludeFile(filePath, globPatterns, ignoreInstance), - ); }packages/project-builder-server/src/diff/snapshot/snapshot-management.ts (1)
53-149: Consider refactoring this long function into smaller helper functions.This function is 96 lines long with complex nested logic. Consider extracting the logic for handling deleted files (lines 88-97) and modified/added files (lines 98-139) into separate helper functions for better maintainability and testability.
| export async function saveSnapshot( | ||
| directory: string, | ||
| generatorOutput: GeneratorOutput, | ||
| { ignoreInstance, snapshotDir }: SaveSnapshotOptions = {}, | ||
| ): Promise<SaveSnapshotResult> { | ||
| // Get current diff state | ||
| const diffSummary = await compareFiles( | ||
| directory, | ||
| generatorOutput, | ||
| undefined, | ||
| ignoreInstance, | ||
| ); | ||
|
|
||
| // Create snapshot directory structure | ||
| const snapshotDirectory = await createSnapshotDirectory( | ||
| directory, | ||
| snapshotDir, | ||
| ); | ||
|
|
||
| // Create manifest | ||
| const { diffs } = diffSummary; | ||
|
|
||
| // For now, we ignore binary modifications | ||
| const modifiedTextDiffs = diffs.filter( | ||
| (diff) => diff.type === 'modified' && !diff.isBinary, | ||
| ); | ||
| const manifest: SnapshotManifest = { | ||
| version: SNAPSHOT_VERSION, | ||
| files: { | ||
| modified: modifiedTextDiffs.map((diff) => ({ | ||
| path: diff.path, | ||
| diffFile: pathToSafeDiffFilename(diff.path), | ||
| })), | ||
| added: diffs | ||
| .filter((diff) => diff.type === 'added') | ||
| .map((diff) => diff.path), | ||
| deleted: diffs | ||
| .filter((diff) => diff.type === 'deleted') | ||
| .map((diff) => diff.path), | ||
| }, | ||
| }; | ||
|
|
||
| // Clear out existing diffs | ||
| await rm(snapshotDirectory.diffsPath, { recursive: true }); | ||
| await mkdir(snapshotDirectory.diffsPath, { recursive: true }); | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add error handling for directory operations.
The function clears the diffs directory but doesn't handle potential errors during the recursive operations.
// Clear out existing diffs
- await rm(snapshotDirectory.diffsPath, { recursive: true });
+ await rm(snapshotDirectory.diffsPath, { recursive: true, force: true });
await mkdir(snapshotDirectory.diffsPath, { recursive: true });Adding force: true ensures the operation succeeds even if the directory doesn't exist.
🤖 Prompt for AI Agents
In packages/project-builder-server/src/diff/snapshot/save-snapshot.ts between
lines 40 and 85, the code clears the diffs directory using rm and mkdir without
error handling. To fix this, add the option force: true to the rm call to avoid
errors if the directory does not exist, and consider wrapping these directory
operations in try-catch blocks or handling promise rejections to properly manage
any errors during recursive directory removal or creation.
| import type { SchemaParserContext } from '@baseplate-dev/project-builder-lib'; | ||
| import type { Logger } from '@baseplate-dev/sync'; | ||
|
|
||
| import { enhanceErrorWithContext } from '@baseplate-dev/utils'; | ||
| import { handleFileNotFoundError } from '@baseplate-dev/utils/node'; | ||
| import { readFile } from 'node:fs/promises'; | ||
| import path from 'node:path'; | ||
|
|
||
| import type { GeneratorOperations } from '#src/sync/types.js'; | ||
|
|
||
| import { compileApplications } from '#src/compiler/index.js'; | ||
| import { getSingleAppDirectoryForProject } from '#src/project-definition/get-single-app-directory-for-project.js'; | ||
| import { loadProjectDefinition } from '#src/project-definition/load-project-definition.js'; | ||
| import { createTemplateMetadataOptions } from '#src/sync/template-metadata-utils.js'; | ||
| import { DEFAULT_GENERATOR_OPERATIONS } from '#src/sync/types.js'; | ||
|
|
||
| import { | ||
| removeSnapshotDiffFile, | ||
| saveSnapshotDiffFile, | ||
| } from './snapshot-diff-utils.js'; | ||
| import { | ||
| initializeSnapshotManifest, | ||
| loadSnapshotManifest, | ||
| saveSnapshotManifest, | ||
| snapshotManifestUtils, | ||
| } from './snapshot-manifest.js'; | ||
| import { resolveSnapshotDirectory } from './snapshot-utils.js'; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Sort imports by group: external libraries first, then local imports.
The imports should be reorganized to follow the coding guidelines. External packages should come before local imports.
import type { SchemaParserContext } from '@baseplate-dev/project-builder-lib';
import type { Logger } from '@baseplate-dev/sync';
-
import { enhanceErrorWithContext } from '@baseplate-dev/utils';
import { handleFileNotFoundError } from '@baseplate-dev/utils/node';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import type { GeneratorOperations } from '#src/sync/types.js';
-
import { compileApplications } from '#src/compiler/index.js';
import { getSingleAppDirectoryForProject } from '#src/project-definition/get-single-app-directory-for-project.js';
import { loadProjectDefinition } from '#src/project-definition/load-project-definition.js';
import { createTemplateMetadataOptions } from '#src/sync/template-metadata-utils.js';
import { DEFAULT_GENERATOR_OPERATIONS } from '#src/sync/types.js';
-
import {
removeSnapshotDiffFile,
saveSnapshotDiffFile,
} from './snapshot-diff-utils.js';
import {
initializeSnapshotManifest,
loadSnapshotManifest,
saveSnapshotManifest,
snapshotManifestUtils,
} from './snapshot-manifest.js';
import { resolveSnapshotDirectory } from './snapshot-utils.js';Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/project-builder-server/src/diff/snapshot/snapshot-management.ts
lines 1 to 27, the imports are not sorted correctly. Reorder the imports so that
all external libraries (like 'node:fs/promises', 'node:path', and packages
starting with '@baseplate-dev') come first, followed by local imports (those
starting with './' or '#src/'). Group and sort them alphabetically within these
categories to follow the coding guidelines.
| logger.info(`Snapshot contents (${snapshotDir.path}):`); | ||
|
|
||
| if (manifest.files.modified.length > 0) { | ||
| logger.info(`\\nModified files (${manifest.files.modified.length}):`); |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify that the logger correctly interprets escaped newline characters.
The escaped \n characters in the logger output might render literally instead of as newlines, depending on the logger implementation.
If the logger doesn't interpret escape sequences, consider using separate logger calls instead:
- logger.info(`\\nModified files (${manifest.files.modified.length}):`);
+ logger.info('');
+ logger.info(`Modified files (${manifest.files.modified.length}):`);Also applies to: 259-259, 266-266
🏁 Script executed:
#!/bin/bash
# Search for the Logger type definition and its usage to understand how it handles escape sequences
ast-grep --pattern 'interface Logger {
$$$
}'
# Search for logger implementations
rg -A 10 "class.*Logger|function.*createLogger|export.*logger" --type tsLength of output: 5501
🏁 Script executed:
#!/bin/bash
echo "=== Logger import in snapshot-management.ts ==="
rg -n "import .*logger" packages/project-builder-server/src/diff/snapshot/snapshot-management.ts
echo
echo "=== Logger usage around lines 240-280 ==="
sed -n '240,280p' packages/project-builder-server/src/diff/snapshot/snapshot-management.ts
echo
echo "=== Evented Logger implementation (first 200 lines) ==="
sed -n '1,200p' packages/sync/src/utils/evented-logger.tsLength of output: 3278
Replace literal “\n” escapes with real newlines or separate logger calls
Our investigation shows that the EventedLogger (and console.info) prints strings as-is—it won’t turn "\n" sequences embedded in the string into line breaks when you escape the backslash ("\\n"). As a result, you’ll see a literal \n in the output instead of an empty line. To restore the intended formatting, update each of these calls in
packages/project-builder-server/src/diff/snapshot/snapshot-management.ts:
• Around line 254 (Modified files)
• Around line 259 (Added files)
• Around line 266 (Deleted files)
Example fix for “Modified files”:
- logger.info(`\\nModified files (${manifest.files.modified.length}):`);
+ // print a blank line, then the header
+ logger.info('');
+ logger.info(`Modified files (${manifest.files.modified.length}):`);Apply the same change to the “Added files” and “Deleted files” sections. This ensures you get a real blank line before each header.
📝 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.
| logger.info(`\\nModified files (${manifest.files.modified.length}):`); | |
| // print a blank line, then the header | |
| logger.info(''); | |
| logger.info(`Modified files (${manifest.files.modified.length}):`); |
🤖 Prompt for AI Agents
In packages/project-builder-server/src/diff/snapshot/snapshot-management.ts at
lines 252, 257, and 264, replace the literal string "\\n" in logger.info calls
with actual newline characters or separate the calls to produce real blank lines
before the headers "Modified files", "Added files", and "Deleted files". This
will ensure the output shows proper line breaks instead of the literal "\n"
sequence.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
packages/project-builder-server/src/diff/snapshot/snapshot-management.ts (2)
1-27: Sort imports by group: external libraries first, then local imports.
252-252: Replace literal "\n" escapes with real newlines or separate logger calls.Also applies to: 259-259, 266-266
🧹 Nitpick comments (2)
packages/project-builder-server/src/diff/snapshot/snapshot-management.ts (2)
209-215: Reduce interface duplication by extending from SnapshotManagementOptions.The
SnapshotListOptionsinterface duplicates most fields fromSnapshotManagementOptions. Consider refactoring to follow the DRY principle.-export interface SnapshotListOptions { - projectDirectory: string; - appName: string; - snapshotDirectory?: string; - context: SchemaParserContext; - logger: Logger; -} +export interface SnapshotListOptions extends Omit<SnapshotManagementOptions, 'generatorOperations'> {}
201-206: Use consistent error handling pattern across functions.The error handling here differs from other functions in this module. Consider using
enhanceErrorWithContextfor consistency.} catch (error) { - logger.error( - `Failed to remove files from snapshot: ${(error as Error).message}`, - ); - throw error; + throw enhanceErrorWithContext(error, `Failed to remove files from snapshot`); }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
packages/project-builder-server/src/diff/snapshot/create-snapshot-for-project.ts(1 hunks)packages/project-builder-server/src/diff/snapshot/snapshot-diff-utils.ts(1 hunks)packages/project-builder-server/src/diff/snapshot/snapshot-management.ts(1 hunks)packages/project-builder-server/src/sync/generate-for-directory.ts(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/project-builder-server/src/diff/snapshot/snapshot-diff-utils.ts
- packages/project-builder-server/src/diff/snapshot/create-snapshot-for-project.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (CLAUDE.md)
**/*.{ts,tsx}: Import UI components from the@baseplate-dev/ui-componentspackage as shown in the provided examples.
Use both standalone and React Hook Form controller variants for form components from@baseplate-dev/ui-componentsas appropriate.
If a particular interface or type is not exported, change the file so it is exported.
**/*.{ts,tsx}: TypeScript with strict type checking
Always include return types on top-level functions including React components (React.ReactElement)
Include absolute paths in import statements via tsconfig paths (@src/is the alias forsrc/)
If a particular interface or type is not exported, change the file so it is exported
Files:
packages/project-builder-server/src/diff/snapshot/snapshot-management.tspackages/project-builder-server/src/sync/generate-for-directory.ts
**/*.{js,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/code-style.mdc)
Node 16 module resolution - include file extensions in imports (
.js)
Files:
packages/project-builder-server/src/diff/snapshot/snapshot-management.tspackages/project-builder-server/src/sync/generate-for-directory.ts
**/*.{ts,tsx,js}
📄 CodeRabbit Inference Engine (.cursor/rules/code-style.mdc)
**/*.{ts,tsx,js}: Sort imports by group: external libs first, then local imports
Use camelCase for variables/functions, PascalCase for types/classes
Order functions such that functions are placed below the variables/functions they use
We use the prefer using nullish coalescing operator (??) ESLint rule instead of a logical or (||), as it is a safer operator
Use console.info/warn/error instead of console.log
Files:
packages/project-builder-server/src/diff/snapshot/snapshot-management.tspackages/project-builder-server/src/sync/generate-for-directory.ts
**/*
📄 CodeRabbit Inference Engine (.cursor/rules/code-style.mdc)
Use kebab-case for file names
Files:
packages/project-builder-server/src/diff/snapshot/snapshot-management.tspackages/project-builder-server/src/sync/generate-for-directory.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-22T09:09:23.016Z
Learning: Applies to .changeset/*.md : When adding a new feature or changing an existing feature, add a new Changeset in the `.changeset/` directory in the specified markdown format.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/ui-rules.mdc:0-0
Timestamp: 2025-07-22T09:11:29.223Z
Learning: Applies to {packages/project-builder-web/**,packages/ui-components/**}/*.tsx : Use ShadCN-based components from `@baseplate-dev/ui-components` and always prefer these components over creating custom ones
packages/project-builder-server/src/diff/snapshot/snapshot-management.ts (19)
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{js,ts,tsx} : Node 16 module resolution - include file extensions in imports (.js)
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-22T09:09:23.016Z
Learning: Applies to **/*.{ts,tsx} : If a particular interface or type is not exported, change the file so it is exported.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{ts,tsx} : If a particular interface or type is not exported, change the file so it is exported
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{ts,tsx} : Include absolute paths in import statements via tsconfig paths (@src/ is the alias for src/)
Learnt from: kingston
PR: #571
File: packages/core-generators/src/renderers/extractor/plugins/typed-templates-file.ts:102-106
Timestamp: 2025-06-11T18:31:22.247Z
Learning: For templateExtractorBarrelExportPlugin.addGeneratedBarrelExport, the generated barrel exports are written into generated/index.ts, therefore the moduleSpecifier must be specified relative to that file (e.g., ./typed-templates.js), not the project root.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-06-30T11:52:28.745Z
Learning: Applies to src/mocks/**/*.{ts,tsx} : Manual mocks are in src/__mocks__/ directory
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-22T09:11:16.930Z
Learning: Applies to src/mocks/**/*.ts : Manual mocks are in src/__mocks__/ directory
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-22T09:11:16.930Z
Learning: Applies to **/*.test.{ts,tsx} : For file system operations in tests, use memfs and mock 'node:fs' and 'node:fs/promises'
Learnt from: kingston
PR: #562
File: plugins/plugin-auth/package.json:32-36
Timestamp: 2025-06-03T09:11:29.651Z
Learning: With TypeScript project references, TypeScript compilation is watched from the root level using "watch:tsc:root" script, so individual packages no longer need to include their "tsc:watch" scripts in their local "watch" commands. The local "tsc:watch" scripts are renamed from "watch:tsc" but are not meant to be run as part of the package's watch command since TypeScript watching is handled centrally at the workspace root.
Learnt from: kingston
PR: #539
File: scripts/check-changesets.ts:10-13
Timestamp: 2025-05-08T12:56:59.222Z
Learning: Node.js 20.12.0 and above include globSync in the core node:fs module, so import { promises as fs, globSync } from 'node:fs'; is valid syntax in projects using these Node.js versions.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{ts,tsx,js} : Sort imports by group: external libs first, then local imports
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/ui-rules.mdc:0-0
Timestamp: 2025-07-22T09:11:29.223Z
Learning: Applies to {packages/project-builder-web/,packages/ui-components/}/*.tsx : Use ShadCN-based components from @baseplate-dev/ui-components and always prefer these components over creating custom ones
Learnt from: kingston
PR: #428
File: packages/project-builder-server/src/sync/index.ts:5-5
Timestamp: 2025-01-23T09:12:46.178Z
Learning: Avoid importing directly from 'dist' directories. Instead, expose functionality through the package's public API and import from the main package entry point.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-22T09:09:23.016Z
Learning: Applies to **/*.{ts,tsx} : Import UI components from the @baseplate-dev/ui-components package as shown in the provided examples.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{ts,tsx,js} : Order functions such that functions are placed below the variables/functions they use
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-22T09:11:16.930Z
Learning: Refactor code to be more easily testable, such as exporting types or functions
Learnt from: kingston
PR: #521
File: packages/react-generators/src/generators/admin/admin-crud-edit/admin-crud-edit.generator.ts:90-94
Timestamp: 2025-05-05T06:36:50.687Z
Learning: In this codebase, import paths can include .ts extensions, and the resolveModuleSpecifier function will handle them appropriately. There's no need to strip file extensions before passing paths to functions like TsCodeUtils.importFragment.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{ts,tsx,js} : Use console.info/warn/error instead of console.log
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-22T09:09:23.016Z
Learning: Run pnpm lint:affected and pnpm typecheck before committing changes.
packages/project-builder-server/src/sync/generate-for-directory.ts (17)
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-22T09:09:23.016Z
Learning: Applies to **/*.{ts,tsx} : If a particular interface or type is not exported, change the file so it is exported.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{ts,tsx} : If a particular interface or type is not exported, change the file so it is exported
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{ts,tsx} : Include absolute paths in import statements via tsconfig paths (@src/ is the alias for src/)
Learnt from: kingston
PR: #562
File: plugins/plugin-auth/package.json:32-36
Timestamp: 2025-06-03T09:11:29.651Z
Learning: With TypeScript project references, TypeScript compilation is watched from the root level using "watch:tsc:root" script, so individual packages no longer need to include their "tsc:watch" scripts in their local "watch" commands. The local "tsc:watch" scripts are renamed from "watch:tsc" but are not meant to be run as part of the package's watch command since TypeScript watching is handled centrally at the workspace root.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{js,ts,tsx} : Node 16 module resolution - include file extensions in imports (.js)
Learnt from: kingston
PR: #609
File: packages/ui-components/src/components/badge/badge-with-icon.stories.tsx:3-3
Timestamp: 2025-07-14T12:02:36.595Z
Learning: For TypeScript/TSX files: #src/ is the new path alias standard for src/ directory imports, replacing the previous @src/ convention.
Learnt from: kingston
PR: #539
File: scripts/check-changesets.ts:10-13
Timestamp: 2025-05-08T12:56:59.222Z
Learning: Node.js 20.12.0 and above include globSync in the core node:fs module, so import { promises as fs, globSync } from 'node:fs'; is valid syntax in projects using these Node.js versions.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/ui-rules.mdc:0-0
Timestamp: 2025-07-22T09:11:29.223Z
Learning: Applies to {packages/project-builder-web/,packages/ui-components/}/*.tsx : Use ShadCN-based components from @baseplate-dev/ui-components and always prefer these components over creating custom ones
Learnt from: kingston
PR: #606
File: plugins/plugin-auth/src/auth/core/generators/auth-apollo/auth-apollo.generator.ts:24-32
Timestamp: 2025-07-12T19:56:08.559Z
Learning: For generator functions and configuration object methods like those in createGeneratorTask, inferred return types are acceptable when the structure is clear from the implementation. ESLint rules handle enforcement of explicit return types where truly needed, so manual review for this is not necessary.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-22T09:09:23.016Z
Learning: Applies to **/*.{ts,tsx} : Import UI components from the @baseplate-dev/ui-components package as shown in the provided examples.
Learnt from: kingston
PR: #428
File: packages/project-builder-server/src/sync/index.ts:5-5
Timestamp: 2025-01-23T09:12:46.178Z
Learning: Avoid importing directly from 'dist' directories. Instead, expose functionality through the package's public API and import from the main package entry point.
Learnt from: kingston
PR: #539
File: scripts/check-changesets.ts:10-13
Timestamp: 2025-05-08T12:56:59.222Z
Learning: Node.js 22.0.0 and later versions include both glob and globSync functionality in the core node:fs module, making import { promises as fs, globSync } from 'node:fs'; valid syntax.
Learnt from: kingston
PR: #592
File: plugins/plugin-auth/src/auth0/generators/react/auth0-hooks/templates/src/hooks/use-required-user-id.ts:1-2
Timestamp: 2025-07-07T18:24:17.522Z
Learning: Files under templates/** directories can use // @ts-nocheck because they are templates meant for code generation, not direct type checking.
Learnt from: kingston
PR: #571
File: packages/core-generators/src/renderers/extractor/plugins/typed-templates-file.ts:102-106
Timestamp: 2025-06-11T18:31:22.247Z
Learning: For templateExtractorBarrelExportPlugin.addGeneratedBarrelExport, the generated barrel exports are written into generated/index.ts, therefore the moduleSpecifier must be specified relative to that file (e.g., ./typed-templates.js), not the project root.
Learnt from: kingston
PR: #521
File: packages/react-generators/src/generators/admin/admin-components/admin-components.generator.ts:55-61
Timestamp: 2025-05-05T06:35:13.300Z
Learning: In generators, paths should be merged with forward slashes (/) only since JavaScript generated files use POSIX style separators. The system handles conversion to Windows style separators at later stages when writing out files.
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/dev-commands.mdc:0-0
Timestamp: 2025-07-22T09:11:00.767Z
Learning: Build the project from the repository root using pnpm build
Learnt from: CR
PR: halfdomelabs/baseplate#0
File: .cursor/rules/dev-commands.mdc:0-0
Timestamp: 2025-07-22T09:11:00.767Z
Learning: Build a package using pnpm build from within the package directory
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Lint
- GitHub Check: Test E2E
🔇 Additional comments (5)
packages/project-builder-server/src/sync/generate-for-directory.ts (5)
8-8: LGTM! Import changes support the snapshot functionality correctly.The import additions properly follow the coding guidelines with file extensions, absolute paths using the
#src/alias, and appropriate grouping. The refactoring to importGeneratorOperationsfromtypes.jsand the new snapshot-related imports align well with the PR's snapshot management objectives.Also applies to: 17-17, 19-24
36-37: Interface changes improve clarity and add snapshot support.The rename from
forceOverwritetooverwriteis more concise and clear. The addition of the optionalsnapshotDirectoryparameter properly supports the new snapshot functionality while maintaining backward compatibility.
47-47: Function parameters correctly implement the interface changes.The use of
DEFAULT_GENERATOR_OPERATIONSas the default value and the parameter renaming fromforceOverwritetooverwritealign properly with the interface updates. The newsnapshotDirectoryparameter is correctly destructured.Also applies to: 50-51
60-60: Well-implemented snapshot application logic with comprehensive error handling.The snapshot application logic is properly structured with:
- Correct conditional checking for the
overwriteflag- Proper async/await usage for snapshot operations
- Comprehensive error handling with informative messages directing users to fix conflicts
- Good logging practices with clear info and error messages
- Appropriate variable mutation pattern (changing
outputfromconsttolet)The flow from resolving the snapshot directory to loading the manifest and applying diffs is logical and robust.
Also applies to: 66-94
130-130: Correct parameter mapping for the renamed variable.The change properly maps the renamed
overwriteparameter to the expectedforceOverwriteproperty, maintaining compatibility with thewriteGeneratorOutputAPI while using the clearer internal parameter name.
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Chores
Tests
Documentation