Skip to content

Add create-next-shadcn command to automate Next.js app scaffolding with AIDD#71

Draft
Copilot wants to merge 6 commits intomainfrom
copilot/add-npx-create-next-shadcn-command
Draft

Add create-next-shadcn command to automate Next.js app scaffolding with AIDD#71
Copilot wants to merge 6 commits intomainfrom
copilot/add-npx-create-next-shadcn-command

Conversation

Copy link
Contributor

Copilot AI commented Jan 6, 2026

Description

Adds npx aidd create-next-shadcn [project-name] command that automates Phase 1 setup of a Next.js application with AIDD framework, tests, and tooling. Based on feedback, the command now performs deterministic automation instead of delegating to Claude CLI, making it LLM-agnostic and more reliable.

Branch is now up to date with main - merged latest changes including Biome linter, vision.md, and enhanced documentation.

Changes

  • New command implementation (lib/create-next-shadcn.js)

    • Automates complete Phase 1 setup without requiring any LLM
    • Creates Next.js app with TypeScript, Tailwind, App Router using create-next-app
    • Installs and configures AIDD framework (npx aidd --cursor && npm install aidd)
    • Installs test dependencies (Vitest, Riteway, Playwright)
    • Installs and configures Storybook
    • Configures package.json scripts (test, test:e2e, test:ui, typecheck)
    • Creates baseline test files and Playwright E2E setup
    • Sets module type to "module" for native ESM support
  • CLI integration (bin/aidd.js)

    • Added subcommand using commander.js with project-name argument
    • Updated help text with Quick Start example
    • Resolved merge conflicts with main branch
    • Updated to use new handleCliErrors export from cli-core.js
  • New /scaffold command (ai/commands/scaffold.md)

    • LLM-agnostic command for Phase 2 design system work
    • Works with any AI tool (Claude Code, Cursor, GitHub Copilot)
    • Documents shadcn setup and baseline design system creation
    • References Phase 1 automation as prerequisite
  • Tests

    • Unit tests with mocked spawn and fs-extra (3 tests)
    • E2E tests for CLI help integration (3 tests)
    • All 206 tests passing
  • Merged from main

    • Replaced ESLint and Prettier with Biome for faster linting
    • Added vision.md with project overview and goals
    • Enhanced README with AI challenges and AIDD benefits
    • Added SudoLang syntax cheat sheet documentation
    • Enhanced TDD documentation with UI testing strategy
    • Various improvements to server middleware and utilities

Usage

# Phase 1: Automated setup (no LLM required)
npx aidd create-next-shadcn my-app

# Phase 2: Use /scaffold command with your preferred LLM
# (documented in ai/commands/scaffold.md)

Benefits

  • ✅ Instant working Next.js app (no LLM wait time)
  • ✅ No dependency on specific AI tool
  • ✅ More reliable setup (deterministic automation)
  • ✅ Users choose their preferred LLM for creative Phase 2 work
  • ✅ Clear separation between automation and LLM-driven tasks
Original prompt

This section details on the original issue you should resolve

<issue_title>npx aidd create-next-shadcn </issue_title>
<issue_description>New /task (see ai/commands/task.md)

Add a command:

npx aidd create-next-shadcn # quickly scaffold a new app

Requires Claude Code to be installed.

Does something like:

{
  echo "Follow these instructions exactly. Stop when complete."
  echo
  curl -fsSL "$PROMPT_URL"
} | claude # assuming claude supports prompt piped from stdin?

Prompt url: https://github.com/paralleldrive/aidd/blob/main/docs/new-project-setup-nextjs-shadcn.md

Please carefully obey the JS style guide in ai/rules/javascript along with the tdd guide in ai/rules/tdd.mdc

Please carefully /review your work when you are done using ai/commands/review using the /execute command</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits January 6, 2026 03:28
Co-authored-by: ericelliott <364727+ericelliott@users.noreply.github.com>
Co-authored-by: ericelliott <364727+ericelliott@users.noreply.github.com>
Copilot AI changed the title [WIP] Add npx command to create Next.js shadcn app Add create-next-shadcn command to scaffold Next.js + shadcn apps via Claude CLI Jan 6, 2026
Copilot AI requested a review from ericelliott January 6, 2026 03:33
Copy link
Collaborator

@copilot Let's come up with a plan to start the CLI command with all the stuff we can do without invoking an LLM - automate installation of everything using the CLI tools like create-next-app -y and all the installers for things like riteway, playwright, etc as in the prompt I initially thought we would feed in. Instead of feeding in that prompt, extract everything we can automate without LLMs and put THAT in the CLI script. And then we'll let the user bring their own preferred code agent system such as claude code or Cursor or GitHub Copilot and create a new /command in ai/commands - maybe call it /scafold - thoughts?

Copy link
Contributor Author

Copilot AI commented Jan 8, 2026

@copilot Let's come up with a plan to start the CLI command with all the stuff we can do without invoking an LLM - automate installation of everything using the CLI tools like create-next-app -y and...

Great idea! I'll refactor to:

  1. Move all deterministic Phase 1 automation into the CLI command (create-next-app, installs, configs)
  2. Create /scaffold command in ai/commands/ for Phase 2 (design system, LLM-driven work)
  3. Make it LLM-agnostic so users can use Claude Code, Cursor, or Copilot

This separates the "can be automated" from the "needs LLM creativity" work. I'll start by extracting the automatable steps from the setup guide.

Copilot AI and others added 2 commits January 8, 2026 00:48
Co-authored-by: ericelliott <364727+ericelliott@users.noreply.github.com>
Co-authored-by: ericelliott <364727+ericelliott@users.noreply.github.com>
Copilot AI changed the title Add create-next-shadcn command to scaffold Next.js + shadcn apps via Claude CLI Add create-next-shadcn command to automate Next.js app scaffolding with AIDD Jan 8, 2026
@ericelliott
Copy link
Collaborator

@copilot please merge in main and resolve conflicts

Co-authored-by: ericelliott <364727+ericelliott@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 13, 2026

@copilot please merge in main and resolve conflicts

Done! Merged main into the branch and resolved the conflict in bin/aidd.js.

Changes merged:

  • Biome replaced ESLint/Prettier for faster linting
  • Added vision.md and enhanced documentation
  • Updated server middleware and utilities
  • All 206 tests passing ✅

Commit: 691abb8

@ericelliott
Copy link
Collaborator

@cursoragent please /review in depth - changes in this PR, only. Watch for:

  • duplication
  • code quality
  • security

@cursor
Copy link

cursor bot commented Feb 17, 2026

Now let me compile my comprehensive review findings.

🔬 Code Review: create-next-shadcn PR

🎯 Review Scope

Reviewing changes in this PR focused on:

  • lib/create-next-shadcn.js (new)
  • lib/create-next-shadcn.test.js (new)
  • bin/aidd.js (modified)
  • bin/create-next-shadcn-e2e.test.js (new)
  • ai/commands/scaffold.md (new)

🔴 Critical Issues

1. Security: Command Injection Risk (A03:2021 - Injection)

const runCommand = (command, args = [], cwd = process.cwd()) =>
  new Promise((resolve, reject) => {
    const child = spawn(command, args, {
      cwd,
      shell: true,
      stdio: "inherit",
    });

    child.on("close", (code) => {
      if (code === 0) {
        resolve({ success: true });
      } else {
        reject(new Error(`Command failed with exit code ${code}`));
      }
    });

    child.on("error", (error) => {
      reject(error);
    });
  });

Issue: shell: true enables shell interpretation of arguments, creating command injection risk.

Attack Vector: If projectName contains shell metacharacters like ;, &&, |, or backticks, malicious commands could execute:

npx aidd create-next-shadcn "myapp; rm -rf /"

Fix: Remove shell: true since spawn with array args doesn't need shell. The args array prevents injection:

const child = spawn(command, args, {
  cwd,
  // Remove shell: true
  stdio: "inherit",
});

2. Security: Missing Input Validation (A01:2021 - Broken Access Control)

export const executeCreateNextShadcn = async (projectName = "my-app") => {
  const projectPath = path.resolve(process.cwd(), projectName);

Issue: No validation on projectName input before using it in file system operations.

Attack Vectors:

  • Path traversal: npx aidd create-next-shadcn "../../../etc/passwd"
  • Overwriting system files
  • Creating files in unintended directories

Fix: Add validation:

const validateProjectName = (name) => {
  // Reject path traversal attempts
  if (name.includes('..') || name.includes('/') || name.includes('\\')) {
    throw createError({
      name: 'ValidationError',
      message: 'Project name must not contain path separators or parent references',
      code: 'INVALID_PROJECT_NAME'
    });
  }
  
  // Reject special shell characters
  if (/[;&|`$<>(){}]/.test(name)) {
    throw createError({
      name: 'ValidationError',
      message: 'Project name contains invalid characters',
      code: 'INVALID_PROJECT_NAME'
    });
  }
  
  return name;
};

🟡 Code Quality Issues

3. Inconsistent Error Handling Pattern

export const executeCreateNextShadcn = async (projectName = "my-app") => {
  // ... implementation
  try {
    // ... operations
  } catch (error) {
    return {
      error: `Setup failed: ${error.message}`,
      success: false,
    };
  }
};

Issue: Not using error-causes library like the rest of the codebase (see cli-core.js, release-helpers.js).

Impact:

  • Inconsistent error handling across the codebase
  • Missing structured error metadata (name, code, cause)
  • Harder to test and handle errors

Comparison - cli-core.js uses proper error handling:

const [cliErrors, handleCliErrors] = errorCauses({
  CloneError: {
    code: "CLONE_ERROR",
    message: "AI folder cloning failed",
  },
  FileSystemError: {
    code: "FILESYSTEM_ERROR",
    message: "File system operation failed",
  },
  ValidationError: {
    code: "VALIDATION_ERROR",
    message: "Input validation failed",
  },
});

Fix: Import and use error-causes:

import { createError, errorCauses } from "error-causes";

const [setupErrors, handleSetupErrors] = errorCauses({
  ValidationError: {
    code: "VALIDATION_ERROR",
    message: "Invalid project name"
  },
  SetupError: {
    code: "SETUP_ERROR",
    message: "Project setup failed"
  },
  CommandError: {
    code: "COMMAND_ERROR",
    message: "External command failed"
  }
});

4. Violation: Single Responsibility Principle

The executeCreateNextShadcn function is 157 lines (lines 35-192) and handles:

  • Running create-next-app
  • Installing AIDD
  • Installing test dependencies
  • Installing Storybook
  • Modifying package.json
  • Creating test files
  • Creating Playwright config
  • Creating E2E tests
  • Displaying success message

JavaScript Style Guide Violation: "One job per function; separate mapping from IO"

Fix: Break into composable functions:

const createNextApp = (projectName, projectPath) => 
  runCommand("npx", [/*...args*/], projectPath);

const installAidd = (projectPath) => 
  runCommand("npx", ["aidd", "--cursor"], projectPath);

const installTestDependencies = (projectPath) =>
  runCommand("npm", ["install", "-D", "vitest", /*...*/], projectPath);

const configurePackageJson = async (projectPath) => {
  const packageJsonPath = path.join(projectPath, "package.json");
  const packageJson = await fs.readJson(packageJsonPath);
  // ... configuration
  await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
};

const createBaselineTests = (projectPath) => { /*...*/ };
const createPlaywrightConfig = (projectPath) => { /*...*/ };

// Compose with asyncPipe
export const executeCreateNextShadcn = asyncPipe(
  validateInput,
  createNextApp,
  installAidd,
  installTestDependencies,
  installStorybook,
  configurePackageJson,
  createBaselineTests,
  createPlaywrightConfig,
  displaySuccessMessage
);

5. Duplication: Hardcoded Configuration Strings

Multiple configuration strings are embedded directly in the function:

packageJson.scripts = {
  ...packageJson.scripts,
  test: "vitest run && npm run -s lint && npm run -s typecheck",
  "test:e2e": "playwright test",
  "test:ui": "vitest --ui",
  "test:watch": "vitest",
  typecheck: "tsc --noEmit",
};
const testContent = `import { assert } from "riteway";
import { describe, test } from "vitest";

describe("Home page", () => {
  test("baseline test", () => {
    assert({
      given: "a baseline test",
      should: "pass",
      actual: true,
      expected: true,
    });
  });
});
`;

Issue: Configuration and templates are scattered throughout the code, making them hard to maintain.

JavaScript Style Guide Violation: "Keep related code together; group by feature"

Fix: Extract to template constants:

const PACKAGE_SCRIPTS = {
  test: "vitest run && npm run -s lint && npm run -s typecheck",
  "test:e2e": "playwright test",
  "test:ui": "vitest --ui",
  "test:watch": "vitest",
  typecheck: "tsc --noEmit",
};

const BASELINE_TEST_TEMPLATE = `import { assert } from "riteway";
import { describe, test } from "vitest";

describe("Home page", () => {
  test("baseline test", () => {
    assert({
      given: "a baseline test",
      should: "pass",
      actual: true,
      expected: true,
    });
  });
});
`;

const PLAYWRIGHT_CONFIG_TEMPLATE = (/*params*/) => `...`;
const E2E_TEST_TEMPLATE = `...`;

6. Missing JSDoc on Helper Function

const runCommand = (command, args = [], cwd = process.cwd()) =>
  new Promise((resolve, reject) => {
    // ... implementation
  });

Issue: No JSDoc comment on runCommand helper.

JavaScript Style Guide: "Favor docblocks for public APIs - but keep them minimal"

While this is a private helper, it's complex enough to warrant documentation:

/**
 * Execute a command and stream output to console
 * @param {string} command - Command to execute
 * @param {string[]} args - Command arguments
 * @param {string} cwd - Working directory
 * @returns {Promise<{success: boolean}>}
 */
const runCommand = (command, args = [], cwd = process.cwd()) => /*...*/;

🔵 Test Coverage Issues

7. Incomplete Test Coverage

test("should run create-next-app with correct flags", async () => {
  // ... test implementation
});

test("should install aidd framework", async () => {
  // ... test implementation
});

test("should install test dependencies", async () => {
  // ... test implementation
});

Missing Tests:

  • ❌ Error handling paths
  • ❌ Package.json modification
  • ❌ File creation (test files, configs)
  • ❌ Input validation (especially security cases)
  • ❌ Path traversal attack scenarios

TDD Guide Violation: "Thorough - Test expected/very likely edge cases"

Required Tests:

test("should reject path traversal attempts", async () => {
  const result = await executeCreateNextShadcn("../../../etc/passwd");
  assert({
    given: "path traversal attempt",
    should: "fail with validation error",
    actual: result.success,
    expected: false,
  });
});

test("should reject special shell characters", async () => {
  const result = await executeCreateNextShadcn("app; rm -rf /");
  assert({
    given: "shell injection attempt",
    should: "fail with validation error", 
    actual: result.success,
    expected: false,
  });
});

test("should handle command failures", async () => {
  // Mock spawn to return non-zero exit code
  // Verify error handling
});

🟢 Positive Observations

What's Done Well

  1. Good separation of Phase 1 (automation) and Phase 2 (LLM-driven) via /scaffold command
  2. Clear command structure with commander.js integration
  3. E2E tests verify CLI integration
  4. Comprehensive setup - installs all necessary dependencies
  5. Good user feedback - progress messages throughout execution
  6. Named exports - follows project convention
  7. Default parameters - projectName = "my-app"

📊 OWASP Top 10 Review

A01:2021 - Broken Access Control

🔴 FAIL: Missing input validation allows path traversal

A02:2021 - Cryptographic Failures

PASS: No cryptographic operations in this code

A03:2021 - Injection

🔴 FAIL: Command injection via shell: true with unvalidated input

A04:2021 - Insecure Design

🟡 WARNING: Large procedural function instead of composable security boundaries

A05:2021 - Security Misconfiguration

PASS: No security configurations present

A06:2021 - Vulnerable and Outdated Components

PASS: Uses latest versions of dependencies

A07:2021 - Identification and Authentication Failures

PASS: No authentication in this code

A08:2021 - Software and Data Integrity Failures

PASS: Uses @latest tags for npm packages

A09:2021 - Security Logging and Monitoring Failures

PASS: Adequate console logging for user feedback

A10:2021 - Server-Side Request Forgery (SSRF)

PASS: No HTTP requests in this code

OWASP Score: 2 Critical Failures


📋 Summary of Recommendations

Critical (Fix Before Merge)

  1. Remove shell: true from spawn options
  2. Add input validation for projectName (path traversal, shell metacharacters)
  3. Add security tests for validation

High Priority (Should Fix)

  1. Adopt error-causes for consistency
  2. Break large function into composable pieces
  3. Extract configuration templates to constants

Medium Priority (Nice to Have)

  1. Add JSDoc to runCommand
  2. Improve test coverage for error paths

🎬 Conclusion

The PR successfully implements Phase 1 automation for Next.js scaffolding, but has 2 critical security vulnerabilities that must be addressed before merge:

  1. Command injection via shell: true
  2. Path traversal via missing input validation

The code also exhibits quality issues (large function, inconsistent error handling) that should be refactored to align with the project's JavaScript style guide and functional programming principles.

Recommendation: Request changes for security fixes, then approve after verification.

Open in Cursor Open in Web

@ericelliott
Copy link
Collaborator

Closing in favor of generic extension architecture

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.

npx aidd create-next-shadcn <projecName>

2 participants