diff --git a/get-shit-done/templates/codebase/conventions.md b/get-shit-done/templates/codebase/conventions.md new file mode 100644 index 000000000..361283bea --- /dev/null +++ b/get-shit-done/templates/codebase/conventions.md @@ -0,0 +1,307 @@ +# Coding Conventions Template + +Template for `.planning/codebase/CONVENTIONS.md` - captures coding style and patterns. + +**Purpose:** Document how code is written in this codebase. Prescriptive guide for Claude to match existing style. + +--- + +## File Template + +```markdown +# Coding Conventions + +**Analysis Date:** [YYYY-MM-DD] + +## Naming Patterns + +**Files:** +- [Pattern: e.g., "kebab-case for all files"] +- [Test files: e.g., "*.test.ts alongside source"] +- [Components: e.g., "PascalCase.tsx for React components"] + +**Functions:** +- [Pattern: e.g., "camelCase for all functions"] +- [Async: e.g., "no special prefix for async functions"] +- [Handlers: e.g., "handleEventName for event handlers"] + +**Variables:** +- [Pattern: e.g., "camelCase for variables"] +- [Constants: e.g., "UPPER_SNAKE_CASE for constants"] +- [Private: e.g., "_prefix for private members" or "no prefix"] + +**Types:** +- [Interfaces: e.g., "PascalCase, no I prefix"] +- [Types: e.g., "PascalCase for type aliases"] +- [Enums: e.g., "PascalCase for enum name, UPPER_CASE for values"] + +## Code Style + +**Formatting:** +- [Tool: e.g., "Prettier with config in .prettierrc"] +- [Line length: e.g., "100 characters max"] +- [Quotes: e.g., "single quotes for strings"] +- [Semicolons: e.g., "required" or "omitted"] + +**Linting:** +- [Tool: e.g., "ESLint with eslint.config.js"] +- [Rules: e.g., "extends airbnb-base, no console in production"] +- [Run: e.g., "npm run lint"] + +## Import Organization + +**Order:** +1. [e.g., "External packages (react, express, etc.)"] +2. [e.g., "Internal modules (@/lib, @/components)"] +3. [e.g., "Relative imports (., ..)"] +4. [e.g., "Type imports (import type {})"] + +**Grouping:** +- [Blank lines: e.g., "blank line between groups"] +- [Sorting: e.g., "alphabetical within each group"] + +**Path Aliases:** +- [Aliases used: e.g., "@/ for src/, @components/ for src/components/"] + +## Error Handling + +**Patterns:** +- [Strategy: e.g., "throw errors, catch at boundaries"] +- [Custom errors: e.g., "extend Error class, named *Error"] +- [Async: e.g., "use try/catch, no .catch() chains"] + +**Error Types:** +- [When to throw: e.g., "invalid input, missing dependencies"] +- [When to return: e.g., "expected failures return Result"] +- [Logging: e.g., "log error with context before throwing"] + +## Logging + +**Framework:** +- [Tool: e.g., "console.log, pino, winston"] +- [Levels: e.g., "debug, info, warn, error"] + +**Patterns:** +- [Format: e.g., "structured logging with context object"] +- [When: e.g., "log state transitions, external calls"] +- [Where: e.g., "log at service boundaries, not in utils"] + +## Comments + +**When to Comment:** +- [e.g., "explain why, not what"] +- [e.g., "document business logic, algorithms, edge cases"] +- [e.g., "avoid obvious comments like // increment counter"] + +**JSDoc/TSDoc:** +- [Usage: e.g., "required for public APIs, optional for internal"] +- [Format: e.g., "use @param, @returns, @throws tags"] + +**TODO Comments:** +- [Pattern: e.g., "// TODO(username): description"] +- [Tracking: e.g., "link to issue number if available"] + +## Function Design + +**Size:** +- [e.g., "keep under 50 lines, extract helpers"] + +**Parameters:** +- [e.g., "max 3 parameters, use object for more"] +- [e.g., "destructure objects in parameter list"] + +**Return Values:** +- [e.g., "explicit returns, no implicit undefined"] +- [e.g., "return early for guard clauses"] + +## Module Design + +**Exports:** +- [e.g., "named exports preferred, default exports for React components"] +- [e.g., "export from index.ts for public API"] + +**Barrel Files:** +- [e.g., "use index.ts to re-export public API"] +- [e.g., "avoid circular dependencies"] + +--- + +*Convention analysis: [date]* +*Update when patterns change* +``` + + +```markdown +# Coding Conventions + +**Analysis Date:** 2025-01-20 + +## Naming Patterns + +**Files:** +- kebab-case for all files (command-handler.ts, user-service.ts) +- *.test.ts alongside source files +- index.ts for barrel exports + +**Functions:** +- camelCase for all functions +- No special prefix for async functions +- handleEventName for event handlers (handleClick, handleSubmit) + +**Variables:** +- camelCase for variables +- UPPER_SNAKE_CASE for constants (MAX_RETRIES, API_BASE_URL) +- No underscore prefix (no private marker in TS) + +**Types:** +- PascalCase for interfaces, no I prefix (User, not IUser) +- PascalCase for type aliases (UserConfig, ResponseData) +- PascalCase for enum names, UPPER_CASE for values (Status.PENDING) + +## Code Style + +**Formatting:** +- Prettier with .prettierrc +- 100 character line length +- Single quotes for strings +- Semicolons required +- 2 space indentation + +**Linting:** +- ESLint with eslint.config.js +- Extends @typescript-eslint/recommended +- No console.log in production code (use logger) +- Run: npm run lint + +## Import Organization + +**Order:** +1. External packages (react, express, commander) +2. Internal modules (@/lib, @/services) +3. Relative imports (./utils, ../types) +4. Type imports (import type { User }) + +**Grouping:** +- Blank line between groups +- Alphabetical within each group +- Type imports last within each group + +**Path Aliases:** +- @/ maps to src/ +- No other aliases defined + +## Error Handling + +**Patterns:** +- Throw errors, catch at boundaries (route handlers, main functions) +- Extend Error class for custom errors (ValidationError, NotFoundError) +- Async functions use try/catch, no .catch() chains + +**Error Types:** +- Throw on invalid input, missing dependencies, invariant violations +- Log error with context before throwing: logger.error({ err, userId }, 'Failed to process') +- Include cause in error message: new Error('Failed to X', { cause: originalError }) + +## Logging + +**Framework:** +- pino logger instance exported from lib/logger.ts +- Levels: debug, info, warn, error (no trace) + +**Patterns:** +- Structured logging with context: logger.info({ userId, action }, 'User action') +- Log at service boundaries, not in utility functions +- Log state transitions, external API calls, errors +- No console.log in committed code + +## Comments + +**When to Comment:** +- Explain why, not what: // Retry 3 times because API has transient failures +- Document business rules: // Users must verify email within 24 hours +- Explain non-obvious algorithms or workarounds +- Avoid obvious comments: // set count to 0 + +**JSDoc/TSDoc:** +- Required for public API functions +- Optional for internal functions if signature is self-explanatory +- Use @param, @returns, @throws tags + +**TODO Comments:** +- Format: // TODO: description (no username, using git blame) +- Link to issue if exists: // TODO: Fix race condition (issue #123) + +## Function Design + +**Size:** +- Keep under 50 lines +- Extract helpers for complex logic +- One level of abstraction per function + +**Parameters:** +- Max 3 parameters +- Use options object for 4+ parameters: function create(options: CreateOptions) +- Destructure in parameter list: function process({ id, name }: ProcessParams) + +**Return Values:** +- Explicit return statements +- Return early for guard clauses +- Use Result type for expected failures + +## Module Design + +**Exports:** +- Named exports preferred +- Default exports only for React components +- Export public API from index.ts barrel files + +**Barrel Files:** +- index.ts re-exports public API +- Keep internal helpers private (don't export from index) +- Avoid circular dependencies (import from specific files if needed) + +--- + +*Convention analysis: 2025-01-20* +*Update when patterns change* +``` + + + +**What belongs in CONVENTIONS.md:** +- Naming patterns observed in the codebase +- Formatting rules (Prettier config, linting rules) +- Import organization patterns +- Error handling strategy +- Logging approach +- Comment conventions +- Function and module design patterns + +**What does NOT belong here:** +- Architecture decisions (that's ARCHITECTURE.md) +- Technology choices (that's STACK.md) +- Test patterns (that's TESTING.md) +- File organization (that's STRUCTURE.md) + +**When filling this template:** +- Check .prettierrc, .eslintrc, or similar config files +- Examine 5-10 representative source files for patterns +- Look for consistency: if 80%+ follows a pattern, document it +- Be prescriptive: "Use X" not "Sometimes Y is used" +- Note deviations: "Legacy code uses Y, new code should use X" +- Keep under ~150 lines total + +**Useful for phase planning when:** +- Writing new code (match existing style) +- Adding features (follow naming patterns) +- Refactoring (apply consistent conventions) +- Code review (check against documented patterns) +- Onboarding (understand style expectations) + +**Analysis approach:** +- Scan src/ directory for file naming patterns +- Check package.json scripts for lint/format commands +- Read 5-10 files to identify function naming, error handling +- Look for config files (.prettierrc, eslint.config.js) +- Note patterns in imports, comments, function signatures + diff --git a/get-shit-done/templates/codebase/testing.md b/get-shit-done/templates/codebase/testing.md new file mode 100644 index 000000000..95e53902a --- /dev/null +++ b/get-shit-done/templates/codebase/testing.md @@ -0,0 +1,480 @@ +# Testing Patterns Template + +Template for `.planning/codebase/TESTING.md` - captures test framework and patterns. + +**Purpose:** Document how tests are written and run. Guide for adding tests that match existing patterns. + +--- + +## File Template + +```markdown +# Testing Patterns + +**Analysis Date:** [YYYY-MM-DD] + +## Test Framework + +**Runner:** +- [Framework: e.g., "Jest 29.x", "Vitest 1.x"] +- [Config: e.g., "jest.config.js in project root"] + +**Assertion Library:** +- [Library: e.g., "built-in expect", "chai"] +- [Matchers: e.g., "toBe, toEqual, toThrow"] + +**Run Commands:** +```bash +[e.g., "npm test" or "npm run test"] # Run all tests +[e.g., "npm test -- --watch"] # Watch mode +[e.g., "npm test -- path/to/file.test.ts"] # Single file +[e.g., "npm run test:coverage"] # Coverage report +``` + +## Test File Organization + +**Location:** +- [Pattern: e.g., "*.test.ts alongside source files"] +- [Alternative: e.g., "__tests__/ directory" or "separate tests/ tree"] + +**Naming:** +- [Unit tests: e.g., "module-name.test.ts"] +- [Integration: e.g., "feature-name.integration.test.ts"] +- [E2E: e.g., "user-flow.e2e.test.ts"] + +**Structure:** +``` +[Show actual directory pattern, e.g.: +src/ + lib/ + utils.ts + utils.test.ts + services/ + user-service.ts + user-service.test.ts +] +``` + +## Test Structure + +**Suite Organization:** +```typescript +[Show actual pattern used, e.g.: + +describe('ModuleName', () => { + describe('functionName', () => { + it('should handle success case', () => { + // arrange + // act + // assert + }); + + it('should handle error case', () => { + // test code + }); + }); +}); +] +``` + +**Patterns:** +- [Setup: e.g., "beforeEach for shared setup, avoid beforeAll"] +- [Teardown: e.g., "afterEach to clean up, restore mocks"] +- [Structure: e.g., "arrange/act/assert pattern required"] + +## Mocking + +**Framework:** +- [Tool: e.g., "Jest built-in mocking", "Vitest vi", "Sinon"] +- [Import mocking: e.g., "vi.mock() at top of file"] + +**Patterns:** +```typescript +[Show actual mocking pattern, e.g.: + +// Mock external dependency +vi.mock('./external-service', () => ({ + fetchData: vi.fn() +})); + +// Mock in test +const mockFetch = vi.mocked(fetchData); +mockFetch.mockResolvedValue({ data: 'test' }); +] +``` + +**What to Mock:** +- [e.g., "External APIs, file system, database"] +- [e.g., "Time/dates (use vi.useFakeTimers)"] +- [e.g., "Network calls (use mock fetch)"] + +**What NOT to Mock:** +- [e.g., "Pure functions, utilities"] +- [e.g., "Internal business logic"] + +## Fixtures and Factories + +**Test Data:** +```typescript +[Show pattern for creating test data, e.g.: + +// Factory pattern +function createTestUser(overrides?: Partial): User { + return { + id: 'test-id', + name: 'Test User', + email: 'test@example.com', + ...overrides + }; +} + +// Fixture file +// tests/fixtures/users.ts +export const mockUsers = [/* ... */]; +] +``` + +**Location:** +- [e.g., "tests/fixtures/ for shared fixtures"] +- [e.g., "factory functions in test file or tests/factories/"] + +## Coverage + +**Requirements:** +- [Target: e.g., "80% line coverage", "no specific target"] +- [Enforcement: e.g., "CI blocks <80%", "coverage for awareness only"] + +**Configuration:** +- [Tool: e.g., "built-in coverage via --coverage flag"] +- [Exclusions: e.g., "exclude *.test.ts, config files"] + +**View Coverage:** +```bash +[e.g., "npm run test:coverage"] +[e.g., "open coverage/index.html"] +``` + +## Test Types + +**Unit Tests:** +- [Scope: e.g., "test single function/class in isolation"] +- [Mocking: e.g., "mock all external dependencies"] +- [Speed: e.g., "must run in <1s per test"] + +**Integration Tests:** +- [Scope: e.g., "test multiple modules together"] +- [Mocking: e.g., "mock external services, use real internal modules"] +- [Setup: e.g., "use test database, seed data"] + +**E2E Tests:** +- [Framework: e.g., "Playwright for E2E"] +- [Scope: e.g., "test full user flows"] +- [Location: e.g., "e2e/ directory separate from unit tests"] + +## Common Patterns + +**Async Testing:** +```typescript +[Show pattern, e.g.: + +it('should handle async operation', async () => { + const result = await asyncFunction(); + expect(result).toBe('expected'); +}); +] +``` + +**Error Testing:** +```typescript +[Show pattern, e.g.: + +it('should throw on invalid input', () => { + expect(() => functionCall()).toThrow('error message'); +}); + +// Async error +it('should reject on failure', async () => { + await expect(asyncCall()).rejects.toThrow('error message'); +}); +] +``` + +**Snapshot Testing:** +- [Usage: e.g., "for React components only" or "not used"] +- [Location: e.g., "__snapshots__/ directory"] + +--- + +*Testing analysis: [date]* +*Update when test patterns change* +``` + + +```markdown +# Testing Patterns + +**Analysis Date:** 2025-01-20 + +## Test Framework + +**Runner:** +- Vitest 1.0.4 +- Config: vitest.config.ts in project root + +**Assertion Library:** +- Vitest built-in expect +- Matchers: toBe, toEqual, toThrow, toMatchObject + +**Run Commands:** +```bash +npm test # Run all tests +npm test -- --watch # Watch mode +npm test -- path/to/file.test.ts # Single file +npm run test:coverage # Coverage report +``` + +## Test File Organization + +**Location:** +- *.test.ts alongside source files +- No separate tests/ directory + +**Naming:** +- unit-name.test.ts for all tests +- No distinction between unit/integration in filename + +**Structure:** +``` +src/ + lib/ + parser.ts + parser.test.ts + services/ + install-service.ts + install-service.test.ts + bin/ + install.ts + (no test - integration tested via CLI) +``` + +## Test Structure + +**Suite Organization:** +```typescript +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; + +describe('ModuleName', () => { + describe('functionName', () => { + beforeEach(() => { + // reset state + }); + + it('should handle valid input', () => { + // arrange + const input = createTestInput(); + + // act + const result = functionName(input); + + // assert + expect(result).toEqual(expectedOutput); + }); + + it('should throw on invalid input', () => { + expect(() => functionName(null)).toThrow('Invalid input'); + }); + }); +}); +``` + +**Patterns:** +- Use beforeEach for per-test setup, avoid beforeAll +- Use afterEach to restore mocks: vi.restoreAllMocks() +- Explicit arrange/act/assert comments in complex tests +- One assertion focus per test (but multiple expects OK) + +## Mocking + +**Framework:** +- Vitest built-in mocking (vi) +- Module mocking via vi.mock() at top of test file + +**Patterns:** +```typescript +import { vi } from 'vitest'; +import { externalFunction } from './external'; + +// Mock module +vi.mock('./external', () => ({ + externalFunction: vi.fn() +})); + +describe('test suite', () => { + it('mocks function', () => { + const mockFn = vi.mocked(externalFunction); + mockFn.mockReturnValue('mocked result'); + + // test code using mocked function + + expect(mockFn).toHaveBeenCalledWith('expected arg'); + }); +}); +``` + +**What to Mock:** +- File system operations (fs-extra) +- Child process execution (child_process.exec) +- External API calls +- Environment variables (process.env) + +**What NOT to Mock:** +- Internal pure functions +- Simple utilities (string manipulation, array helpers) +- TypeScript types + +## Fixtures and Factories + +**Test Data:** +```typescript +// Factory functions in test file +function createTestConfig(overrides?: Partial): Config { + return { + targetDir: '/tmp/test', + global: false, + ...overrides + }; +} + +// Shared fixtures in tests/fixtures/ +// tests/fixtures/sample-command.md +export const sampleCommand = `--- +description: Test command +--- +Content here`; +``` + +**Location:** +- Factory functions: define in test file near usage +- Shared fixtures: tests/fixtures/ (for multi-file test data) +- Mock data: inline in test when simple, factory when complex + +## Coverage + +**Requirements:** +- No enforced coverage target +- Coverage tracked for awareness +- Focus on critical paths (parsers, service logic) + +**Configuration:** +- Vitest coverage via c8 (built-in) +- Excludes: *.test.ts, bin/install.ts, config files + +**View Coverage:** +```bash +npm run test:coverage +open coverage/index.html +``` + +## Test Types + +**Unit Tests:** +- Test single function in isolation +- Mock all external dependencies (fs, child_process) +- Fast: each test <100ms +- Examples: parser.test.ts, validator.test.ts + +**Integration Tests:** +- Test multiple modules together +- Mock only external boundaries (file system, process) +- Examples: install-service.test.ts (tests service + parser) + +**E2E Tests:** +- Not currently used +- CLI integration tested manually + +## Common Patterns + +**Async Testing:** +```typescript +it('should handle async operation', async () => { + const result = await asyncFunction(); + expect(result).toBe('expected'); +}); +``` + +**Error Testing:** +```typescript +it('should throw on invalid input', () => { + expect(() => parse(null)).toThrow('Cannot parse null'); +}); + +// Async error +it('should reject on file not found', async () => { + await expect(readConfig('invalid.txt')).rejects.toThrow('ENOENT'); +}); +``` + +**File System Mocking:** +```typescript +import { vi } from 'vitest'; +import * as fs from 'fs-extra'; + +vi.mock('fs-extra'); + +it('mocks file system', () => { + vi.mocked(fs.readFile).mockResolvedValue('file content'); + // test code +}); +``` + +**Snapshot Testing:** +- Not used in this codebase +- Prefer explicit assertions for clarity + +--- + +*Testing analysis: 2025-01-20* +*Update when test patterns change* +``` + + + +**What belongs in TESTING.md:** +- Test framework and runner configuration +- Test file location and naming patterns +- Test structure (describe/it, beforeEach patterns) +- Mocking approach and examples +- Fixture/factory patterns +- Coverage requirements +- How to run tests (commands) +- Common testing patterns in actual code + +**What does NOT belong here:** +- Specific test cases (defer to actual test files) +- Technology choices (that's STACK.md) +- CI/CD setup (that's deployment docs) + +**When filling this template:** +- Check package.json scripts for test commands +- Find test config file (jest.config.js, vitest.config.ts) +- Read 3-5 existing test files to identify patterns +- Look for test utilities in tests/ or test-utils/ +- Check for coverage configuration +- Document actual patterns used, not ideal patterns + +**Useful for phase planning when:** +- Adding new features (write matching tests) +- Refactoring (maintain test patterns) +- Fixing bugs (add regression tests) +- Understanding verification approach +- Setting up test infrastructure + +**Analysis approach:** +- Check package.json for test framework and scripts +- Read test config file for coverage, setup +- Examine test file organization (collocated vs separate) +- Review 5 test files for patterns (mocking, structure, assertions) +- Look for test utilities, fixtures, factories +- Note any test types (unit, integration, e2e) +- Document commands for running tests +