Skip to content

Conversation

@ian
Copy link
Owner

@ian ian commented Nov 3, 2025

Fixes STARTUP-105
Fixes STARTUP-106


Summary by cubic

Adds authentication to the Next.js template using @repo/auth with Email OTP and Google OAuth, plus a protected dashboard and updated UI for signed-in state. Also switches the CLI to Vitest with unit/integration tests and updated scaffolding; this aligns with Linear issues STARTUP-106 and STARTUP-105.

  • New Features

    • Auth handler at app/(auth)/auth/[...all] using @repo/auth/server (Next.js adapter for GET/POST).
    • Sign-in page with Email OTP and Google OAuth (send, verify, redirect on success).
    • Protected dashboard using withAuth and redirect to /sign-in when unauthenticated.
    • Header updated with user menu and sign out; Home updated with auth and dashboard CTAs.
    • Providers tightened types; removed unused router refresh.
    • @repo/auth: re-exported useAuth via local hook; switched to Next.js handler adapter.
    • Database + env: initial Drizzle schema/migration for auth (User/Session/Account/Verification/Team), pool tuning in @repo/db, and DATABASE_URL checks.
    • Docs: README expanded with env/setup/routes/examples; AGENTS.md clarifies templates architecture and /auth route path.
  • Refactors

    • CLI now uses Vitest with unit and integration tests for init, plus coverage and config.
    • CLI init clones both repo and packages templates to scaffold projects.
    • Moved app templates to templates/apps/*; updated CLI add and workflows (new placeholder replacements PROJECT_NEXT/PROJECT_VITE).

Written for commit c65bf54. Summary will update automatically on new commits.

@linear
Copy link

linear bot commented Nov 3, 2025

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Nov 3, 2025

Deploying startupkit with  Cloudflare Pages  Cloudflare Pages

Latest commit: c65bf54
Status: ✅  Deploy successful!
Preview URL: https://2629ec34.startupkit-975.pages.dev
Branch Preview URL: https://startup-106-add-auth-to-next.startupkit-975.pages.dev

View logs

@socket-security
Copy link

socket-security bot commented Nov 3, 2025

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 11 files

Prompt for AI agents (all 2 issues)

Understand the root cause of the following 2 issues and fix them.


<file name="templates/next/src/app/sign-in/page.tsx">

<violation number="1" location="templates/next/src/app/sign-in/page.tsx:21">
Triggering router.push inside the render path causes a navigation side-effect during render; move this redirect into a useEffect (or similar) to avoid repeated pushes and React warnings.</violation>
</file>

<file name="templates/next/README.md">

<violation number="1" location="templates/next/README.md:176">
This documentation line points developers to `packages/auth/src/lib/auth.ts`, but the template does not contain a `packages/` directory, so the instructions cannot be followed.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

Reviewed changes from recent commits (found 5 issues).

5 issues found across 12 files

Prompt for AI agents (all 5 issues)

Understand the root cause of the following 5 issues and fix them.


<file name="templates/repo/packages/auth/src/lib/auth.ts">

<violation number="1" location="templates/repo/packages/auth/src/lib/auth.ts:28">
This new runtime error forces both GOOGLE_* env vars to be set, so the module now crashes during import when they are missing. Because the Google provider is already gated by the `enabled` flag, this prevents running the template with email-only auth.</violation>
</file>

<file name="templates/next/package.json">

<violation number="1" location="templates/next/package.json:8">
Switching the dev script to the default port 3000 breaks the documented quickstart, which still tells users to open http://localhost:2999. Please keep the explicit -p 2999 override (or update the docs accordingly) so the instructions continue to work.</violation>
</file>

<file name="templates/repo/packages/db/src/index.ts">

<violation number="1" location="templates/repo/packages/db/src/index.ts:27">
This pool instance is cached across reloads, so registering the error listener on every module evaluation leads to duplicate handlers and potential MaxListenersExceeded warnings. Guard the listener so it only attaches when a new pool is created.</violation>
</file>

<file name="templates/repo/packages/db/drizzle/meta/0000_snapshot.json">

<violation number="1" location="templates/repo/packages/db/drizzle/meta/0000_snapshot.json:103">
The Account table should enforce uniqueness on providerId+accountId; leaving this index non-unique allows duplicate external accounts for the same user and can break auth linking.</violation>
</file>

<file name="package.json">

<violation number="1" location="package.json:22">
This script creates a named Postgres container but never removes it; after the first run the name persists (even if the container is stopped), so rerunning `pnpm pg:start` fails with a name collision. Add `--rm` so the container cleans up when stopped and the script stays reusable.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 5 files

@ian ian changed the title Add auth to next template Add auth to next template, switch to vitest for CLI Nov 5, 2025
@linear
Copy link

linear bot commented Nov 5, 2025

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

Reviewed changes from recent commits (found 22 issues).

22 issues found across 205 files

Note: This PR contains a large number of files. cubic only reviews up to 150 files per PR, so some files may not have been reviewed.

Prompt for AI agents (all 22 issues)

Understand the root cause of the following 22 issues and fix them.


<file name="packages/cli/src/cmd/README.test.md">

<violation number="1" location="packages/cli/src/cmd/README.test.md:42">
The integration test section references `init.full.test.ts`, but the actual file is `init.integration.test.ts`, so the doc points to a non-existent test file.</violation>
</file>

<file name="templates/packages/ui/src/components/card.stories.tsx">

<violation number="1" location="templates/packages/ui/src/components/card.stories.tsx:1">
Project formatting rules keep singleQuote disabled, so switching these imports to single quotes will fail Prettier/lint. Please keep double quotes here.</violation>
</file>

<file name="templates/packages/ui/src/components/breadcrumb.tsx">

<violation number="1" location="templates/packages/ui/src/components/breadcrumb.tsx:66">
The current breadcrumb page should not be exposed as a focusable link. Remove the link role, tabIndex, and aria-disabled here so keyboard users aren’t taken to a dead-end element.</violation>

<violation number="2" location="templates/packages/ui/src/components/breadcrumb.tsx:106">
Typo in displayName: it should read “BreadcrumbEllipsis” so the component reports the correct name in debugging tools.</violation>
</file>

<file name="templates/packages/ui/src/components/input.tsx">

<violation number="1" location="templates/packages/ui/src/components/input.tsx:29">
Only checking for `ariaInvalid === true` misses valid string values (&quot;true&quot;, &quot;grammar&quot;, &quot;spelling&quot;) for `aria-invalid`, so the error state fails to render when consumers pass those strings. Please treat all non-false values as invalid to keep the UI in sync with the attribute.</violation>
</file>

<file name="templates/packages/ui/src/components/avatar.tsx">

<violation number="1" location="templates/packages/ui/src/components/avatar.tsx:76">
Splitting the label on a literal space leaves empty tokens for names with leading/trailing or repeated whitespace, so the fallback initials become blank. Trim and split on whitespace to skip empty words.</violation>
</file>

<file name="templates/packages/ui/src/components/markdown.tsx">

<violation number="1" location="templates/packages/ui/src/components/markdown.tsx:51">
The unordered list override renders with `list-decimal`, causing bullet lists to appear numbered. Update the class to use the unordered list style.</violation>
</file>

<file name="templates/packages/ui/src/components/badge.tsx">

<violation number="1" location="templates/packages/ui/src/components/badge.tsx:32">
Define Badge with React.forwardRef so callers can attach refs, matching the rest of the UI primitives.</violation>
</file>

<file name="templates/packages/ui/src/components/button.tsx">

<violation number="1" location="templates/packages/ui/src/components/button.tsx:10">
`focus-visible:ring-none` is not a valid Tailwind class, so with `focus-visible:outline-none` this button loses any visible focus indicator; please restore a legitimate focus ring utility.</violation>

<violation number="2" location="templates/packages/ui/src/components/button.tsx:107">
The new `iconPosition` prop is never applied—`{icon}` always renders before the children—so callers cannot actually place the icon at the end; please wire the prop into the layout.</violation>
</file>

<file name="templates/packages/ui/src/styles/colors.css">

<violation number="1" location="templates/packages/ui/src/styles/colors.css:1">
`@tailwind base;` is already declared in the parent stylesheet (`index.css`). Keeping this directive here causes Tailwind to inject its base layer twice, duplicating resets and inflating the compiled CSS. Please remove the duplicate directive.</violation>
</file>

<file name="templates/packages/ui/src/components/select.tsx">

<violation number="1" location="templates/packages/ui/src/components/select.tsx:22">
Tailwind doesn&#39;t generate an h-10.5 utility, so the trigger falls back to auto height and loses the intended sizing. Switch to a supported height (e.g. h-10) to keep the control consistent.</violation>
</file>

<file name="templates/packages/ui/src/components/separator.tsx">

<violation number="1" location="templates/packages/ui/src/components/separator.tsx:13">
Defaulting `decorative` to true makes every Separator instance decorative-only, stripping the semantic role and hiding it from screen readers. Please let it default to false so separators remain accessible unless explicitly opted out.</violation>
</file>

<file name="templates/packages/ui/src/components/alert-dialog.tsx">

<violation number="1" location="templates/packages/ui/src/components/alert-dialog.tsx:119">
Add a top margin to the cancel button so stacked alert dialogs keep spacing consistent on small screens; otherwise the cancel and action buttons touch each other when the footer collapses into a column.</violation>
</file>

<file name="templates/packages/ui/src/components/alert.tsx">

<violation number="1" location="templates/packages/ui/src/components/alert.tsx:38">
AlertDescription forwards its ref as HTMLParagraphElement even though it renders a &lt;div&gt;, giving consumers the wrong ref type. Please update the generic to HTMLDivElement.</violation>

<violation number="2" location="templates/packages/ui/src/components/alert.tsx:38">
AlertTitle forwards its ref as HTMLParagraphElement even though it renders an &lt;h5&gt;, which misleads ref consumers. Please switch the generic to HTMLHeadingElement so the ref type matches the DOM node.</violation>

<violation number="3" location="templates/packages/ui/src/components/alert.tsx:51">
AlertDescription props are typed for HTMLParagraphElement, but the component renders a &lt;div&gt;. Update the attributes generic to HTMLDivElement to keep the types consistent.</violation>
</file>

<file name="templates/apps/next/tsconfig.json">

<violation number="1" location="templates/apps/next/tsconfig.json:16">
.next/types/**/*.ts is now excluded from the project because excluding &quot;.next&quot; overrides the include entry, so the generated Next.js type augmentations will be missing.</violation>
</file>

<file name="templates/packages/ui/src/components/sidebar.tsx">

<violation number="1" location="templates/packages/ui/src/components/sidebar.tsx:443">
The arbitrary transition property is truncated as `transition-[margin,opa]`, so Tailwind drops the rule and the label loses its opacity transition. Replace it with `transition-[margin,opacity]`.</violation>

<violation number="2" location="templates/packages/ui/src/components/sidebar.tsx:792">
`disabled: cursor-not-allowed` has a stray space, so Tailwind applies `cursor-not-allowed` unconditionally; users see a disabled cursor even when the submenu link is active. Remove the space so the variant only applies when disabled.</violation>
</file>

<file name="templates/apps/next/src/app/(auth)/sign-in/page.tsx">

<violation number="1" location="templates/apps/next/src/app/(auth)/sign-in/page.tsx:29">
Move the redirect into a `useEffect` instead of firing `router.push` directly during render; side-effects must not run in the render phase.</violation>
</file>

<file name="templates/apps/vite/package.json">

<violation number="1" location="templates/apps/vite/package.json:2">
Package names in package.json must be lowercase. Rename this template package to use lowercase characters to stay compatible with npm tooling.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

ian and others added 2 commits November 5, 2025 12:54
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
ian and others added 8 commits November 5, 2025 12:59
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

Reviewed changes from recent commits (found 13 issues).

13 issues found across 207 files

Note: This PR contains a large number of files. cubic only reviews up to 150 files per PR, so some files may not have been reviewed.

Prompt for AI agents (all 13 issues)

Understand the root cause of the following 13 issues and fix them.


<file name="templates/packages/ui/src/components/collapsible.tsx">

<violation number="1" location="templates/packages/ui/src/components/collapsible.tsx:7">
Re-exporting CollapsibleTrigger from an undefined primitive member causes runtime React crashes.</violation>

<violation number="2" location="templates/packages/ui/src/components/collapsible.tsx:9">
CollapsibleContent is sourced from a non-existent primitive member, so consuming it crashes at runtime.</violation>
</file>

<file name="templates/packages/ui/src/components/button.tsx">

<violation number="1" location="templates/packages/ui/src/components/button.tsx:75">
`loading` is meant to disable the button, but spreading `...props` after the disabled attribute restores the caller’s original `disabled` value. If a consumer passes `disabled={false}`, the button stays enabled while loading, allowing duplicate submissions. Please ensure the loading flag can’t be overridden by the spread.</violation>
</file>

<file name="templates/packages/ui/src/components/avatar.tsx">

<violation number="1" location="templates/packages/ui/src/components/avatar.tsx:77">
Use a code point-safe operation (e.g. Array.from) when deriving initials so emoji or astral characters render correctly.</violation>
</file>

<file name="packages/cli/src/cmd/init.test.ts">

<violation number="1" location="packages/cli/src/cmd/init.test.ts:5">
These tests redefine slugify locally, so they never exercise the init command&#39;s real slugify helper and will miss regressions. Import the production implementation (or expose it for testing) so the unit test covers the actual code.</violation>

<violation number="2" location="packages/cli/src/cmd/init.test.ts:44">
The path resolution tests recreate the implementation inline instead of invoking the init command’s logic, leaving the real code untested. Consider refactoring to exercise the actual helper or init flow so changes in init.ts are covered.</violation>
</file>

<file name="pnpm-workspace.yaml">

<violation number="1" location="pnpm-workspace.yaml:7">
Adding templates/apps/** to the workspace picks up templates/apps/next/package.json, whose name &quot;PROJECT_NEXT&quot; contains uppercase letters. npm/pnpm reject uppercase package names, so workspace installation will fail before templates can run locally. Please either exclude the template directories from the workspace or change their package names to valid lowercase values.</violation>
</file>

<file name="packages/cli/src/cmd/init.ts">

<violation number="1" location="packages/cli/src/cmd/init.ts:84">
Branch-specific repo paths now duplicate `/templates/repo`, so `degit` points at a non-existent directory and `init` fails for repoArgs like `ian/startupkit/templates/repo#branch`.</violation>
</file>

<file name="packages/cli/src/cmd/README.test.md">

<violation number="1" location="packages/cli/src/cmd/README.test.md:113">
Update the example to include the value inside expect(); Vitest requires `expect(value)` before calling matchers like toBeTruthy.</violation>

<violation number="2" location="packages/cli/src/cmd/README.test.md:114">
Include the subject inside expect() so the guidance reflects a valid Vitest assertion (e.g., `expect(value).toBeDefined()`).</violation>
</file>

<file name="templates/packages/ui/src/components/markdown.tsx">

<violation number="1" location="templates/packages/ui/src/components/markdown.tsx:19">
Code fences without a language stop rendering as blocks because this guard requires a language match before returning the &lt;pre&gt; branch. Drop the match check (or otherwise handle the inline=false case) so unlabeled code blocks still render as block-level &lt;pre&gt;&lt;code&gt; content.</violation>

<violation number="2" location="templates/packages/ui/src/components/markdown.tsx:28">
If className is undefined (the default for inline code), this template literal produces a literal &quot;undefined&quot; CSS class. Default the prefix to &quot;&quot; before concatenating.</violation>
</file>

<file name="templates/packages/ui/src/components/input.tsx">

<violation number="1" location="templates/packages/ui/src/components/input.tsx:19">
Defaulting `onePassword` to true disables 1Password autofill for every field using this component. Please default it to false so consumers explicitly opt out only where needed.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
disabled={loading || props.disabled}
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

loading is meant to disable the button, but spreading ...props after the disabled attribute restores the caller’s original disabled value. If a consumer passes disabled={false}, the button stays enabled while loading, allowing duplicate submissions. Please ensure the loading flag can’t be overridden by the spread.

Prompt for AI agents
Address the following comment on templates/packages/ui/src/components/button.tsx at line 75:

<comment>`loading` is meant to disable the button, but spreading `...props` after the disabled attribute restores the caller’s original `disabled` value. If a consumer passes `disabled={false}`, the button stays enabled while loading, allowing duplicate submissions. Please ensure the loading flag can’t be overridden by the spread.</comment>

<file context>
@@ -0,0 +1,144 @@
+      &lt;Comp
+        className={cn(buttonVariants({ variant, size, className }))}
+        ref={ref}
+        disabled={loading || props.disabled}
+        {...props}
+      &gt;
</file context>

✅ Addressed in 7e3d247

children?: React.ReactNode;
} & React.HTMLAttributes<HTMLPreElement>) => {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

Code fences without a language stop rendering as blocks because this guard requires a language match before returning the

 branch. Drop the match check (or otherwise handle the inline=false case) so unlabeled code blocks still render as block-level 
 content.

Prompt for AI agents
Address the following comment on templates/packages/ui/src/components/markdown.tsx at line 19:

<comment>Code fences without a language stop rendering as blocks because this guard requires a language match before returning the &lt;pre&gt; branch. Drop the match check (or otherwise handle the inline=false case) so unlabeled code blocks still render as block-level &lt;pre&gt;&lt;code&gt; content.</comment>

<file context>
@@ -0,0 +1,131 @@
+      children?: React.ReactNode;
+    } &amp; React.HTMLAttributes&lt;HTMLPreElement&gt;) =&gt; {
+      const match = /language-(\w+)/.exec(className || &#39;&#39;);
+      return !inline &amp;&amp; match ? (
+        &lt;pre
+          {...props}
</file context>

✅ Addressed in a1ada34

ian and others added 7 commits November 5, 2025 14:25
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

Reviewed changes from recent commits (found 11 issues).

11 issues found across 207 files

Note: This PR contains a large number of files. cubic only reviews up to 150 files per PR, so some files may not have been reviewed.

Prompt for AI agents (all 11 issues)

Understand the root cause of the following 11 issues and fix them.


<file name="templates/packages/ui/src/components/markdown.tsx">

<violation number="1" location="templates/packages/ui/src/components/markdown.tsx:23">
Composing the pre element classes with `${className}` causes a literal `undefined` class whenever the markdown fence omits a language. Use the existing `cn` helper to guard against missing class names.</violation>

<violation number="2" location="templates/packages/ui/src/components/markdown.tsx:25">
Setting the code element class to `match?.[1]` strips the incoming `language-` prefix (e.g. `language-js`), breaking syntax highlighting and any styles that target those selectors. Preserve the original class name from ReactMarkdown.</violation>
</file>

<file name="templates/packages/ui/src/components/button.tsx">

<violation number="1" location="templates/packages/ui/src/components/button.tsx:73">
Please provide a default `type=&quot;button&quot;` when rendering as a native button; otherwise these buttons default to `type=&quot;submit&quot;` in forms and will submit unintentionally when used for non-submit actions.</violation>
</file>

<file name="pnpm-workspace.yaml">

<violation number="1" location="pnpm-workspace.yaml:7">
Importing the templates/apps/** packages into the workspace will make pnpm treat PROJECT_NEXT and PROJECT_VITE (uppercase/underscore names) as workspace packages, but npm-style package names must be lowercase and cannot contain underscores, so pnpm install will fail for the whole repo.</violation>
</file>

<file name="templates/packages/ui/src/components/input.tsx">

<violation number="1" location="templates/packages/ui/src/components/input.tsx:19">
Defaulting `onePassword` to true means every Input renders with `data-1p-ignore`, so 1Password (and other managers honoring the flag) refuse to autofill even standard email/password fields. Please let consumers opt-in instead of blocking autofill by default.</violation>
</file>

<file name="templates/packages/ui/src/components/breadcrumb.tsx">

<violation number="1" location="templates/packages/ui/src/components/breadcrumb.tsx:12">
`Breadcrumb` advertises a `separator` prop, but the implementation just forwards all props to `&lt;nav&gt;`, so the prop is ignored and leaks onto the DOM as an invalid attribute. Please either remove the prop or handle it before spreading to the element.</violation>
</file>

<file name="packages/cli/src/cmd/init.ts">

<violation number="1" location="packages/cli/src/cmd/init.ts:24">
buildDegitSources appends `/templates/...` even when repoArg already points at those subdirectories, so valid inputs like `ian/startupkit/templates/repo` now resolve to `.../templates/repo/templates/repo`, and the CLI can no longer clone the template.</violation>
</file>

<file name="packages/cli/src/cmd/init.integration.test.ts">

<violation number="1" location="packages/cli/src/cmd/init.integration.test.ts:20">
Calling init with repoArg undefined makes the test clone the upstream template and run a full `pnpm install`, turning this integration test into a multi-minute, network-dependent operation that will flake or time out in automation.</violation>
</file>

<file name="packages/cli/src/cmd/add.ts">

<violation number="1" location="packages/cli/src/cmd/add.ts:136">
Restricting replacement to /PROJECT_NEXT/g means existing Next repoArg templates that still use PROJECT (the placeholder we previously supported) no longer get their slug substituted, so generated projects keep the placeholder string. Please continue matching PROJECT as well so custom templates don’t regress.</violation>
</file>

<file name="templates/apps/next/src/app/(auth)/layout.tsx">

<violation number="1" location="templates/apps/next/src/app/(auth)/layout.tsx:60">
Setting `maximumScale` to 1 prevents users from zooming the auth pages, which is an accessibility failure under WCAG 1.4.4. Please allow a higher maximum scale (or omit the restriction) so users can resize content.</violation>

<violation number="2" location="templates/apps/next/src/app/(auth)/layout.tsx:61">
`userScalable: &#39;no&#39;` disables pinch-zoom, blocking users who need to enlarge the auth UI and violating WCAG 1.4.4. Please allow zoom by re-enabling user scaling.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

{...props}
className={`${className} text-sm w-[80dvw] md:max-w-[500px] overflow-x-scroll bg-zinc-100 p-3 rounded-lg mt-2 dark:bg-zinc-800`}
>
<code className={match?.[1]}>{children}</code>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

Setting the code element class to match?.[1] strips the incoming language- prefix (e.g. language-js), breaking syntax highlighting and any styles that target those selectors. Preserve the original class name from ReactMarkdown.

Prompt for AI agents
Address the following comment on templates/packages/ui/src/components/markdown.tsx at line 25:

<comment>Setting the code element class to `match?.[1]` strips the incoming `language-` prefix (e.g. `language-js`), breaking syntax highlighting and any styles that target those selectors. Preserve the original class name from ReactMarkdown.</comment>

<file context>
@@ -0,0 +1,135 @@
+          {...props}
+          className={`${className} text-sm w-[80dvw] md:max-w-[500px] overflow-x-scroll bg-zinc-100 p-3 rounded-lg mt-2 dark:bg-zinc-800`}
+        &gt;
+          &lt;code className={match?.[1]}&gt;{children}&lt;/code&gt;
+        &lt;/pre&gt;
+      ) : (
</file context>
Suggested change
<code className={match?.[1]}>{children}</code>
<code className={className}>{children}</code>
Fix with Cubic

return !inline ? (
<pre
{...props}
className={`${className} text-sm w-[80dvw] md:max-w-[500px] overflow-x-scroll bg-zinc-100 p-3 rounded-lg mt-2 dark:bg-zinc-800`}
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

Composing the pre element classes with ${className} causes a literal undefined class whenever the markdown fence omits a language. Use the existing cn helper to guard against missing class names.

Prompt for AI agents
Address the following comment on templates/packages/ui/src/components/markdown.tsx at line 23:

<comment>Composing the pre element classes with `${className}` causes a literal `undefined` class whenever the markdown fence omits a language. Use the existing `cn` helper to guard against missing class names.</comment>

<file context>
@@ -0,0 +1,135 @@
+      return !inline ? (
+        &lt;pre
+          {...props}
+          className={`${className} text-sm w-[80dvw] md:max-w-[500px] overflow-x-scroll bg-zinc-100 p-3 rounded-lg mt-2 dark:bg-zinc-800`}
+        &gt;
+          &lt;code className={match?.[1]}&gt;{children}&lt;/code&gt;
</file context>
Suggested change
className={`${className} text-sm w-[80dvw] md:max-w-[500px] overflow-x-scroll bg-zinc-100 p-3 rounded-lg mt-2 dark:bg-zinc-800`}
className={cn(className, 'text-sm w-[80dvw] md:max-w-[500px] overflow-x-scroll bg-zinc-100 p-3 rounded-lg mt-2 dark:bg-zinc-800')}
Fix with Cubic

) => {
const Comp = asChild ? Slot : 'button';
return (
<Comp
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

Please provide a default type="button" when rendering as a native button; otherwise these buttons default to type="submit" in forms and will submit unintentionally when used for non-submit actions.

Prompt for AI agents
Address the following comment on templates/packages/ui/src/components/button.tsx at line 73:

<comment>Please provide a default `type=&quot;button&quot;` when rendering as a native button; otherwise these buttons default to `type=&quot;submit&quot;` in forms and will submit unintentionally when used for non-submit actions.</comment>

<file context>
@@ -0,0 +1,145 @@
+  ) =&gt; {
+    const Comp = asChild ? Slot : &#39;button&#39;;
+    return (
+      &lt;Comp
+        className={cn(buttonVariants({ variant, size, className }))}
+        ref={ref}
</file context>
Fix with Cubic

- "packages/**"
- "!packages/cli/tmp/**"
# these are just to allow us to run template projects locally
- "templates/apps/**"
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

Importing the templates/apps/** packages into the workspace will make pnpm treat PROJECT_NEXT and PROJECT_VITE (uppercase/underscore names) as workspace packages, but npm-style package names must be lowercase and cannot contain underscores, so pnpm install will fail for the whole repo.

Prompt for AI agents
Address the following comment on pnpm-workspace.yaml at line 7:

<comment>Importing the templates/apps/** packages into the workspace will make pnpm treat PROJECT_NEXT and PROJECT_VITE (uppercase/underscore names) as workspace packages, but npm-style package names must be lowercase and cannot contain underscores, so pnpm install will fail for the whole repo.</comment>

<file context>
@@ -2,8 +2,11 @@ packages:
-  - &quot;templates/repo/packages/**&quot;
+  - &quot;!packages/cli/tmp/**&quot;
+  # these are just to allow us to run template projects locally
+  - &quot;templates/apps/**&quot;
+  - &quot;templates/packages/**&quot;
+  - &quot;templates/repo/config/**&quot;
</file context>
Fix with Cubic

prefix,
leftIcon,
rightIcon,
onePassword = true,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

Defaulting onePassword to true means every Input renders with data-1p-ignore, so 1Password (and other managers honoring the flag) refuse to autofill even standard email/password fields. Please let consumers opt-in instead of blocking autofill by default.

Prompt for AI agents
Address the following comment on templates/packages/ui/src/components/input.tsx at line 19:

<comment>Defaulting `onePassword` to true means every Input renders with `data-1p-ignore`, so 1Password (and other managers honoring the flag) refuse to autofill even standard email/password fields. Please let consumers opt-in instead of blocking autofill by default.</comment>

<file context>
@@ -0,0 +1,71 @@
+      prefix,
+      leftIcon,
+      rightIcon,
+      onePassword = true,
+      &#39;aria-invalid&#39;: ariaInvalid,
+      ...props
</file context>
Suggested change
onePassword = true,
onePassword = false,
Fix with Cubic

.replace(/^-+|-+$/g, "")
}

export function buildDegitSources(repoBase: string): {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

buildDegitSources appends /templates/... even when repoArg already points at those subdirectories, so valid inputs like ian/startupkit/templates/repo now resolve to .../templates/repo/templates/repo, and the CLI can no longer clone the template.

Prompt for AI agents
Address the following comment on packages/cli/src/cmd/init.ts at line 24:

<comment>buildDegitSources appends `/templates/...` even when repoArg already points at those subdirectories, so valid inputs like `ian/startupkit/templates/repo` now resolve to `.../templates/repo/templates/repo`, and the CLI can no longer clone the template.</comment>

<file context>
@@ -21,6 +21,23 @@ function slugify(input: string): string {
 		.replace(/^-+|-+$/g, &quot;&quot;)
 }
 
+export function buildDegitSources(repoBase: string): {
+	repoSource: string
+	packagesSource: string
</file context>

✅ Addressed in 4b27557


try {
process.chdir(testDir)
await init({ name: projectName, repoArg: undefined })
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

Calling init with repoArg undefined makes the test clone the upstream template and run a full pnpm install, turning this integration test into a multi-minute, network-dependent operation that will flake or time out in automation.

Prompt for AI agents
Address the following comment on packages/cli/src/cmd/init.integration.test.ts at line 20:

<comment>Calling init with repoArg undefined makes the test clone the upstream template and run a full `pnpm install`, turning this integration test into a multi-minute, network-dependent operation that will flake or time out in automation.</comment>

<file context>
@@ -0,0 +1,172 @@
+
+		try {
+			process.chdir(testDir)
+			await init({ name: projectName, repoArg: undefined })
+		} finally {
+			process.chdir(originalCwd)
</file context>
Fix with Cubic

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

Reviewed changes from recent commits (found 2 issues).

2 issues found across 4 files

Prompt for AI agents (all 2 issues)

Understand the root cause of the following 2 issues and fix them.


<file name="packages/cli/src/cmd/add.ts">

<violation number="1" location="packages/cli/src/cmd/add.ts:152">
Running pnpm install with cwd set to the caller’s current directory breaks scenarios where the CLI is invoked from apps/ or packages/, because those folders lack a package.json; pnpm now fails even though addApp previously supported being run from those locations.</violation>
</file>

<file name="packages/cli/src/cli.ts">

<violation number="1" location="packages/cli/src/cli.ts:19">
Making this handler async without switching run() to use program.parseAsync means Commander never awaits or catches rejections from init(). Any failure in init()/add() now turns into an unhandled promise rejection (Node 20 prints a stack trace and exits abruptly). Please either revert to a synchronous handler (return init(...) without async/await) or update run() to await program.parseAsync(process.argv).</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.


// Install dependencies
// Install dependencies from workspace root
const workspaceRoot = process.cwd()
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

Running pnpm install with cwd set to the caller’s current directory breaks scenarios where the CLI is invoked from apps/ or packages/, because those folders lack a package.json; pnpm now fails even though addApp previously supported being run from those locations.

Prompt for AI agents
Address the following comment on packages/cli/src/cmd/add.ts at line 152:

<comment>Running pnpm install with cwd set to the caller’s current directory breaks scenarios where the CLI is invoked from apps/ or packages/, because those folders lack a package.json; pnpm now fails even though addApp previously supported being run from those locations.</comment>

<file context>
@@ -148,10 +148,11 @@ async function addApp(props: {
 
-	// Install dependencies
+	// Install dependencies from workspace root
+	const workspaceRoot = process.cwd()
 	await spinner(`Installing dependencies`, async () =&gt; {
-		await exec(&quot;pnpm install --no-frozen-lockfile&quot;, {
</file context>
Fix with Cubic

.option("--repo <repo>", "Template repo to use")
.action((options) => {
init({ name: options.name, repoArg: options.repo })
.action(async (options) => {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 5, 2025

Choose a reason for hiding this comment

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

Making this handler async without switching run() to use program.parseAsync means Commander never awaits or catches rejections from init(). Any failure in init()/add() now turns into an unhandled promise rejection (Node 20 prints a stack trace and exits abruptly). Please either revert to a synchronous handler (return init(...) without async/await) or update run() to await program.parseAsync(process.argv).

Prompt for AI agents
Address the following comment on packages/cli/src/cli.ts at line 19:

<comment>Making this handler async without switching run() to use program.parseAsync means Commander never awaits or catches rejections from init(). Any failure in init()/add() now turns into an unhandled promise rejection (Node 20 prints a stack trace and exits abruptly). Please either revert to a synchronous handler (return init(...) without async/await) or update run() to await program.parseAsync(process.argv).</comment>

<file context>
@@ -16,17 +16,17 @@ export function run() {
 		.option(&quot;--repo &lt;repo&gt;&quot;, &quot;Template repo to use&quot;)
-		.action((options) =&gt; {
-			init({ name: options.name, repoArg: options.repo })
+		.action(async (options) =&gt; {
+			await init({ name: options.name, repoArg: options.repo })
 		})
</file context>

✅ Addressed in 08f804d

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

@ian ian merged commit 04212d2 into main Nov 6, 2025
13 of 14 checks passed
@ian ian deleted the startup-106-add-auth-to-next-template branch November 6, 2025 03:44
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.

3 participants