Skip to content

fix: normalize spaced project names#193

Merged
4 commits merged intomainfrom
codex/cli-name-normalization
Mar 20, 2026
Merged

fix: normalize spaced project names#193
4 commits merged intomainfrom
codex/cli-name-normalization

Conversation

@eluce2
Copy link
Copy Markdown
Collaborator

@eluce2 eluce2 commented Mar 20, 2026

  • remove --ui from init help
  • normalize spaces to dashes in project names
  • add changesets

Checks:

  • pnpm --filter @proofkit/cli typecheck pass
  • pnpm --filter @proofkit/cli test -- --run tests/init-non-interactive-failures.test.ts tests/project-name.test.ts pass
  • pnpm run ci fails in @proofkit/registry on sandboxed tsx IPC listen EPERM

Summary by CodeRabbit

  • Breaking Changes

    • Removed the --ui CLI flag; init now always scaffolds the shadcn UI.
  • New Features

    • Project names with spaces are normalized to dashes and lowercased.
    • Init now generates a .cursorignore and includes an agents reference file in new projects.
  • Documentation

    • Clarified that . during init refers to the current directory.
  • Tests

    • Expanded tests for name normalization, absence of --ui help, and generated files.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
proofkit-docs Ready Ready Preview Mar 20, 2026 2:23pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 20, 2026

🦋 Changeset detected

Latest commit: fe43be6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@proofkit/cli Patch

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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 20, 2026

Open in StackBlitz

@proofkit/better-auth

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/better-auth@193

@proofkit/cli

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/cli@193

create-proofkit

pnpm add https://pkg.pr.new/proofgeist/proofkit/create-proofkit@193

@proofkit/fmdapi

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/fmdapi@193

@proofkit/fmodata

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/fmodata@193

@proofkit/typegen

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/typegen@193

@proofkit/webviewer

pnpm add https://pkg.pr.new/proofgeist/proofkit/@proofkit/webviewer@193

commit: fe43be6

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 96c5ad34-e183-43c9-b7ca-fed7a70af93e

📥 Commits

Reviewing files that changed from the base of the PR and between 4f40bfe and fe43be6.

⛔ Files ignored due to path filters (2)
  • packages/cli/template/nextjs-mantine/public/favicon.ico is excluded by !**/*.ico
  • packages/cli/template/nextjs-mantine/public/proofkit.png is excluded by !**/*.png
📒 Files selected for processing (39)
  • .changeset/mean-worms-notice.md
  • packages/cli/src/helpers/createProject.ts
  • packages/cli/src/helpers/scaffoldProject.ts
  • packages/cli/src/services/live.ts
  • packages/cli/src/state.ts
  • packages/cli/template/nextjs-mantine/AGENTS.md
  • packages/cli/template/nextjs-mantine/CLAUDE.md
  • packages/cli/template/nextjs-mantine/README.md
  • packages/cli/template/nextjs-mantine/_gitignore
  • packages/cli/template/nextjs-mantine/components.json
  • packages/cli/template/nextjs-mantine/next.config.ts
  • packages/cli/template/nextjs-mantine/package.json
  • packages/cli/template/nextjs-mantine/postcss.config.cjs
  • packages/cli/template/nextjs-mantine/proofkit.json
  • packages/cli/template/nextjs-mantine/src/app/(main)/layout.tsx
  • packages/cli/template/nextjs-mantine/src/app/(main)/page.tsx
  • packages/cli/template/nextjs-mantine/src/app/layout.tsx
  • packages/cli/template/nextjs-mantine/src/app/navigation.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppLogo.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/AppShell.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/Header.module.css
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/Header.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/HeaderMobileMenu.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/HeaderNavLink.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/config.ts
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-center.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-left.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-mobile-content.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-right.tsx
  • packages/cli/template/nextjs-mantine/src/config/env.ts
  • packages/cli/template/nextjs-mantine/src/config/theme/globals.css
  • packages/cli/template/nextjs-mantine/src/config/theme/mantine-theme.ts
  • packages/cli/template/nextjs-mantine/src/server/safe-action.ts
  • packages/cli/template/nextjs-mantine/src/utils/notification-helpers.ts
  • packages/cli/template/nextjs-mantine/src/utils/styles.ts
  • packages/cli/template/nextjs-mantine/tsconfig.json
  • packages/cli/tests/init-fixtures.ts
  • packages/cli/tests/init-run-init-regression.test.ts
  • packages/cli/tests/test-layer.ts
💤 Files with no reviewable changes (31)
  • packages/cli/template/nextjs-mantine/AGENTS.md
  • packages/cli/template/nextjs-mantine/README.md
  • packages/cli/template/nextjs-mantine/proofkit.json
  • packages/cli/template/nextjs-mantine/src/components/AppLogo.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/config.ts
  • packages/cli/template/nextjs-mantine/postcss.config.cjs
  • packages/cli/template/nextjs-mantine/package.json
  • packages/cli/template/nextjs-mantine/src/server/safe-action.ts
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/AppShell.tsx
  • packages/cli/template/nextjs-mantine/src/config/env.ts
  • packages/cli/template/nextjs-mantine/_gitignore
  • packages/cli/template/nextjs-mantine/src/app/(main)/layout.tsx
  • packages/cli/template/nextjs-mantine/src/utils/styles.ts
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/HeaderMobileMenu.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/Header.module.css
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-right.tsx
  • packages/cli/template/nextjs-mantine/components.json
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/Header.tsx
  • packages/cli/template/nextjs-mantine/next.config.ts
  • packages/cli/template/nextjs-mantine/src/config/theme/mantine-theme.ts
  • packages/cli/template/nextjs-mantine/src/config/theme/globals.css
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-left.tsx
  • packages/cli/template/nextjs-mantine/src/app/(main)/page.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-mobile-content.tsx
  • packages/cli/template/nextjs-mantine/src/app/navigation.tsx
  • packages/cli/template/nextjs-mantine/tsconfig.json
  • packages/cli/template/nextjs-mantine/src/app/layout.tsx
  • packages/cli/template/nextjs-mantine/src/utils/notification-helpers.ts
  • packages/cli/template/nextjs-mantine/CLAUDE.md
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/HeaderNavLink.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-center.tsx
✅ Files skipped from review due to trivial changes (3)
  • .changeset/mean-worms-notice.md
  • packages/cli/src/state.ts
  • packages/cli/tests/init-run-init-regression.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/tests/init-fixtures.ts

📝 Walkthrough

Walkthrough

Removes the --ui init flag and hardcodes UI to shadcn; normalizes project names by converting whitespace to dashes and lowercasing; treats . as the current directory for init; adds CLAUDE.md to templates and writes a .cursorignore file during scaffolding; tests updated accordingly.

Changes

Cohort / File(s) Summary
Changesets
./.changeset/remove-cli-ui-flag.md, ./.changeset/soften-project-name-spaces.md, ./.changeset/tidy-dots-speak.md, ./.changeset/cli-init-claude-cursorignore.md, ./.changeset/fix-cli-dot-name-normalization.md, ./.changeset/mean-worms-notice.md
Added multiple changeset entries documenting removal of --ui, project-name normalization (whitespace→dash + lowercase), . handling for init, CLAUDE/.cursorignore additions, and removal of Mantine scaffold.
CLI init & entry
packages/cli/src/cli/init.ts, packages/cli/src/index.ts
Removed --ui option and CliFlags.ui; state.ui and generated proofkit.json now always use "shadcn"; init help updated to clarify . usage.
Project name normalization & validation
packages/cli/src/utils/parseNameAndPath.ts, packages/cli/src/utils/projectName.ts, packages/cli/src/utils/validateAppName.ts
Normalize inputs by trimming trailing slashes, replacing whitespace sequences with -, and lowercasing; introduced normalizeProjectNameForPackage() and applied normalization to . (cwd) cases.
Scaffold/templates & plan
packages/cli/src/helpers/scaffoldProject.ts, packages/cli/src/core/planInit.ts, packages/cli/src/services/live.ts, packages/cli/src/createProject.ts, packages/cli/src/state.ts
Always select nextjs-shadcn for browser scaffolds (removed mantine path), add .cursorignore write to init plan, and set default ui fallback to shadcn; updated template service to ignore ui param.
Template content removals/changes
packages/cli/template/nextjs-mantine/... (many files removed), packages/cli/template/nextjs-shadcn/CLAUDE.md, packages/cli/template/vite-wv/CLAUDE.md
Removed the Mantine template and many of its files; added/updated CLAUDE.md references in shadcn and vite-wv templates.
Tests & fixtures
packages/cli/tests/* (cli.test.ts, init-non-interactive-failures.test.ts, project-name.test.ts, init-fixtures.ts, init-scaffold-contract.test.ts, integration.test.ts, legacy-project-name-utils.test.ts, init-run-init-regression.test.ts, test-layer.ts)
Updated/added tests to assert --ui absence, project-name whitespace→dash normalization and . behavior, and to validate generated CLAUDE.md and .cursorignore; test fixtures now return cursorIgnoreFile and template selection in test layer ignores ui.
Minor cosmetic
apps/docs/src/app/layout.tsx
Reordered an import only (no behavioral change).

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI as "ProofKit CLI (init)"
  participant NameUtils as "parseNameAndPath/validateAppName"
  participant TemplateSvc as "TemplateService"
  participant Scaffold as "scaffoldProject"
  participant FS as "Filesystem"

  User->>CLI: run `proofkit init [dir]` (no --ui)
  CLI->>NameUtils: normalize/validate project name (whitespace→dash, lowercased, handle ".")
  NameUtils-->>CLI: normalized name + path
  CLI->>TemplateSvc: getTemplateDir(appType, _ui) -- ui ignored
  TemplateSvc-->>CLI: template path (e.g., nextjs-shadcn)
  CLI->>Scaffold: scaffold chosen template into targetDir
  Scaffold->>FS: write scaffold files (including `CLAUDE.md`)
  Scaffold->>FS: write `.cursorignore` with content `CLAUDE.md\n`
  FS-->>Scaffold: write confirmations
  Scaffold-->>CLI: scaffold complete
  CLI-->>User: success (created project)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: normalize spaced project names' directly summarizes the main change: normalizing spaces to dashes in project names, which is a core objective documented in the PR description and reflected throughout the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/cli-name-normalization
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/cli/src/utils/parseNameAndPath.ts (1)

30-33: ⚠️ Potential issue | 🟠 Major

Normalize cwd-derived appName to match input normalization and validation.

When appName === ".", the code derives it from process.cwd() basename without normalizing. However, the initial input is normalized at line 24 (.replace(whitespaceRegex, "-").toLowerCase()), and validateAppName also normalizes cwd-derived names before validation. This creates an inconsistency: if the directory is /tmp/My App, validation passes (normalizes to my-app), but parseNameAndPath returns "My App" unnormalized, which then gets written to package.json as an invalid package name (spaces violate the valid name regex).

Normalize the cwd-derived appName to match the initial input normalization:

Suggested fix
  if (appName === ".") {
    const parsedCwd = pathModule.resolve(process.cwd());
    appName = pathModule.basename(parsedCwd);
    appName = appName.replace(whitespaceRegex, "-").toLowerCase();
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/utils/parseNameAndPath.ts` around lines 30 - 33, When
appName is set from the cwd in parseNameAndPath (the block checking if appName
=== "."), normalize it using the same logic as the initial input normalization
so it matches validateAppName; specifically, after deriving appName from
pathModule.basename(process.cwd()), run appName =
appName.replace(whitespaceRegex, "-").toLowerCase() so the cwd-derived name is
hyphenized and lowercased before being returned or written to package.json.
packages/cli/src/utils/validateAppName.ts (1)

19-21: ⚠️ Potential issue | 🟠 Major

The "." check bypasses validation.

When input === ".", the function returns undefined (valid) without actually validating that the current working directory name conforms to validationRegExp. This differs from projectName.ts (lines 41-46), which normalizes and validates the current directory name when the input is ".".

If the user runs the CLI in a directory with an invalid name (e.g., containing uppercase letters or special characters), this version would incorrectly report it as valid.

🐛 Proposed fix to validate the current directory name
-  if (input === "." || validationRegExp.test(appName ?? "")) {
-    return;
+  if (input === ".") {
+    const path = await import("node:path");
+    const currentDirName = path.basename(path.resolve(process.cwd()));
+    const normalizedDir = currentDirName.replace(whitespaceRegex, "-").toLowerCase();
+    return validationRegExp.test(normalizedDir)
+      ? undefined
+      : "Name must consist of only lowercase alphanumeric characters, '-', and '_'";
+  }
+
+  if (validationRegExp.test(appName ?? "")) {
+    return;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/utils/validateAppName.ts` around lines 19 - 21, The current
early-return when input === "." bypasses validation; in validateAppName replace
that branch so the code derives the current directory name (e.g., appName =
path.basename(process.cwd()) or same logic used in projectName.ts) and then run
validationRegExp.test(appName) instead of returning; update validateAppName to
normalize/compute appName for "." inputs, ensure validationRegExp is used
against that computed appName, and add an import for path if necessary so the
behavior matches projectName.ts's handling of ".".
packages/cli/src/utils/projectName.ts (1)

25-27: ⚠️ Potential issue | 🟡 Minor

Inconsistent normalization for "." case between parseNameAndPath and validateAppName.

When the input resolves to ".", parseNameAndPath uses the raw path.basename(process.cwd()) without applying whitespace-to-dash normalization or lowercasing (line 26). However, validateAppName (lines 43) does normalize the current directory name before validation.

This could lead to a mismatch: the project might be created with an unnormalized directory name (e.g., "My App") while validation expects the normalized form.

♻️ Proposed fix to normalize the cwd basename consistently
   if (scopedAppName === ".") {
-    scopedAppName = path.basename(path.resolve(process.cwd()));
+    scopedAppName = path.basename(path.resolve(process.cwd())).replace(WHITESPACE_REGEX, "-").toLowerCase();
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/utils/projectName.ts` around lines 25 - 27, parseNameAndPath
sets scopedAppName to path.basename(path.resolve(process.cwd())) when the input
is "." but doesn't apply the same whitespace-to-dash normalization and
lowercasing that validateAppName expects, causing inconsistent names; update
parseNameAndPath so that when scopedAppName === "." it computes the cwd basename
and then runs the same normalization routine (convert whitespace to dashes and
lowercase) before returning/using scopedAppName (ensure you reuse or mirror the
same normalization logic used in validateAppName to normalize the cwd basename).
🧹 Nitpick comments (1)
packages/cli/src/utils/parseNameAndPath.ts (1)

36-39: Redundant findIndex call.

indexOfDelimiter is already computed on line 36, but line 37 calls findIndex again with the same predicate. Use indexOfDelimiter in the condition instead.

♻️ Proposed fix
   // If the first part is a @, it's a scoped package
   const indexOfDelimiter = paths.findIndex((p) => p.startsWith("@"));
-  if (paths.findIndex((p) => p.startsWith("@")) !== -1) {
+  if (indexOfDelimiter !== -1) {
     appName = paths.slice(indexOfDelimiter).join("/");
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/utils/parseNameAndPath.ts` around lines 36 - 39, The code
computes indexOfDelimiter using paths.findIndex but then redundantly calls
paths.findIndex again in the if condition; replace the second findIndex call
with the computed indexOfDelimiter (i.e. use if (indexOfDelimiter !== -1) {
appName = paths.slice(indexOfDelimiter).join("/"); }) so the function
parseNameAndPath uses the existing indexOfDelimiter variable rather than calling
findIndex twice.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/cli/src/utils/parseNameAndPath.ts`:
- Around line 30-33: When appName is set from the cwd in parseNameAndPath (the
block checking if appName === "."), normalize it using the same logic as the
initial input normalization so it matches validateAppName; specifically, after
deriving appName from pathModule.basename(process.cwd()), run appName =
appName.replace(whitespaceRegex, "-").toLowerCase() so the cwd-derived name is
hyphenized and lowercased before being returned or written to package.json.

In `@packages/cli/src/utils/projectName.ts`:
- Around line 25-27: parseNameAndPath sets scopedAppName to
path.basename(path.resolve(process.cwd())) when the input is "." but doesn't
apply the same whitespace-to-dash normalization and lowercasing that
validateAppName expects, causing inconsistent names; update parseNameAndPath so
that when scopedAppName === "." it computes the cwd basename and then runs the
same normalization routine (convert whitespace to dashes and lowercase) before
returning/using scopedAppName (ensure you reuse or mirror the same normalization
logic used in validateAppName to normalize the cwd basename).

In `@packages/cli/src/utils/validateAppName.ts`:
- Around line 19-21: The current early-return when input === "." bypasses
validation; in validateAppName replace that branch so the code derives the
current directory name (e.g., appName = path.basename(process.cwd()) or same
logic used in projectName.ts) and then run validationRegExp.test(appName)
instead of returning; update validateAppName to normalize/compute appName for
"." inputs, ensure validationRegExp is used against that computed appName, and
add an import for path if necessary so the behavior matches projectName.ts's
handling of ".".

---

Nitpick comments:
In `@packages/cli/src/utils/parseNameAndPath.ts`:
- Around line 36-39: The code computes indexOfDelimiter using paths.findIndex
but then redundantly calls paths.findIndex again in the if condition; replace
the second findIndex call with the computed indexOfDelimiter (i.e. use if
(indexOfDelimiter !== -1) { appName = paths.slice(indexOfDelimiter).join("/");
}) so the function parseNameAndPath uses the existing indexOfDelimiter variable
rather than calling findIndex twice.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 730839a9-084a-42cd-9135-000f8025f990

📥 Commits

Reviewing files that changed from the base of the PR and between a024980 and 9add5ca.

📒 Files selected for processing (11)
  • .changeset/remove-cli-ui-flag.md
  • .changeset/soften-project-name-spaces.md
  • .changeset/tidy-dots-speak.md
  • packages/cli/src/cli/init.ts
  • packages/cli/src/index.ts
  • packages/cli/src/utils/parseNameAndPath.ts
  • packages/cli/src/utils/projectName.ts
  • packages/cli/src/utils/validateAppName.ts
  • packages/cli/tests/cli.test.ts
  • packages/cli/tests/init-non-interactive-failures.test.ts
  • packages/cli/tests/project-name.test.ts

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/cli/tests/integration.test.ts (1)

77-78: De-duplicate pointer-content literals in this suite

Consider constants for @AGENTS.md and .cursorignore content to avoid future drift between test blocks.

As per coding guidelines, "Use meaningful variable names instead of magic numbers - extract constants with descriptive names".

Also applies to: 204-205

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/tests/integration.test.ts` around lines 77 - 78, Extract the
literal expected strings "@AGENTS.md\n" and "CLAUDE.md\n" into descriptively
named constants (e.g., EXPECTED_AGENTS_POINTER_CONTENT and
EXPECTED_CURSORIGNORE_CONTENT) near the top of the test suite and replace
occurrences used in the assertions for claudeFile and cursorIgnoreFile (and the
other occurrences at the second block around the previously noted lines) so all
tests reference the same constants instead of duplicating magic literals.
packages/cli/tests/init-fixtures.ts (1)

34-55: Type the exported scaffold-artifact contract explicitly

Since this helper is shared across tests and keeps expanding, an explicit return type will prevent silent contract drift.

♻️ Proposed patch
+interface ScaffoldArtifacts {
+  packageJson: Record<string, unknown>;
+  proofkitJson: Record<string, unknown>;
+  envFile: string;
+  typegenConfig: string | undefined;
+  agentsFile: string | undefined;
+  claudeFile: string | undefined;
+  cursorIgnoreFile: string | undefined;
+  launchConfig: string | undefined;
+}
+
-export async function readScaffoldArtifacts(projectDir: string) {
+export async function readScaffoldArtifacts(projectDir: string): Promise<ScaffoldArtifacts> {
As per coding guidelines, "Use explicit types for function parameters and return values when they enhance clarity".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/tests/init-fixtures.ts` around lines 34 - 55, Add an explicit
exported return type for readScaffoldArtifacts to lock the scaffold-artifact
contract: define and export an interface (e.g., ReadScaffoldArtifactsResult)
listing each property (packageJson, proofkitJson, envFile, typegenConfig,
agentsFile, claudeFile, cursorIgnoreFile, launchConfig) with their correct types
(strings or undefined where pathExists makes them optional, and the JSON types
for packageJson/proofkitJson), then annotate the function signature as export
async function readScaffoldArtifacts(projectDir: string):
Promise<ReadScaffoldArtifactsResult> and ensure the returned object matches the
interface.
packages/cli/tests/init-scaffold-contract.test.ts (1)

151-153: Extract repeated agent-pointer literals into constants

"@AGENTS.md\n" and "CLAUDE.md\n" are duplicated across cases; constants make intent clearer and reduce drift.

🧹 Proposed patch
 const ansiStylePrefixPattern = /^[0-9;]*m/;
+const claudePointerContent = "@AGENTS.md\n" as const;
+const cursorIgnoreContent = "CLAUDE.md\n" as const;
@@
-    expect(readFileSync(join(browserProjectDir, "CLAUDE.md"), "utf-8")).toBe("@AGENTS.md\n");
-    expect(readFileSync(join(browserProjectDir, ".cursorignore"), "utf-8")).toBe("CLAUDE.md\n");
+    expect(readFileSync(join(browserProjectDir, "CLAUDE.md"), "utf-8")).toBe(claudePointerContent);
+    expect(readFileSync(join(browserProjectDir, ".cursorignore"), "utf-8")).toBe(cursorIgnoreContent);
@@
-    expect(readFileSync(join(webviewerProjectDir, "CLAUDE.md"), "utf-8")).toBe("@AGENTS.md\n");
-    expect(readFileSync(join(webviewerProjectDir, ".cursorignore"), "utf-8")).toBe("CLAUDE.md\n");
+    expect(readFileSync(join(webviewerProjectDir, "CLAUDE.md"), "utf-8")).toBe(claudePointerContent);
+    expect(readFileSync(join(webviewerProjectDir, ".cursorignore"), "utf-8")).toBe(cursorIgnoreContent);
As per coding guidelines, "Use meaningful variable names instead of magic numbers - extract constants with descriptive names".

Also applies to: 192-193

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/tests/init-scaffold-contract.test.ts` around lines 151 - 153,
Replace repeated string literals with named constants: define e.g. const
AGENTS_POINTER = "@AGENTS.md\n" and const CLAUDE_POINTER = "CLAUDE.md\n" at the
top of the test file, then use those constants in the expect assertions that
call readFileSync(join(browserProjectDir, "CLAUDE.md"), ...) and
readFileSync(join(browserProjectDir, ".cursorignore"), ...), and in any other
occurrences (including the other cases noted) so the expectations reference
AGENTS_POINTER and CLAUDE_POINTER instead of raw string literals.
🤖 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/cli/src/helpers/scaffoldProject.ts`:
- Line 132: The current call in scaffoldProject that unconditionally writes
".cursorignore" (fs.writeFileSync(path.join(projectDir, ".cursorignore"),
"CLAUDE.md\n", "utf8")) will clobber any existing ignores; change it to merge
safely by checking for an existing file (fs.existsSync / fs.readFileSync),
reading its contents, appending "CLAUDE.md" only if not already present (ensure
newline normalization and deduplication), and then write the merged content back
with fs.writeFileSync; reference scaffoldProject and the
projectDir/.cursorignore handling when implementing the read-merge-write
behavior.

---

Nitpick comments:
In `@packages/cli/tests/init-fixtures.ts`:
- Around line 34-55: Add an explicit exported return type for
readScaffoldArtifacts to lock the scaffold-artifact contract: define and export
an interface (e.g., ReadScaffoldArtifactsResult) listing each property
(packageJson, proofkitJson, envFile, typegenConfig, agentsFile, claudeFile,
cursorIgnoreFile, launchConfig) with their correct types (strings or undefined
where pathExists makes them optional, and the JSON types for
packageJson/proofkitJson), then annotate the function signature as export async
function readScaffoldArtifacts(projectDir: string):
Promise<ReadScaffoldArtifactsResult> and ensure the returned object matches the
interface.

In `@packages/cli/tests/init-scaffold-contract.test.ts`:
- Around line 151-153: Replace repeated string literals with named constants:
define e.g. const AGENTS_POINTER = "@AGENTS.md\n" and const CLAUDE_POINTER =
"CLAUDE.md\n" at the top of the test file, then use those constants in the
expect assertions that call readFileSync(join(browserProjectDir, "CLAUDE.md"),
...) and readFileSync(join(browserProjectDir, ".cursorignore"), ...), and in any
other occurrences (including the other cases noted) so the expectations
reference AGENTS_POINTER and CLAUDE_POINTER instead of raw string literals.

In `@packages/cli/tests/integration.test.ts`:
- Around line 77-78: Extract the literal expected strings "@AGENTS.md\n" and
"CLAUDE.md\n" into descriptively named constants (e.g.,
EXPECTED_AGENTS_POINTER_CONTENT and EXPECTED_CURSORIGNORE_CONTENT) near the top
of the test suite and replace occurrences used in the assertions for claudeFile
and cursorIgnoreFile (and the other occurrences at the second block around the
previously noted lines) so all tests reference the same constants instead of
duplicating magic literals.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f32be084-2253-4658-8560-8f33c5c72939

📥 Commits

Reviewing files that changed from the base of the PR and between 9add5ca and 03294e5.

📒 Files selected for processing (13)
  • .changeset/cli-init-claude-cursorignore.md
  • apps/docs/src/app/layout.tsx
  • packages/cli/src/core/planInit.ts
  • packages/cli/src/helpers/scaffoldProject.ts
  • packages/cli/template/nextjs-mantine/CLAUDE.md
  • packages/cli/template/nextjs-mantine/CLAUDE.md
  • packages/cli/template/nextjs-shadcn/CLAUDE.md
  • packages/cli/template/nextjs-shadcn/CLAUDE.md
  • packages/cli/template/vite-wv/CLAUDE.md
  • packages/cli/template/vite-wv/CLAUDE.md
  • packages/cli/tests/init-fixtures.ts
  • packages/cli/tests/init-scaffold-contract.test.ts
  • packages/cli/tests/integration.test.ts
✅ Files skipped from review due to trivial changes (9)
  • packages/cli/template/vite-wv/CLAUDE.md
  • packages/cli/template/vite-wv/CLAUDE.md
  • packages/cli/template/nextjs-shadcn/CLAUDE.md
  • apps/docs/src/app/layout.tsx
  • .changeset/cli-init-claude-cursorignore.md
  • packages/cli/template/nextjs-mantine/CLAUDE.md
  • packages/cli/template/nextjs-mantine/CLAUDE.md
  • packages/cli/template/nextjs-shadcn/CLAUDE.md
  • packages/cli/src/core/planInit.ts

@eluce2 eluce2 closed this pull request by merging all changes into main in e93ba31 Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant