Skip to content

Enhance project setup: add vitest for testing, update .gitignore to include .pnpm-store, and improve README with authentication options and usage instructions. Introduce new files for ESLint and PostCSS configurations, and create a template for a C1 App with Next.js.#7

Merged
zahlekhan merged 6 commits into
mainfrom
zk/enhc/auth
Feb 16, 2026

Conversation

@zahlekhan
Copy link
Copy Markdown
Contributor

@zahlekhan zahlekhan commented Feb 16, 2026


EntelligenceAI PR Summary

This PR refactors authentication to support multiple methods via a new --auth flag and adds a complete Next.js C1 chat application template with modern tooling.

  • Introduced --auth flag with oauth/manual/skip options, deprecating --skip-auth with backward compatibility
  • Added authentication helper functions: resolveAuthMethod, resolveAuthDecision, shouldPromptForAuthMethod in src/index.ts
  • Migrated testing framework from Jest to Vitest with comprehensive auth test coverage in tests/auth-options.test.ts
  • Created complete Next.js 15 application template in my-c1-app/ with Thesys C1 integration, React 19, TypeScript 5, and Tailwind CSS v4
  • Implemented chat API route with OpenAI streaming, message store, and Server-Sent Events in my-c1-app/src/app/api/chat/
  • Added GitHub Actions workflow for multi-version Node.js build verification
  • Added pnpm support with .pnpm-store/ in .gitignore and pnpm lockfile
  • Updated CLIOptions interface with optional auth property in src/types/index.ts
  • Configured ESLint, PostCSS, and Vitest for modern development workflow

…nclude .pnpm-store, and improve README with authentication options and usage instructions. Introduce new files for ESLint and PostCSS configurations, and create a template for a C1 App with Next.js.
Copy link
Copy Markdown

@entelligence-ai-pr-reviews entelligence-ai-pr-reviews Bot left a comment

Choose a reason for hiding this comment

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

Walkthrough

This PR introduces a comprehensive authentication refactoring and adds a new Next.js C1 chat application template. The main changes include: (1) replacing the --skip-auth flag with a more flexible --auth flag supporting OAuth, manual, and skip modes with proper deprecation handling, (2) migrating the testing framework from Jest to Vitest with full test coverage for authentication logic, (3) adding a complete Next.js 15 application template with AI-powered chat functionality using Thesys C1 and Crayon AI packages, (4) implementing GitHub Actions workflow for automated build verification, and (5) adding pnpm package manager support. The changes improve authentication flexibility, modernize testing infrastructure, and provide a production-ready template for developers.

Changes

File(s) Summary
.gitignore Added .pnpm-store/ to exclude pnpm's local package store directory from version control.
README.md Refactored CLI options table formatting, added new --auth flag with oauth/manual/skip options, deprecated --skip-auth, removed 'Non-Interactive / CI / Agent Usage' section, and expanded Authentication Options documentation with clearer workflow explanations.
src/index.ts Introduced AuthMethod and AuthDecision types, added helper functions (resolveAuthMethod, resolveAuthDecision, shouldPromptForAuthMethod) for authentication flow logic, implemented new --auth CLI option, added placeholder API key constant for skip mode, and converted code formatting from double to single quotes.
src/types/index.ts Added optional auth property to CLIOptions interface with union type 'oauth' | 'manual' | 'skip' for explicit authentication method specification.
tests/auth-options.test.ts Added comprehensive test coverage for authentication functions including auth method resolution, deprecation warnings, decision logic, and prompt conditions across interactive and non-interactive modes.
package.json
pnpm-lock.yaml Migrated testing framework from Jest to Vitest, removed Jest dependencies, added Vitest v4.0.18 with associated dependencies (chai, tinybench, Vite v7.3.1, esbuild, rollup), and added test/test:watch npm scripts.
vitest.config.ts Added Vitest configuration file specifying Node.js test environment and test file pattern tests/**/*.test.ts.
my-c1-app/.github/workflows/build-check.yml Added GitHub Actions workflow for automated build verification across Node.js versions 20.9.0, 22, and 24 with dependency installation, build, and linting steps.
my-c1-app/.gitignore Added comprehensive Next.js .gitignore file with exclusion rules for dependencies, build artifacts, environment files, debug logs, and platform-specific files.
my-c1-app/README.md Added documentation for C1 App Template including setup instructions, API key configuration, development server commands, system prompt customization guidance, and Vercel deployment button.
my-c1-app/eslint.config.mjs Added ESLint flat config extending 'next/core-web-vitals' and 'next/typescript' with FlatCompat for backward compatibility and ES module polyfills.
my-c1-app/favicon.ico Added favicon.ico binary asset file for browser tab branding.
my-c1-app/next.config.ts Added Next.js TypeScript configuration file with empty NextConfig object as foundational setup.
my-c1-app/package.json
my-c1-app/package-lock.json
my-c1-app/pnpm-lock.yaml Created package configuration and lockfiles for Next.js 15.2.8 application with dependencies including @crayonai packages, @thesysai/genui-sdk, React 19, OpenAI SDK, Tailwind CSS v4, TypeScript 5, and ESLint 9, enforcing Node.js >=20.9.0.
my-c1-app/postcss.config.mjs Added PostCSS configuration with Tailwind CSS plugin for CSS processing pipeline.
my-c1-app/src/app/api/chat/messageStore.ts Implemented in-memory message store module with DBMessage type and getMessageStore() function providing thread-specific message management with add, list, and OpenAI-compatible retrieval capabilities.
my-c1-app/src/app/api/chat/route.ts Added Next.js API route handler for chat functionality integrating OpenAI API through Thesys endpoint with streaming responses using Server-Sent Events and @crayonai/stream library.
my-c1-app/src/app/globals.css Added global CSS with Tailwind integration, custom CSS variables for light/dark mode theming, and Geist font family configuration.
my-c1-app/src/app/layout.tsx Added root layout component with Inter font configuration, metadata ('C1 Chat' title), and base HTML structure wrapper.
my-c1-app/src/app/page.tsx Created client-side chat interface page component rendering C1Chat with dark theme and '/api/chat' endpoint configuration.

🔗 Cross-Repository Impact Analysis

Enable automatic detection of breaking changes across your dependent repositories. → Set up now

Learn more about Cross-Repository Analysis

What It Does

  • Automatically identifies repositories that depend on this code
  • Analyzes potential breaking changes across your entire codebase
  • Provides risk assessment before merging to prevent cross-repo issues

How to Enable

  1. Visit Settings → Code Management
  2. Configure repository dependencies
  3. Future PRs will automatically include cross-repo impact analysis!

Benefits

  • 🛡️ Prevent breaking changes across repositories
  • 🔍 Catch integration issues before they reach production
  • 📊 Better visibility into your multi-repo architecture

▶️AI Code Reviews for VS Code, Cursor, Windsurf
Install the extension

Note for Windsurf Please change the default marketplace provider to the following in the windsurf settings:

Marketplace Extension Gallery Service URL: https://marketplace.visualstudio.com/_apis/public/gallery

Marketplace Gallery Item URL: https://marketplace.visualstudio.com/items

Entelligence.ai can learn from your feedback. Simply add 👍 / 👎 emojis to teach it your preferences. More shortcuts below

Emoji Descriptions:

  • ⚠️ Potential Issue - May require further investigation.
  • 🔒 Security Vulnerability - Fix to ensure system safety.
  • 💻 Code Improvement - Suggestions to enhance code quality.
  • 🔨 Refactor Suggestion - Recommendations for restructuring code.
  • ℹ️ Others - General comments and information.

Interact with the Bot:

  • Send a message or request using the format:
    @entelligenceai + *your message*
Example: @entelligenceai Can you suggest improvements for this code?
  • Help the Bot learn by providing feedback on its responses.
    @entelligenceai + *feedback*
Example: @entelligenceai Do not comment on `save_auth` function !

Also you can trigger various commands with the bot by doing
@entelligenceai command

The current supported commands are

  1. config - shows the current config
  2. retrigger_review - retriggers the review

More commands to be added soon.

Comment thread src/index.ts Outdated
Comment on lines 26 to 52
const fetchOptions: RequestInit = {
method: data ? 'POST' : 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
...headers
}
}

try {
const response = await fetch(url, fetchOptions);
const body = await response.text();
if (data) {
fetchOptions.body = data
}

return {
statusCode: response.status,
body,
};
} catch (error) {
throw new Error(
`HTTP request failed: ${error instanceof Error ? error.message : "Unknown error"}`,
);
}
try {
const response = await fetch(url, fetchOptions)
const body = await response.text()

return {
statusCode: response.status,
body
}
} catch (error) {
throw new Error(`HTTP request failed: ${error instanceof Error ? error.message : 'Unknown error'}`)
}
}

// Check Node.js version before doing anything else
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: In gatherProjectConfig, the removal of the this.nonInteractive check introduces a regression. In non-interactive environments (e.g., CI, non-TTY shells), calling input() or select() will cause the process to crash because @inquirer/prompts requires a TTY. Restore the logic to provide default values (e.g., projectName = 'my-c1-app' and template = 'template-c1-next') when this.nonInteractive is true.

Affected Locations:

  • src/index.ts:26-52
  • src/index.ts:75-90

Comment thread src/index.ts Outdated
Comment on lines +86 to +110
| { type: 'skip', apiKey: string }
| { type: 'manual' }
| { type: 'oauth' }
| { type: 'error', message: string }

// Step 2: Create project
await this.createProject();
export function resolveAuthMethod(options: CLIOptions, authWasExplicitlyProvided = false): AuthMethod {
if (options.skipAuth === true) {
if (authWasExplicitlyProvided && options.auth !== undefined) {
logger.warning('Both --auth and deprecated --skip-auth were provided. Using --auth.')
return options.auth
}

// Step 3: Setup environment with dotenv
await this.setupEnvironment(authResult.apiKey);
logger.warning('The --skip-auth flag is deprecated. Use --auth skip instead.')
return 'skip'
}

// Track successful completion
await telemetry.track("completed_create_c1_app", {
template: this.config.template,
});
if (options.auth !== undefined) {
return options.auth
}

// Success message
this.showSuccessMessage();
return 'oauth'
}

// Flush and shutdown telemetry before exit
await telemetry.flush();
await telemetry.shutdown();
this.spinner.stop();
} catch (error) {
// Track error
await telemetry.track("failed_create_c1_app");
export function resolveAuthDecision(
options: CLIOptions,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate Code: ⚠️ Duplicate Code Detected (Similarity: 95%)

This function Authentication decision logic (resolveAuthDecision) duplicates existing code.

📍 Original Location:

src/index.ts:158-196

Function: Authentication decision logic (inline in main method)

💡 Recommendation:
The PR functions should REPLACE the inline authentication logic in the existing codebase. This is not a duplicate to consolidate, but rather a refactoring improvement. The new approach:

  1. Is more testable (as evidenced by /home/user/pr_files/tests/auth-options.test.ts)
  2. Separates concerns (decision logic vs execution)
  3. Adds new functionality (--auth flag with oauth/manual/skip options)
  4. Maintains backward compatibility (--skip-auth still works with deprecation warning)

Recommendation: Accept the PR changes as they improve code quality while maintaining the same business logic.

Consider importing and reusing the existing function instead of duplicating the logic.

Comment thread src/index.ts Outdated
Comment on lines +43 to +59
return {
statusCode: response.status,
body
}
} catch (error) {
throw new Error(`HTTP request failed: ${error instanceof Error ? error.message : 'Unknown error'}`)
}
}

// Check Node.js version before doing anything else
function checkNodeVersion(): void {
const nodeVersion = process.version;
const majorVersion = parseInt(nodeVersion.slice(1).split(".")[0]);
const minorVersion = parseInt(nodeVersion.slice(1).split(".")[1]);

// Check if version is greater than 20.19.0
const isVersionSupported =
majorVersion > 20 || (majorVersion === 20 && minorVersion >= 9);

if (!isVersionSupported) {
console.error(`❌ Node.js version ${nodeVersion} is not supported.`);
console.error(`📋 This package requires Node.js version >= 20.9.0`);
console.error(`🔄 Please upgrade your Node.js version and try again.`);
console.error(``);
console.error(
`💡 You can download the latest Node.js from: https://nodejs.org/`,
);
process.exit(1);
}
const nodeVersion = process.version
const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0])
const minorVersion = parseInt(nodeVersion.slice(1).split('.')[1])

// Check if version is greater than 20.19.0
const isVersionSupported =
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate Code: ⚠️ Duplicate Code Detected (Similarity: 100%)

This function checkNodeVersion (inlined in makeHttpRequest) duplicates existing code.

📍 Original Location:

src/index.ts:62-81

Function: checkNodeVersion

💡 Recommendation:
REJECT this change in the PR. This appears to be a critical bug:

  1. The checkNodeVersion logic should remain a standalone function as in the existing codebase
  2. The PR version has this code unreachably placed after a return statement in makeHttpRequest
  3. This would cause Node version checking to fail silently

Action needed:

  • Keep the existing checkNodeVersion function (lines 62-81 in repo)
  • Remove the incorrectly placed duplicate from makeHttpRequest in the PR
  • Ensure checkNodeVersion() is called at the start of main() as in the existing code

Consider importing and reusing the existing function instead of duplicating the logic.

Comment thread src/index.ts
await telemetry.track("skipped_authentication");
break;
case "manual": {
const apiKey = await this.promptForApiKey();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate Code: ⚠️ Duplicate Code Detected (Similarity: 100%)

This function promptForApiKey duplicates existing code.

📍 Original Location:

src/index.ts:301-345

Function: promptForApiKey

💡 Recommendation:
Complete duplicate - the PR should use the existing promptForApiKey method rather than redefining it. This is a private class method that already exists in the CreateC1App class with identical functionality.

Consider importing and reusing the existing function instead of duplicating the logic.

Comment thread src/index.ts
await telemetry.track("oauth_authentication");
case "oauth":
try {
authResult = await this.authenticateAndGenerateAPIKey();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate Code: ⚠️ Duplicate Code Detected (Similarity: 100%)

This function authenticateAndGenerateAPIKey duplicates existing code.

📍 Original Location:

src/index.ts:347-438

Function: authenticateAndGenerateAPIKey

💡 Recommendation:
Complete duplicate - the PR should use the existing authenticateAndGenerateAPIKey method. This private method already implements the exact same OAuth flow and API key generation. No redefinition needed.

Consider importing and reusing the existing function instead of duplicating the logic.

Comment thread src/index.ts
Comment on lines 157 to +222
this.showWelcome();

// Handle authentication flow
let authResult: AuthenticationResult;
let authWasExplicitlyProvided = hideBin(process.argv).some(
(arg) => arg === "--auth" || arg.startsWith("--auth="),
);
let resolvedOptions: CLIOptions = options;

if (
options.apiKey !== undefined &&
options.apiKey !== null &&
options.apiKey.trim().length > 0
shouldPromptForAuthMethod(
options,
this.nonInteractive,
authWasExplicitlyProvided,
)
) {
// Use provided API key
const apiKey = options.apiKey.trim();
logger.info(`🔑 Using provided API key: ${apiKey.substring(0, 8)}...`);
authResult = { apiKey };
await telemetry.track("provided_api_key");
} else if (this.nonInteractive) {
// In non-interactive mode, we cannot open a browser or prompt for input
throw new Error(
"An API key is required in non-interactive mode. " +
"Provide one with --api-key <key>.\n" +
" Example: npx create-c1-app my-project --template template-c1-next --api-key <your-key>\n" +
" Get a key at: https://console.thesys.dev/keys",
);
} else {
// Perform OAuth authentication flow
try {
authResult = await this.authenticateAndGenerateAPIKey();
} catch (error) {
console.log(error);
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
logger.error(`Authentication failed: ${errorMessage}`);
logger.newLine();

// Fallback to manual API key input
logger.info("💡 Falling back to manual API key input...");
const apiKey = await this.promptForApiKey();
const { select } = await import("@inquirer/prompts");
const selectedAuth = (await select({
message: "How would you like to authenticate?",
choices: [
{ name: "OAuth (recommended)", value: "oauth" },
{ name: "Manual API key entry", value: "manual" },
{ name: "Skip authentication", value: "skip" },
],
default: "oauth",
})) as AuthMethod;

resolvedOptions = {
...options,
auth: selectedAuth,
};
authWasExplicitlyProvided = true;
}

const authDecision = resolveAuthDecision(
resolvedOptions,
this.nonInteractive,
authWasExplicitlyProvided,
);
let authResult: AuthenticationResult;

switch (authDecision.type) {
case "provided-api-key":
logger.info(
`🔑 Using provided API key: ${authDecision.apiKey.substring(0, 8)}...`,
);
authResult = { apiKey: authDecision.apiKey };
await telemetry.track("provided_api_key");
break;
case "skip":
logger.info(
"⏩ Skipping authentication and key generation as requested",
);
logger.info(
"📝 A placeholder API key will be written to your .env file. Replace it before running your app.",
);
authResult = { apiKey: authDecision.apiKey };
await telemetry.track("skipped_authentication");
break;
case "manual": {
const apiKey = await this.promptForApiKey();
authResult = { apiKey };
await telemetry.track("manual_api_key_entry");
break;
}
await telemetry.track("oauth_authentication");
case "oauth":
try {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate Code: ⚠️ Duplicate Code Detected (Similarity: 75%)

This function Authentication flow in main() method duplicates existing code.

📍 Original Location:

src/index.ts:158-196

Function: Authentication flow in main() method

💡 Recommendation:
This represents semantic duplication with enhancement. The PR refactors the inline authentication logic from the existing repo into separate, reusable functions (resolveAuthDecision, shouldPromptForAuthMethod, resolveAuthMethod) and adds new authentication options. The existing inline logic in repo/src/index.ts:158-196 should be replaced with calls to the new helper functions from pr_files/src/auth/resolve.ts to: (1) Eliminate duplication, (2) Improve maintainability and testability, (3) Support the new 'skip' and 'manual' auth modes, (4) Centralize auth decision logic. The switch statement approach is more extensible than the if-else chain.

Consider importing and reusing the existing function instead of duplicating the logic.

@zahlekhan zahlekhan merged commit 5cdb77c into main Feb 16, 2026
9 checks passed
Comment thread src/index.ts
Comment on lines +22 to 28
} from "./auth/resolve.js";

// Load package.json for version info (ESM workaround)
const require = createRequire(import.meta.url);
const packageJson = require("../package.json");
const pkgRequire = createRequire(import.meta.url);
const packageJson = pkgRequire("../package.json");

const THESYS_API_URL = "https://api.app.thesys.dev";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate Code: ⚠️ Duplicate Code Detected (Similarity: 100%)

This function validate callback (inline arrow function) duplicates existing code.

📍 Original Location:

src/index.ts:466-472

Function: validate callback in gatherProjectConfig input()

💡 Recommendation:
Extract this validation logic into a reusable named function, either: 1) As a static method in the Validator module: "static getInputValidator(): (input: string) => string | boolean" which returns the callback function, or 2) As a module-level constant in index.ts: "const PROJECT_NAME_INPUT_VALIDATOR = (input: string) => { ... }", or 3) As a class method in CreateC1App: "private getProjectNameValidator()". This function can then be referenced by name in all input() prompts that need project name validation, ensuring consistency and reducing duplication.

Consider importing and reusing the existing function instead of duplicating the logic.

Comment thread src/index.ts
const packageJson = pkgRequire("../package.json");

const THESYS_API_URL = "https://api.app.thesys.dev";
const THESYS_ISSUER_URL = "https://api.app.thesys.dev/oidc";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate Code: ⚠️ Duplicate Code Detected (Similarity: 100%)

This function transformer callback (inline arrow function) duplicates existing code.

📍 Original Location:

src/index.ts:473

Function: transformer callback in gatherProjectConfig input()

💡 Recommendation:
Since this is a direct pass-through to Validator.sanitizeProjectName, consider: 1) If the function signatures match exactly, pass Validator.sanitizeProjectName directly as the transformer value without wrapping it, or 2) Create a named constant at the module level: "const PROJECT_NAME_TRANSFORMER = (input: string) => Validator.sanitizeProjectName(input)" and reference it in all input() prompts, or 3) Add a static helper to the Validator module: "static getProjectNameTransformer()" that returns this function. This eliminates the duplication of the wrapper function.

Consider importing and reusing the existing function instead of duplicating the logic.

Comment thread src/index.ts
Comment on lines 6 to 12
import SpinnerManager from "./utils/spinner.js";
import * as Validator from "./utils/validation.js";
import {
type AuthMethod,
type CLIOptions,
type CreateC1AppConfig,
type AuthenticationResult,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate Code: ⚠️ Duplicate Code Detected (Similarity: 100%)

This function epilogue help text duplicates existing code.

📍 Original Location:

src/index.ts:286-294

Function: epilogue in parseArguments()

💡 Recommendation:
Extract the epilogue text into a module-level constant: "const API_KEY_HELP_EPILOGUE = ..." at the top of the file. Then reference this constant in the .epilogue() call: ".epilogue(API_KEY_HELP_EPILOGUE)". This ensures: 1) The help text is defined once and can be easily updated, 2) Consistency across all locations where this help text is needed, 3) Better maintainability as any changes to URLs, steps, or examples only need to be made in one place. If the epilogue should only appear once in the yargs configuration, investigate why the PR is adding it again.

Consider importing and reusing the existing function instead of duplicating the logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant