Skip to content

Fix CLI app name normalization and make typegen API deps optional#195

Merged
eluce2 merged 9 commits intomainfrom
codex/check-webviewer-template-fmodata
Mar 20, 2026
Merged

Fix CLI app name normalization and make typegen API deps optional#195
eluce2 merged 9 commits intomainfrom
codex/check-webviewer-template-fmodata

Conversation

@eluce2
Copy link
Copy Markdown
Collaborator

@eluce2 eluce2 commented Mar 20, 2026

Summary

  • fix CLI app name parsing and normalization for spaced, dotted, and non-interactive project names
  • update scaffold/init flows and tests to match the new naming behavior
  • add the nextjs-mantine CLI template and related agent/docs files
  • make @proofkit/fmdapi and @proofkit/fmodata optional peers in @proofkit/typegen
  • lazy-load typegen fmdapi and fmodata paths so one install path does not require the other

Testing

  • pnpm run ci

Summary by CodeRabbit

  • New Features

    • Init now creates a CLAUDE.md (referencing agent instructions) and emits a .cursorignore to exclude it.
    • Project names with spaces are normalized to dashed, lowercased names.
  • Changed Behavior

    • The --ui flag was removed; init always scaffolds the shadcn template (mantine template removed).
    • TypeGen treats certain tooling as optional peers and loads them on demand to avoid hard-requiring unused packages.

@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 9:57pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 20, 2026

🦋 Changeset detected

Latest commit: 6da0c9a

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

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 20, 2026

Caution

Review failed

Pull request was closed or merged during review

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: 4db70776-c504-4324-a775-e5c06eb69335

📥 Commits

Reviewing files that changed from the base of the PR and between b2de39e and 6da0c9a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • .changeset/fair-lamps-taste.md
  • packages/typegen/src/server/createDataApiClient.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/fair-lamps-taste.md

📝 Walkthrough

Walkthrough

This PR defaults the CLI scaffold UI to shadcn (removing Mantine templates and the --ui flag), normalizes project names (spaces → dashes, lowercase, "." → cwd basename), writes CLAUDE.md and a .cursorignore on scaffolds, and makes @proofkit/fmdapi and @proofkit/fmodata optional peer deps with lazy/dynamic imports and standardized missing-dependency handling in typegen.

Changes

Cohort / File(s) Summary
Changesets
\.changeset/*
Added multiple patch changesets documenting CLI/init behavior changes and typegen optional-peer bumps.
CLI: init & flags
packages/cli/src/cli/init.ts, packages/cli/src/index.ts, packages/cli/src/state.ts
Removed --ui flag; state.ui now always "shadcn"; help text updated.
CLI: scaffolding & template selection
packages/cli/src/helpers/createProject.ts, packages/cli/src/helpers/scaffoldProject.ts, packages/cli/src/core/planInit.ts, packages/cli/src/services/live.ts
Dropped Mantine branches; always scaffold nextjs-shadcn for browser apps; plan/scaffold now emits CLAUDE.md and .cursorignore containing CLAUDE.md\n.
Mantine template removal
packages/cli/template/nextjs-mantine/*
Entire Mantine template removed (pages, components, configs, styles, package.json, etc.).
CLI: name handling
packages/cli/src/utils/parseNameAndPath.ts, packages/cli/src/utils/projectName.ts, packages/cli/src/utils/validateAppName.ts
Normalize final package segment: replace whitespace with -, lowercase; . resolves to normalized cwd basename; preserve leading path segments.
CLI: tests & fixtures
packages/cli/tests/*, packages/cli/tests/init-fixtures.ts
Tests added/updated to assert --ui removal, name normalization, presence/content of CLAUDE.md and .cursorignore; fixtures limit templates to supported ones.
Typegen: packaging
packages/typegen/package.json
Moved @proofkit/fmdapi and @proofkit/fmodata from dependencies → optional peerDependencies and kept them in devDependencies for development.
Typegen: dynamic loading & error handling
packages/typegen/src/optionalDeps.ts, packages/typegen/src/cli.ts, packages/typegen/src/typegen.ts, packages/typegen/src/getLayoutMetadata.ts
Added optional-dep helpers; converted many static imports to awaited dynamic import(); standardized missing-dependency detection/wrapping and error-code extraction.
Typegen: server & client
packages/typegen/src/server/createDataApiClient.ts, packages/typegen/src/server/app.ts
Converted client-creation APIs to async, dynamic-loaded fmdapi/fmodata, narrowed client shapes/types, awaited factory calls, and improved error handling/HTTP response shapes.
Minor
apps/docs/src/app/layout.tsx
Reordered import statements; no runtime behavior change.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor User
    participant CLI
    participant Parser as NameParser
    participant Planner as InitPlanner
    participant Scaffold
    participant FS as FileSystem

    User->>CLI: proofkit init <name>
    CLI->>Parser: parseNameAndPath(raw)
    Parser-->>CLI: normalizedName, path
    CLI->>Planner: runInit(state ui="shadcn")
    Planner->>Scaffold: scaffoldProject(nextjs-shadcn)
    Scaffold->>FS: copy template files
    Scaffold->>FS: write `CLAUDE.md`
    Scaffold->>FS: write `.cursorignore` ("CLAUDE.md\n")
    FS-->>User: project created
Loading
sequenceDiagram
    autonumber
    actor Caller
    participant Typegen
    participant Loader as DynamicLoader
    participant Fmdapi as "@proofkit/fmdapi"
    participant Fmodata as "@proofkit/fmodata"

    Caller->>Typegen: generateTypedClients(config)
    alt config.type == "fmodata"
        Typegen->>Loader: await import("./fmodata/typegen")
        Loader->>Fmodata: try load
        alt missing
            Loader-->>Typegen: missing-dep → rethrowMissingDependency
        else loaded
            Fmodata-->>Typegen: run generation
        end
    else config.type == "fmdapi"
        Typegen->>Loader: await import("@proofkit/fmdapi") & helpers
        Loader->>Fmdapi: try load
        alt missing
            Loader-->>Typegen: missing-dep → rethrowMissingDependency
        else loaded
            Fmdapi-->>Typegen: provide client/adapters
        end
    end
    Typegen-->>Caller: generated outputs / errors
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • chriscors
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.56% 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 title accurately summarizes the main changes: CLI app name normalization improvements and making typegen API dependencies optional.

✏️ 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/check-webviewer-template-fmodata

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.

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (1)
packages/cli/src/helpers/createProject.ts (1)

74-85: ⚠️ Potential issue | 🟠 Major

Reject unsupported UIs before scaffoldProject().

This is the first runtime check that treats non-shadcn values as invalid, but scaffoldProject() already ran on Line 33. A legacy state.ui === "mantine" will leave a partially scaffolded project on disk and only then throw here.

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

In `@packages/cli/src/helpers/createProject.ts` around lines 74 - 85, Reject
unsupported UI values before calling scaffoldProject(): validate state.ui at the
start of the createProject flow and throw for anything other than "shadcn" (or
allowed values) so scaffoldProject() and subsequent operations (like
addPackageDependency) never run when UI is unsupported; update the check that
currently throws after addPackageDependency to run earlier (e.g., before
scaffoldProject() is invoked) and reference state.ui, scaffoldProject(), and
addPackageDependency to locate and modify the logic.
🧹 Nitpick comments (3)
packages/cli/src/state.ts (1)

10-10: Schema still accepts "mantine" but support has been removed.

The ui field schema allows "mantine" as a valid value, but the template service in live.ts now ignores the ui parameter entirely and always uses nextjs-shadcn. Consider restricting the enum to only "shadcn" or removing the ui field altogether to avoid confusion:

♻️ Option 1: Restrict to shadcn only
-    ui: z.enum(["shadcn", "mantine"]).optional().catch("shadcn"),
+    ui: z.literal("shadcn").optional().catch("shadcn"),
♻️ Option 2: Remove the field if no longer needed

If ui is no longer a meaningful configuration option, consider removing it from the schema entirely to simplify the codebase.

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

In `@packages/cli/src/state.ts` at line 10, The schema still exposes the ui field
(the z.enum([...]) call creating ui) allowing "mantine" even though
live.ts/template service always uses nextjs-shadcn; either restrict the enum to
only "shadcn" by changing the ui enum to
z.enum(["shadcn"]).optional().catch("shadcn"), or remove the ui property from
the exported schema entirely if it is no longer used—also search for any
consumers referencing the ui symbol and remove or adapt them so the schema and
runtime behavior remain consistent.
packages/typegen/src/getLayoutMetadata.ts (1)

6-13: Prefer narrowing-only access in getErrorCode.

getErrorCode currently uses a type assertion (error as { code?: unknown }). You can avoid assertions entirely here.

♻️ Proposed refactor
 function getErrorCode(error: unknown): string | undefined {
   if (!error || typeof error !== "object" || !("code" in error)) {
     return undefined;
   }

-  const { code } = error as { code?: unknown };
+  const code = Reflect.get(error, "code");
   return typeof code === "string" ? code : undefined;
 }

As per coding guidelines, "Leverage TypeScript's type narrowing instead of type assertions."

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

In `@packages/typegen/src/getLayoutMetadata.ts` around lines 6 - 13, The function
getErrorCode currently uses a type assertion to extract code; change it to rely
on TypeScript narrowing by checking error !== null && typeof error === "object"
&& "code" in error, then read code from the narrowed object (e.g., inside that
guarded block access error.code) and return it only if typeof code === "string";
update the function to remove the "error as { code?: unknown }" assertion and
use the narrowed variable (getErrorCode).
packages/cli/src/utils/validateAppName.ts (1)

10-23: Please route this legacy validator through ~/utils/projectName.ts.

This copy still splits only on /, while the shared helper now normalizes \ first. Inputs like apps\\My App will validate differently depending on which module a caller imports. Re-exporting the shared implementation would keep future normalization fixes in one place.

🤖 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 10 - 23, Replace the
local legacy validation logic in validateAppName.ts with a re-export or wrapper
around the shared validator in ~/utils/projectName.ts: import the projectName
normalization/validation function from that module and call it instead of using
the local removeTrailingSlash/whitespaceRegex/split-on-"/" logic (including the
appName, indexOfDelimiter, and "." basename handling) so backslash normalization
and other fixes from projectName.ts are applied consistently; keep the external
API the same by exporting the shared function from validateAppName.ts (or
returning its result) so callers are unaffected.
🤖 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/core/planInit.ts`:
- Around line 87-92: The current init plan unconditionally writes
".cursorignore" via the writes entry (path.join(targetDir, ".cursorignore")),
which will overwrite any existing ignore entries; update the init flow so that
before writing you read the existing ".cursorignore" (use the same target path
used in the writes entry and the logic in executeInitPlan.ts that currently uses
fs.writeFile), check whether the line "CLAUDE.md" already exists (account for
trailing newlines), and only append that line if it's missing, otherwise leave
the file unchanged; if the file does not exist create it with "CLAUDE.md\n".
Ensure this logic lives in the code path that processes the writes array (or
replace the writes entry with a preparatory read/merge step) so existing entries
are preserved.

In `@packages/cli/src/utils/parseNameAndPath.ts`:
- Around line 22-25: The function parseNameAndPath currently normalizes the
entire input before splitting, which rewrites parent directories; change it to
first call removeTrailingSlash(rawInput) and split that result by "/" into
segments, then only normalize the final segment (the project/package name) using
.replace(whitespaceRegex, "-").toLowerCase(); leave all leading directory
segments verbatim. Update references in parseNameAndPath to use the split
segments and the normalized last segment (keep removeTrailingSlash and
whitespaceRegex usage, but apply them only to the last path element).

In `@packages/cli/src/utils/projectName.ts`:
- Around line 16-22: parseNameAndPath currently normalizes the whole input via
normalizeProjectNameForPackage which lowercases leading directories; instead
split the raw projectName by "/", detect if the package is scoped (if the
penultimate segment startsWith("@") then treat the last two segments as the
package scope+name, otherwise the last segment is the package), normalize only
those package segments using normalizeProjectNameForPackage (apply it to each
package segment), then reconstruct scopedAppName from the normalized package
segments and build appDir by joining the original leading directories (preserve
their exact casing) with the normalized package segments; update
parseNameAndPath to use this logic and keep normalizeProjectNameForPackage only
for package/scope segments.

In `@packages/typegen/src/server/createDataApiClient.ts`:
- Around line 203-218: The catch block in createDataApiClient (around
FMServerConnection creation after loadFmodataDeps) currently maps all errors to
a 500/unknown; change it to detect malformed server URL errors (thrown by the
URL constructor inside FMServerConnection) and return a 400 response with kind:
"adapter_error", suspectedField: "server" and the error message; otherwise keep
the existing 500/unknown behavior — i.e., if error is a TypeError whose message
indicates an invalid/malformed URL (e.g., message contains "Invalid URL" or
similar), return { error: error.message, statusCode: 400, kind: "adapter_error",
suspectedField: "server" }, else return the current 500 object.
- Around line 13-17: The exported CreateClientResult currently exposes
clientTypes.LayoutOrFolder[] via the client.layouts signature which leaks the
`@proofkit/fmdapi` peer type; change the public surface so CreateClientResult does
not reference clientTypes directly — either replace client.layouts' return type
with a package-local structural type (e.g., declare a local LayoutOrFolder shape
used in the client: { layouts?: () => Promise<{ layouts: LocalLayoutOrFolder[]
}>; }) or make the client property opaque (e.g., layouts returns unknown/any)
and perform any narrowing inside app.ts; update the CreateClientResult/interface
that contains client and the layouts method signature (and any related exports)
accordingly so no clientTypes.* symbol appears in this module's exported types.

---

Outside diff comments:
In `@packages/cli/src/helpers/createProject.ts`:
- Around line 74-85: Reject unsupported UI values before calling
scaffoldProject(): validate state.ui at the start of the createProject flow and
throw for anything other than "shadcn" (or allowed values) so scaffoldProject()
and subsequent operations (like addPackageDependency) never run when UI is
unsupported; update the check that currently throws after addPackageDependency
to run earlier (e.g., before scaffoldProject() is invoked) and reference
state.ui, scaffoldProject(), and addPackageDependency to locate and modify the
logic.

---

Nitpick comments:
In `@packages/cli/src/state.ts`:
- Line 10: The schema still exposes the ui field (the z.enum([...]) call
creating ui) allowing "mantine" even though live.ts/template service always uses
nextjs-shadcn; either restrict the enum to only "shadcn" by changing the ui enum
to z.enum(["shadcn"]).optional().catch("shadcn"), or remove the ui property from
the exported schema entirely if it is no longer used—also search for any
consumers referencing the ui symbol and remove or adapt them so the schema and
runtime behavior remain consistent.

In `@packages/cli/src/utils/validateAppName.ts`:
- Around line 10-23: Replace the local legacy validation logic in
validateAppName.ts with a re-export or wrapper around the shared validator in
~/utils/projectName.ts: import the projectName normalization/validation function
from that module and call it instead of using the local
removeTrailingSlash/whitespaceRegex/split-on-"/" logic (including the appName,
indexOfDelimiter, and "." basename handling) so backslash normalization and
other fixes from projectName.ts are applied consistently; keep the external API
the same by exporting the shared function from validateAppName.ts (or returning
its result) so callers are unaffected.

In `@packages/typegen/src/getLayoutMetadata.ts`:
- Around line 6-13: The function getErrorCode currently uses a type assertion to
extract code; change it to rely on TypeScript narrowing by checking error !==
null && typeof error === "object" && "code" in error, then read code from the
narrowed object (e.g., inside that guarded block access error.code) and return
it only if typeof code === "string"; update the function to remove the "error as
{ code?: unknown }" assertion and use the narrowed variable (getErrorCode).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9eef0720-f258-4084-9cb2-2ddb1a683110

📥 Commits

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

⛔ 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 (69)
  • .changeset/clean-suns-matter.md
  • .changeset/cli-init-claude-cursorignore.md
  • .changeset/fix-cli-dot-name-normalization.md
  • .changeset/mean-worms-notice.md
  • .changeset/remove-cli-ui-flag.md
  • .changeset/soften-project-name-spaces.md
  • .changeset/tidy-dots-speak.md
  • apps/docs/src/app/layout.tsx
  • packages/cli/src/cli/init.ts
  • packages/cli/src/core/planInit.ts
  • packages/cli/src/helpers/createProject.ts
  • packages/cli/src/helpers/scaffoldProject.ts
  • packages/cli/src/index.ts
  • packages/cli/src/services/live.ts
  • packages/cli/src/state.ts
  • packages/cli/src/utils/parseNameAndPath.ts
  • packages/cli/src/utils/projectName.ts
  • packages/cli/src/utils/validateAppName.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/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/cli.test.ts
  • packages/cli/tests/init-fixtures.ts
  • packages/cli/tests/init-non-interactive-failures.test.ts
  • packages/cli/tests/init-run-init-regression.test.ts
  • packages/cli/tests/init-scaffold-contract.test.ts
  • packages/cli/tests/integration.test.ts
  • packages/cli/tests/legacy-project-name-utils.test.ts
  • packages/cli/tests/project-name.test.ts
  • packages/cli/tests/test-layer.ts
  • packages/typegen/package.json
  • packages/typegen/src/cli.ts
  • packages/typegen/src/getLayoutMetadata.ts
  • packages/typegen/src/optionalDeps.ts
  • packages/typegen/src/server/app.ts
  • packages/typegen/src/server/createDataApiClient.ts
  • packages/typegen/src/typegen.ts
💤 Files with no reviewable changes (31)
  • packages/cli/template/nextjs-mantine/src/components/AppLogo.tsx
  • packages/cli/template/nextjs-mantine/CLAUDE.md
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/Header.module.css
  • packages/cli/template/nextjs-mantine/postcss.config.cjs
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/config.ts
  • packages/cli/template/nextjs-mantine/src/app/(main)/layout.tsx
  • packages/cli/template/nextjs-mantine/next.config.ts
  • packages/cli/template/nextjs-mantine/_gitignore
  • packages/cli/template/nextjs-mantine/src/server/safe-action.ts
  • packages/cli/template/nextjs-mantine/AGENTS.md
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/HeaderMobileMenu.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-left.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/components/AppShell/slot-header-right.tsx
  • packages/cli/template/nextjs-mantine/src/utils/styles.ts
  • packages/cli/template/nextjs-mantine/README.md
  • packages/cli/template/nextjs-mantine/proofkit.json
  • packages/cli/template/nextjs-mantine/src/config/theme/mantine-theme.ts
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/HeaderNavLink.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-center.tsx
  • packages/cli/template/nextjs-mantine/tsconfig.json
  • packages/cli/template/nextjs-mantine/src/app/layout.tsx
  • packages/cli/template/nextjs-mantine/components.json
  • packages/cli/template/nextjs-mantine/src/app/(main)/page.tsx
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/AppShell.tsx
  • packages/cli/template/nextjs-mantine/package.json
  • packages/cli/template/nextjs-mantine/src/components/AppShell/internal/Header.tsx
  • packages/cli/template/nextjs-mantine/src/app/navigation.tsx
  • packages/cli/template/nextjs-mantine/src/utils/notification-helpers.ts
  • packages/cli/template/nextjs-mantine/src/components/AppShell/slot-header-mobile-content.tsx

- keep leading path segments verbatim
- normalize only final package segment
- add regression coverage
Comment on lines +25 to +29
const normalizedPaths = [...paths];
const lastPathIndex = normalizedPaths.length - 1;

let appName = paths.at(-1) ?? "";
let appName = (normalizedPaths.at(-1) ?? "").replace(whitespaceRegex, "-").toLowerCase();
normalizedPaths[lastPathIndex] = appName;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Critical Bug: Incorrect normalization order for scoped packages

The code normalizes only the last path segment before checking for scoped packages:

let appName = (normalizedPaths.at(-1) ?? "").replace(whitespaceRegex, "-").toLowerCase();
normalizedPaths[lastPathIndex] = appName;

But when a scoped package is detected, it joins from normalizedPaths which has only the last segment normalized:

appName = normalizedPaths.slice(indexOfDelimiter).join("/");

Example: Input "@My Scope/My App" produces paths = ["@My Scope", "My App"], then normalizedPaths = ["@My Scope", "my-app"], and finally appName = "@My Scope/my-app" (scope not normalized).

This conflicts with projectName.ts which normalizes ALL package segments. The scope segment "@My Scope" should be normalized to "@my-scope". Fix by normalizing the scope segment:

const indexOfDelimiter = normalizedPaths.findIndex((p) => p.startsWith("@"));
if (indexOfDelimiter !== -1) {
  // Normalize the scope segment as well
  normalizedPaths[indexOfDelimiter] = normalizedPaths[indexOfDelimiter].replace(whitespaceRegex, "-").toLowerCase();
  appName = normalizedPaths.slice(indexOfDelimiter).join("/");
}
Suggested change
const normalizedPaths = [...paths];
const lastPathIndex = normalizedPaths.length - 1;
let appName = paths.at(-1) ?? "";
let appName = (normalizedPaths.at(-1) ?? "").replace(whitespaceRegex, "-").toLowerCase();
normalizedPaths[lastPathIndex] = appName;
const normalizedPaths = [...paths];
const lastPathIndex = normalizedPaths.length - 1;
let appName = (normalizedPaths.at(-1) ?? "").replace(whitespaceRegex, "-").toLowerCase();
normalizedPaths[lastPathIndex] = appName;
const indexOfDelimiter = normalizedPaths.findIndex((p) => p.startsWith("@"));
if (indexOfDelimiter !== -1) {
// Normalize the scope segment as well
normalizedPaths[indexOfDelimiter] = normalizedPaths[indexOfDelimiter].replace(whitespaceRegex, "-").toLowerCase();
appName = normalizedPaths.slice(indexOfDelimiter).join("/");
}

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

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 (1)
packages/typegen/src/server/createDataApiClient.ts (1)

2-2: Please verify the shared env helper is still peer-agnostic.

Lines 2, 52, and 164 still pull OttoAPIKey from @proofkit/fmdapi into the shared auth path. If this module is source-exported or its declarations preserve that import, OData-only consumers still need the optional peer to resolve types. Keeping the shared auth shape local (string) and narrowing only inside the Otto branch would remove that remaining compile-time edge. As per coding guidelines, "Leverage TypeScript's type narrowing instead of type assertions".

Also applies to: 46-53, 160-165

🤖 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/typegen/src/server/createDataApiClient.ts`:
- Around line 67-72: The exported OdataClientError type is too narrow compared
to actual errors returned (e.g., errors from getEnvVarsFromConfig are returned
verbatim); update the OdataClientError interface to include the additional
fields returned such as message?: string and details?: unknown (or a more
specific shape if known) so callers retain typed access to structured payloads;
locate the OdataClientError declaration and add these fields, and ensure code
paths that return env/config errors (the code that calls getEnvVarsFromConfig)
are still compatible with the widened type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 340a318a-9dcb-453a-a1d2-e8d84e1f8080

📥 Commits

Reviewing files that changed from the base of the PR and between db11fda and b2de39e.

📒 Files selected for processing (1)
  • packages/typegen/src/server/createDataApiClient.ts

- Refresh pnpm lock resolution
- Rehome fmdapi/fmodata dev deps
@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@195

@proofkit/cli

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

create-proofkit

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

@proofkit/fmdapi

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

@proofkit/fmodata

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

@proofkit/typegen

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

@proofkit/webviewer

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

commit: 6da0c9a

- include `message` and `details` on client errors
- add changeset for `@proofkit/typegen` patch
@eluce2 eluce2 merged commit e93ba31 into main Mar 20, 2026
13 of 14 checks passed
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