# Claude Instructions

## Task Completion Protocol

**CRITICAL: Follow this checklist before reporting ANY task as complete.**

### Completion Checklist

1. **Unit tests pass with clean output:** `npm test` - No warnings, no console.log/error leaks
2. **E2E verification** (if code was changed - see criteria below)
3. **Clean up** any test artifacts

### When E2E is Required

E2E tests MUST be run after changes to:

- `index.js`
- Any file in `helpers/`
- Any tool module (`eslint/`, `prettier/`, `stylelint/`, `jest/`, `storybook/`, `lefthook/`)

E2E can be skipped ONLY for:

- Pure documentation changes (README, CLAUDE.md, comments)
- Test file changes (`*.spec.js`) that don't affect scaffold behavior
- Package.json metadata changes (description, keywords, but NOT dependencies)

**When in doubt, run e2e.** It's better to run an unnecessary test than to miss a broken scaffold.

### E2E Test Procedure

Run each command separately (not chained with `&&`) to ensure permissions auto-approve correctly:

```bash
# 1. Scaffold a test project in sibling directory
cd ../angular-scaffold-playground
npx ../angular-scaffold my-app

# 2. Verify the scaffolded project works
cd my-app
npm test
npm run lint

# 3. Clean up (return to repo root first)
cd ../../angular-scaffold
rm -rf ../angular-scaffold-playground/my-app
```

**Note:** E2E tests must run in a sibling directory (not inside this repo) because Angular CLI skips git init when it
detects a parent `.git/`. The sibling `angular-scaffold-playground/` directory is already configured in
`additionalDirectories`. Commands must be run separately because permission patterns like `Bash(rm:*)` only match
commands that start with that prefix.

### Reporting Completion

Only after ALL applicable checklist items pass, report the task as complete. If any step fails, the task is NOT
complete - fix the issue first.

---

## Project Overview

**scaffold-angular** is an NPX-based scaffolding tool for Angular projects. It works like `create-react-app` - users run
it once with `npx scaffold-angular <app-name>` to set up a new Angular project with standard tooling, then never
interact with this package again.

**Important:** This is a one-time scaffold tool, not a dependency. Users do not install or keep this package. After
scaffolding, developers maintain installed dependencies themselves.

## Quick Reference

```bash
npm test          # Run Jest unit tests
npm run release   # Bump version and update changelog (runs tests first)
```

## Project Structure

```
index.js              # Main CLI entry point (executable)
helpers/              # Utility functions (exec, logging, git, angular-cli version)
eslint/               # ESLint installation and config template
prettier/             # Prettier installation
stylelint/            # Stylelint installation
jest/                 # Jest (jest-preset-angular) installation and config templates
storybook/            # Storybook installation
lefthook/             # Git hooks (Lefthook) installation and config template
```

## How It Works

When run via `npx scaffold-angular <app-name> [--style <style>]`:

1. Parses CLI arguments with commander (supports --help, --version, --style)
2. Validates style option (scss, css, less, sass - defaults to scss)
3. Ensures Angular CLI v21 is available (prompts to update if needed)
4. Creates new Angular app with chosen styling and `--minimal` flag
5. Sequentially installs tooling, each as a separate git commit:

**Note on `--minimal` flag:** This flag is used solely to prevent Angular CLI from installing its default test
framework (Vitest as of Angular 21). We install Jest instead. If `--minimal` starts affecting other desired scaffolding
behavior, reconsider the approach (e.g., use explicit `--test-runner` flag or post-scaffold removal).

- ESLint (with `@epam/eslint-config-angular`)
- Prettier
- Stylelint (with sass-guidelines or standard config based on --style)
- SVGO
- Jest (with `jest-preset-angular`)
- Storybook (component documentation and development)
- Lefthook (git hooks for pre-commit, pre-push, commit-msg)

## Key Dependencies

- `commander` - CLI argument parsing
- `ora` - Terminal spinners for progress indication
- `chalk` - Colored console output
- `shelljs` - Cross-platform shell commands

## Testing

Unit tests verify code logic; e2e tests verify integration. **Both are required** for code changes.

Tests use Jest with Babel for ESM support. Each module has a corresponding `.spec.js` file:

- `helpers/*.spec.js` - Utility function tests
- `eslint/index.spec.js`, `prettier/index.spec.js`, `jest/index.spec.js`, etc. - Module tests

### Why index.js Has No Unit Tests

The main `index.js` is tested via e2e only. **Do not add unit tests for index.js.** Rationale:

- Unit tests for index.js require mocking ALL dependencies (commander, shelljs, every tool module)
- Tests with all mocks just verify that mocks call each other - providing false confidence
- E2E tests verify the actual integration works end-to-end
- The real value is in testing individual modules with targeted mocks, plus e2e for integration

### Never Remove Tests During Refactors

When refactoring code, **preserve or update existing tests** - never delete them. If tests become difficult to maintain
due to refactoring:

1. Update the tests to work with the new code structure
2. If a function is split/renamed, split/rename the tests accordingly
3. If mocking becomes complex, simplify the production code's dependencies
4. Only remove tests if the functionality they test is being removed

### Test Output Must Be Clean

Test output should show ONLY the test results - no console warnings, errors, or log leaks. If code under test calls
`console.log`, `console.error`, or `process.exit`, these MUST be mocked:

```javascript
// Mock console methods to prevent output pollution
const mockConsoleError = jest
  .spyOn(console, "error")
  .mockImplementation(() => {});

// Mock process.exit to prevent test termination
const mockProcessExit = jest
  .spyOn(process, "exit")
  .mockImplementation(() => {});
```

If `npm test` shows a "Console" section with leaked output, fix the test by adding appropriate mocks.

## Code Conventions

- **Config templates:** Use `config.js` when configuration is complex or has multiple templates (eslint, jest,
  lefthook). Simple inline configs are acceptable for straightforward cases (prettier, stylelint).
- **Execution pattern:** Use `execOrFail()` helper for shell commands with spinner progress
- **Git commits:** Each tool installation creates a separate commit (e.g., "Add ESLint", "Add Prettier")
- **Spinners:** Use `startSpinner()`, `succeedSpinner()`, `failSpinner()` from `helpers/spinner.js`
- **File writes:** Use `fs.writeFileSync` with UTF-8 encoding for config files

## What Gets Scaffolded

Generated projects include:

- `eslint.config.mjs` - Flat ESLint config with Angular rules
- `prettier.config.js` - Prettier config (empty, uses defaults)
- `stylelint.config.js` - Stylelint with sass-guidelines or standard config (based on --style)
- `jest.config.ts` - Jest config using `jest-preset-angular`
- `setup-jest.ts` - Jest setup file for Angular zoneless environment
- `tsconfig.spec.json` - TypeScript config for Jest tests
- `src/app/app.spec.ts` - Example test for the default App component
- `src/stories/` - Storybook stories directory
- `lefthook.yml` - Git hooks config (pre-commit: lint/format, pre-push: test, commit-msg: validate)
- `.gitignore` additions for cache files

## Version Constraints

- Node.js ^20.19.0 || ^22.12.0 || ^24.0.0 (aligned with Angular 21)
- Angular CLI v21 (checked/prompted at runtime)
- All scaffolded tool versions are pinned in respective module files

## Commit Message Format

Follow Conventional Commits: `type(scope): description`

- Types: `feat`, `fix`, `chore`, `docs`, `refactor`, `test`
- Example: `feat: add jest support`
- Do not add Claude references in commits

## Shell Guidelines

1. **Run npm commands from repo root** - Always ensure you're in the correct directory before running npm commands.

2. **Never delete a directory while the shell is in it** - If you `cd` into a test directory, return to repo root before
   deleting:

   ```bash
   # WRONG - shell left in deleted directory, subsequent commands fail
   cd ../angular-scaffold-playground/my-app
   npm test
   rm -rf ../angular-scaffold-playground/my-app

   # CORRECT - return to repo root first
   cd ../../angular-scaffold
   rm -rf ../angular-scaffold-playground/my-app
   ```
