# Contributing to repo2txt Thank you for your interest in contributing! This document provides comprehensive guidance on the project architecture, design patterns, and development workflow. ## πŸ“‹ Table of Contents - [Getting Started](#getting-started) - [Architecture Overview](#architecture-overview) - [Design Patterns](#design-patterns) - [Project Structure](#project-structure) - [Development Workflow](#development-workflow) - [Testing Strategy](#testing-strategy) - [Code Style](#code-style) - [Pull Request Process](#pull-request-process) ## πŸš€ Getting Started ### Prerequisites - Node.js 20+ (LTS recommended) - npm 10+ - Git - A code editor (VS Code recommended) ### Initial Setup ```bash # Fork the repository on GitHub # Clone your fork git clone https://github.com/YOUR_USERNAME/repo2txt.git cd repo2txt # Add upstream remote git remote add upstream https://github.com/abinthomasonline/repo2txt.git # Install dependencies npm install # Copy test configuration template cp tests/test-config.example.ts tests/test-config.ts # Add your GitHub token to test-config.ts (optional, for E2E tests) # Start development server npm run dev ``` ### Development Commands ```bash # Development npm run dev # Start dev server (http://localhost:5173/repo2txt/) npm run build # Production build npm run preview # Preview production build # Testing npm run test:unit # Run unit tests npm run test:e2e # Run E2E tests npm run test:watch # Watch mode for unit tests npm run test:coverage # Generate coverage report # Code Quality npm run typecheck # TypeScript type checking npm run lint # Lint code npm run lint:fix # Auto-fix linting issues npm run format # Format code with Prettier npm run format:check # Check formatting # CI Pipeline (runs all checks) npm run ci # typecheck + lint + test:unit ``` ## πŸ—οΈ Architecture Overview ### Core Design Principles 1. **Provider Pattern** - Unified interface for multiple data sources 2. **Separation of Concerns** - Clear boundaries between UI, business logic, and data 3. **Type Safety** - TypeScript everywhere with strict mode 4. **Performance First** - Virtual scrolling, code splitting, Web Workers 5. **Privacy First** - All processing happens in the browser ### System Architecture ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ React App β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ UI β”‚ β”‚ Store β”‚ β”‚ Workers β”‚ β”‚ β”‚ β”‚ Components │◄── (Zustand) │◄── (Tokenizer) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β–² β–² β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Provider Interface β”‚ β”‚ β”‚ β”‚ (BaseProvider - Abstract Base Class) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β–² β–² β–² β–² β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”¬β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”΄β”€β”€β”€β”€β” β”‚ β”‚ β”‚ GitHub β”‚ Local β”‚ GitLab β”‚ Azure β”‚ β”‚ β”‚ β”‚Providerβ”‚ Providerβ”‚ Provider β”‚Provider β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Data Flow ``` User Input β†’ URL Parsing β†’ Provider Selection β†’ Tree Fetch ↓ File Tree (Virtual Scrolling) β†’ User Selection β†’ Filters ↓ Content Fetch β†’ Formatting β†’ Tokenization (Web Worker) ↓ Output Display β†’ Copy/Download ``` ## 🎨 Design Patterns ### 1. Provider Pattern **Purpose:** Abstract different data sources (GitHub, Local, GitLab, Azure) behind a unified interface. **Implementation:** ```typescript // Base provider interface abstract class BaseProvider { abstract getType(): ProviderType; abstract validateUrl(url: string): boolean; abstract parseUrl(url: string): ParsedRepoInfo; abstract fetchTree(url: string, options?: FetchOptions): Promise; abstract fetchFile(node: FileNode): Promise; // Shared utilities async *fetchMultiple(nodes: FileNode[]): AsyncGenerator { // Progressive loading implementation } } // Concrete implementation class GitHubProvider extends BaseProvider { async fetchTree(url: string): Promise { // GitHub-specific implementation const parsed = this.parseUrl(url); const tree = await this.fetchGitHubTree(parsed); return this.normalizeTree(tree); } } ``` **Benefits:** - Easy to add new providers (GitLab, Bitbucket, etc.) - Consistent interface across all sources - Shared functionality in base class (error handling, retries, caching) - Type-safe provider switching ### 2. State Management with Zustand **Purpose:** Centralized, reactive state management without Redux boilerplate. **Store Structure:** ```typescript // Modular stores (slices pattern) interface AppState { // UI State theme: ThemeMode; isLoading: boolean; error: ErrorState | null; // Data State currentProvider: ProviderType; tree: FileNode[]; selectedPaths: Set; excludedPaths: Set; // Actions setProvider: (provider: ProviderType) => void; toggleSelection: (path: string) => void; // ...more actions } // Store composition const useStore = create()( devtools( persist( (set, get) => ({ // Initial state theme: 'system', // Actions setTheme: (theme) => set({ theme }), // Computed selectors getSelectedNodes: () => { const { tree, selectedPaths } = get(); return tree.filter(n => selectedPaths.has(n.path)); } }), { name: 'repo2txt-store' } ) ) ); ``` **Benefits:** - Simple API with hooks - DevTools integration - Persistence support - Computed selectors - Minimal re-renders ### 3. Virtual Scrolling **Purpose:** Efficiently render large file trees (10,000+ files) without performance degradation. **Implementation:** ```typescript // Using TanStack Virtual import { useVirtualizer } from '@tanstack/react-virtual'; function FileTree({ nodes }: { nodes: TreeNode[] }) { const parentRef = useRef(null); // Flatten tree for virtual scrolling const flatNodes = useMemo(() => flattenTree(nodes), [nodes]); const virtualizer = useVirtualizer({ count: flatNodes.length, getScrollElement: () => parentRef.current, estimateSize: () => 32, // Row height overscan: 10, // Render extra rows outside viewport }); return (
{virtualizer.getVirtualItems().map(virtualRow => ( ))}
); } ``` **Benefits:** - Constant memory usage regardless of tree size - Smooth scrolling - Only renders visible items + overscan - Automatic height calculation ### 4. Code Splitting with Dynamic Imports **Purpose:** Reduce initial bundle size by lazy-loading provider implementations. **Implementation:** ```typescript // Provider registry with lazy loading const PROVIDERS = { github: () => import('@/features/github/GitHubProvider'), local: () => import('@/features/local/LocalProvider'), gitlab: () => import('@/features/gitlab/GitLabProvider'), azure: () => import('@/features/azure/AzureDevOpsProvider'), }; // Dynamic provider loading in ProviderSelector const loadProvider = async (type: ProviderType) => { const ProviderModule = await PROVIDERS[type](); const ProviderClass = ProviderModule.default; return new ProviderClass(); }; ``` **Bundle Impact:** - Main chunk: ~330KB - GitHub provider: ~50KB (loaded on demand) - Local provider: ~30KB (loaded on demand) - Each provider only loads when selected ### 5. Web Worker for Tokenization **Purpose:** Offload CPU-intensive tokenization to background thread. **Implementation:** ```typescript // Worker wrapper class TokenizerWorker { private worker: Worker; async tokenize(text: string): Promise { return new Promise((resolve) => { this.worker.postMessage({ type: 'tokenize', text }); this.worker.onmessage = (e) => resolve(e.data.tokenCount); }); } async tokenizeBatch( files: FileContent[], onProgress?: (progress: number) => void ): Promise<{ totalTokens: number; files: FileWithStats[] }> { // Progressive tokenization with progress callbacks } } // Worker implementation (tokenizer.worker.ts) self.onmessage = async (event) => { const { type, text, files } = event.data; if (type === 'tokenize') { const tokenCount = encode(text).length; self.postMessage({ tokenCount }); } else if (type === 'tokenize_batch') { for (const file of files) { const tokenCount = encode(file.content).length; self.postMessage({ type: 'progress', file: { ...file, tokenCount } }); } } }; ``` **Benefits:** - Non-blocking UI during tokenization - Progress updates for long operations - Better perceived performance - Utilizes multi-core CPUs ### 6. Error Handling Strategy **Layered error handling with custom error types:** ```typescript // Custom error classes class ProviderError extends Error { constructor( message: string, public code: ErrorCode, public userMessage: string, public recovery?: () => void ) { super(message); } } // Error boundaries in React class ErrorBoundary extends Component { componentDidCatch(error: Error, errorInfo: ErrorInfo) { // Log to error tracking service console.error('Caught error:', error, errorInfo); } } // Error dialog for user-facing errors {error && ( setError(null)} onAction={error.recovery} actionLabel={error.recoveryLabel} /> )} ``` ## πŸ“ Project Structure ``` repo2txt/ β”œβ”€β”€ .github/ β”‚ └── workflows/ β”‚ └── deploy.yml # GitHub Actions CI/CD β”‚ β”œβ”€β”€ src/ β”‚ β”œβ”€β”€ features/ # Feature modules (domain-driven) β”‚ β”‚ β”œβ”€β”€ github/ β”‚ β”‚ β”‚ β”œβ”€β”€ GitHubProvider.ts # GitHub API implementation β”‚ β”‚ β”‚ β”œβ”€β”€ components/ # GitHub-specific UI β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ GitHubAuth.tsx # Token management β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ GitHubForm.tsx # URL input form β”‚ β”‚ β”‚ β”‚ └── GitHubUrlInput.tsx β”‚ β”‚ β”‚ └── __tests__/ # Feature tests β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ local/ β”‚ β”‚ β”‚ β”œβ”€β”€ LocalProvider.ts # File System API β”‚ β”‚ β”‚ └── components/ β”‚ β”‚ β”‚ β”œβ”€β”€ DirectoryPicker.tsx β”‚ β”‚ β”‚ β”œβ”€β”€ ZipUploader.tsx β”‚ β”‚ β”‚ └── LocalForm.tsx β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ gitlab/ # GitLab provider (beta) β”‚ β”‚ └── azure/ # Azure DevOps (beta) β”‚ β”‚ β”‚ β”œβ”€β”€ components/ # Shared UI components β”‚ β”‚ β”œβ”€β”€ ui/ # Base components (buttons, dialogs) β”‚ β”‚ β”‚ β”œβ”€β”€ Button.tsx β”‚ β”‚ β”‚ β”œβ”€β”€ ErrorDialog.tsx β”‚ β”‚ β”‚ └── ThemeToggle.tsx β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ file-tree/ # File tree components β”‚ β”‚ β”‚ β”œβ”€β”€ FileTree.tsx # Virtual scrolling tree β”‚ β”‚ β”‚ └── FileTreeNode.tsx # Individual node β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ filters/ # Filtering components β”‚ β”‚ β”‚ β”œβ”€β”€ AdvancedFilters.tsx β”‚ β”‚ β”‚ β”œβ”€β”€ ExtensionFilter.tsx β”‚ β”‚ β”‚ └── GitignoreEditor.tsx β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ OutputPanel.tsx # Output display & actions β”‚ β”‚ β”œβ”€β”€ FileStats.tsx # Token/line statistics β”‚ β”‚ └── ProviderSelector.tsx # Provider tabs β”‚ β”‚ β”‚ β”œβ”€β”€ lib/ # Core business logic β”‚ β”‚ β”œβ”€β”€ providers/ β”‚ β”‚ β”‚ β”œβ”€β”€ BaseProvider.ts # Abstract base class β”‚ β”‚ β”‚ └── types.ts # Shared provider types β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ formatter/ β”‚ β”‚ β”‚ β”œβ”€β”€ Formatter.ts # Output formatting β”‚ β”‚ β”‚ β”œβ”€β”€ TokenizerWorker.ts # Web Worker wrapper β”‚ β”‚ β”‚ └── __tests__/ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ gitignore/ β”‚ β”‚ β”‚ └── GitignoreParser.ts # .gitignore parsing β”‚ β”‚ β”‚ β”‚ β”‚ └── utils.ts # Shared utilities β”‚ β”‚ β”‚ β”œβ”€β”€ store/ # Zustand state management β”‚ β”‚ β”œβ”€β”€ index.ts # Store composition β”‚ β”‚ └── slices/ # Store slices β”‚ β”‚ β”œβ”€β”€ providerSlice.ts # Provider state β”‚ β”‚ β”œβ”€β”€ fileTreeSlice.ts # File tree state β”‚ β”‚ β”œβ”€β”€ filterSlice.ts # Filter state β”‚ β”‚ └── uiSlice.ts # UI state (theme, loading) β”‚ β”‚ β”‚ β”œβ”€β”€ hooks/ # Custom React hooks β”‚ β”‚ β”œβ”€β”€ useFileTree.ts β”‚ β”‚ β”œβ”€β”€ useProvider.ts β”‚ β”‚ └── useTheme.ts β”‚ β”‚ β”‚ β”œβ”€β”€ workers/ # Web Workers β”‚ β”‚ └── tokenizer.worker.ts # GPT tokenizer β”‚ β”‚ β”‚ β”œβ”€β”€ types/ # Shared TypeScript types β”‚ β”‚ └── index.ts β”‚ β”‚ β”‚ β”œβ”€β”€ App.tsx # Root component β”‚ β”œβ”€β”€ main.tsx # Entry point β”‚ └── index.css # Global styles β”‚ β”œβ”€β”€ tests/ β”‚ β”œβ”€β”€ e2e/ # End-to-end tests (Playwright) β”‚ β”‚ β”œβ”€β”€ dark-mode.spec.ts β”‚ β”‚ β”œβ”€β”€ error-scenarios.spec.ts β”‚ β”‚ β”œβ”€β”€ github-flow.spec.ts β”‚ β”‚ └── local-flow.spec.ts β”‚ β”‚ β”‚ β”œβ”€β”€ test-config.ts # Test configuration (git-ignored) β”‚ └── test-config.example.ts # Template β”‚ β”œβ”€β”€ public/ # Static assets β”œβ”€β”€ dist/ # Build output (git-ignored) β”‚ β”œβ”€β”€ .eslintrc.cjs # ESLint configuration β”œβ”€β”€ .prettierrc # Prettier configuration β”œβ”€β”€ tsconfig.json # TypeScript configuration β”œβ”€β”€ vite.config.ts # Vite configuration β”œβ”€β”€ playwright.config.ts # Playwright configuration β”œβ”€β”€ vitest.config.ts # Vitest configuration └── package.json # Dependencies & scripts ``` ### Key Directories Explained **`features/`** - Domain-driven feature modules. Each feature (GitHub, Local, etc.) is self-contained with its provider implementation, UI components, and tests. **`components/`** - Shared UI components used across features. Organized by functionality (ui, file-tree, filters). **`lib/`** - Core business logic independent of UI framework. Could be extracted to a separate package if needed. **`store/`** - Centralized state management using Zustand slices pattern. Each slice manages a specific concern. **`workers/`** - Web Workers for CPU-intensive tasks. Keeps UI thread responsive. ## πŸ§ͺ Testing Strategy ### Testing Pyramid ``` /\ / \ E2E (Playwright) - 25 tests /____\ Critical user flows / \ / \ Integration - Provider + UI /__________\ / \ Unit (Vitest) - 80%+ coverage /______________\ Business logic, utilities, components ``` ### Unit Tests (Vitest + React Testing Library) **What to test:** - Pure functions (formatters, parsers, utilities) - React components in isolation - Provider methods - Store actions and selectors **Example:** ```typescript // lib/formatter/__tests__/Formatter.test.ts describe('Formatter', () => { it('should format directory tree', () => { const tree = [ { path: 'src', type: 'tree' }, { path: 'src/index.ts', type: 'blob' }, ]; const formatted = Formatter.formatTree(tree); expect(formatted).toContain('β”œβ”€β”€ πŸ“ src'); expect(formatted).toContain('└── πŸ“„ index.ts'); }); it('should count tokens accurately', () => { const text = 'Hello world'; const count = Formatter.countTokens(text); expect(count).toBeGreaterThan(0); }); }); ``` ### Integration Tests **What to test:** - Provider + FileTree interactions - Filter + FileTree updates - Store + Component integration **Example:** ```typescript describe('GitHub Provider Integration', () => { it('should load and display file tree', async () => { const provider = new GitHubProvider(); const tree = await provider.fetchTree('https://github.com/facebook/react'); render(); expect(screen.getByText('package.json')).toBeInTheDocument(); }); }); ``` ### E2E Tests (Playwright) **What to test:** - Complete user workflows - Cross-browser compatibility - Real API interactions **Current Coverage:** - βœ… Dark mode (5 tests) - βœ… Error scenarios (8 tests) - βœ… GitHub flow (6 tests) - βœ… Local flow (6 tests) **Example:** ```typescript // tests/e2e/github-flow.spec.ts test('should complete full GitHub public repo flow', async ({ page }) => { await page.goto('/'); // Enter URL const urlInput = page.getByPlaceholder('https://github.com/facebook/react'); await urlInput.fill('https://github.com/abinthomasonline/repo2txt'); // Load repo const loadButton = page.getByRole('button', { name: /Load Repository/i }); await loadButton.click(); // Verify file tree await expect(page.getByTestId('file-tree-heading')).toBeVisible({ timeout: 30000 }); // Generate output const generateButton = page.getByTestId('generate-output-button'); await generateButton.click(); // Verify output await expect(page.getByText('Directory Structure:')).toBeVisible(); // Download const downloadPromise = page.waitForEvent('download'); await page.getByRole('button', { name: /Download/i }).click(); const download = await downloadPromise; expect(download.suggestedFilename()).toMatch(/\.txt/); }); ``` ### Running Tests ```bash # Unit tests npm run test:unit # Run once npm run test:watch # Watch mode npm run test:coverage # With coverage # E2E tests npm run test:e2e # All browsers npm run test:e2e -- --project=chromium # Single browser npm run test:e2e:ui # Interactive UI # Test specific file npm run test:unit -- Formatter.test.ts npm run test:e2e -- github-flow.spec.ts ``` ### Test Configuration **E2E Test Token Setup:** ```bash # Copy template cp tests/test-config.example.ts tests/test-config.ts # Add your token to test-config.ts export const testConfig = { githubToken: process.env.GITHUB_TOKEN || 'your_token_here', }; ``` **CI Configuration:** Tests run automatically on PRs via GitHub Actions. Set `GITHUB_TOKEN` secret in repository settings for E2E tests. ## πŸ’… Code Style ### TypeScript - **Strict mode enabled** - No implicit any, strict null checks - **Explicit return types** - For public functions and methods - **Interface over type** - Prefer interfaces for object shapes - **Functional style** - Prefer pure functions, immutability **Example:** ```typescript // βœ… Good interface FileNode { path: string; type: 'blob' | 'tree'; children?: FileNode[]; } function filterNodes(nodes: FileNode[], predicate: (node: FileNode) => boolean): FileNode[] { return nodes.filter(predicate).map(node => ({ ...node, children: node.children ? filterNodes(node.children, predicate) : undefined, })); } // ❌ Bad function filterNodes(nodes: any, predicate): any { return nodes.filter(predicate); } ``` ### React Components - **Functional components** - Use hooks, avoid class components - **Named exports** - Except for default component export - **Props interfaces** - Named after component: `ComponentNameProps` - **Early returns** - Handle edge cases first **Example:** ```typescript // βœ… Good interface FileTreeNodeProps { node: TreeNode; depth: number; onToggle: (path: string) => void; } export function FileTreeNode({ node, depth, onToggle }: FileTreeNodeProps) { if (!node) return null; const isDirectory = node.type === 'tree'; return (
); } ``` ### CSS/Tailwind - **Tailwind first** - Use utility classes - **Component classes** - For reusable patterns, define in component - **Dark mode** - Always add dark: variants - **Responsive** - Mobile-first with sm:, md:, lg: breakpoints **Example:** ```tsx // βœ… Good
// ❌ Bad
``` ### File Naming - **Components**: PascalCase (e.g., `FileTree.tsx`, `ErrorDialog.tsx`) - **Utilities**: camelCase (e.g., `formatTree.ts`, `parseUrl.ts`) - **Types**: PascalCase (e.g., `FileNode`, `ProviderType`) - **Tests**: Same as file + `.test.ts` or `.spec.ts` ### Code Organization **Import Order:** ```typescript // 1. React/external libraries import { useState, useEffect } from 'react'; import { useVirtualizer } from '@tanstack/react-virtual'; // 2. Internal imports (@/ aliases) import { BaseProvider } from '@/lib/providers/BaseProvider'; import { FileTree } from '@/components/file-tree/FileTree'; // 3. Types import type { FileNode, ProviderType } from '@/types'; // 4. Relative imports import { formatTree } from './utils'; // 5. Styles (if any) import './styles.css'; ``` ### ESLint & Prettier All code must pass linting and formatting: ```bash npm run lint # Check for issues npm run lint:fix # Auto-fix npm run format # Format with Prettier npm run format:check # Check formatting ``` ## πŸ”„ Development Workflow ### Branch Strategy - **`master`** - Production-ready code - **`v2-development`** - Main development branch - **`feature/*`** - New features (e.g., `feature/gitlab-support`) - **`fix/*`** - Bug fixes (e.g., `fix/token-storage`) - **`refactor/*`** - Code refactoring (e.g., `refactor/provider-interface`) ### Commit Messages Follow [Conventional Commits](https://www.conventionalcommits.org/): ``` ():