feat(config): Schema support - #19

Merged
dmoerner merged 3 commits into
mainfrom
daniel/config-schema
Mar 8, 2026
Merged

feat(config): Schema support#19
dmoerner merged 3 commits into
mainfrom
daniel/config-schema

Conversation

@dmoerner

@dmoernerdmoerner commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Implement config schema command to allow fetching the schema from PLAPI. This will make Clerk CLI config self-documenting, to an extent. The bare command dumps the whole schema, there is also a --keys argument to dump only a specific key. This can be useful to save context.

Implement `config schema` command to allow fetching the schema from
PLAPI. This will make Clerk CLI config self-documenting, to an extent.
The bare command dumps the whole schema, there is also a `--keys`
argument to dump only a specific key.
WIP commit, tests will need to be rebased to use the new patterns once
#18 is merged.
Update schema tests to use new patterns
@dmoerner
dmoerner marked this pull request as ready for review March 6, 2026 20:14
Comment threadsrc/commands/config/schema.ts Outdated
const resolved = await resolveProfile(process.cwd());
if (!resolved) {
console.error(
"No Clerk project linked to this directory. Run `clerk init` to set up.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should recommend link here, as init will go through the full Clerk setup

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.

Maybe worthwhile to consider in the future (not now) a standardized error class which can enforce links + formatting for errors with the CLI?

process.exit(1);
}

// Use `console.error` for informational messages so stdout is just the JSON response.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

clever

@dmoerner
dmoerner merged commit 119f7f0 into mainMar 8, 2026
1 check passed
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
…mpts (#38)
* chore: add magicast dependency for AST-based code manipulation
Used by the init command's framework scaffolders to safely add imports
and modify config files without breaking existing code.
* refactor: fix framework SDK names and detection priority
- Fix @clerk/clerk-react → @clerk/react
- Fix @clerk/tanstack-start → @clerk/tanstack-react-start
- Remove standalone vite detection (covered by react)
- Reorder priority: scaffoldable frameworks first, then expo, react,
express, fastify
- Export readDeps for use by init context module
* feat(init): add project context gathering
Detects framework, TypeScript, src/ directory convention, package
manager, Next.js router variant, middleware filename, layout path,
and existing Clerk SDK installation.
* feat(init): add scaffold system with framework-specific scaffolders
Add idempotent scaffolders for Next.js (App + Pages Router), React,
React Router, Nuxt, TanStack Start, Astro, and Vue. Each scaffolder
generates framework-appropriate boilerplate (middleware, providers,
auth pages) while preserving existing user code.
Shared helpers handle AST-based import injection (magicast with string
fallback), middleware composition, and auth page creation.
* feat(init): add scan, format, preview, and agent prompt modules
- scan: detect competing auth libraries pre-scaffold and scan for
hardcoded keys/leftover imports post-scaffold
- format: run Prettier/Biome on generated files
- preview: show planned file changes and confirm before writing
- prompts: framework-specific agent mode prompts with exact code
snippets and file paths
* feat(init): rewrite init command with scaffold and scan flow
Replace the minimal init (login + link + install + env pull) with a
full orchestrator that also scaffolds framework boilerplate and scans
for issues. Skips login/link when already authenticated and linked.
* docs(init): update README with scaffolding docs and framework table
- Add Agent Mode section
- Add env var column to framework detection table
- Add Expo, Express, Fastify to detection table
- Document scaffolding actions for all 8 supported frameworks
- Note that Expo/Express/Fastify are detected but not scaffolded
* refactor(init): restructure agent prompts into markdown templates
Replace monolithic prompts.ts with individual .md template files per
framework, matching the clerk-docs structured format (sections, rules,
deprecated patterns, verification checklists).
- Move prompts to src/commands/init/prompts/*.md with {{PLACEHOLDER}}
interpolation
- Add prompts for expo, express, and fastify frameworks
- Merge DOCS_URLS + TEMPLATE_MAP into single FRAMEWORK_PROMPTS record
- Extract shared pmInstallCommand, remove duplicate pmAddCommand
- Fix formatter-escaped underscores (\_app, \_\_root) in template loader
- Add "After Setup" section to all prompts (matching clerk-docs)
* refactor(init): make FileAction a discriminated union and extend FrameworkScaffold
FileAction is now a proper discriminated union with a dedicated `skip`
variant that has no `content` field, enforced at the type level. The
FrameworkScaffold interface gains `dep`, `variant`, `minMajorVersion`,
`matches()`, and optional `enrichContext()` so each scaffolder is
self-describing. Enrichment fields (variant, layoutPath,
middlewareBasename) become optional on ProjectContext since they are
populated after gatherContext.
* refactor(init): extract Next.js context enrichment to frameworks/nextjs-context
Move parseNextMajorVersion, detectMiddlewareBasename, detectNextjsVariant,
and detectLayoutPath from context.ts into a dedicated nextjs-context.ts
module. This isolates framework-specific logic behind the enrichContext
hook on FrameworkScaffold rather than coupling it to gatherContext.
Parallelize dirExists calls with Promise.all in both files.
* refactor(init): replace scaffold key map with matches() dispatch and version check
Replace the Record<string, FrameworkScaffold> keyed map with an array
using satisfies and matches()-based lookup. Add enrichProjectContext()
that delegates to each scaffolder's enrichContext hook. Add minMajorVersion
guard that checks the framework dep version before scaffolding.
* refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
Add parseMajorVersion, insertAfterLastImport, wrapBodyWithProvider, and
resolveNextjsMiddlewareBasename to helpers. Use proper skip FileAction
in scaffoldAuthPage and scaffoldNextjsMiddleware. Flatten nested ifs
with early returns and store BunFile reference once. The middleware
fallback now resolves from the actual Next.js version in deps.
* refactor(init): update all scaffolders with skip actions, dep/matches, and minMajorVersion
Each scaffolder now exports dep, matches(), and minMajorVersion. All skip
cases use the proper FileAction skip variant. Flatten nested ifs with
early returns across scaffoldLayout, scaffoldApp, scaffoldMiddleware, and
scaffoldConfig. Use shared wrapBodyWithProvider (nextjs-app, tanstack-start),
insertAfterLastImport (react-router, vue), and extract wrapWithClerkProvider
in react.ts. Store BunFile references to avoid duplicate creation.
* refactor(init): remove findings cap, precompile regexes, and unexport internal types
Remove MAX_FINDINGS so no context is lost. Convert IGNORE_DIRS to a Set
for O(1) lookups. Precompile CODE_SCANS regexes once at module level.
Inline matchesFramework guard. Convert AuthLibraryScan and CodeScan from
exported interfaces to local types since they are not imported elsewhere.
* refactor(init): replace readFileSync with static text imports for compiled binaries
Use Bun's `import ... with { type: "text" }` to embed markdown prompt
templates at build time. This replaces the runtime readFileSync +
import.meta.dir approach that would break in compiled Bun binaries.
Remove the template cache since imports are already static.
* refactor(init): abstract formatter config into data-driven array
Replace inline if-checks for prettier/biome with a FormatterConfig type
and a FORMATTERS array. The runFormatters loop now iterates the config,
making it trivial to add new formatters.
* test(init): update tests for discriminated union, enrichContext, and version check
Update context tests to call enrichProjectContext separately from
gatherContext and import parseMajorVersion from helpers. Add tests for
scaffold version check (below minimum, meets minimum, Next.js 16 proxy).
Update nextjs-app tests to assert on the skip type instead of skipReason
field. Update scan test to verify all findings are returned without cap.
* chore: update bun.lock with magicast dependency
* refactor(init): extract shared auth and config scaffolding helpers
Add jsxAuthPageContent with type-safe JsxClerkPackage union,
scaffoldConfigFile generic for the find→check→modify pattern,
authComponentName, and inline capitalize. These shared helpers
eliminate duplication across framework scaffolders.
* refactor(init): use shared helpers in framework scaffolders
Replace duplicated authRouteContent/nextjsAuthPageContent with
jsxAuthPageContent, replace per-framework scaffoldConfig with
scaffoldConfigFile in astro, nuxt, and react-router. Remove
unused imports and add enableV8Middleware documentation.
* refactor(init): restructure preview, prompts, and scan modules
Update preview formatting to use switch on discriminated union,
restructure prompts/index.ts with typed template resolution and
variable building, and minor scan.ts cleanup.
* test(init): add framework scaffolder and scan tests
Add tests for nextjs-app (middleware composition, provider wrapping,
src/ paths, proxy basename), react-router (root modification, loader
merge), tanstack-start (base dir detection), and scan (no findings cap).
* chore(init): add markdown type declaration for static text imports
* feat(init): add framework lookup utility with aliases
Export FRAMEWORK_MAP and add lookupFramework() to resolve framework
names or aliases (e.g. "tanstack-start" → "@tanstack/react-start")
along with FRAMEWORK_NAMES for validation and display.
* feat(init): add i18nLocaleDir to ProjectContext type
Add optional i18nLocaleDir field to ProjectContext for frameworks
that detect locale-based routing directories (e.g. [locale], [lang]).
* refactor(init): extract previewPlan display function
Split preview logic into previewPlan() (display only) and
previewAndConfirm() (display + prompt) to support --yes mode
without duplicating the plan rendering code.
* feat(init): add shared scaffolding helpers for auth, env, and i18n
Add reusable helpers for all framework scaffolders:
- authFileSpecs() factory for sign-in/sign-up file generation
- scaffoldEnvVars() and SIGN_ROUTE_ENV_VARS for env file management
- htmlAuthComponentMarkup() and jsxAuthComponentMarkup() with
Tailwind/plain CSS variants
- hasTailwindStyles() for style detection
- i18n middleware detection, composition, and routing helpers
(detectI18nMiddlewareLib, composeWithI18nMiddleware, etc.)
- findFirstDirMatch() for generic directory scanning
* feat(init): detect i18n locale directory in Next.js context
Add detectI18nLocaleDir() to identify App Router locale directories
(e.g. [locale], [lang]) by checking for layout files inside dynamic
segments. Populate i18nLocaleDir in enrichNextjsContext() so
scaffolders can place auth pages inside locale-prefixed paths.
* feat(init): support framework override in context gathering
Accept optional frameworkOverride parameter in gatherContext() to
skip auto-detection when the user specifies --framework explicitly.
* feat(init): wire --framework, --yes, and --prompt CLI options
Register --framework <name>, -y/--yes, and --prompt options on the
init command. Wire them through to framework override resolution,
preview-only plan display, and agent prompt output respectively.
* refactor(init): migrate framework scaffolders to shared helpers
Update all six framework scaffolders (Astro, Next.js App/Pages,
Nuxt, React Router, TanStack Start) to use the shared helpers:
- authFileSpecs() factory for sign-in/sign-up generation
- scaffoldEnvVars() for .env file management
- hasTailwindStyles() for consistent style detection
- i18n-aware auth page placement using locale directory detection
- htmlAuthComponentMarkup()/jsxAuthComponentMarkup() for rendering
* test(init): add i18n detection and locale routing tests
Add tests for i18n support across frameworks:
- Context: locale directory detection ([locale], [lang]) with
layout file validation and src/ convention support
- Next.js App Router: i18n auth page placement, composed Clerk +
next-intl middleware, expression export handling, env var scaffolding
- React Router: ($locale) prefix detection for auth routes
- TanStack Start: {-$locale} directory detection for auth routes
* docs(init): document new CLI options and update help output
Add --framework, --yes, and --prompt options to init command README
with usage examples. Update root README help output with --verbose
flag documentation.
* refactor(init): address PR review comments
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
* test(init): add missing framework scaffolder tests
Add test coverage for the 5 framework scaffolders that were missing
tests (jfoshee #21/#22):
- astro.test.ts (10 tests)
- nuxt.test.ts (8 tests)
- vue.test.ts (6 tests)
- react.test.ts (7 tests)
- nextjs-pages.test.ts (10 tests)
All tests use semantic path-based lookups via findAction() helper.
Sign up for freeto 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

@dmoerner@wyattjoh@brkalow
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(config): Schema support - #19

Merged
dmoerner merged 3 commits into
mainfrom
daniel/config-schema
Mar 8, 2026
Merged

feat(config): Schema support#19
dmoerner merged 3 commits into
mainfrom
daniel/config-schema

Conversation

@dmoerner

@dmoernerdmoerner commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Implement config schema command to allow fetching the schema from PLAPI. This will make Clerk CLI config self-documenting, to an extent. The bare command dumps the whole schema, there is also a --keys argument to dump only a specific key. This can be useful to save context.

Implement `config schema` command to allow fetching the schema from
PLAPI. This will make Clerk CLI config self-documenting, to an extent.
The bare command dumps the whole schema, there is also a `--keys`
argument to dump only a specific key.
WIP commit, tests will need to be rebased to use the new patterns once
#18 is merged.
Update schema tests to use new patterns
@dmoerner
dmoerner marked this pull request as ready for review March 6, 2026 20:14
Comment threadsrc/commands/config/schema.ts Outdated
const resolved = await resolveProfile(process.cwd());
if (!resolved) {
console.error(
"No Clerk project linked to this directory. Run `clerk init` to set up.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should recommend link here, as init will go through the full Clerk setup

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.

Maybe worthwhile to consider in the future (not now) a standardized error class which can enforce links + formatting for errors with the CLI?

process.exit(1);
}

// Use `console.error` for informational messages so stdout is just the JSON response.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

clever

@dmoerner
dmoerner merged commit 119f7f0 into mainMar 8, 2026
1 check passed
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
…mpts (#38)
* chore: add magicast dependency for AST-based code manipulation
Used by the init command's framework scaffolders to safely add imports
and modify config files without breaking existing code.
* refactor: fix framework SDK names and detection priority
- Fix @clerk/clerk-react → @clerk/react
- Fix @clerk/tanstack-start → @clerk/tanstack-react-start
- Remove standalone vite detection (covered by react)
- Reorder priority: scaffoldable frameworks first, then expo, react,
express, fastify
- Export readDeps for use by init context module
* feat(init): add project context gathering
Detects framework, TypeScript, src/ directory convention, package
manager, Next.js router variant, middleware filename, layout path,
and existing Clerk SDK installation.
* feat(init): add scaffold system with framework-specific scaffolders
Add idempotent scaffolders for Next.js (App + Pages Router), React,
React Router, Nuxt, TanStack Start, Astro, and Vue. Each scaffolder
generates framework-appropriate boilerplate (middleware, providers,
auth pages) while preserving existing user code.
Shared helpers handle AST-based import injection (magicast with string
fallback), middleware composition, and auth page creation.
* feat(init): add scan, format, preview, and agent prompt modules
- scan: detect competing auth libraries pre-scaffold and scan for
hardcoded keys/leftover imports post-scaffold
- format: run Prettier/Biome on generated files
- preview: show planned file changes and confirm before writing
- prompts: framework-specific agent mode prompts with exact code
snippets and file paths
* feat(init): rewrite init command with scaffold and scan flow
Replace the minimal init (login + link + install + env pull) with a
full orchestrator that also scaffolds framework boilerplate and scans
for issues. Skips login/link when already authenticated and linked.
* docs(init): update README with scaffolding docs and framework table
- Add Agent Mode section
- Add env var column to framework detection table
- Add Expo, Express, Fastify to detection table
- Document scaffolding actions for all 8 supported frameworks
- Note that Expo/Express/Fastify are detected but not scaffolded
* refactor(init): restructure agent prompts into markdown templates
Replace monolithic prompts.ts with individual .md template files per
framework, matching the clerk-docs structured format (sections, rules,
deprecated patterns, verification checklists).
- Move prompts to src/commands/init/prompts/*.md with {{PLACEHOLDER}}
interpolation
- Add prompts for expo, express, and fastify frameworks
- Merge DOCS_URLS + TEMPLATE_MAP into single FRAMEWORK_PROMPTS record
- Extract shared pmInstallCommand, remove duplicate pmAddCommand
- Fix formatter-escaped underscores (\_app, \_\_root) in template loader
- Add "After Setup" section to all prompts (matching clerk-docs)
* refactor(init): make FileAction a discriminated union and extend FrameworkScaffold
FileAction is now a proper discriminated union with a dedicated `skip`
variant that has no `content` field, enforced at the type level. The
FrameworkScaffold interface gains `dep`, `variant`, `minMajorVersion`,
`matches()`, and optional `enrichContext()` so each scaffolder is
self-describing. Enrichment fields (variant, layoutPath,
middlewareBasename) become optional on ProjectContext since they are
populated after gatherContext.
* refactor(init): extract Next.js context enrichment to frameworks/nextjs-context
Move parseNextMajorVersion, detectMiddlewareBasename, detectNextjsVariant,
and detectLayoutPath from context.ts into a dedicated nextjs-context.ts
module. This isolates framework-specific logic behind the enrichContext
hook on FrameworkScaffold rather than coupling it to gatherContext.
Parallelize dirExists calls with Promise.all in both files.
* refactor(init): replace scaffold key map with matches() dispatch and version check
Replace the Record<string, FrameworkScaffold> keyed map with an array
using satisfies and matches()-based lookup. Add enrichProjectContext()
that delegates to each scaffolder's enrichContext hook. Add minMajorVersion
guard that checks the framework dep version before scaffolding.
* refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
Add parseMajorVersion, insertAfterLastImport, wrapBodyWithProvider, and
resolveNextjsMiddlewareBasename to helpers. Use proper skip FileAction
in scaffoldAuthPage and scaffoldNextjsMiddleware. Flatten nested ifs
with early returns and store BunFile reference once. The middleware
fallback now resolves from the actual Next.js version in deps.
* refactor(init): update all scaffolders with skip actions, dep/matches, and minMajorVersion
Each scaffolder now exports dep, matches(), and minMajorVersion. All skip
cases use the proper FileAction skip variant. Flatten nested ifs with
early returns across scaffoldLayout, scaffoldApp, scaffoldMiddleware, and
scaffoldConfig. Use shared wrapBodyWithProvider (nextjs-app, tanstack-start),
insertAfterLastImport (react-router, vue), and extract wrapWithClerkProvider
in react.ts. Store BunFile references to avoid duplicate creation.
* refactor(init): remove findings cap, precompile regexes, and unexport internal types
Remove MAX_FINDINGS so no context is lost. Convert IGNORE_DIRS to a Set
for O(1) lookups. Precompile CODE_SCANS regexes once at module level.
Inline matchesFramework guard. Convert AuthLibraryScan and CodeScan from
exported interfaces to local types since they are not imported elsewhere.
* refactor(init): replace readFileSync with static text imports for compiled binaries
Use Bun's `import ... with { type: "text" }` to embed markdown prompt
templates at build time. This replaces the runtime readFileSync +
import.meta.dir approach that would break in compiled Bun binaries.
Remove the template cache since imports are already static.
* refactor(init): abstract formatter config into data-driven array
Replace inline if-checks for prettier/biome with a FormatterConfig type
and a FORMATTERS array. The runFormatters loop now iterates the config,
making it trivial to add new formatters.
* test(init): update tests for discriminated union, enrichContext, and version check
Update context tests to call enrichProjectContext separately from
gatherContext and import parseMajorVersion from helpers. Add tests for
scaffold version check (below minimum, meets minimum, Next.js 16 proxy).
Update nextjs-app tests to assert on the skip type instead of skipReason
field. Update scan test to verify all findings are returned without cap.
* chore: update bun.lock with magicast dependency
* refactor(init): extract shared auth and config scaffolding helpers
Add jsxAuthPageContent with type-safe JsxClerkPackage union,
scaffoldConfigFile generic for the find→check→modify pattern,
authComponentName, and inline capitalize. These shared helpers
eliminate duplication across framework scaffolders.
* refactor(init): use shared helpers in framework scaffolders
Replace duplicated authRouteContent/nextjsAuthPageContent with
jsxAuthPageContent, replace per-framework scaffoldConfig with
scaffoldConfigFile in astro, nuxt, and react-router. Remove
unused imports and add enableV8Middleware documentation.
* refactor(init): restructure preview, prompts, and scan modules
Update preview formatting to use switch on discriminated union,
restructure prompts/index.ts with typed template resolution and
variable building, and minor scan.ts cleanup.
* test(init): add framework scaffolder and scan tests
Add tests for nextjs-app (middleware composition, provider wrapping,
src/ paths, proxy basename), react-router (root modification, loader
merge), tanstack-start (base dir detection), and scan (no findings cap).
* chore(init): add markdown type declaration for static text imports
* feat(init): add framework lookup utility with aliases
Export FRAMEWORK_MAP and add lookupFramework() to resolve framework
names or aliases (e.g. "tanstack-start" → "@tanstack/react-start")
along with FRAMEWORK_NAMES for validation and display.
* feat(init): add i18nLocaleDir to ProjectContext type
Add optional i18nLocaleDir field to ProjectContext for frameworks
that detect locale-based routing directories (e.g. [locale], [lang]).
* refactor(init): extract previewPlan display function
Split preview logic into previewPlan() (display only) and
previewAndConfirm() (display + prompt) to support --yes mode
without duplicating the plan rendering code.
* feat(init): add shared scaffolding helpers for auth, env, and i18n
Add reusable helpers for all framework scaffolders:
- authFileSpecs() factory for sign-in/sign-up file generation
- scaffoldEnvVars() and SIGN_ROUTE_ENV_VARS for env file management
- htmlAuthComponentMarkup() and jsxAuthComponentMarkup() with
Tailwind/plain CSS variants
- hasTailwindStyles() for style detection
- i18n middleware detection, composition, and routing helpers
(detectI18nMiddlewareLib, composeWithI18nMiddleware, etc.)
- findFirstDirMatch() for generic directory scanning
* feat(init): detect i18n locale directory in Next.js context
Add detectI18nLocaleDir() to identify App Router locale directories
(e.g. [locale], [lang]) by checking for layout files inside dynamic
segments. Populate i18nLocaleDir in enrichNextjsContext() so
scaffolders can place auth pages inside locale-prefixed paths.
* feat(init): support framework override in context gathering
Accept optional frameworkOverride parameter in gatherContext() to
skip auto-detection when the user specifies --framework explicitly.
* feat(init): wire --framework, --yes, and --prompt CLI options
Register --framework <name>, -y/--yes, and --prompt options on the
init command. Wire them through to framework override resolution,
preview-only plan display, and agent prompt output respectively.
* refactor(init): migrate framework scaffolders to shared helpers
Update all six framework scaffolders (Astro, Next.js App/Pages,
Nuxt, React Router, TanStack Start) to use the shared helpers:
- authFileSpecs() factory for sign-in/sign-up generation
- scaffoldEnvVars() for .env file management
- hasTailwindStyles() for consistent style detection
- i18n-aware auth page placement using locale directory detection
- htmlAuthComponentMarkup()/jsxAuthComponentMarkup() for rendering
* test(init): add i18n detection and locale routing tests
Add tests for i18n support across frameworks:
- Context: locale directory detection ([locale], [lang]) with
layout file validation and src/ convention support
- Next.js App Router: i18n auth page placement, composed Clerk +
next-intl middleware, expression export handling, env var scaffolding
- React Router: ($locale) prefix detection for auth routes
- TanStack Start: {-$locale} directory detection for auth routes
* docs(init): document new CLI options and update help output
Add --framework, --yes, and --prompt options to init command README
with usage examples. Update root README help output with --verbose
flag documentation.
* refactor(init): address PR review comments
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
* test(init): add missing framework scaffolder tests
Add test coverage for the 5 framework scaffolders that were missing
tests (jfoshee #21/#22):
- astro.test.ts (10 tests)
- nuxt.test.ts (8 tests)
- vue.test.ts (6 tests)
- react.test.ts (7 tests)
- nextjs-pages.test.ts (10 tests)
All tests use semantic path-based lookups via findAction() helper.
Sign up for freeto 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

@dmoerner@wyattjoh@brkalow
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(config): Schema support - #19

Merged
dmoerner merged 3 commits into
mainfrom
daniel/config-schema
Mar 8, 2026
Merged

feat(config): Schema support#19
dmoerner merged 3 commits into
mainfrom
daniel/config-schema

Conversation

@dmoerner

@dmoernerdmoerner commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Implement config schema command to allow fetching the schema from PLAPI. This will make Clerk CLI config self-documenting, to an extent. The bare command dumps the whole schema, there is also a --keys argument to dump only a specific key. This can be useful to save context.

Implement `config schema` command to allow fetching the schema from
PLAPI. This will make Clerk CLI config self-documenting, to an extent.
The bare command dumps the whole schema, there is also a `--keys`
argument to dump only a specific key.
WIP commit, tests will need to be rebased to use the new patterns once
#18 is merged.
Update schema tests to use new patterns
@dmoerner
dmoerner marked this pull request as ready for review March 6, 2026 20:14
Comment threadsrc/commands/config/schema.ts Outdated
const resolved = await resolveProfile(process.cwd());
if (!resolved) {
console.error(
"No Clerk project linked to this directory. Run `clerk init` to set up.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should recommend link here, as init will go through the full Clerk setup

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.

Maybe worthwhile to consider in the future (not now) a standardized error class which can enforce links + formatting for errors with the CLI?

process.exit(1);
}

// Use `console.error` for informational messages so stdout is just the JSON response.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

clever

@dmoerner
dmoerner merged commit 119f7f0 into mainMar 8, 2026
1 check passed
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
…mpts (#38)
* chore: add magicast dependency for AST-based code manipulation
Used by the init command's framework scaffolders to safely add imports
and modify config files without breaking existing code.
* refactor: fix framework SDK names and detection priority
- Fix @clerk/clerk-react → @clerk/react
- Fix @clerk/tanstack-start → @clerk/tanstack-react-start
- Remove standalone vite detection (covered by react)
- Reorder priority: scaffoldable frameworks first, then expo, react,
express, fastify
- Export readDeps for use by init context module
* feat(init): add project context gathering
Detects framework, TypeScript, src/ directory convention, package
manager, Next.js router variant, middleware filename, layout path,
and existing Clerk SDK installation.
* feat(init): add scaffold system with framework-specific scaffolders
Add idempotent scaffolders for Next.js (App + Pages Router), React,
React Router, Nuxt, TanStack Start, Astro, and Vue. Each scaffolder
generates framework-appropriate boilerplate (middleware, providers,
auth pages) while preserving existing user code.
Shared helpers handle AST-based import injection (magicast with string
fallback), middleware composition, and auth page creation.
* feat(init): add scan, format, preview, and agent prompt modules
- scan: detect competing auth libraries pre-scaffold and scan for
hardcoded keys/leftover imports post-scaffold
- format: run Prettier/Biome on generated files
- preview: show planned file changes and confirm before writing
- prompts: framework-specific agent mode prompts with exact code
snippets and file paths
* feat(init): rewrite init command with scaffold and scan flow
Replace the minimal init (login + link + install + env pull) with a
full orchestrator that also scaffolds framework boilerplate and scans
for issues. Skips login/link when already authenticated and linked.
* docs(init): update README with scaffolding docs and framework table
- Add Agent Mode section
- Add env var column to framework detection table
- Add Expo, Express, Fastify to detection table
- Document scaffolding actions for all 8 supported frameworks
- Note that Expo/Express/Fastify are detected but not scaffolded
* refactor(init): restructure agent prompts into markdown templates
Replace monolithic prompts.ts with individual .md template files per
framework, matching the clerk-docs structured format (sections, rules,
deprecated patterns, verification checklists).
- Move prompts to src/commands/init/prompts/*.md with {{PLACEHOLDER}}
interpolation
- Add prompts for expo, express, and fastify frameworks
- Merge DOCS_URLS + TEMPLATE_MAP into single FRAMEWORK_PROMPTS record
- Extract shared pmInstallCommand, remove duplicate pmAddCommand
- Fix formatter-escaped underscores (\_app, \_\_root) in template loader
- Add "After Setup" section to all prompts (matching clerk-docs)
* refactor(init): make FileAction a discriminated union and extend FrameworkScaffold
FileAction is now a proper discriminated union with a dedicated `skip`
variant that has no `content` field, enforced at the type level. The
FrameworkScaffold interface gains `dep`, `variant`, `minMajorVersion`,
`matches()`, and optional `enrichContext()` so each scaffolder is
self-describing. Enrichment fields (variant, layoutPath,
middlewareBasename) become optional on ProjectContext since they are
populated after gatherContext.
* refactor(init): extract Next.js context enrichment to frameworks/nextjs-context
Move parseNextMajorVersion, detectMiddlewareBasename, detectNextjsVariant,
and detectLayoutPath from context.ts into a dedicated nextjs-context.ts
module. This isolates framework-specific logic behind the enrichContext
hook on FrameworkScaffold rather than coupling it to gatherContext.
Parallelize dirExists calls with Promise.all in both files.
* refactor(init): replace scaffold key map with matches() dispatch and version check
Replace the Record<string, FrameworkScaffold> keyed map with an array
using satisfies and matches()-based lookup. Add enrichProjectContext()
that delegates to each scaffolder's enrichContext hook. Add minMajorVersion
guard that checks the framework dep version before scaffolding.
* refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
Add parseMajorVersion, insertAfterLastImport, wrapBodyWithProvider, and
resolveNextjsMiddlewareBasename to helpers. Use proper skip FileAction
in scaffoldAuthPage and scaffoldNextjsMiddleware. Flatten nested ifs
with early returns and store BunFile reference once. The middleware
fallback now resolves from the actual Next.js version in deps.
* refactor(init): update all scaffolders with skip actions, dep/matches, and minMajorVersion
Each scaffolder now exports dep, matches(), and minMajorVersion. All skip
cases use the proper FileAction skip variant. Flatten nested ifs with
early returns across scaffoldLayout, scaffoldApp, scaffoldMiddleware, and
scaffoldConfig. Use shared wrapBodyWithProvider (nextjs-app, tanstack-start),
insertAfterLastImport (react-router, vue), and extract wrapWithClerkProvider
in react.ts. Store BunFile references to avoid duplicate creation.
* refactor(init): remove findings cap, precompile regexes, and unexport internal types
Remove MAX_FINDINGS so no context is lost. Convert IGNORE_DIRS to a Set
for O(1) lookups. Precompile CODE_SCANS regexes once at module level.
Inline matchesFramework guard. Convert AuthLibraryScan and CodeScan from
exported interfaces to local types since they are not imported elsewhere.
* refactor(init): replace readFileSync with static text imports for compiled binaries
Use Bun's `import ... with { type: "text" }` to embed markdown prompt
templates at build time. This replaces the runtime readFileSync +
import.meta.dir approach that would break in compiled Bun binaries.
Remove the template cache since imports are already static.
* refactor(init): abstract formatter config into data-driven array
Replace inline if-checks for prettier/biome with a FormatterConfig type
and a FORMATTERS array. The runFormatters loop now iterates the config,
making it trivial to add new formatters.
* test(init): update tests for discriminated union, enrichContext, and version check
Update context tests to call enrichProjectContext separately from
gatherContext and import parseMajorVersion from helpers. Add tests for
scaffold version check (below minimum, meets minimum, Next.js 16 proxy).
Update nextjs-app tests to assert on the skip type instead of skipReason
field. Update scan test to verify all findings are returned without cap.
* chore: update bun.lock with magicast dependency
* refactor(init): extract shared auth and config scaffolding helpers
Add jsxAuthPageContent with type-safe JsxClerkPackage union,
scaffoldConfigFile generic for the find→check→modify pattern,
authComponentName, and inline capitalize. These shared helpers
eliminate duplication across framework scaffolders.
* refactor(init): use shared helpers in framework scaffolders
Replace duplicated authRouteContent/nextjsAuthPageContent with
jsxAuthPageContent, replace per-framework scaffoldConfig with
scaffoldConfigFile in astro, nuxt, and react-router. Remove
unused imports and add enableV8Middleware documentation.
* refactor(init): restructure preview, prompts, and scan modules
Update preview formatting to use switch on discriminated union,
restructure prompts/index.ts with typed template resolution and
variable building, and minor scan.ts cleanup.
* test(init): add framework scaffolder and scan tests
Add tests for nextjs-app (middleware composition, provider wrapping,
src/ paths, proxy basename), react-router (root modification, loader
merge), tanstack-start (base dir detection), and scan (no findings cap).
* chore(init): add markdown type declaration for static text imports
* feat(init): add framework lookup utility with aliases
Export FRAMEWORK_MAP and add lookupFramework() to resolve framework
names or aliases (e.g. "tanstack-start" → "@tanstack/react-start")
along with FRAMEWORK_NAMES for validation and display.
* feat(init): add i18nLocaleDir to ProjectContext type
Add optional i18nLocaleDir field to ProjectContext for frameworks
that detect locale-based routing directories (e.g. [locale], [lang]).
* refactor(init): extract previewPlan display function
Split preview logic into previewPlan() (display only) and
previewAndConfirm() (display + prompt) to support --yes mode
without duplicating the plan rendering code.
* feat(init): add shared scaffolding helpers for auth, env, and i18n
Add reusable helpers for all framework scaffolders:
- authFileSpecs() factory for sign-in/sign-up file generation
- scaffoldEnvVars() and SIGN_ROUTE_ENV_VARS for env file management
- htmlAuthComponentMarkup() and jsxAuthComponentMarkup() with
Tailwind/plain CSS variants
- hasTailwindStyles() for style detection
- i18n middleware detection, composition, and routing helpers
(detectI18nMiddlewareLib, composeWithI18nMiddleware, etc.)
- findFirstDirMatch() for generic directory scanning
* feat(init): detect i18n locale directory in Next.js context
Add detectI18nLocaleDir() to identify App Router locale directories
(e.g. [locale], [lang]) by checking for layout files inside dynamic
segments. Populate i18nLocaleDir in enrichNextjsContext() so
scaffolders can place auth pages inside locale-prefixed paths.
* feat(init): support framework override in context gathering
Accept optional frameworkOverride parameter in gatherContext() to
skip auto-detection when the user specifies --framework explicitly.
* feat(init): wire --framework, --yes, and --prompt CLI options
Register --framework <name>, -y/--yes, and --prompt options on the
init command. Wire them through to framework override resolution,
preview-only plan display, and agent prompt output respectively.
* refactor(init): migrate framework scaffolders to shared helpers
Update all six framework scaffolders (Astro, Next.js App/Pages,
Nuxt, React Router, TanStack Start) to use the shared helpers:
- authFileSpecs() factory for sign-in/sign-up generation
- scaffoldEnvVars() for .env file management
- hasTailwindStyles() for consistent style detection
- i18n-aware auth page placement using locale directory detection
- htmlAuthComponentMarkup()/jsxAuthComponentMarkup() for rendering
* test(init): add i18n detection and locale routing tests
Add tests for i18n support across frameworks:
- Context: locale directory detection ([locale], [lang]) with
layout file validation and src/ convention support
- Next.js App Router: i18n auth page placement, composed Clerk +
next-intl middleware, expression export handling, env var scaffolding
- React Router: ($locale) prefix detection for auth routes
- TanStack Start: {-$locale} directory detection for auth routes
* docs(init): document new CLI options and update help output
Add --framework, --yes, and --prompt options to init command README
with usage examples. Update root README help output with --verbose
flag documentation.
* refactor(init): address PR review comments
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
* test(init): add missing framework scaffolder tests
Add test coverage for the 5 framework scaffolders that were missing
tests (jfoshee #21/#22):
- astro.test.ts (10 tests)
- nuxt.test.ts (8 tests)
- vue.test.ts (6 tests)
- react.test.ts (7 tests)
- nextjs-pages.test.ts (10 tests)
All tests use semantic path-based lookups via findAction() helper.
Sign up for freeto 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

@dmoerner@wyattjoh@brkalow
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(config): Schema support - #19

Merged
dmoerner merged 3 commits into
mainfrom
daniel/config-schema
Mar 8, 2026
Merged

feat(config): Schema support#19
dmoerner merged 3 commits into
mainfrom
daniel/config-schema

Conversation

@dmoerner

@dmoernerdmoerner commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Implement config schema command to allow fetching the schema from PLAPI. This will make Clerk CLI config self-documenting, to an extent. The bare command dumps the whole schema, there is also a --keys argument to dump only a specific key. This can be useful to save context.

Implement `config schema` command to allow fetching the schema from
PLAPI. This will make Clerk CLI config self-documenting, to an extent.
The bare command dumps the whole schema, there is also a `--keys`
argument to dump only a specific key.
WIP commit, tests will need to be rebased to use the new patterns once
#18 is merged.
Update schema tests to use new patterns
@dmoerner
dmoerner marked this pull request as ready for review March 6, 2026 20:14
Comment threadsrc/commands/config/schema.ts Outdated
const resolved = await resolveProfile(process.cwd());
if (!resolved) {
console.error(
"No Clerk project linked to this directory. Run `clerk init` to set up.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should recommend link here, as init will go through the full Clerk setup

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.

Maybe worthwhile to consider in the future (not now) a standardized error class which can enforce links + formatting for errors with the CLI?

process.exit(1);
}

// Use `console.error` for informational messages so stdout is just the JSON response.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

clever

@dmoerner
dmoerner merged commit 119f7f0 into mainMar 8, 2026
1 check passed
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
…mpts (#38)
* chore: add magicast dependency for AST-based code manipulation
Used by the init command's framework scaffolders to safely add imports
and modify config files without breaking existing code.
* refactor: fix framework SDK names and detection priority
- Fix @clerk/clerk-react → @clerk/react
- Fix @clerk/tanstack-start → @clerk/tanstack-react-start
- Remove standalone vite detection (covered by react)
- Reorder priority: scaffoldable frameworks first, then expo, react,
express, fastify
- Export readDeps for use by init context module
* feat(init): add project context gathering
Detects framework, TypeScript, src/ directory convention, package
manager, Next.js router variant, middleware filename, layout path,
and existing Clerk SDK installation.
* feat(init): add scaffold system with framework-specific scaffolders
Add idempotent scaffolders for Next.js (App + Pages Router), React,
React Router, Nuxt, TanStack Start, Astro, and Vue. Each scaffolder
generates framework-appropriate boilerplate (middleware, providers,
auth pages) while preserving existing user code.
Shared helpers handle AST-based import injection (magicast with string
fallback), middleware composition, and auth page creation.
* feat(init): add scan, format, preview, and agent prompt modules
- scan: detect competing auth libraries pre-scaffold and scan for
hardcoded keys/leftover imports post-scaffold
- format: run Prettier/Biome on generated files
- preview: show planned file changes and confirm before writing
- prompts: framework-specific agent mode prompts with exact code
snippets and file paths
* feat(init): rewrite init command with scaffold and scan flow
Replace the minimal init (login + link + install + env pull) with a
full orchestrator that also scaffolds framework boilerplate and scans
for issues. Skips login/link when already authenticated and linked.
* docs(init): update README with scaffolding docs and framework table
- Add Agent Mode section
- Add env var column to framework detection table
- Add Expo, Express, Fastify to detection table
- Document scaffolding actions for all 8 supported frameworks
- Note that Expo/Express/Fastify are detected but not scaffolded
* refactor(init): restructure agent prompts into markdown templates
Replace monolithic prompts.ts with individual .md template files per
framework, matching the clerk-docs structured format (sections, rules,
deprecated patterns, verification checklists).
- Move prompts to src/commands/init/prompts/*.md with {{PLACEHOLDER}}
interpolation
- Add prompts for expo, express, and fastify frameworks
- Merge DOCS_URLS + TEMPLATE_MAP into single FRAMEWORK_PROMPTS record
- Extract shared pmInstallCommand, remove duplicate pmAddCommand
- Fix formatter-escaped underscores (\_app, \_\_root) in template loader
- Add "After Setup" section to all prompts (matching clerk-docs)
* refactor(init): make FileAction a discriminated union and extend FrameworkScaffold
FileAction is now a proper discriminated union with a dedicated `skip`
variant that has no `content` field, enforced at the type level. The
FrameworkScaffold interface gains `dep`, `variant`, `minMajorVersion`,
`matches()`, and optional `enrichContext()` so each scaffolder is
self-describing. Enrichment fields (variant, layoutPath,
middlewareBasename) become optional on ProjectContext since they are
populated after gatherContext.
* refactor(init): extract Next.js context enrichment to frameworks/nextjs-context
Move parseNextMajorVersion, detectMiddlewareBasename, detectNextjsVariant,
and detectLayoutPath from context.ts into a dedicated nextjs-context.ts
module. This isolates framework-specific logic behind the enrichContext
hook on FrameworkScaffold rather than coupling it to gatherContext.
Parallelize dirExists calls with Promise.all in both files.
* refactor(init): replace scaffold key map with matches() dispatch and version check
Replace the Record<string, FrameworkScaffold> keyed map with an array
using satisfies and matches()-based lookup. Add enrichProjectContext()
that delegates to each scaffolder's enrichContext hook. Add minMajorVersion
guard that checks the framework dep version before scaffolding.
* refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
Add parseMajorVersion, insertAfterLastImport, wrapBodyWithProvider, and
resolveNextjsMiddlewareBasename to helpers. Use proper skip FileAction
in scaffoldAuthPage and scaffoldNextjsMiddleware. Flatten nested ifs
with early returns and store BunFile reference once. The middleware
fallback now resolves from the actual Next.js version in deps.
* refactor(init): update all scaffolders with skip actions, dep/matches, and minMajorVersion
Each scaffolder now exports dep, matches(), and minMajorVersion. All skip
cases use the proper FileAction skip variant. Flatten nested ifs with
early returns across scaffoldLayout, scaffoldApp, scaffoldMiddleware, and
scaffoldConfig. Use shared wrapBodyWithProvider (nextjs-app, tanstack-start),
insertAfterLastImport (react-router, vue), and extract wrapWithClerkProvider
in react.ts. Store BunFile references to avoid duplicate creation.
* refactor(init): remove findings cap, precompile regexes, and unexport internal types
Remove MAX_FINDINGS so no context is lost. Convert IGNORE_DIRS to a Set
for O(1) lookups. Precompile CODE_SCANS regexes once at module level.
Inline matchesFramework guard. Convert AuthLibraryScan and CodeScan from
exported interfaces to local types since they are not imported elsewhere.
* refactor(init): replace readFileSync with static text imports for compiled binaries
Use Bun's `import ... with { type: "text" }` to embed markdown prompt
templates at build time. This replaces the runtime readFileSync +
import.meta.dir approach that would break in compiled Bun binaries.
Remove the template cache since imports are already static.
* refactor(init): abstract formatter config into data-driven array
Replace inline if-checks for prettier/biome with a FormatterConfig type
and a FORMATTERS array. The runFormatters loop now iterates the config,
making it trivial to add new formatters.
* test(init): update tests for discriminated union, enrichContext, and version check
Update context tests to call enrichProjectContext separately from
gatherContext and import parseMajorVersion from helpers. Add tests for
scaffold version check (below minimum, meets minimum, Next.js 16 proxy).
Update nextjs-app tests to assert on the skip type instead of skipReason
field. Update scan test to verify all findings are returned without cap.
* chore: update bun.lock with magicast dependency
* refactor(init): extract shared auth and config scaffolding helpers
Add jsxAuthPageContent with type-safe JsxClerkPackage union,
scaffoldConfigFile generic for the find→check→modify pattern,
authComponentName, and inline capitalize. These shared helpers
eliminate duplication across framework scaffolders.
* refactor(init): use shared helpers in framework scaffolders
Replace duplicated authRouteContent/nextjsAuthPageContent with
jsxAuthPageContent, replace per-framework scaffoldConfig with
scaffoldConfigFile in astro, nuxt, and react-router. Remove
unused imports and add enableV8Middleware documentation.
* refactor(init): restructure preview, prompts, and scan modules
Update preview formatting to use switch on discriminated union,
restructure prompts/index.ts with typed template resolution and
variable building, and minor scan.ts cleanup.
* test(init): add framework scaffolder and scan tests
Add tests for nextjs-app (middleware composition, provider wrapping,
src/ paths, proxy basename), react-router (root modification, loader
merge), tanstack-start (base dir detection), and scan (no findings cap).
* chore(init): add markdown type declaration for static text imports
* feat(init): add framework lookup utility with aliases
Export FRAMEWORK_MAP and add lookupFramework() to resolve framework
names or aliases (e.g. "tanstack-start" → "@tanstack/react-start")
along with FRAMEWORK_NAMES for validation and display.
* feat(init): add i18nLocaleDir to ProjectContext type
Add optional i18nLocaleDir field to ProjectContext for frameworks
that detect locale-based routing directories (e.g. [locale], [lang]).
* refactor(init): extract previewPlan display function
Split preview logic into previewPlan() (display only) and
previewAndConfirm() (display + prompt) to support --yes mode
without duplicating the plan rendering code.
* feat(init): add shared scaffolding helpers for auth, env, and i18n
Add reusable helpers for all framework scaffolders:
- authFileSpecs() factory for sign-in/sign-up file generation
- scaffoldEnvVars() and SIGN_ROUTE_ENV_VARS for env file management
- htmlAuthComponentMarkup() and jsxAuthComponentMarkup() with
Tailwind/plain CSS variants
- hasTailwindStyles() for style detection
- i18n middleware detection, composition, and routing helpers
(detectI18nMiddlewareLib, composeWithI18nMiddleware, etc.)
- findFirstDirMatch() for generic directory scanning
* feat(init): detect i18n locale directory in Next.js context
Add detectI18nLocaleDir() to identify App Router locale directories
(e.g. [locale], [lang]) by checking for layout files inside dynamic
segments. Populate i18nLocaleDir in enrichNextjsContext() so
scaffolders can place auth pages inside locale-prefixed paths.
* feat(init): support framework override in context gathering
Accept optional frameworkOverride parameter in gatherContext() to
skip auto-detection when the user specifies --framework explicitly.
* feat(init): wire --framework, --yes, and --prompt CLI options
Register --framework <name>, -y/--yes, and --prompt options on the
init command. Wire them through to framework override resolution,
preview-only plan display, and agent prompt output respectively.
* refactor(init): migrate framework scaffolders to shared helpers
Update all six framework scaffolders (Astro, Next.js App/Pages,
Nuxt, React Router, TanStack Start) to use the shared helpers:
- authFileSpecs() factory for sign-in/sign-up generation
- scaffoldEnvVars() for .env file management
- hasTailwindStyles() for consistent style detection
- i18n-aware auth page placement using locale directory detection
- htmlAuthComponentMarkup()/jsxAuthComponentMarkup() for rendering
* test(init): add i18n detection and locale routing tests
Add tests for i18n support across frameworks:
- Context: locale directory detection ([locale], [lang]) with
layout file validation and src/ convention support
- Next.js App Router: i18n auth page placement, composed Clerk +
next-intl middleware, expression export handling, env var scaffolding
- React Router: ($locale) prefix detection for auth routes
- TanStack Start: {-$locale} directory detection for auth routes
* docs(init): document new CLI options and update help output
Add --framework, --yes, and --prompt options to init command README
with usage examples. Update root README help output with --verbose
flag documentation.
* refactor(init): address PR review comments
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
* test(init): add missing framework scaffolder tests
Add test coverage for the 5 framework scaffolders that were missing
tests (jfoshee #21/#22):
- astro.test.ts (10 tests)
- nuxt.test.ts (8 tests)
- vue.test.ts (6 tests)
- react.test.ts (7 tests)
- nextjs-pages.test.ts (10 tests)
All tests use semantic path-based lookups via findAction() helper.
Sign up for freeto 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

@dmoerner@wyattjoh@brkalow
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(config): Schema support - #19

Merged
dmoerner merged 3 commits into
mainfrom
daniel/config-schema
Mar 8, 2026
Merged

feat(config): Schema support#19
dmoerner merged 3 commits into
mainfrom
daniel/config-schema

Conversation

@dmoerner

@dmoernerdmoerner commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Implement config schema command to allow fetching the schema from PLAPI. This will make Clerk CLI config self-documenting, to an extent. The bare command dumps the whole schema, there is also a --keys argument to dump only a specific key. This can be useful to save context.

Implement `config schema` command to allow fetching the schema from
PLAPI. This will make Clerk CLI config self-documenting, to an extent.
The bare command dumps the whole schema, there is also a `--keys`
argument to dump only a specific key.
WIP commit, tests will need to be rebased to use the new patterns once
#18 is merged.
Update schema tests to use new patterns
@dmoerner
dmoerner marked this pull request as ready for review March 6, 2026 20:14
Comment threadsrc/commands/config/schema.ts Outdated
const resolved = await resolveProfile(process.cwd());
if (!resolved) {
console.error(
"No Clerk project linked to this directory. Run `clerk init` to set up.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should recommend link here, as init will go through the full Clerk setup

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.

Maybe worthwhile to consider in the future (not now) a standardized error class which can enforce links + formatting for errors with the CLI?

process.exit(1);
}

// Use `console.error` for informational messages so stdout is just the JSON response.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

clever

@dmoerner
dmoerner merged commit 119f7f0 into mainMar 8, 2026
1 check passed
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
…mpts (#38)
* chore: add magicast dependency for AST-based code manipulation
Used by the init command's framework scaffolders to safely add imports
and modify config files without breaking existing code.
* refactor: fix framework SDK names and detection priority
- Fix @clerk/clerk-react → @clerk/react
- Fix @clerk/tanstack-start → @clerk/tanstack-react-start
- Remove standalone vite detection (covered by react)
- Reorder priority: scaffoldable frameworks first, then expo, react,
express, fastify
- Export readDeps for use by init context module
* feat(init): add project context gathering
Detects framework, TypeScript, src/ directory convention, package
manager, Next.js router variant, middleware filename, layout path,
and existing Clerk SDK installation.
* feat(init): add scaffold system with framework-specific scaffolders
Add idempotent scaffolders for Next.js (App + Pages Router), React,
React Router, Nuxt, TanStack Start, Astro, and Vue. Each scaffolder
generates framework-appropriate boilerplate (middleware, providers,
auth pages) while preserving existing user code.
Shared helpers handle AST-based import injection (magicast with string
fallback), middleware composition, and auth page creation.
* feat(init): add scan, format, preview, and agent prompt modules
- scan: detect competing auth libraries pre-scaffold and scan for
hardcoded keys/leftover imports post-scaffold
- format: run Prettier/Biome on generated files
- preview: show planned file changes and confirm before writing
- prompts: framework-specific agent mode prompts with exact code
snippets and file paths
* feat(init): rewrite init command with scaffold and scan flow
Replace the minimal init (login + link + install + env pull) with a
full orchestrator that also scaffolds framework boilerplate and scans
for issues. Skips login/link when already authenticated and linked.
* docs(init): update README with scaffolding docs and framework table
- Add Agent Mode section
- Add env var column to framework detection table
- Add Expo, Express, Fastify to detection table
- Document scaffolding actions for all 8 supported frameworks
- Note that Expo/Express/Fastify are detected but not scaffolded
* refactor(init): restructure agent prompts into markdown templates
Replace monolithic prompts.ts with individual .md template files per
framework, matching the clerk-docs structured format (sections, rules,
deprecated patterns, verification checklists).
- Move prompts to src/commands/init/prompts/*.md with {{PLACEHOLDER}}
interpolation
- Add prompts for expo, express, and fastify frameworks
- Merge DOCS_URLS + TEMPLATE_MAP into single FRAMEWORK_PROMPTS record
- Extract shared pmInstallCommand, remove duplicate pmAddCommand
- Fix formatter-escaped underscores (\_app, \_\_root) in template loader
- Add "After Setup" section to all prompts (matching clerk-docs)
* refactor(init): make FileAction a discriminated union and extend FrameworkScaffold
FileAction is now a proper discriminated union with a dedicated `skip`
variant that has no `content` field, enforced at the type level. The
FrameworkScaffold interface gains `dep`, `variant`, `minMajorVersion`,
`matches()`, and optional `enrichContext()` so each scaffolder is
self-describing. Enrichment fields (variant, layoutPath,
middlewareBasename) become optional on ProjectContext since they are
populated after gatherContext.
* refactor(init): extract Next.js context enrichment to frameworks/nextjs-context
Move parseNextMajorVersion, detectMiddlewareBasename, detectNextjsVariant,
and detectLayoutPath from context.ts into a dedicated nextjs-context.ts
module. This isolates framework-specific logic behind the enrichContext
hook on FrameworkScaffold rather than coupling it to gatherContext.
Parallelize dirExists calls with Promise.all in both files.
* refactor(init): replace scaffold key map with matches() dispatch and version check
Replace the Record<string, FrameworkScaffold> keyed map with an array
using satisfies and matches()-based lookup. Add enrichProjectContext()
that delegates to each scaffolder's enrichContext hook. Add minMajorVersion
guard that checks the framework dep version before scaffolding.
* refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
Add parseMajorVersion, insertAfterLastImport, wrapBodyWithProvider, and
resolveNextjsMiddlewareBasename to helpers. Use proper skip FileAction
in scaffoldAuthPage and scaffoldNextjsMiddleware. Flatten nested ifs
with early returns and store BunFile reference once. The middleware
fallback now resolves from the actual Next.js version in deps.
* refactor(init): update all scaffolders with skip actions, dep/matches, and minMajorVersion
Each scaffolder now exports dep, matches(), and minMajorVersion. All skip
cases use the proper FileAction skip variant. Flatten nested ifs with
early returns across scaffoldLayout, scaffoldApp, scaffoldMiddleware, and
scaffoldConfig. Use shared wrapBodyWithProvider (nextjs-app, tanstack-start),
insertAfterLastImport (react-router, vue), and extract wrapWithClerkProvider
in react.ts. Store BunFile references to avoid duplicate creation.
* refactor(init): remove findings cap, precompile regexes, and unexport internal types
Remove MAX_FINDINGS so no context is lost. Convert IGNORE_DIRS to a Set
for O(1) lookups. Precompile CODE_SCANS regexes once at module level.
Inline matchesFramework guard. Convert AuthLibraryScan and CodeScan from
exported interfaces to local types since they are not imported elsewhere.
* refactor(init): replace readFileSync with static text imports for compiled binaries
Use Bun's `import ... with { type: "text" }` to embed markdown prompt
templates at build time. This replaces the runtime readFileSync +
import.meta.dir approach that would break in compiled Bun binaries.
Remove the template cache since imports are already static.
* refactor(init): abstract formatter config into data-driven array
Replace inline if-checks for prettier/biome with a FormatterConfig type
and a FORMATTERS array. The runFormatters loop now iterates the config,
making it trivial to add new formatters.
* test(init): update tests for discriminated union, enrichContext, and version check
Update context tests to call enrichProjectContext separately from
gatherContext and import parseMajorVersion from helpers. Add tests for
scaffold version check (below minimum, meets minimum, Next.js 16 proxy).
Update nextjs-app tests to assert on the skip type instead of skipReason
field. Update scan test to verify all findings are returned without cap.
* chore: update bun.lock with magicast dependency
* refactor(init): extract shared auth and config scaffolding helpers
Add jsxAuthPageContent with type-safe JsxClerkPackage union,
scaffoldConfigFile generic for the find→check→modify pattern,
authComponentName, and inline capitalize. These shared helpers
eliminate duplication across framework scaffolders.
* refactor(init): use shared helpers in framework scaffolders
Replace duplicated authRouteContent/nextjsAuthPageContent with
jsxAuthPageContent, replace per-framework scaffoldConfig with
scaffoldConfigFile in astro, nuxt, and react-router. Remove
unused imports and add enableV8Middleware documentation.
* refactor(init): restructure preview, prompts, and scan modules
Update preview formatting to use switch on discriminated union,
restructure prompts/index.ts with typed template resolution and
variable building, and minor scan.ts cleanup.
* test(init): add framework scaffolder and scan tests
Add tests for nextjs-app (middleware composition, provider wrapping,
src/ paths, proxy basename), react-router (root modification, loader
merge), tanstack-start (base dir detection), and scan (no findings cap).
* chore(init): add markdown type declaration for static text imports
* feat(init): add framework lookup utility with aliases
Export FRAMEWORK_MAP and add lookupFramework() to resolve framework
names or aliases (e.g. "tanstack-start" → "@tanstack/react-start")
along with FRAMEWORK_NAMES for validation and display.
* feat(init): add i18nLocaleDir to ProjectContext type
Add optional i18nLocaleDir field to ProjectContext for frameworks
that detect locale-based routing directories (e.g. [locale], [lang]).
* refactor(init): extract previewPlan display function
Split preview logic into previewPlan() (display only) and
previewAndConfirm() (display + prompt) to support --yes mode
without duplicating the plan rendering code.
* feat(init): add shared scaffolding helpers for auth, env, and i18n
Add reusable helpers for all framework scaffolders:
- authFileSpecs() factory for sign-in/sign-up file generation
- scaffoldEnvVars() and SIGN_ROUTE_ENV_VARS for env file management
- htmlAuthComponentMarkup() and jsxAuthComponentMarkup() with
Tailwind/plain CSS variants
- hasTailwindStyles() for style detection
- i18n middleware detection, composition, and routing helpers
(detectI18nMiddlewareLib, composeWithI18nMiddleware, etc.)
- findFirstDirMatch() for generic directory scanning
* feat(init): detect i18n locale directory in Next.js context
Add detectI18nLocaleDir() to identify App Router locale directories
(e.g. [locale], [lang]) by checking for layout files inside dynamic
segments. Populate i18nLocaleDir in enrichNextjsContext() so
scaffolders can place auth pages inside locale-prefixed paths.
* feat(init): support framework override in context gathering
Accept optional frameworkOverride parameter in gatherContext() to
skip auto-detection when the user specifies --framework explicitly.
* feat(init): wire --framework, --yes, and --prompt CLI options
Register --framework <name>, -y/--yes, and --prompt options on the
init command. Wire them through to framework override resolution,
preview-only plan display, and agent prompt output respectively.
* refactor(init): migrate framework scaffolders to shared helpers
Update all six framework scaffolders (Astro, Next.js App/Pages,
Nuxt, React Router, TanStack Start) to use the shared helpers:
- authFileSpecs() factory for sign-in/sign-up generation
- scaffoldEnvVars() for .env file management
- hasTailwindStyles() for consistent style detection
- i18n-aware auth page placement using locale directory detection
- htmlAuthComponentMarkup()/jsxAuthComponentMarkup() for rendering
* test(init): add i18n detection and locale routing tests
Add tests for i18n support across frameworks:
- Context: locale directory detection ([locale], [lang]) with
layout file validation and src/ convention support
- Next.js App Router: i18n auth page placement, composed Clerk +
next-intl middleware, expression export handling, env var scaffolding
- React Router: ($locale) prefix detection for auth routes
- TanStack Start: {-$locale} directory detection for auth routes
* docs(init): document new CLI options and update help output
Add --framework, --yes, and --prompt options to init command README
with usage examples. Update root README help output with --verbose
flag documentation.
* refactor(init): address PR review comments
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
* test(init): add missing framework scaffolder tests
Add test coverage for the 5 framework scaffolders that were missing
tests (jfoshee #21/#22):
- astro.test.ts (10 tests)
- nuxt.test.ts (8 tests)
- vue.test.ts (6 tests)
- react.test.ts (7 tests)
- nextjs-pages.test.ts (10 tests)
All tests use semantic path-based lookups via findAction() helper.
Sign up for freeto 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

@dmoerner@wyattjoh@brkalow
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(config): Schema support - #19

Merged
dmoerner merged 3 commits into
mainfrom
daniel/config-schema
Mar 8, 2026
Merged

feat(config): Schema support#19
dmoerner merged 3 commits into
mainfrom
daniel/config-schema

Conversation

@dmoerner

@dmoernerdmoerner commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Implement config schema command to allow fetching the schema from PLAPI. This will make Clerk CLI config self-documenting, to an extent. The bare command dumps the whole schema, there is also a --keys argument to dump only a specific key. This can be useful to save context.

Implement `config schema` command to allow fetching the schema from
PLAPI. This will make Clerk CLI config self-documenting, to an extent.
The bare command dumps the whole schema, there is also a `--keys`
argument to dump only a specific key.
WIP commit, tests will need to be rebased to use the new patterns once
#18 is merged.
Update schema tests to use new patterns
@dmoerner
dmoerner marked this pull request as ready for review March 6, 2026 20:14
Comment threadsrc/commands/config/schema.ts Outdated
const resolved = await resolveProfile(process.cwd());
if (!resolved) {
console.error(
"No Clerk project linked to this directory. Run `clerk init` to set up.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should recommend link here, as init will go through the full Clerk setup

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.

Maybe worthwhile to consider in the future (not now) a standardized error class which can enforce links + formatting for errors with the CLI?

process.exit(1);
}

// Use `console.error` for informational messages so stdout is just the JSON response.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

clever

@dmoerner
dmoerner merged commit 119f7f0 into mainMar 8, 2026
1 check passed
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
…mpts (#38)
* chore: add magicast dependency for AST-based code manipulation
Used by the init command's framework scaffolders to safely add imports
and modify config files without breaking existing code.
* refactor: fix framework SDK names and detection priority
- Fix @clerk/clerk-react → @clerk/react
- Fix @clerk/tanstack-start → @clerk/tanstack-react-start
- Remove standalone vite detection (covered by react)
- Reorder priority: scaffoldable frameworks first, then expo, react,
express, fastify
- Export readDeps for use by init context module
* feat(init): add project context gathering
Detects framework, TypeScript, src/ directory convention, package
manager, Next.js router variant, middleware filename, layout path,
and existing Clerk SDK installation.
* feat(init): add scaffold system with framework-specific scaffolders
Add idempotent scaffolders for Next.js (App + Pages Router), React,
React Router, Nuxt, TanStack Start, Astro, and Vue. Each scaffolder
generates framework-appropriate boilerplate (middleware, providers,
auth pages) while preserving existing user code.
Shared helpers handle AST-based import injection (magicast with string
fallback), middleware composition, and auth page creation.
* feat(init): add scan, format, preview, and agent prompt modules
- scan: detect competing auth libraries pre-scaffold and scan for
hardcoded keys/leftover imports post-scaffold
- format: run Prettier/Biome on generated files
- preview: show planned file changes and confirm before writing
- prompts: framework-specific agent mode prompts with exact code
snippets and file paths
* feat(init): rewrite init command with scaffold and scan flow
Replace the minimal init (login + link + install + env pull) with a
full orchestrator that also scaffolds framework boilerplate and scans
for issues. Skips login/link when already authenticated and linked.
* docs(init): update README with scaffolding docs and framework table
- Add Agent Mode section
- Add env var column to framework detection table
- Add Expo, Express, Fastify to detection table
- Document scaffolding actions for all 8 supported frameworks
- Note that Expo/Express/Fastify are detected but not scaffolded
* refactor(init): restructure agent prompts into markdown templates
Replace monolithic prompts.ts with individual .md template files per
framework, matching the clerk-docs structured format (sections, rules,
deprecated patterns, verification checklists).
- Move prompts to src/commands/init/prompts/*.md with {{PLACEHOLDER}}
interpolation
- Add prompts for expo, express, and fastify frameworks
- Merge DOCS_URLS + TEMPLATE_MAP into single FRAMEWORK_PROMPTS record
- Extract shared pmInstallCommand, remove duplicate pmAddCommand
- Fix formatter-escaped underscores (\_app, \_\_root) in template loader
- Add "After Setup" section to all prompts (matching clerk-docs)
* refactor(init): make FileAction a discriminated union and extend FrameworkScaffold
FileAction is now a proper discriminated union with a dedicated `skip`
variant that has no `content` field, enforced at the type level. The
FrameworkScaffold interface gains `dep`, `variant`, `minMajorVersion`,
`matches()`, and optional `enrichContext()` so each scaffolder is
self-describing. Enrichment fields (variant, layoutPath,
middlewareBasename) become optional on ProjectContext since they are
populated after gatherContext.
* refactor(init): extract Next.js context enrichment to frameworks/nextjs-context
Move parseNextMajorVersion, detectMiddlewareBasename, detectNextjsVariant,
and detectLayoutPath from context.ts into a dedicated nextjs-context.ts
module. This isolates framework-specific logic behind the enrichContext
hook on FrameworkScaffold rather than coupling it to gatherContext.
Parallelize dirExists calls with Promise.all in both files.
* refactor(init): replace scaffold key map with matches() dispatch and version check
Replace the Record<string, FrameworkScaffold> keyed map with an array
using satisfies and matches()-based lookup. Add enrichProjectContext()
that delegates to each scaffolder's enrichContext hook. Add minMajorVersion
guard that checks the framework dep version before scaffolding.
* refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
Add parseMajorVersion, insertAfterLastImport, wrapBodyWithProvider, and
resolveNextjsMiddlewareBasename to helpers. Use proper skip FileAction
in scaffoldAuthPage and scaffoldNextjsMiddleware. Flatten nested ifs
with early returns and store BunFile reference once. The middleware
fallback now resolves from the actual Next.js version in deps.
* refactor(init): update all scaffolders with skip actions, dep/matches, and minMajorVersion
Each scaffolder now exports dep, matches(), and minMajorVersion. All skip
cases use the proper FileAction skip variant. Flatten nested ifs with
early returns across scaffoldLayout, scaffoldApp, scaffoldMiddleware, and
scaffoldConfig. Use shared wrapBodyWithProvider (nextjs-app, tanstack-start),
insertAfterLastImport (react-router, vue), and extract wrapWithClerkProvider
in react.ts. Store BunFile references to avoid duplicate creation.
* refactor(init): remove findings cap, precompile regexes, and unexport internal types
Remove MAX_FINDINGS so no context is lost. Convert IGNORE_DIRS to a Set
for O(1) lookups. Precompile CODE_SCANS regexes once at module level.
Inline matchesFramework guard. Convert AuthLibraryScan and CodeScan from
exported interfaces to local types since they are not imported elsewhere.
* refactor(init): replace readFileSync with static text imports for compiled binaries
Use Bun's `import ... with { type: "text" }` to embed markdown prompt
templates at build time. This replaces the runtime readFileSync +
import.meta.dir approach that would break in compiled Bun binaries.
Remove the template cache since imports are already static.
* refactor(init): abstract formatter config into data-driven array
Replace inline if-checks for prettier/biome with a FormatterConfig type
and a FORMATTERS array. The runFormatters loop now iterates the config,
making it trivial to add new formatters.
* test(init): update tests for discriminated union, enrichContext, and version check
Update context tests to call enrichProjectContext separately from
gatherContext and import parseMajorVersion from helpers. Add tests for
scaffold version check (below minimum, meets minimum, Next.js 16 proxy).
Update nextjs-app tests to assert on the skip type instead of skipReason
field. Update scan test to verify all findings are returned without cap.
* chore: update bun.lock with magicast dependency
* refactor(init): extract shared auth and config scaffolding helpers
Add jsxAuthPageContent with type-safe JsxClerkPackage union,
scaffoldConfigFile generic for the find→check→modify pattern,
authComponentName, and inline capitalize. These shared helpers
eliminate duplication across framework scaffolders.
* refactor(init): use shared helpers in framework scaffolders
Replace duplicated authRouteContent/nextjsAuthPageContent with
jsxAuthPageContent, replace per-framework scaffoldConfig with
scaffoldConfigFile in astro, nuxt, and react-router. Remove
unused imports and add enableV8Middleware documentation.
* refactor(init): restructure preview, prompts, and scan modules
Update preview formatting to use switch on discriminated union,
restructure prompts/index.ts with typed template resolution and
variable building, and minor scan.ts cleanup.
* test(init): add framework scaffolder and scan tests
Add tests for nextjs-app (middleware composition, provider wrapping,
src/ paths, proxy basename), react-router (root modification, loader
merge), tanstack-start (base dir detection), and scan (no findings cap).
* chore(init): add markdown type declaration for static text imports
* feat(init): add framework lookup utility with aliases
Export FRAMEWORK_MAP and add lookupFramework() to resolve framework
names or aliases (e.g. "tanstack-start" → "@tanstack/react-start")
along with FRAMEWORK_NAMES for validation and display.
* feat(init): add i18nLocaleDir to ProjectContext type
Add optional i18nLocaleDir field to ProjectContext for frameworks
that detect locale-based routing directories (e.g. [locale], [lang]).
* refactor(init): extract previewPlan display function
Split preview logic into previewPlan() (display only) and
previewAndConfirm() (display + prompt) to support --yes mode
without duplicating the plan rendering code.
* feat(init): add shared scaffolding helpers for auth, env, and i18n
Add reusable helpers for all framework scaffolders:
- authFileSpecs() factory for sign-in/sign-up file generation
- scaffoldEnvVars() and SIGN_ROUTE_ENV_VARS for env file management
- htmlAuthComponentMarkup() and jsxAuthComponentMarkup() with
Tailwind/plain CSS variants
- hasTailwindStyles() for style detection
- i18n middleware detection, composition, and routing helpers
(detectI18nMiddlewareLib, composeWithI18nMiddleware, etc.)
- findFirstDirMatch() for generic directory scanning
* feat(init): detect i18n locale directory in Next.js context
Add detectI18nLocaleDir() to identify App Router locale directories
(e.g. [locale], [lang]) by checking for layout files inside dynamic
segments. Populate i18nLocaleDir in enrichNextjsContext() so
scaffolders can place auth pages inside locale-prefixed paths.
* feat(init): support framework override in context gathering
Accept optional frameworkOverride parameter in gatherContext() to
skip auto-detection when the user specifies --framework explicitly.
* feat(init): wire --framework, --yes, and --prompt CLI options
Register --framework <name>, -y/--yes, and --prompt options on the
init command. Wire them through to framework override resolution,
preview-only plan display, and agent prompt output respectively.
* refactor(init): migrate framework scaffolders to shared helpers
Update all six framework scaffolders (Astro, Next.js App/Pages,
Nuxt, React Router, TanStack Start) to use the shared helpers:
- authFileSpecs() factory for sign-in/sign-up generation
- scaffoldEnvVars() for .env file management
- hasTailwindStyles() for consistent style detection
- i18n-aware auth page placement using locale directory detection
- htmlAuthComponentMarkup()/jsxAuthComponentMarkup() for rendering
* test(init): add i18n detection and locale routing tests
Add tests for i18n support across frameworks:
- Context: locale directory detection ([locale], [lang]) with
layout file validation and src/ convention support
- Next.js App Router: i18n auth page placement, composed Clerk +
next-intl middleware, expression export handling, env var scaffolding
- React Router: ($locale) prefix detection for auth routes
- TanStack Start: {-$locale} directory detection for auth routes
* docs(init): document new CLI options and update help output
Add --framework, --yes, and --prompt options to init command README
with usage examples. Update root README help output with --verbose
flag documentation.
* refactor(init): address PR review comments
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
* test(init): add missing framework scaffolder tests
Add test coverage for the 5 framework scaffolders that were missing
tests (jfoshee #21/#22):
- astro.test.ts (10 tests)
- nuxt.test.ts (8 tests)
- vue.test.ts (6 tests)
- react.test.ts (7 tests)
- nextjs-pages.test.ts (10 tests)
All tests use semantic path-based lookups via findAction() helper.
Sign up for freeto 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

@dmoerner@wyattjoh@brkalow
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(config): Schema support - #19

Merged
dmoerner merged 3 commits into
mainfrom
daniel/config-schema
Mar 8, 2026
Merged

feat(config): Schema support#19
dmoerner merged 3 commits into
mainfrom
daniel/config-schema

Conversation

@dmoerner

@dmoernerdmoerner commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Implement config schema command to allow fetching the schema from PLAPI. This will make Clerk CLI config self-documenting, to an extent. The bare command dumps the whole schema, there is also a --keys argument to dump only a specific key. This can be useful to save context.

Implement `config schema` command to allow fetching the schema from
PLAPI. This will make Clerk CLI config self-documenting, to an extent.
The bare command dumps the whole schema, there is also a `--keys`
argument to dump only a specific key.
WIP commit, tests will need to be rebased to use the new patterns once
#18 is merged.
Update schema tests to use new patterns
@dmoerner
dmoerner marked this pull request as ready for review March 6, 2026 20:14
Comment threadsrc/commands/config/schema.ts Outdated
const resolved = await resolveProfile(process.cwd());
if (!resolved) {
console.error(
"No Clerk project linked to this directory. Run `clerk init` to set up.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should recommend link here, as init will go through the full Clerk setup

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.

Maybe worthwhile to consider in the future (not now) a standardized error class which can enforce links + formatting for errors with the CLI?

process.exit(1);
}

// Use `console.error` for informational messages so stdout is just the JSON response.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

clever

@dmoerner
dmoerner merged commit 119f7f0 into mainMar 8, 2026
1 check passed
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
…mpts (#38)
* chore: add magicast dependency for AST-based code manipulation
Used by the init command's framework scaffolders to safely add imports
and modify config files without breaking existing code.
* refactor: fix framework SDK names and detection priority
- Fix @clerk/clerk-react → @clerk/react
- Fix @clerk/tanstack-start → @clerk/tanstack-react-start
- Remove standalone vite detection (covered by react)
- Reorder priority: scaffoldable frameworks first, then expo, react,
express, fastify
- Export readDeps for use by init context module
* feat(init): add project context gathering
Detects framework, TypeScript, src/ directory convention, package
manager, Next.js router variant, middleware filename, layout path,
and existing Clerk SDK installation.
* feat(init): add scaffold system with framework-specific scaffolders
Add idempotent scaffolders for Next.js (App + Pages Router), React,
React Router, Nuxt, TanStack Start, Astro, and Vue. Each scaffolder
generates framework-appropriate boilerplate (middleware, providers,
auth pages) while preserving existing user code.
Shared helpers handle AST-based import injection (magicast with string
fallback), middleware composition, and auth page creation.
* feat(init): add scan, format, preview, and agent prompt modules
- scan: detect competing auth libraries pre-scaffold and scan for
hardcoded keys/leftover imports post-scaffold
- format: run Prettier/Biome on generated files
- preview: show planned file changes and confirm before writing
- prompts: framework-specific agent mode prompts with exact code
snippets and file paths
* feat(init): rewrite init command with scaffold and scan flow
Replace the minimal init (login + link + install + env pull) with a
full orchestrator that also scaffolds framework boilerplate and scans
for issues. Skips login/link when already authenticated and linked.
* docs(init): update README with scaffolding docs and framework table
- Add Agent Mode section
- Add env var column to framework detection table
- Add Expo, Express, Fastify to detection table
- Document scaffolding actions for all 8 supported frameworks
- Note that Expo/Express/Fastify are detected but not scaffolded
* refactor(init): restructure agent prompts into markdown templates
Replace monolithic prompts.ts with individual .md template files per
framework, matching the clerk-docs structured format (sections, rules,
deprecated patterns, verification checklists).
- Move prompts to src/commands/init/prompts/*.md with {{PLACEHOLDER}}
interpolation
- Add prompts for expo, express, and fastify frameworks
- Merge DOCS_URLS + TEMPLATE_MAP into single FRAMEWORK_PROMPTS record
- Extract shared pmInstallCommand, remove duplicate pmAddCommand
- Fix formatter-escaped underscores (\_app, \_\_root) in template loader
- Add "After Setup" section to all prompts (matching clerk-docs)
* refactor(init): make FileAction a discriminated union and extend FrameworkScaffold
FileAction is now a proper discriminated union with a dedicated `skip`
variant that has no `content` field, enforced at the type level. The
FrameworkScaffold interface gains `dep`, `variant`, `minMajorVersion`,
`matches()`, and optional `enrichContext()` so each scaffolder is
self-describing. Enrichment fields (variant, layoutPath,
middlewareBasename) become optional on ProjectContext since they are
populated after gatherContext.
* refactor(init): extract Next.js context enrichment to frameworks/nextjs-context
Move parseNextMajorVersion, detectMiddlewareBasename, detectNextjsVariant,
and detectLayoutPath from context.ts into a dedicated nextjs-context.ts
module. This isolates framework-specific logic behind the enrichContext
hook on FrameworkScaffold rather than coupling it to gatherContext.
Parallelize dirExists calls with Promise.all in both files.
* refactor(init): replace scaffold key map with matches() dispatch and version check
Replace the Record<string, FrameworkScaffold> keyed map with an array
using satisfies and matches()-based lookup. Add enrichProjectContext()
that delegates to each scaffolder's enrichContext hook. Add minMajorVersion
guard that checks the framework dep version before scaffolding.
* refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
Add parseMajorVersion, insertAfterLastImport, wrapBodyWithProvider, and
resolveNextjsMiddlewareBasename to helpers. Use proper skip FileAction
in scaffoldAuthPage and scaffoldNextjsMiddleware. Flatten nested ifs
with early returns and store BunFile reference once. The middleware
fallback now resolves from the actual Next.js version in deps.
* refactor(init): update all scaffolders with skip actions, dep/matches, and minMajorVersion
Each scaffolder now exports dep, matches(), and minMajorVersion. All skip
cases use the proper FileAction skip variant. Flatten nested ifs with
early returns across scaffoldLayout, scaffoldApp, scaffoldMiddleware, and
scaffoldConfig. Use shared wrapBodyWithProvider (nextjs-app, tanstack-start),
insertAfterLastImport (react-router, vue), and extract wrapWithClerkProvider
in react.ts. Store BunFile references to avoid duplicate creation.
* refactor(init): remove findings cap, precompile regexes, and unexport internal types
Remove MAX_FINDINGS so no context is lost. Convert IGNORE_DIRS to a Set
for O(1) lookups. Precompile CODE_SCANS regexes once at module level.
Inline matchesFramework guard. Convert AuthLibraryScan and CodeScan from
exported interfaces to local types since they are not imported elsewhere.
* refactor(init): replace readFileSync with static text imports for compiled binaries
Use Bun's `import ... with { type: "text" }` to embed markdown prompt
templates at build time. This replaces the runtime readFileSync +
import.meta.dir approach that would break in compiled Bun binaries.
Remove the template cache since imports are already static.
* refactor(init): abstract formatter config into data-driven array
Replace inline if-checks for prettier/biome with a FormatterConfig type
and a FORMATTERS array. The runFormatters loop now iterates the config,
making it trivial to add new formatters.
* test(init): update tests for discriminated union, enrichContext, and version check
Update context tests to call enrichProjectContext separately from
gatherContext and import parseMajorVersion from helpers. Add tests for
scaffold version check (below minimum, meets minimum, Next.js 16 proxy).
Update nextjs-app tests to assert on the skip type instead of skipReason
field. Update scan test to verify all findings are returned without cap.
* chore: update bun.lock with magicast dependency
* refactor(init): extract shared auth and config scaffolding helpers
Add jsxAuthPageContent with type-safe JsxClerkPackage union,
scaffoldConfigFile generic for the find→check→modify pattern,
authComponentName, and inline capitalize. These shared helpers
eliminate duplication across framework scaffolders.
* refactor(init): use shared helpers in framework scaffolders
Replace duplicated authRouteContent/nextjsAuthPageContent with
jsxAuthPageContent, replace per-framework scaffoldConfig with
scaffoldConfigFile in astro, nuxt, and react-router. Remove
unused imports and add enableV8Middleware documentation.
* refactor(init): restructure preview, prompts, and scan modules
Update preview formatting to use switch on discriminated union,
restructure prompts/index.ts with typed template resolution and
variable building, and minor scan.ts cleanup.
* test(init): add framework scaffolder and scan tests
Add tests for nextjs-app (middleware composition, provider wrapping,
src/ paths, proxy basename), react-router (root modification, loader
merge), tanstack-start (base dir detection), and scan (no findings cap).
* chore(init): add markdown type declaration for static text imports
* feat(init): add framework lookup utility with aliases
Export FRAMEWORK_MAP and add lookupFramework() to resolve framework
names or aliases (e.g. "tanstack-start" → "@tanstack/react-start")
along with FRAMEWORK_NAMES for validation and display.
* feat(init): add i18nLocaleDir to ProjectContext type
Add optional i18nLocaleDir field to ProjectContext for frameworks
that detect locale-based routing directories (e.g. [locale], [lang]).
* refactor(init): extract previewPlan display function
Split preview logic into previewPlan() (display only) and
previewAndConfirm() (display + prompt) to support --yes mode
without duplicating the plan rendering code.
* feat(init): add shared scaffolding helpers for auth, env, and i18n
Add reusable helpers for all framework scaffolders:
- authFileSpecs() factory for sign-in/sign-up file generation
- scaffoldEnvVars() and SIGN_ROUTE_ENV_VARS for env file management
- htmlAuthComponentMarkup() and jsxAuthComponentMarkup() with
Tailwind/plain CSS variants
- hasTailwindStyles() for style detection
- i18n middleware detection, composition, and routing helpers
(detectI18nMiddlewareLib, composeWithI18nMiddleware, etc.)
- findFirstDirMatch() for generic directory scanning
* feat(init): detect i18n locale directory in Next.js context
Add detectI18nLocaleDir() to identify App Router locale directories
(e.g. [locale], [lang]) by checking for layout files inside dynamic
segments. Populate i18nLocaleDir in enrichNextjsContext() so
scaffolders can place auth pages inside locale-prefixed paths.
* feat(init): support framework override in context gathering
Accept optional frameworkOverride parameter in gatherContext() to
skip auto-detection when the user specifies --framework explicitly.
* feat(init): wire --framework, --yes, and --prompt CLI options
Register --framework <name>, -y/--yes, and --prompt options on the
init command. Wire them through to framework override resolution,
preview-only plan display, and agent prompt output respectively.
* refactor(init): migrate framework scaffolders to shared helpers
Update all six framework scaffolders (Astro, Next.js App/Pages,
Nuxt, React Router, TanStack Start) to use the shared helpers:
- authFileSpecs() factory for sign-in/sign-up generation
- scaffoldEnvVars() for .env file management
- hasTailwindStyles() for consistent style detection
- i18n-aware auth page placement using locale directory detection
- htmlAuthComponentMarkup()/jsxAuthComponentMarkup() for rendering
* test(init): add i18n detection and locale routing tests
Add tests for i18n support across frameworks:
- Context: locale directory detection ([locale], [lang]) with
layout file validation and src/ convention support
- Next.js App Router: i18n auth page placement, composed Clerk +
next-intl middleware, expression export handling, env var scaffolding
- React Router: ($locale) prefix detection for auth routes
- TanStack Start: {-$locale} directory detection for auth routes
* docs(init): document new CLI options and update help output
Add --framework, --yes, and --prompt options to init command README
with usage examples. Update root README help output with --verbose
flag documentation.
* refactor(init): address PR review comments
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
* test(init): add missing framework scaffolder tests
Add test coverage for the 5 framework scaffolders that were missing
tests (jfoshee #21/#22):
- astro.test.ts (10 tests)
- nuxt.test.ts (8 tests)
- vue.test.ts (6 tests)
- react.test.ts (7 tests)
- nextjs-pages.test.ts (10 tests)
All tests use semantic path-based lookups via findAction() helper.
Sign up for freeto 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

@dmoerner@wyattjoh@brkalow
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(config): Schema support - #19

Merged
dmoerner merged 3 commits into
mainfrom
daniel/config-schema
Mar 8, 2026
Merged

feat(config): Schema support#19
dmoerner merged 3 commits into
mainfrom
daniel/config-schema

Conversation

@dmoerner

@dmoernerdmoerner commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Implement config schema command to allow fetching the schema from PLAPI. This will make Clerk CLI config self-documenting, to an extent. The bare command dumps the whole schema, there is also a --keys argument to dump only a specific key. This can be useful to save context.

Implement `config schema` command to allow fetching the schema from
PLAPI. This will make Clerk CLI config self-documenting, to an extent.
The bare command dumps the whole schema, there is also a `--keys`
argument to dump only a specific key.
WIP commit, tests will need to be rebased to use the new patterns once
#18 is merged.
Update schema tests to use new patterns
@dmoerner
dmoerner marked this pull request as ready for review March 6, 2026 20:14
Comment threadsrc/commands/config/schema.ts Outdated
const resolved = await resolveProfile(process.cwd());
if (!resolved) {
console.error(
"No Clerk project linked to this directory. Run `clerk init` to set up.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should recommend link here, as init will go through the full Clerk setup

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.

Maybe worthwhile to consider in the future (not now) a standardized error class which can enforce links + formatting for errors with the CLI?

process.exit(1);
}

// Use `console.error` for informational messages so stdout is just the JSON response.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

clever

@dmoerner
dmoerner merged commit 119f7f0 into mainMar 8, 2026
1 check passed
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
rafa-thayto added a commit that referenced this pull request Mar 24, 2026
…mpts (#38)
* chore: add magicast dependency for AST-based code manipulation
Used by the init command's framework scaffolders to safely add imports
and modify config files without breaking existing code.
* refactor: fix framework SDK names and detection priority
- Fix @clerk/clerk-react → @clerk/react
- Fix @clerk/tanstack-start → @clerk/tanstack-react-start
- Remove standalone vite detection (covered by react)
- Reorder priority: scaffoldable frameworks first, then expo, react,
express, fastify
- Export readDeps for use by init context module
* feat(init): add project context gathering
Detects framework, TypeScript, src/ directory convention, package
manager, Next.js router variant, middleware filename, layout path,
and existing Clerk SDK installation.
* feat(init): add scaffold system with framework-specific scaffolders
Add idempotent scaffolders for Next.js (App + Pages Router), React,
React Router, Nuxt, TanStack Start, Astro, and Vue. Each scaffolder
generates framework-appropriate boilerplate (middleware, providers,
auth pages) while preserving existing user code.
Shared helpers handle AST-based import injection (magicast with string
fallback), middleware composition, and auth page creation.
* feat(init): add scan, format, preview, and agent prompt modules
- scan: detect competing auth libraries pre-scaffold and scan for
hardcoded keys/leftover imports post-scaffold
- format: run Prettier/Biome on generated files
- preview: show planned file changes and confirm before writing
- prompts: framework-specific agent mode prompts with exact code
snippets and file paths
* feat(init): rewrite init command with scaffold and scan flow
Replace the minimal init (login + link + install + env pull) with a
full orchestrator that also scaffolds framework boilerplate and scans
for issues. Skips login/link when already authenticated and linked.
* docs(init): update README with scaffolding docs and framework table
- Add Agent Mode section
- Add env var column to framework detection table
- Add Expo, Express, Fastify to detection table
- Document scaffolding actions for all 8 supported frameworks
- Note that Expo/Express/Fastify are detected but not scaffolded
* refactor(init): restructure agent prompts into markdown templates
Replace monolithic prompts.ts with individual .md template files per
framework, matching the clerk-docs structured format (sections, rules,
deprecated patterns, verification checklists).
- Move prompts to src/commands/init/prompts/*.md with {{PLACEHOLDER}}
interpolation
- Add prompts for expo, express, and fastify frameworks
- Merge DOCS_URLS + TEMPLATE_MAP into single FRAMEWORK_PROMPTS record
- Extract shared pmInstallCommand, remove duplicate pmAddCommand
- Fix formatter-escaped underscores (\_app, \_\_root) in template loader
- Add "After Setup" section to all prompts (matching clerk-docs)
* refactor(init): make FileAction a discriminated union and extend FrameworkScaffold
FileAction is now a proper discriminated union with a dedicated `skip`
variant that has no `content` field, enforced at the type level. The
FrameworkScaffold interface gains `dep`, `variant`, `minMajorVersion`,
`matches()`, and optional `enrichContext()` so each scaffolder is
self-describing. Enrichment fields (variant, layoutPath,
middlewareBasename) become optional on ProjectContext since they are
populated after gatherContext.
* refactor(init): extract Next.js context enrichment to frameworks/nextjs-context
Move parseNextMajorVersion, detectMiddlewareBasename, detectNextjsVariant,
and detectLayoutPath from context.ts into a dedicated nextjs-context.ts
module. This isolates framework-specific logic behind the enrichContext
hook on FrameworkScaffold rather than coupling it to gatherContext.
Parallelize dirExists calls with Promise.all in both files.
* refactor(init): replace scaffold key map with matches() dispatch and version check
Replace the Record<string, FrameworkScaffold> keyed map with an array
using satisfies and matches()-based lookup. Add enrichProjectContext()
that delegates to each scaffolder's enrichContext hook. Add minMajorVersion
guard that checks the framework dep version before scaffolding.
* refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
Add parseMajorVersion, insertAfterLastImport, wrapBodyWithProvider, and
resolveNextjsMiddlewareBasename to helpers. Use proper skip FileAction
in scaffoldAuthPage and scaffoldNextjsMiddleware. Flatten nested ifs
with early returns and store BunFile reference once. The middleware
fallback now resolves from the actual Next.js version in deps.
* refactor(init): update all scaffolders with skip actions, dep/matches, and minMajorVersion
Each scaffolder now exports dep, matches(), and minMajorVersion. All skip
cases use the proper FileAction skip variant. Flatten nested ifs with
early returns across scaffoldLayout, scaffoldApp, scaffoldMiddleware, and
scaffoldConfig. Use shared wrapBodyWithProvider (nextjs-app, tanstack-start),
insertAfterLastImport (react-router, vue), and extract wrapWithClerkProvider
in react.ts. Store BunFile references to avoid duplicate creation.
* refactor(init): remove findings cap, precompile regexes, and unexport internal types
Remove MAX_FINDINGS so no context is lost. Convert IGNORE_DIRS to a Set
for O(1) lookups. Precompile CODE_SCANS regexes once at module level.
Inline matchesFramework guard. Convert AuthLibraryScan and CodeScan from
exported interfaces to local types since they are not imported elsewhere.
* refactor(init): replace readFileSync with static text imports for compiled binaries
Use Bun's `import ... with { type: "text" }` to embed markdown prompt
templates at build time. This replaces the runtime readFileSync +
import.meta.dir approach that would break in compiled Bun binaries.
Remove the template cache since imports are already static.
* refactor(init): abstract formatter config into data-driven array
Replace inline if-checks for prettier/biome with a FormatterConfig type
and a FORMATTERS array. The runFormatters loop now iterates the config,
making it trivial to add new formatters.
* test(init): update tests for discriminated union, enrichContext, and version check
Update context tests to call enrichProjectContext separately from
gatherContext and import parseMajorVersion from helpers. Add tests for
scaffold version check (below minimum, meets minimum, Next.js 16 proxy).
Update nextjs-app tests to assert on the skip type instead of skipReason
field. Update scan test to verify all findings are returned without cap.
* chore: update bun.lock with magicast dependency
* refactor(init): extract shared auth and config scaffolding helpers
Add jsxAuthPageContent with type-safe JsxClerkPackage union,
scaffoldConfigFile generic for the find→check→modify pattern,
authComponentName, and inline capitalize. These shared helpers
eliminate duplication across framework scaffolders.
* refactor(init): use shared helpers in framework scaffolders
Replace duplicated authRouteContent/nextjsAuthPageContent with
jsxAuthPageContent, replace per-framework scaffoldConfig with
scaffoldConfigFile in astro, nuxt, and react-router. Remove
unused imports and add enableV8Middleware documentation.
* refactor(init): restructure preview, prompts, and scan modules
Update preview formatting to use switch on discriminated union,
restructure prompts/index.ts with typed template resolution and
variable building, and minor scan.ts cleanup.
* test(init): add framework scaffolder and scan tests
Add tests for nextjs-app (middleware composition, provider wrapping,
src/ paths, proxy basename), react-router (root modification, loader
merge), tanstack-start (base dir detection), and scan (no findings cap).
* chore(init): add markdown type declaration for static text imports
* feat(init): add framework lookup utility with aliases
Export FRAMEWORK_MAP and add lookupFramework() to resolve framework
names or aliases (e.g. "tanstack-start" → "@tanstack/react-start")
along with FRAMEWORK_NAMES for validation and display.
* feat(init): add i18nLocaleDir to ProjectContext type
Add optional i18nLocaleDir field to ProjectContext for frameworks
that detect locale-based routing directories (e.g. [locale], [lang]).
* refactor(init): extract previewPlan display function
Split preview logic into previewPlan() (display only) and
previewAndConfirm() (display + prompt) to support --yes mode
without duplicating the plan rendering code.
* feat(init): add shared scaffolding helpers for auth, env, and i18n
Add reusable helpers for all framework scaffolders:
- authFileSpecs() factory for sign-in/sign-up file generation
- scaffoldEnvVars() and SIGN_ROUTE_ENV_VARS for env file management
- htmlAuthComponentMarkup() and jsxAuthComponentMarkup() with
Tailwind/plain CSS variants
- hasTailwindStyles() for style detection
- i18n middleware detection, composition, and routing helpers
(detectI18nMiddlewareLib, composeWithI18nMiddleware, etc.)
- findFirstDirMatch() for generic directory scanning
* feat(init): detect i18n locale directory in Next.js context
Add detectI18nLocaleDir() to identify App Router locale directories
(e.g. [locale], [lang]) by checking for layout files inside dynamic
segments. Populate i18nLocaleDir in enrichNextjsContext() so
scaffolders can place auth pages inside locale-prefixed paths.
* feat(init): support framework override in context gathering
Accept optional frameworkOverride parameter in gatherContext() to
skip auto-detection when the user specifies --framework explicitly.
* feat(init): wire --framework, --yes, and --prompt CLI options
Register --framework <name>, -y/--yes, and --prompt options on the
init command. Wire them through to framework override resolution,
preview-only plan display, and agent prompt output respectively.
* refactor(init): migrate framework scaffolders to shared helpers
Update all six framework scaffolders (Astro, Next.js App/Pages,
Nuxt, React Router, TanStack Start) to use the shared helpers:
- authFileSpecs() factory for sign-in/sign-up generation
- scaffoldEnvVars() for .env file management
- hasTailwindStyles() for consistent style detection
- i18n-aware auth page placement using locale directory detection
- htmlAuthComponentMarkup()/jsxAuthComponentMarkup() for rendering
* test(init): add i18n detection and locale routing tests
Add tests for i18n support across frameworks:
- Context: locale directory detection ([locale], [lang]) with
layout file validation and src/ convention support
- Next.js App Router: i18n auth page placement, composed Clerk +
next-intl middleware, expression export handling, env var scaffolding
- React Router: ($locale) prefix detection for auth routes
- TanStack Start: {-$locale} directory detection for auth routes
* docs(init): document new CLI options and update help output
Add --framework, --yes, and --prompt options to init command README
with usage examples. Update root README help output with --verbose
flag documentation.
* refactor(init): address PR review comments
- Extract utility helpers from index.ts into heuristics.ts (jfoshee #18)
- Extract text transformations into transformations.ts (jfoshee #19)
- Fix wrapBodyWithProvider whitespace/formatting bug (jfoshee #20)
- Refactor tests to use semantic path lookups instead of positional
array indexing (jfoshee #13/#17)
- Add doc comment to helpers.ts clarifying shared usage (jfoshee #15)
- Update astro.md NEVER rules to start with "Never" (jfoshee #25)
- Remove section banner comments from init command files
* test(init): add missing framework scaffolder tests
Add test coverage for the 5 framework scaffolders that were missing
tests (jfoshee #21/#22):
- astro.test.ts (10 tests)
- nuxt.test.ts (8 tests)
- vue.test.ts (6 tests)
- react.test.ts (7 tests)
- nextjs-pages.test.ts (10 tests)
All tests use semantic path-based lookups via findAction() helper.
Sign up for freeto 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

@dmoerner@wyattjoh@brkalow