vibe-and-thrive 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/.claude/commands/add-tests.md +240 -0
  2. package/.claude/commands/e2e-scaffold.md +212 -0
  3. package/.claude/commands/explain.md +110 -0
  4. package/.claude/commands/fix-types.md +238 -0
  5. package/.claude/commands/refactor.md +184 -0
  6. package/.claude/commands/review.md +136 -0
  7. package/.claude/commands/security-check.md +223 -0
  8. package/.claude/commands/styleguide.md +446 -0
  9. package/.claude/commands/tdd-feature.md +227 -0
  10. package/.claude/commands/vibe-check.md +112 -0
  11. package/.pre-commit-hooks.yaml +77 -0
  12. package/LICENSE +21 -0
  13. package/README.md +167 -0
  14. package/bin/vibe-check.js +19 -0
  15. package/dist/cli.d.ts +13 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +206 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/eslint-plugin/index.d.ts +66 -0
  20. package/dist/eslint-plugin/index.d.ts.map +1 -0
  21. package/dist/eslint-plugin/index.js +67 -0
  22. package/dist/eslint-plugin/index.js.map +1 -0
  23. package/dist/eslint-plugin/rules/max-function-length.d.ts +8 -0
  24. package/dist/eslint-plugin/rules/max-function-length.d.ts.map +1 -0
  25. package/dist/eslint-plugin/rules/max-function-length.js +69 -0
  26. package/dist/eslint-plugin/rules/max-function-length.js.map +1 -0
  27. package/dist/eslint-plugin/rules/no-any-type.d.ts +8 -0
  28. package/dist/eslint-plugin/rules/no-any-type.d.ts.map +1 -0
  29. package/dist/eslint-plugin/rules/no-any-type.js +29 -0
  30. package/dist/eslint-plugin/rules/no-any-type.js.map +1 -0
  31. package/dist/eslint-plugin/rules/no-debug-statements.d.ts +8 -0
  32. package/dist/eslint-plugin/rules/no-debug-statements.d.ts.map +1 -0
  33. package/dist/eslint-plugin/rules/no-debug-statements.js +59 -0
  34. package/dist/eslint-plugin/rules/no-debug-statements.js.map +1 -0
  35. package/dist/eslint-plugin/rules/no-deep-nesting.d.ts +8 -0
  36. package/dist/eslint-plugin/rules/no-deep-nesting.d.ts.map +1 -0
  37. package/dist/eslint-plugin/rules/no-deep-nesting.js +56 -0
  38. package/dist/eslint-plugin/rules/no-deep-nesting.js.map +1 -0
  39. package/dist/eslint-plugin/rules/no-empty-catch.d.ts +8 -0
  40. package/dist/eslint-plugin/rules/no-empty-catch.d.ts.map +1 -0
  41. package/dist/eslint-plugin/rules/no-empty-catch.js +31 -0
  42. package/dist/eslint-plugin/rules/no-empty-catch.js.map +1 -0
  43. package/dist/eslint-plugin/rules/no-magic-numbers.d.ts +8 -0
  44. package/dist/eslint-plugin/rules/no-magic-numbers.d.ts.map +1 -0
  45. package/dist/eslint-plugin/rules/no-magic-numbers.js +58 -0
  46. package/dist/eslint-plugin/rules/no-magic-numbers.js.map +1 -0
  47. package/dist/eslint-plugin/rules/no-snake-case-props.d.ts +8 -0
  48. package/dist/eslint-plugin/rules/no-snake-case-props.d.ts.map +1 -0
  49. package/dist/eslint-plugin/rules/no-snake-case-props.js +48 -0
  50. package/dist/eslint-plugin/rules/no-snake-case-props.js.map +1 -0
  51. package/dist/hooks/check-any-types.d.ts +6 -0
  52. package/dist/hooks/check-any-types.d.ts.map +1 -0
  53. package/dist/hooks/check-any-types.js +73 -0
  54. package/dist/hooks/check-any-types.js.map +1 -0
  55. package/dist/hooks/check-commented-code.d.ts +6 -0
  56. package/dist/hooks/check-commented-code.d.ts.map +1 -0
  57. package/dist/hooks/check-commented-code.js +81 -0
  58. package/dist/hooks/check-commented-code.js.map +1 -0
  59. package/dist/hooks/check-console-error.d.ts +6 -0
  60. package/dist/hooks/check-console-error.d.ts.map +1 -0
  61. package/dist/hooks/check-console-error.js +41 -0
  62. package/dist/hooks/check-console-error.js.map +1 -0
  63. package/dist/hooks/check-debug-statements.d.ts +6 -0
  64. package/dist/hooks/check-debug-statements.d.ts.map +1 -0
  65. package/dist/hooks/check-debug-statements.js +120 -0
  66. package/dist/hooks/check-debug-statements.js.map +1 -0
  67. package/dist/hooks/check-deep-nesting.d.ts +6 -0
  68. package/dist/hooks/check-deep-nesting.d.ts.map +1 -0
  69. package/dist/hooks/check-deep-nesting.js +116 -0
  70. package/dist/hooks/check-deep-nesting.js.map +1 -0
  71. package/dist/hooks/check-docker-platform.d.ts +6 -0
  72. package/dist/hooks/check-docker-platform.d.ts.map +1 -0
  73. package/dist/hooks/check-docker-platform.js +42 -0
  74. package/dist/hooks/check-docker-platform.js.map +1 -0
  75. package/dist/hooks/check-dry-violations.d.ts +6 -0
  76. package/dist/hooks/check-dry-violations.d.ts.map +1 -0
  77. package/dist/hooks/check-dry-violations.js +124 -0
  78. package/dist/hooks/check-dry-violations.js.map +1 -0
  79. package/dist/hooks/check-empty-catch.d.ts +6 -0
  80. package/dist/hooks/check-empty-catch.d.ts.map +1 -0
  81. package/dist/hooks/check-empty-catch.js +111 -0
  82. package/dist/hooks/check-empty-catch.js.map +1 -0
  83. package/dist/hooks/check-function-length.d.ts +6 -0
  84. package/dist/hooks/check-function-length.d.ts.map +1 -0
  85. package/dist/hooks/check-function-length.js +152 -0
  86. package/dist/hooks/check-function-length.js.map +1 -0
  87. package/dist/hooks/check-hardcoded-urls.d.ts +6 -0
  88. package/dist/hooks/check-hardcoded-urls.d.ts.map +1 -0
  89. package/dist/hooks/check-hardcoded-urls.js +124 -0
  90. package/dist/hooks/check-hardcoded-urls.js.map +1 -0
  91. package/dist/hooks/check-magic-numbers.d.ts +6 -0
  92. package/dist/hooks/check-magic-numbers.d.ts.map +1 -0
  93. package/dist/hooks/check-magic-numbers.js +116 -0
  94. package/dist/hooks/check-magic-numbers.js.map +1 -0
  95. package/dist/hooks/check-secrets.d.ts +6 -0
  96. package/dist/hooks/check-secrets.d.ts.map +1 -0
  97. package/dist/hooks/check-secrets.js +138 -0
  98. package/dist/hooks/check-secrets.js.map +1 -0
  99. package/dist/hooks/check-snake-case-ts.d.ts +6 -0
  100. package/dist/hooks/check-snake-case-ts.d.ts.map +1 -0
  101. package/dist/hooks/check-snake-case-ts.js +78 -0
  102. package/dist/hooks/check-snake-case-ts.js.map +1 -0
  103. package/dist/hooks/check-todo-fixme.d.ts +6 -0
  104. package/dist/hooks/check-todo-fixme.d.ts.map +1 -0
  105. package/dist/hooks/check-todo-fixme.js +41 -0
  106. package/dist/hooks/check-todo-fixme.js.map +1 -0
  107. package/dist/hooks/check-unsafe-html.d.ts +6 -0
  108. package/dist/hooks/check-unsafe-html.d.ts.map +1 -0
  109. package/dist/hooks/check-unsafe-html.js +101 -0
  110. package/dist/hooks/check-unsafe-html.js.map +1 -0
  111. package/dist/hooks/index.d.ts +29 -0
  112. package/dist/hooks/index.d.ts.map +1 -0
  113. package/dist/hooks/index.js +54 -0
  114. package/dist/hooks/index.js.map +1 -0
  115. package/dist/index.d.ts +9 -0
  116. package/dist/index.d.ts.map +1 -0
  117. package/dist/index.js +10 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/lint-staged/config.d.ts +20 -0
  120. package/dist/lint-staged/config.d.ts.map +1 -0
  121. package/dist/lint-staged/config.js +27 -0
  122. package/dist/lint-staged/config.js.map +1 -0
  123. package/dist/utils/file-reader.d.ts +24 -0
  124. package/dist/utils/file-reader.d.ts.map +1 -0
  125. package/dist/utils/file-reader.js +140 -0
  126. package/dist/utils/file-reader.js.map +1 -0
  127. package/dist/utils/patterns.d.ts +27 -0
  128. package/dist/utils/patterns.d.ts.map +1 -0
  129. package/dist/utils/patterns.js +84 -0
  130. package/dist/utils/patterns.js.map +1 -0
  131. package/dist/utils/reporters.d.ts +21 -0
  132. package/dist/utils/reporters.d.ts.map +1 -0
  133. package/dist/utils/reporters.js +115 -0
  134. package/dist/utils/reporters.js.map +1 -0
  135. package/dist/utils/types.d.ts +71 -0
  136. package/dist/utils/types.d.ts.map +1 -0
  137. package/dist/utils/types.js +5 -0
  138. package/dist/utils/types.js.map +1 -0
  139. package/integrations/cursorrules.template +147 -0
  140. package/integrations/eslint.config.js +34 -0
  141. package/integrations/lint-staged.config.js +34 -0
  142. package/integrations/ruff.toml +125 -0
  143. package/integrations/vibe-check.yml +116 -0
  144. package/integrations/vscode-settings.json +127 -0
  145. package/package.json +81 -0
@@ -0,0 +1,240 @@
1
+ # Add Tests
2
+
3
+ Add tests to existing code to improve coverage and confidence.
4
+
5
+ ## Instructions
6
+
7
+ When asked to add tests:
8
+
9
+ ### Step 1: Analyze the Code
10
+
11
+ 1. Read the code to understand what it does
12
+ 2. Identify the public interface (what should be tested)
13
+ 3. Find edge cases and error conditions
14
+ 4. Check existing test patterns in the project
15
+
16
+ ### Step 2: Determine Test Type
17
+
18
+ | Code Type | Test Type | Framework |
19
+ |-----------|-----------|-----------|
20
+ | Utility functions | Unit tests | Jest, pytest |
21
+ | React components | Component tests | React Testing Library |
22
+ | API endpoints | Integration tests | supertest, pytest |
23
+ | User flows | E2E tests | Playwright, Cypress |
24
+ | Hooks | Hook tests | @testing-library/react-hooks |
25
+
26
+ ### Step 3: Identify Test Cases
27
+
28
+ For each function/component, consider:
29
+
30
+ **Happy Path**
31
+ - Normal inputs produce expected outputs
32
+ - Main use case works correctly
33
+
34
+ **Edge Cases**
35
+ - Empty inputs
36
+ - Null/undefined values
37
+ - Boundary values (0, -1, max)
38
+ - Single item vs multiple items
39
+
40
+ **Error Cases**
41
+ - Invalid inputs
42
+ - Network failures
43
+ - Permission errors
44
+ - Timeout scenarios
45
+
46
+ **State Transitions**
47
+ - Before/after state changes
48
+ - Loading → success → idle
49
+ - Loading → error → retry
50
+
51
+ ### Step 4: Write Tests
52
+
53
+ Use this structure for each test:
54
+
55
+ ```typescript
56
+ test('descriptive name of what is being tested', () => {
57
+ // Arrange: Set up test data and conditions
58
+ const input = createTestInput();
59
+
60
+ // Act: Perform the action being tested
61
+ const result = functionUnderTest(input);
62
+
63
+ // Assert: Verify the expected outcome
64
+ expect(result).toEqual(expectedOutput);
65
+ });
66
+ ```
67
+
68
+ ### Step 5: Document Test Purpose
69
+
70
+ Use the SCENARIO/EXPECTED/FAILURE pattern:
71
+
72
+ ```typescript
73
+ test('user can submit form with valid data', () => {
74
+ /**
75
+ * SCENARIO: User fills out all required fields correctly
76
+ * EXPECTED: Form submits successfully, success message shown
77
+ * FAILURE: Form doesn't submit, or error message shown
78
+ */
79
+ });
80
+ ```
81
+
82
+ ## Output Format
83
+
84
+ ```markdown
85
+ ## Tests for: [filename]
86
+
87
+ ### Test File Location
88
+ `[path/to/test/file.test.ts]`
89
+
90
+ ### Test Cases
91
+
92
+ 1. **Happy Path**: [description]
93
+ 2. **Edge Case**: [description]
94
+ 3. **Error Case**: [description]
95
+
96
+ ### Generated Tests
97
+
98
+ ```typescript
99
+ [complete test file]
100
+ ```
101
+
102
+ ### Coverage Summary
103
+ - Functions tested: X/Y
104
+ - Edge cases covered: [list]
105
+ - Not covered (intentionally): [list with reasons]
106
+
107
+ ### Running the Tests
108
+ ```bash
109
+ [command to run tests]
110
+ ```
111
+ ```
112
+
113
+ ## Test Patterns
114
+
115
+ ### Unit Test (Function)
116
+ ```typescript
117
+ describe('calculateTotal', () => {
118
+ it('returns sum of item prices', () => {
119
+ const items = [{ price: 10 }, { price: 20 }];
120
+ expect(calculateTotal(items)).toBe(30);
121
+ });
122
+
123
+ it('returns 0 for empty array', () => {
124
+ expect(calculateTotal([])).toBe(0);
125
+ });
126
+
127
+ it('handles single item', () => {
128
+ expect(calculateTotal([{ price: 15 }])).toBe(15);
129
+ });
130
+ });
131
+ ```
132
+
133
+ ### Component Test (React)
134
+ ```typescript
135
+ describe('LoginForm', () => {
136
+ it('submits with valid credentials', async () => {
137
+ const onSubmit = vi.fn();
138
+ render(<LoginForm onSubmit={onSubmit} />);
139
+
140
+ await userEvent.type(screen.getByLabelText(/email/i), 'test@example.com');
141
+ await userEvent.type(screen.getByLabelText(/password/i), 'password123');
142
+ await userEvent.click(screen.getByRole('button', { name: /login/i }));
143
+
144
+ expect(onSubmit).toHaveBeenCalledWith({
145
+ email: 'test@example.com',
146
+ password: 'password123',
147
+ });
148
+ });
149
+
150
+ it('shows error for invalid email', async () => {
151
+ render(<LoginForm onSubmit={vi.fn()} />);
152
+
153
+ await userEvent.type(screen.getByLabelText(/email/i), 'invalid');
154
+ await userEvent.click(screen.getByRole('button', { name: /login/i }));
155
+
156
+ expect(screen.getByText(/valid email/i)).toBeInTheDocument();
157
+ });
158
+ });
159
+ ```
160
+
161
+ ### API Test (Integration)
162
+ ```python
163
+ def test_create_user_success(client, db):
164
+ """
165
+ SCENARIO: POST /api/users with valid data
166
+ EXPECTED: 201 Created, user in database
167
+ """
168
+ response = client.post('/api/users', json={
169
+ 'email': 'test@example.com',
170
+ 'name': 'Test User',
171
+ })
172
+
173
+ assert response.status_code == 201
174
+ assert User.objects.filter(email='test@example.com').exists()
175
+
176
+
177
+ def test_create_user_duplicate_email(client, db, existing_user):
178
+ """
179
+ SCENARIO: POST /api/users with existing email
180
+ EXPECTED: 400 Bad Request, error message
181
+ """
182
+ response = client.post('/api/users', json={
183
+ 'email': existing_user.email,
184
+ 'name': 'Another User',
185
+ })
186
+
187
+ assert response.status_code == 400
188
+ assert 'already exists' in response.json()['error']
189
+ ```
190
+
191
+ ### E2E Test (Playwright)
192
+ ```typescript
193
+ test('user can complete checkout', async ({ page }) => {
194
+ /**
195
+ * SCENARIO: User adds item to cart and completes checkout
196
+ * EXPECTED: Order confirmation page shown
197
+ * FAILURE: Stuck on checkout, error message, or wrong page
198
+ */
199
+
200
+ // Add item to cart
201
+ await page.goto('/products/1');
202
+ await page.click('button:has-text("Add to Cart")');
203
+
204
+ // Go to checkout
205
+ await page.click('a:has-text("Checkout")');
206
+
207
+ // Fill shipping info
208
+ await page.fill('[name="address"]', '123 Main St');
209
+ await page.fill('[name="city"]', 'Anytown');
210
+
211
+ // Complete order
212
+ await page.click('button:has-text("Place Order")');
213
+
214
+ // Verify success
215
+ await expect(page.getByText('Order Confirmed')).toBeVisible();
216
+ });
217
+ ```
218
+
219
+ ## Test Modes
220
+
221
+ ### Quick Tests
222
+ Add basic happy path tests:
223
+ > "Add basic tests for this function"
224
+
225
+ ### Comprehensive Tests
226
+ Full coverage with edge cases:
227
+ > "Add comprehensive tests for UserService"
228
+
229
+ ### Specific Scenario
230
+ Test a specific case:
231
+ > "Add a test for when the API returns a 404"
232
+
233
+ ## Tips
234
+
235
+ - **Test behavior, not implementation**
236
+ - **One assertion per test** (when possible)
237
+ - **Use descriptive test names**
238
+ - **Don't test framework code** (React, Django, etc.)
239
+ - **Mock external dependencies**
240
+ - **Keep tests fast**
@@ -0,0 +1,212 @@
1
+ # E2E Test Scaffold
2
+
3
+ Generate a Playwright E2E test file structure for a new feature.
4
+
5
+ ## Instructions
6
+
7
+ Before generating the scaffold, **discover the project's testing setup**:
8
+
9
+ ### Step 1: Discovery Phase
10
+
11
+ Check for existing patterns in this order:
12
+
13
+ 1. **Playwright config**: Look for `playwright.config.ts` or `playwright.config.js`
14
+ - Note the `testDir` setting
15
+ - Check for `baseURL` configuration
16
+ - Look for any custom fixtures or global setup
17
+
18
+ 2. **Test directory structure**: Search for existing E2E tests
19
+ - Common locations: `e2e/`, `tests/`, `tests/e2e/`, `__tests__/e2e/`
20
+ - Note the file naming pattern (`.spec.ts`, `.test.ts`, etc.)
21
+
22
+ 3. **Existing helpers**: Look for helper files
23
+ - `e2e/helpers.ts`, `tests/helpers.ts`, `tests/utils.ts`
24
+ - Note API call patterns, auth setup, common utilities
25
+
26
+ 4. **Auth patterns**: Search for how tests handle authentication
27
+ - Session-based with cookies
28
+ - JWT tokens
29
+ - OAuth flows
30
+ - No auth needed
31
+
32
+ 5. **API patterns**: Check the tech stack
33
+ - REST endpoints
34
+ - GraphQL queries
35
+ - tRPC calls
36
+
37
+ ### Step 2: Ask User
38
+
39
+ If patterns are unclear, ask:
40
+ - "What feature are you building tests for?"
41
+ - "Does this feature require authentication?"
42
+ - "What API endpoints will the feature use?"
43
+
44
+ ### Step 3: Generate Scaffold
45
+
46
+ Create a test file with this structure:
47
+
48
+ ```typescript
49
+ import { test, expect, Page } from '@playwright/test';
50
+
51
+ // Configuration - adapt to project's pattern
52
+ const BASE_URL = process.env.BASE_URL || 'http://localhost:3000';
53
+ const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:8000';
54
+
55
+ // ============================================================================
56
+ // HELPER FUNCTIONS
57
+ // ============================================================================
58
+
59
+ /**
60
+ * [Add helper functions for API calls, auth setup, etc.]
61
+ *
62
+ * Example API helper pattern:
63
+ * async function createResourceViaAPI(page: Page): Promise<{ id: number }> {
64
+ * const result = await page.evaluate(async (apiBase) => {
65
+ * const response = await fetch(`${apiBase}/api/v1/resources/`, {
66
+ * method: 'POST',
67
+ * headers: { 'Content-Type': 'application/json' },
68
+ * credentials: 'include',
69
+ * });
70
+ * return response.json();
71
+ * }, API_BASE_URL);
72
+ * return result;
73
+ * }
74
+ */
75
+
76
+ // ============================================================================
77
+ // TEST SUITE: [Feature Name]
78
+ // ============================================================================
79
+
80
+ test.describe('[Feature Name]', () => {
81
+
82
+ test.beforeEach(async ({ page }) => {
83
+ // Setup: navigate to the feature, log in if needed
84
+ await page.goto(BASE_URL);
85
+ });
86
+
87
+ test.afterEach(async ({ page }, testInfo) => {
88
+ // Capture screenshot on failure for debugging
89
+ if (testInfo.status !== testInfo.expectedStatus) {
90
+ const screenshotPath = `e2e-${testInfo.title.replace(/\s+/g, '-')}-failure.png`;
91
+ await page.screenshot({ path: screenshotPath });
92
+ console.log(`Screenshot saved: ${screenshotPath}`);
93
+ }
94
+ });
95
+
96
+ // --------------------------------------------------------------------------
97
+ // Happy Path Tests
98
+ // --------------------------------------------------------------------------
99
+
100
+ test('user can [primary action]', async ({ page }) => {
101
+ /**
102
+ * SCENARIO: As a [user type], when I [action],
103
+ * I should [expected outcome]
104
+ * EXPECTED: [Specific success criteria]
105
+ * FAILURE: [What would indicate failure]
106
+ */
107
+
108
+ // Arrange: Set up test data
109
+
110
+ // Act: Perform user actions
111
+
112
+ // Assert: Verify expected outcome
113
+ // Use the critical assertion pattern:
114
+ // const isSuccess = await page.locator('[data-testid="success"]').isVisible();
115
+ // if (!isSuccess) {
116
+ // console.error('FAIL: Success indicator not visible');
117
+ // await page.screenshot({ path: 'e2e-test-name-debug.png' });
118
+ // }
119
+ // expect(isSuccess).toBeTruthy();
120
+ });
121
+
122
+ // --------------------------------------------------------------------------
123
+ // Edge Cases
124
+ // --------------------------------------------------------------------------
125
+
126
+ test('handles [edge case scenario]', async ({ page }) => {
127
+ /**
128
+ * SCENARIO: As a [user type], when [edge case condition],
129
+ * I should [expected behavior]
130
+ * EXPECTED: [Specific handling criteria]
131
+ * FAILURE: [What would indicate improper handling]
132
+ */
133
+ });
134
+
135
+ // --------------------------------------------------------------------------
136
+ // Error Handling
137
+ // --------------------------------------------------------------------------
138
+
139
+ test('shows error when [error condition]', async ({ page }) => {
140
+ /**
141
+ * SCENARIO: As a [user type], when [error condition occurs],
142
+ * I should see an appropriate error message
143
+ * EXPECTED: Error message displayed, user can recover
144
+ * FAILURE: Silent failure, crash, or unclear error
145
+ */
146
+ });
147
+
148
+ });
149
+ ```
150
+
151
+ ### Step 4: Adapt to Project
152
+
153
+ Based on discovery, customize the scaffold:
154
+
155
+ **If project uses session auth with CSRF:**
156
+ ```typescript
157
+ async function apiCallWithAuth(page: Page, endpoint: string, method: string, body?: object) {
158
+ return await page.evaluate(async ({ apiBase, endpoint, method, body }) => {
159
+ const csrfToken = document.cookie.split('; ')
160
+ .find(row => row.startsWith('csrftoken='))?.split('=')[1];
161
+ const response = await fetch(`${apiBase}${endpoint}`, {
162
+ method,
163
+ headers: {
164
+ 'Content-Type': 'application/json',
165
+ 'X-CSRFToken': csrfToken || ''
166
+ },
167
+ credentials: 'include',
168
+ body: body ? JSON.stringify(body) : undefined,
169
+ });
170
+ return response.json();
171
+ }, { apiBase: API_BASE_URL, endpoint, method, body });
172
+ }
173
+ ```
174
+
175
+ **If project uses JWT:**
176
+ ```typescript
177
+ async function apiCallWithJWT(page: Page, endpoint: string, method: string, body?: object) {
178
+ return await page.evaluate(async ({ apiBase, endpoint, method, body }) => {
179
+ const token = localStorage.getItem('authToken');
180
+ const response = await fetch(`${apiBase}${endpoint}`, {
181
+ method,
182
+ headers: {
183
+ 'Content-Type': 'application/json',
184
+ 'Authorization': `Bearer ${token}`
185
+ },
186
+ body: body ? JSON.stringify(body) : undefined,
187
+ });
188
+ return response.json();
189
+ }, { apiBase: API_BASE_URL, endpoint, method, body });
190
+ }
191
+ ```
192
+
193
+ **If project has existing helpers, import them:**
194
+ ```typescript
195
+ import { loginAsTestUser, createTestData, cleanupTestData } from './helpers';
196
+ ```
197
+
198
+ ### Step 5: Output
199
+
200
+ Provide:
201
+ 1. The scaffold file at the appropriate location
202
+ 2. Summary of discovered patterns used
203
+ 3. List of placeholder TODOs for the user to complete
204
+ 4. Suggestion to run `npx playwright test --ui` to verify setup
205
+
206
+ ## Notes
207
+
208
+ - Always use the SCENARIO/EXPECTED/FAILURE documentation pattern
209
+ - Include screenshot capture on failure
210
+ - Use flexible locators: `page.getByRole()` with `.or()` for fallbacks
211
+ - Keep tests independent - each test should set up its own data
212
+ - Use `test.describe()` to group related tests
@@ -0,0 +1,110 @@
1
+ # Explain Code
2
+
3
+ Explain what code does, line by line, so you can understand and learn from it.
4
+
5
+ ## Instructions
6
+
7
+ When the user asks you to explain code:
8
+
9
+ ### Step 1: Identify the Code
10
+
11
+ If the user provides a file path, read that file. If they paste code directly, use that.
12
+
13
+ If no code is specified, ask:
14
+ > "What code would you like me to explain? Please provide a file path or paste the code."
15
+
16
+ ### Step 2: Provide Overview
17
+
18
+ Start with a high-level summary:
19
+ - What is the purpose of this code?
20
+ - What problem does it solve?
21
+ - How does it fit into the larger application?
22
+
23
+ ### Step 3: Walk Through Line by Line
24
+
25
+ For each significant section, explain:
26
+ - **What** it does (literally)
27
+ - **Why** it's needed (purpose)
28
+ - **How** it works (mechanism)
29
+
30
+ Use this format:
31
+
32
+ ```
33
+ Lines X-Y: [Brief description]
34
+ - This code [what it does]
35
+ - It's needed because [why]
36
+ - It works by [how]
37
+ ```
38
+
39
+ ### Step 4: Highlight Key Concepts
40
+
41
+ Point out important patterns and concepts:
42
+ - Design patterns used
43
+ - Language features that might be unfamiliar
44
+ - Best practices demonstrated
45
+ - Potential gotchas or edge cases
46
+
47
+ ### Step 5: Summarize
48
+
49
+ End with:
50
+ - Key takeaways
51
+ - What the user should understand now
52
+ - Suggestions for further learning if applicable
53
+
54
+ ## Example Output
55
+
56
+ ```
57
+ ## Overview
58
+
59
+ This is a React custom hook that manages authentication state. It handles
60
+ login, logout, and automatic token refresh.
61
+
62
+ ## Line-by-Line Explanation
63
+
64
+ ### Lines 1-5: Imports
65
+ ```typescript
66
+ import { useState, useEffect, useCallback } from 'react';
67
+ import { authApi } from '@/services/api';
68
+ import { User } from '@/types';
69
+ ```
70
+ - Imports React hooks for state management and side effects
71
+ - Imports the auth API service for making authentication requests
72
+ - Imports the User type for type safety
73
+
74
+ ### Lines 7-15: Hook Definition and State
75
+ ```typescript
76
+ export function useAuth() {
77
+ const [user, setUser] = useState<User | null>(null);
78
+ const [loading, setLoading] = useState(true);
79
+ ```
80
+ - Creates a custom hook that can be used in any component
81
+ - `user` state holds the current user (or null if logged out)
82
+ - `loading` state tracks whether we're still checking auth status
83
+ - Starting with `loading: true` prevents flash of unauthenticated content
84
+
85
+ ### Lines 17-30: Auto-refresh Effect
86
+ [... continue explanation ...]
87
+
88
+ ## Key Concepts
89
+
90
+ 1. **Custom Hooks**: Reusable logic extracted from components
91
+ 2. **Optimistic Updates**: UI updates before server confirms
92
+ 3. **Token Refresh**: Automatic re-authentication before expiry
93
+
94
+ ## Takeaways
95
+
96
+ - This hook centralizes all auth logic in one place
97
+ - Components just need to call `useAuth()` to access auth state
98
+ - The refresh logic runs automatically in the background
99
+ ```
100
+
101
+ ## Tips for Users
102
+
103
+ Ask me to explain:
104
+ - "Explain this function" (paste code)
105
+ - "Explain src/hooks/useAuth.ts"
106
+ - "Explain lines 50-100 of api.ts"
107
+ - "What does this regex do?"
108
+ - "Why is this pattern used here?"
109
+
110
+ I'll adjust the depth based on what you ask. For simple code, I'll be brief. For complex code, I'll be thorough.